Files
ScadaBridge/docs/plans/2026-09-10-flow-debugger-method-params-design.md

3.7 KiB

Flow Debugger — method pane takes structured parameters (Gitea #37)

Date: 2026-09-10 · Status: approved (issue-authored spec) · Issue: #37

Problem

The Flow Debugger's Run inbound API method pane rendered one single-line text box per top-level schema field and coerced the text by declared type. For object / array fields it tried JsonNode.Parse on the raw text and, on failure, sent the text as a string; an empty box was silently omitted. A required array-of-object parameter (MesMoveOut WorkOrders, [{WorkOrderNumber, PartNumber}]) could not be entered from the page at all — the QA run reached the site with "WorkOrders":[] and the receiver rejected it with a misleading error. The same payload ran fine through flow-debug run-method --params, so only the UI input surface was at fault. The Run site script pane on the same page already uses the shared ParameterValueForm (typed inputs, nested groups, add/remove list editors, $ref:lib: resolution, inline validation, Monaco escape hatch for unresolved shapes).

Design

  1. The method pane renders ParameterValueForm driven by the method's ParameterDefinitions, keyed on the method id so a change of method remounts the form (the same reason the script pane keys on the script's canonical name). The page holds a _methodParams value tree + _methodParamsValid; BuildParameters() serializes the tree as-is, exactly like BuildScriptParameters(). The flat _inputs / Coerce() / SetInput path is deleted — a failed parse can no longer be sent as a string, and there is no type-specific coercion left on the page.
  2. Whole-payload raw-JSON escape hatch. The Inputs card gains a Form | Raw JSON toggle. Raw mode is a Monaco json editor given the method's root schema (the form's ToJsonSchema made internal static) so completion and hover work. Every edit parses the text and validates it with InboundApiSchema.Validate against the resolved root schema (ParseWithRefs + ISchemaLibraryQueryService, the same resolution the form does); errors render inline under the editor. Switching Form → Raw seeds the editor from the current value tree (indented); Raw → Form loads the last valid tree into the form. The value tree is the single source of truth in both modes.
  3. Run gating. CanRun for the method entry is method chosen && (no parameters || params valid), mirroring _scriptParamsValid. A required field left empty disables Run (the form reports validity on mount, so this holds before the first keystroke).
  4. Persistence. The per-method localStorage entry (flowDebugger.inputs.<id>) now stores the value tree as JSON. On restore the tree is converted back (the form's JsonElementToObject made internal static) and validated against the schema; an invalid tree is discarded. That also retires the old flat Dictionary<string,string> entries without a version flag: legacy strings that still validate (string fields) are kept, anything else is dropped.
  5. Not changed: the runner (FlowDebugRunMethodCommand), the CLI, prediction, Replay, the script pane. No wire, proto or schema change.

Tests

  • bUnit (FlowDebuggerPageTests): an array-of-object field (the WorkOrders shape) round-trips from the list item editors to the RunMethodAsync payload; invalid raw JSON blocks Run and shows the error; valid raw JSON sends exactly that payload; a required scalar left empty disables Run until filled; switching methods resets the form and its validity.
  • Playwright FlowDebuggerTests: the smoke selector moves from flow-input-Text to the form's #param-Text.

Docs

Component-CentralUI.md (Flow Debugger entry points), CLAUDE.md Flow Debugger bullet, this design doc.