0ce6633270
Direction B: the same FlowGraph steps as a filterable list (lane column, lane filter, failures-only), toggled from the flow panel toolbar. The mockup canvas is not in the repo, so this is the minimal faithful version. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
73 lines
2.8 KiB
C#
73 lines
2.8 KiB
C#
using System.Globalization;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.AspNetCore.Components.Web;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Debugging;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared;
|
|
|
|
/// <summary>
|
|
/// Vertical trace list over a <see cref="FlowGraph"/> (Flow Debugger mockup Direction B, Gitea #53): the
|
|
/// steps in display order with the lane as a column, filterable by lane and to failures only.
|
|
/// </summary>
|
|
public partial class FlowTraceList : ComponentBase
|
|
{
|
|
/// <summary>The real graph (from a run or a replay); null before a run.</summary>
|
|
[Parameter] public FlowGraph? Graph { get; set; }
|
|
|
|
/// <summary>The selected step's event id.</summary>
|
|
[Parameter] public Guid? SelectedEventId { get; set; }
|
|
|
|
/// <summary>Raised when a row is clicked or activated with Enter/Space.</summary>
|
|
[Parameter] public EventCallback<FlowStep> OnSelect { get; set; }
|
|
|
|
private string _laneFilter = "";
|
|
private bool _failedOnly;
|
|
|
|
private IReadOnlyList<(FlowStep Step, int Index)> Rows()
|
|
{
|
|
if (Graph == null) return Array.Empty<(FlowStep, int)>();
|
|
// The ordinal is the step's position in the whole flow, so it stays stable while filtering.
|
|
IEnumerable<(FlowStep, int)> q = Graph.Steps.Select((s, i) => (s, i));
|
|
if (Enum.TryParse<FlowLane>(_laneFilter, out var lane)) q = q.Where(t => t.Item1.Lane == lane);
|
|
if (_failedOnly) q = q.Where(t => IsFailure(t.Item1));
|
|
return q.ToList();
|
|
}
|
|
|
|
internal static bool IsFailure(FlowStep s) => s.Outcome is FlowStepOutcome.Failed or FlowStepOutcome.TimedOut;
|
|
|
|
private string Offset(FlowStep s)
|
|
{
|
|
var first = Graph!.Steps[0].OccurredAtUtc;
|
|
var ms = (s.OccurredAtUtc - first).TotalMilliseconds;
|
|
return "+" + ms.ToString("0", CultureInfo.InvariantCulture) + " ms";
|
|
}
|
|
|
|
private async Task OnKeyAsync(KeyboardEventArgs e, FlowStep s)
|
|
{
|
|
if (e.Key is "Enter" or " ") await OnSelect.InvokeAsync(s);
|
|
}
|
|
|
|
private static string PillClass(FlowStepOutcome outcome) => outcome switch
|
|
{
|
|
FlowStepOutcome.Ok => "ft-pill ok",
|
|
FlowStepOutcome.Pending => "ft-pill pending",
|
|
FlowStepOutcome.Parked => "ft-pill parked",
|
|
FlowStepOutcome.Failed or FlowStepOutcome.TimedOut => "ft-pill failed",
|
|
_ => "ft-pill",
|
|
};
|
|
|
|
internal static string KindLabel(FlowStepKind kind) => kind switch
|
|
{
|
|
FlowStepKind.InboundRequest => "Request",
|
|
FlowStepKind.RouteCall => "Route call",
|
|
FlowStepKind.ScriptRun => "Script run",
|
|
FlowStepKind.AttributeWrite => "Write",
|
|
FlowStepKind.AttributeWait => "Wait",
|
|
FlowStepKind.Response => "Response",
|
|
FlowStepKind.ApiCall => "API call",
|
|
FlowStepKind.DbCall => "Database",
|
|
FlowStepKind.Notify => "Notify",
|
|
_ => "Step",
|
|
};
|
|
}
|