perf(ui): shared KPI cache, live-cache-backed alarm summary, coalesced debug renders
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
@page "/monitoring/alarms"
|
||||
@attribute [Authorize(Policy = ZB.MOM.WW.ScadaBridge.Security.AuthorizationPolicies.RequireDeployment)]
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared
|
||||
@using ZB.MOM.WW.ScadaBridge.CentralUI.Services
|
||||
@using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites
|
||||
@@ -196,15 +197,25 @@
|
||||
@onkeydown='e => OnHeaderKeyDown(e, "severity")' @onkeydown:preventDefault="_preventHeaderDefault">Severity @SortGlyph("severity")</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@* Row markup is identical on both paths — the same <tr>, the same cells,
|
||||
the same data-test hook. Only WHO enumerates it differs: a plain
|
||||
foreach for the ordinary case, and Virtualize once the flat table
|
||||
gets long enough that rendering every row per delta dominates the
|
||||
circuit (arch-review WP2.4). Virtualize needs <tr> spacers or the
|
||||
browser hoists its <div>s out of the table and the layout collapses. *@
|
||||
<tbody>
|
||||
@foreach (var row in _visibleRows)
|
||||
@if (_visibleRows.Count <= VirtualizeThreshold)
|
||||
{
|
||||
<tr data-test="alarm-summary-row">
|
||||
<td class="font-monospace small">@row.InstanceUniqueName</td>
|
||||
<td>@row.Alarm.AlarmName</td>
|
||||
<td><AlarmStateBadges Alarm="row.Alarm" /></td>
|
||||
<td class="text-end font-monospace">@row.Alarm.Condition.Severity</td>
|
||||
</tr>
|
||||
@foreach (var row in _visibleRows)
|
||||
{
|
||||
@AlarmRow(row)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<Virtualize Items="_visibleRows" Context="row" ItemSize="37" SpacerElement="tr">
|
||||
@AlarmRow(row)
|
||||
</Virtualize>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -222,7 +233,23 @@
|
||||
// P4 (arch-review): the filtered+sorted view is memoized rather than recomputed
|
||||
// on every render. RecomputeVisibleRows() refreshes it whenever the inputs change
|
||||
// (a fresh snapshot in RefreshAsync, a filter change via @bind:after, or a sort).
|
||||
private IReadOnlyList<AlarmSummaryRow> _visibleRows = Array.Empty<AlarmSummaryRow>();
|
||||
// Concrete List because Virtualize binds ICollection<T>, not IReadOnlyList<T>.
|
||||
private List<AlarmSummaryRow> _visibleRows = new();
|
||||
|
||||
// Above this many visible rows the flat table switches to Virtualize. Below it the
|
||||
// plain foreach is cheaper than the virtualization machinery (and needs no JS), and
|
||||
// an operator filtered down to a handful of alarms should never pay for either.
|
||||
private const int VirtualizeThreshold = 150;
|
||||
|
||||
// One row template, shared by the plain and virtualized paths so the two can never
|
||||
// drift visually.
|
||||
private RenderFragment<AlarmSummaryRow> AlarmRow => row =>
|
||||
@<tr data-test="alarm-summary-row">
|
||||
<td class="font-monospace small">@row.InstanceUniqueName</td>
|
||||
<td>@row.Alarm.AlarmName</td>
|
||||
<td><AlarmStateBadges Alarm="row.Alarm" /></td>
|
||||
<td class="text-end font-monospace">@row.Alarm.Condition.Severity</td>
|
||||
</tr>;
|
||||
|
||||
private IReadOnlyList<string> _notReporting = Array.Empty<string>();
|
||||
private AlarmRollup _rollup = new(0, 0, 0, new Dictionary<AlarmKind, int>());
|
||||
|
||||
Reference in New Issue
Block a user