diff --git a/src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor b/src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor index be7ac4d..5fbab62 100644 --- a/src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor +++ b/src/ScadaLink.CentralUI/Components/Pages/Admin/Sites.razor @@ -10,20 +10,33 @@ @inject CommunicationService CommunicationService @inject AuthenticationStateProvider AuthStateProvider @inject NavigationManager NavigationManager +@inject IJSRuntime JS

Site Management

-
- + +
+ -
@@ -38,70 +51,109 @@ {
@_errorMessage
} + else if (_sites.Count == 0) + { +
+

No sites configured.

+ +
+ } else { - - - - - - - - - - - - - - - - - @if (_sites.Count == 0) - { - - - - } - @foreach (var site in _sites) - { - - - - - - - - - - - - - } - -
IDNameIdentifierDescriptionNode ANode BgRPC Node AgRPC Node BData ConnectionsActions
No sites configured.
@site.Id@site.Name@site.SiteIdentifier@(site.Description ?? "—")@(site.NodeAAddress ?? "—")@(site.NodeBAddress ?? "—")@(site.GrpcNodeAAddress ?? "—")@(site.GrpcNodeBAddress ?? "—") - @{ - var conns = _siteConnections.GetValueOrDefault(site.Id); - } - @if (conns != null && conns.Count > 0) +
+ +
+ + @if (!FilteredSites.Any()) + { +

No sites match the filter.

+ } + +
+ @foreach (var site in FilteredSites) + { + var conns = _siteConnections.GetValueOrDefault(site.Id); + var collapseId = $"cluster-{site.Id}"; +
+
+
+
+
+
@site.Name
+ @site.SiteIdentifier +
+
+ + +
+
+ +

+ @(string.IsNullOrWhiteSpace(site.Description) ? "—" : site.Description) +

+ +
Data connections
+ @if (conns is { Count: > 0 }) { - @foreach (var conn in conns) - { - @conn.Name (@conn.Protocol) - } +
    + @foreach (var c in conns) + { +
  • + @c.Protocol + @c.Name +
  • + } +
} else { - None +

No connections.

} -
- - - -
+ + +
+ @ClusterRow("Node A", site.NodeAAddress) + @ClusterRow("Node B", site.NodeBAddress) + @ClusterRow("gRPC A", site.GrpcNodeAAddress) + @ClusterRow("gRPC B", site.GrpcNodeBAddress) +
+ + + + } + } @@ -118,10 +170,18 @@ private string? _errorMessage; private bool _deploying; + private string _search = ""; private ToastNotification _toast = default!; private ConfirmDialog _confirmDialog = default!; + private IEnumerable FilteredSites => + string.IsNullOrWhiteSpace(_search) + ? _sites + : _sites.Where(s => + (s.Name?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false) || + (s.SiteIdentifier?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false)); + protected override async Task OnInitializedAsync() { await LoadDataAsync(); @@ -225,4 +285,36 @@ _deploying = false; } } + + private RenderFragment ClusterRow(string label, string? address) => __builder => + { +
+
@label
+
+ + @(string.IsNullOrWhiteSpace(address) ? "—" : address) + +
+
+ @if (!string.IsNullOrWhiteSpace(address)) + { + + } +
+
+ }; + + private async Task CopyAsync(string text) + { + try + { + await JS.InvokeVoidAsync("navigator.clipboard.writeText", text); + _toast.ShowSuccess("Copied to clipboard."); + } + catch + { + _toast.ShowError("Copy failed."); + } + } }