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

60 lines
3.7 KiB
Markdown

# 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.