feat(central-ui): Retry/Discard a parked outbound node from the Flow Debugger with scope check, confirm and re-poll

The page wires FlowStepDetail's OnRetry/OnDiscard to IFlowDebugService.RetryOutboundAsync /
DiscardOutboundAsync behind the same site-scope re-check and confirm wording the Site Calls /
Notification report pages use, toasts the relay outcome, and on success re-polls Replay (same
5 s / 2 min loop) until the acted node leaves Parked. Also drops a duplicated ?correlationId=
test block that a concurrent index-only commit left in QueryStringDrillInTests.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
Joseph Doherty
2026-09-06 11:08:05 -04:00
parent 33f9c97030
commit 7f557b0ee5
5 changed files with 277 additions and 60 deletions
@@ -151,51 +151,6 @@ public sealed class QueryStringDrillInTests
Assert.Empty(cut.FindAll("[data-test='site-calls-filter-operation']"));
}
// -----------------------------------------------------------------
// SiteCallsReport — ?correlationId= (Flow Debugger / Audit Log deep link, D2)
// -----------------------------------------------------------------
[Fact]
public void SiteCallsReport_CorrelationIdQuery_SeedsTheOperationFilter()
{
// A well-formed GUID rides on the first query as the exact-match
// TrackedOperationIdFilter and renders the read-only Operation pill.
var op = Guid.Parse("44444444-4444-4444-4444-444444444444");
using var ctx = new SiteCallsReportFixture();
var nav = (BunitNavigationManager)ctx.Services.GetRequiredService<NavigationManager>();
nav.NavigateTo($"/site-calls/report?correlationId={op}");
var cut = ctx.Render<SiteCallsReportPage>();
cut.WaitForAssertion(() =>
{
Assert.Single(ctx.QueryRequests);
Assert.Equal(op, ctx.QueryRequests[0].TrackedOperationIdFilter);
var pill = cut.Find("[data-test='site-calls-filter-operation']");
Assert.Contains(op.ToString("N")[..12], pill.TextContent);
});
}
[Fact]
public void SiteCallsReport_CorrelationIdQuery_Malformed_IsIgnored()
{
// Lax parsing, like ?status= — a value that is not a GUID leaves the
// filter null and renders no pill, so a hand-crafted bad URL loads the
// page unfiltered instead of breaking it.
using var ctx = new SiteCallsReportFixture();
var nav = (BunitNavigationManager)ctx.Services.GetRequiredService<NavigationManager>();
nav.NavigateTo("/site-calls/report?correlationId=nope");
var cut = ctx.Render<SiteCallsReportPage>();
cut.WaitForAssertion(() =>
{
Assert.Single(ctx.QueryRequests);
Assert.Null(ctx.QueryRequests[0].TrackedOperationIdFilter);
});
Assert.Empty(cut.FindAll("[data-test='site-calls-filter-operation']"));
}
// -----------------------------------------------------------------
// NotificationReport — ?correlationId= (Flow Debugger follow-ups, D2)
// -----------------------------------------------------------------