fix(flow-debugger): method pane takes structured parameters via ParameterValueForm + raw-JSON escape hatch (#37)
The Run-inbound-API-method pane rendered one text box per top-level schema field and coerced the text on the page; an array/object field went through JsonNode.Parse and, on failure, was SENT AS A STRING, while an empty box was silently dropped. A required array-of-object parameter (MesMoveOut WorkOrders) could not be entered at all — QA runs reached the site with "WorkOrders":[]. - The method pane now renders the same shared ParameterValueForm the script pane uses (typed inputs, nested groups, add/remove list item editors, $ref:lib: resolution, inline validation), keyed on the method id so a change of method remounts it. The page keeps ONE value tree and BuildParameters() serializes it as-is; the flat _inputs / Coerce() / SetInput path is deleted. - Form | Raw JSON toggle: raw mode is a Monaco json editor for the whole request body, given the method's root schema for completion, parsed and schema-validated (InboundApiSchema.Validate) on every edit with the error inline. Entering raw mode seeds the editor from the tree; leaving it re-mounts the form over the last valid tree. - Run is disabled while the form or the raw document is invalid (a required field left empty disables Run before the first keystroke). - localStorage per-method entry stores the value tree; on restore it is validated against the schema and dropped if invalid, which also retires the pre-#37 flat string-per-field entries. - ParameterValueForm.ToJsonSchema / JsonElementToObject made internal static for page reuse. - Tests: 7 new bUnit tests (WorkOrders array-of-object round-trip to the RunMethodAsync payload, required list-item gating, invalid raw JSON blocks Run + shows parse/schema/non-object errors, valid raw JSON sent verbatim and survives the switch back to the form, method switch resets, persisted tree restored, legacy flat entry dropped); existing method-pane tests moved to the form's #param-<field> ids and fill the required field before Run. Playwright smoke selector moved to #param-Text. - Docs: design doc, Component-CentralUI.md entry-points bullet, CLAUDE.md. CentralUI.Tests 1425/1425 green; Playwright project builds. Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
This commit is contained in:
+39
-10
@@ -214,24 +214,53 @@
|
||||
<div class="col-lg-3">
|
||||
<div class="card fd-inputs" data-test="flow-inputs">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title text-muted">Inputs</h6>
|
||||
@if (_entry == EntryKind.Method)
|
||||
{
|
||||
@foreach (var f in _inputFields)
|
||||
@* Method entry (#37): the same typed ParameterValueForm the script pane uses —
|
||||
per-item list editors, nested object groups, inline validation — keyed on
|
||||
the method so a change of method remounts it; plus a whole-payload raw-JSON
|
||||
escape hatch to paste the exact body an external caller sends. Both edit
|
||||
one value tree, and Run stays disabled while it is invalid. *@
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h6 class="card-title text-muted mb-0">Inputs</h6>
|
||||
<div class="btn-group btn-group-sm" role="group" aria-label="Input mode">
|
||||
<button type="button" class="btn @(!_methodRawMode ? "btn-primary" : "btn-outline-secondary")"
|
||||
data-test="flow-input-mode-form" disabled="@_running" @onclick="() => SetMethodRawMode(false)">Form</button>
|
||||
<button type="button" class="btn @(_methodRawMode ? "btn-primary" : "btn-outline-secondary")"
|
||||
data-test="flow-input-mode-raw" disabled="@_running" @onclick="() => SetMethodRawMode(true)">Raw JSON</button>
|
||||
</div>
|
||||
</div>
|
||||
@if (_methodRawMode)
|
||||
{
|
||||
var field = f;
|
||||
<div class="mb-2">
|
||||
<label class="form-label form-label-sm">
|
||||
@field.Name
|
||||
<span class="text-muted">(@field.Schema.Type@(field.Required ? ", required" : ""))</span>
|
||||
</label>
|
||||
<input class="form-control form-control-sm" data-test="@("flow-input-" + field.Name)"
|
||||
value="@InputValue(field.Name)" @oninput="e => SetInput(field.Name, e.Value?.ToString())" disabled="@_running" />
|
||||
<div data-test="flow-method-raw">
|
||||
<MonacoEditor Language="json" Height="220px" ShowToolbar="false"
|
||||
JsonSchema="@MethodRawJsonSchema"
|
||||
Value="@_methodRawText"
|
||||
ValueChanged="@(v => SetMethodRawJson(v))" />
|
||||
@if (_methodRawError is { } rawError)
|
||||
{
|
||||
<div class="text-danger small mt-1" data-test="flow-method-raw-error">@rawError</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="form-text">The whole request body, validated against the method's parameter definitions.</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div data-test="flow-method-params">
|
||||
<ParameterValueForm @key="@_selectedMethodId"
|
||||
ParameterDefinitions="@_methods.FirstOrDefault(m => m.Id == _selectedMethodId)?.ParameterDefinitions"
|
||||
Values="_methodParams"
|
||||
ValuesChanged="@(v => OnMethodParamsChanged(v))"
|
||||
ValidChanged="@(ok => _methodParamsValid = ok)" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else if (SelectedScript is { } script)
|
||||
{
|
||||
<h6 class="card-title text-muted">Inputs</h6>
|
||||
@* A write kind is fired by writing its own trigger attribute — the operator
|
||||
supplies only the value. Every other kind is called directly with the
|
||||
parameters its definitions declare. *@
|
||||
|
||||
Reference in New Issue
Block a user