feat(central-ui): Flow Debugger script entry — site/instance/script picker, value field or ParameterValueForm by trigger kind

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
Joseph Doherty
2026-09-08 01:21:30 -04:00
parent acf4ab3d4d
commit 6fe67e147c
3 changed files with 217 additions and 59 deletions
@@ -24,8 +24,8 @@
<div class="btn-group btn-group-sm d-block" role="group" aria-label="Entry point">
<button type="button" class="btn @(_entry == EntryKind.Method ? "btn-primary" : "btn-outline-secondary")"
data-test="flow-entry-method" disabled="@_running" @onclick="() => SetEntryAsync(EntryKind.Method)">Inbound API method</button>
<button type="button" class="btn @(_entry == EntryKind.ValueChange ? "btn-primary" : "btn-outline-secondary")"
data-test="flow-entry-value-change" disabled="@_running" @onclick="() => SetEntryAsync(EntryKind.ValueChange)">Value-change trigger</button>
<button type="button" class="btn @(_entry == EntryKind.Script ? "btn-primary" : "btn-outline-secondary")"
data-test="flow-entry-script" disabled="@_running" @onclick="() => SetEntryAsync(EntryKind.Script)">Site script</button>
</div>
</div>
}
@@ -70,14 +70,14 @@
}
</select>
</div>
<div class="col-md-2">
<label class="form-label form-label-sm">Attribute</label>
<select class="form-select form-select-sm" data-test="flow-attribute-select"
@bind="_selectedAttribute" @bind:after="OnAttributeChangedAsync" disabled="@(_running || _selectedInstanceId == 0)">
<div class="col-md-3">
<label class="form-label form-label-sm">Script</label>
<select class="form-select form-select-sm" data-test="flow-script-select"
@bind="_selectedScript" @bind:after="OnScriptChangedAsync" disabled="@(_running || _selectedInstanceId == 0)">
<option value="">— choose —</option>
@foreach (var a in _attributes)
@foreach (var s in _scripts)
{
<option value="@a">@a</option>
<option value="@s.CanonicalName">@s.CanonicalName (@s.TriggerLabel)</option>
}
</select>
</div>
@@ -193,7 +193,7 @@
<div class="row g-3">
@* ── Inputs (Live only) ────────────────────────────────────────────── *@
@if (_mode == FlowMode.Live && (_entry == EntryKind.ValueChange || _inputFields.Count > 0))
@if (_mode == FlowMode.Live && (_entry == EntryKind.Script ? SelectedScript != null : _inputFields.Count > 0))
{
<div class="col-lg-3">
<div class="card fd-inputs" data-test="flow-inputs">
@@ -214,13 +214,33 @@
</div>
}
}
else
else if (SelectedScript is { } script)
{
<div class="mb-2">
<label class="form-label form-label-sm">New value for <span class="font-monospace">@(_selectedAttribute == "" ? "…" : _selectedAttribute)</span></label>
<input class="form-control form-control-sm" data-test="flow-input-value"
@bind="_valueChangeValue" @bind:event="oninput" disabled="@_running" />
</div>
@* 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. *@
@if (script.IsWriteKind)
{
<div class="mb-2">
<label class="form-label form-label-sm">New value for <span class="font-monospace">@(script.TriggerAttribute ?? "…")</span></label>
<input class="form-control form-control-sm" data-test="flow-input-value"
@bind="_valueChangeValue" @bind:event="oninput" disabled="@_running" />
<div class="form-text">@script.TriggerType trigger — writing the attribute fires the script.</div>
</div>
}
else if (string.IsNullOrWhiteSpace(script.ParameterDefinitions))
{
<div class="text-muted small" data-test="flow-script-no-params">This script takes no parameters.</div>
}
else
{
<div data-test="flow-script-params">
<ParameterValueForm ParameterDefinitions="@script.ParameterDefinitions"
Values="_scriptParams"
ValuesChanged="@(v => _scriptParams = v)"
ValidChanged="@(ok => _scriptParamsValid = ok)" />
</div>
}
}
</div>
</div>
@@ -228,7 +248,7 @@
}
@* ── Flow panel ────────────────────────────────────────────────────── *@
<div class="@(_mode == FlowMode.Live && (_entry == EntryKind.ValueChange || _inputFields.Count > 0) ? "col-lg-9" : "col-12")">
<div class="@(_mode == FlowMode.Live && (_entry == EntryKind.Script ? SelectedScript != null : _inputFields.Count > 0) ? "col-lg-9" : "col-12")">
<div class="fd-flow-tools">
<div class="small text-muted">
@if (_graph == null && _predicted != null)
@@ -254,8 +274,8 @@
@* Retry / Discard relay a command to the site — only wired for a Deployer, so the
buttons never render for an auditor (arch-review F3). *@
<FlowStepDetail Step="_selected" Graph="_graph"
SiteDbId="@(_entry == EntryKind.ValueChange && _selectedSiteId > 0 ? _selectedSiteId : null)"
InstanceDbId="@(_entry == EntryKind.ValueChange && _selectedInstanceId > 0 ? _selectedInstanceId : null)"
SiteDbId="@(_entry == EntryKind.Script && _selectedSiteId > 0 ? _selectedSiteId : null)"
InstanceDbId="@(_entry == EntryKind.Script && _selectedInstanceId > 0 ? _selectedInstanceId : null)"
OnRetry="RetryCallback" OnDiscard="DiscardCallback"
ActionInProgress="_actionInProgress" />
</div>