feat(central-ui): Flow Debugger drill-ins from Audit Log + Execution Chain; TraceAllCalls checkbox on the method form

'Open in Flow Debugger' (data-test open-flow-debugger) beside 'View execution chain' in
AuditEventDetail (rendered only with an ExecutionId) and beside 'View this execution in
the Audit Log' on the Execution Chain page — both target
/deployment/flow-debugger?executionId=… which replays on first render. ApiMethodForm gains a
'Trace all calls (Flow Debugger)' form-check under Timeout, loaded from and saved to
ApiMethod.TraceAllCalls on both the update and create paths, with the ~7-rows-per-call
guidance as help text.

Claude-Session: https://claude.ai/code/session_01GSLkkHKz9JrAtmJjmQK3cP
This commit is contained in:
Joseph Doherty
2026-09-06 00:33:37 -04:00
parent 254118a467
commit 66d5a67e4f
5 changed files with 135 additions and 2 deletions
@@ -164,5 +164,10 @@
@onclick="ViewExecutionChain">
View execution chain
</button>
<button class="btn btn-outline-secondary btn-sm"
data-test="open-flow-debugger"
@onclick="OpenInFlowDebugger">
Open in Flow Debugger
</button>
}
</div>
@@ -295,6 +295,16 @@ public partial class AuditEventDetail
Navigation.NavigateTo(uri);
}
/// <summary>
/// Flow Debugger replay drill-in (design 2026-09-05 §4): rebuilds this execution's
/// whole flow — inbound row, route call, traced site steps — as a swimlane.
/// </summary>
private void OpenInFlowDebugger()
{
if (Event.ExecutionId is not { } exec) return;
Navigation.NavigateTo($"/deployment/flow-debugger?executionId={exec}");
}
/// <summary>
/// Build a cURL command from an audit event. The URL comes from
/// <c>Target</c>; when the RequestSummary parses as
@@ -39,12 +39,17 @@
}
else if (_nodes is { Count: > 0 })
{
<div class="mb-2">
<div class="mb-2 d-flex flex-wrap gap-2">
<a class="btn btn-outline-secondary btn-sm"
data-test="execution-tree-back-to-log"
href="@($"/audit/log?executionId={_executionId}")">
View this execution in the Audit Log
</a>
<a class="btn btn-outline-secondary btn-sm"
data-test="open-flow-debugger"
href="@($"/deployment/flow-debugger?executionId={_executionId}")">
Open in Flow Debugger
</a>
</div>
<ExecutionTree Nodes="_nodes" ArrivedFromExecutionId="_executionId.Value"
OnNodeActivated="HandleNodeActivated" />
@@ -35,10 +35,22 @@
<label class="form-label">Name</label>
<input type="text" class="form-control" @bind="_name" disabled="@Id.HasValue" />
</div>
<div class="mb-0">
<div class="mb-3">
<label class="form-label">Timeout (seconds)</label>
<input type="number" class="form-control" @bind="_timeoutSeconds" min="1" />
</div>
<div class="form-check mb-0">
<input class="form-check-input" type="checkbox" id="api-method-trace-all-calls"
data-test="api-method-trace-all-calls" @bind="_traceAllCalls" />
<label class="form-check-label" for="api-method-trace-all-calls">
Trace all calls (Flow Debugger)
</label>
<div class="form-text">
Every call to this method records its routed site steps as audit rows the
Flow Debugger can replay. Adds ~7 audit rows per call; for low-volume
integration methods.
</div>
</div>
</fieldset>
<fieldset class="mb-4">
@@ -211,6 +223,7 @@
private bool _loading = true;
private string _name = "", _script = "";
private int _timeoutSeconds = 30;
private bool _traceAllCalls;
private string? _params, _returns;
private string? _formError;
private MonacoEditor? _editor;
@@ -253,6 +266,7 @@
_name = _existing.Name;
_script = _existing.Script;
_timeoutSeconds = _existing.TimeoutSeconds;
_traceAllCalls = _existing.TraceAllCalls;
_params = _existing.ParameterDefinitions;
_returns = _existing.ReturnDefinition;
// Seed approved keys from the seam: which keys' scopes contain this method.
@@ -291,6 +305,7 @@
{
_existing.Script = _script;
_existing.TimeoutSeconds = _timeoutSeconds;
_existing.TraceAllCalls = _traceAllCalls;
_existing.ParameterDefinitions = _params?.Trim();
_existing.ReturnDefinition = _returns?.Trim();
await InboundApiRepository.UpdateApiMethodAsync(_existing);
@@ -301,6 +316,7 @@
var m = new ApiMethod(_name.Trim(), _script)
{
TimeoutSeconds = _timeoutSeconds,
TraceAllCalls = _traceAllCalls,
ParameterDefinitions = _params?.Trim(),
ReturnDefinition = _returns?.Trim()
};