Files
lmxopcua/src/Server/ZB.MOM.WW.OtOpcUa.Admin/Components/Pages/Home.razor
Joseph Doherty 43291d7fdd fix(admin): add InteractiveServer render mode to all interactive Blazor pages; fix wrong hub URLs
Eight pages were using @onclick handlers, Timers, or HubConnections but had no @rendermode,
causing interactivity to be silently dead under static SSR. Added @rendermode RenderMode.InteractiveServer
(with the required @using Microsoft.AspNetCore.Components.Web) to: AlarmsHistorian, Certificates,
Fleet, Home, Hosts, Reservations, DraftEditor, and ImportEquipment.

Also fixed two hub URL bugs: AclsTab and RedundancyTab were connecting to the non-existent
/hubs/fleet-status path; corrected to /hubs/fleet which matches the MapHub<FleetStatusHub>
call in Program.cs. Build: 0 errors, 0 warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 04:24:29 -04:00

106 lines
3.7 KiB
Plaintext

@page "/"
@using Microsoft.AspNetCore.Components.Web
@using ZB.MOM.WW.OtOpcUa.Admin.Services
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
@rendermode RenderMode.InteractiveServer
@inject ClusterService ClusterSvc
@inject GenerationService GenerationSvc
@inject NavigationManager Nav
<h1 class="page-title">Fleet overview</h1>
@if (_clusters is null)
{
<section class="panel rise" style="animation-delay:.02s">
<div class="panel-head">Loading</div>
<div style="padding:1.4rem;color:var(--ink-faint);font-style:italic">Loading fleet&hellip;</div>
</section>
}
else if (_clusters.Count == 0)
{
<section class="panel notice rise" style="animation-delay:.02s">
No clusters configured yet. <a href="/clusters/new">Create the first cluster</a>.
</section>
}
else
{
<section class="agg-grid rise" style="animation-delay:.02s">
<div class="agg-card">
<div class="agg-label">Clusters</div>
<div class="agg-value numeric">@_clusters.Count</div>
</div>
<div class="agg-card">
<div class="agg-label">Active drafts</div>
<div class="agg-value numeric">@_activeDraftCount</div>
</div>
<div class="agg-card">
<div class="agg-label">Published generations</div>
<div class="agg-value numeric">@_publishedCount</div>
</div>
<div class="agg-card @(_disabledCount > 0 ? "caution" : "")">
<div class="agg-label">Disabled clusters</div>
<div class="agg-value numeric">@_disabledCount</div>
</div>
</section>
<section class="panel rise" style="animation-delay:.08s">
<div class="panel-head">Clusters</div>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr>
<th>Cluster ID</th>
<th>Name</th>
<th>Enterprise / Site</th>
<th>Redundancy</th>
<th>State</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var c in _clusters)
{
<tr @onclick="@(() => Nav.NavigateTo($"/clusters/{c.ClusterId}"))">
<td class="mono">@c.ClusterId</td>
<td>@c.Name</td>
<td>@c.Enterprise / @c.Site</td>
<td class="mono">@c.RedundancyMode</td>
<td>
@if (c.Enabled)
{
<span class="chip chip-ok">enabled</span>
}
else
{
<span class="chip chip-idle">disabled</span>
}
</td>
<td><a href="/clusters/@c.ClusterId">Open</a></td>
</tr>
}
</tbody>
</table>
</div>
</section>
}
@code {
private List<ServerCluster>? _clusters;
private int _activeDraftCount;
private int _publishedCount;
private int _disabledCount;
protected override async Task OnInitializedAsync()
{
_clusters = await ClusterSvc.ListAsync(CancellationToken.None);
_disabledCount = _clusters.Count(c => !c.Enabled);
foreach (var c in _clusters)
{
var gens = await GenerationSvc.ListRecentAsync(c.ClusterId, 50, CancellationToken.None);
_activeDraftCount += gens.Count(g => g.Status.ToString() == "Draft");
_publishedCount += gens.Count(g => g.Status.ToString() == "Published");
}
}
}