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; /// /// Vertical trace list over a (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. /// public partial class FlowTraceList : ComponentBase { /// The real graph (from a run or a replay); null before a run. [Parameter] public FlowGraph? Graph { get; set; } /// The selected step's event id. [Parameter] public Guid? SelectedEventId { get; set; } /// Raised when a row is clicked or activated with Enter/Space. [Parameter] public EventCallback 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(_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", }; }