Brings the Data Connections admin page up to the same UX standard as the Topology page: - Search box with dim non-matches (opacity 0.4, shape preserved) - Toolbar: + Connection (disabled until a site is selected), Refresh, Expand, Collapse - Site context menu gains "Add Connection here" that navigates with ?siteId= so the form preselects + locks the Site field - Form gains "Primary Endpoint" / "Backup Endpoint" h6 subsection headers matching the SiteForm convention; Failover Retry Count moved inside the Backup subsection - URL renamed: /admin/connections (primary) + /admin/data-connections (legacy secondary @page). Same dual-route treatment on the form - Nav label: "Data Connections" -> "Connections" - Adds DataConnectionsPageTests bUnit suite (6 tests)
7.8 KiB
7.8 KiB
Data Connections page — Topology-style refresh
Date: 2026-05-11 Status: Design
Goal
Bring the Data Connections admin page up to the same UX standard as the new Topology page (/deployment/topology). The page already uses TreeView and the form already navigates as a separate page, so the refresh is a layered enhancement, not a rewrite.
Decisions (captured from Q&A)
- Features to add (others explicitly excluded):
- Search with dim non-matches (opacity 0.4, shape preserved — Topology behavior)
- Toolbar: + Connection, Refresh, Expand, Collapse
- No per-node icons / protocol badges beyond what's already rendered
- No selection persistence via sessionStorage (selection is in-memory only)
- Site context menu gains an "Add Connection here" item that navigates to the create form with
?siteId=Npreselecting and locking the Site field. - + Connection toolbar button is disabled until a site is selected. Selecting either a site node or one of its connection nodes resolves to that site; the create form then preselects and locks Site.
- No move support — moving a connection between sites is out of scope (would require a net-new service method and has knock-on effects on
InstanceConnectionBinding). - Empty sites still appear at the top level (so they can be right-clicked to add a connection).
- URL renames:
- List page:
/admin/connections(primary) +/admin/data-connections(legacy secondary). - Form:
/admin/connections/createand/admin/connections/{Id}/edit(primary) +/admin/data-connections/createand/admin/data-connections/{Id}/edit(legacy secondaries). - Nav menu label changes from "Data Connections" to "Connections".
- List page:
- Form cleanup to match the canonical
SiteForm.razorstyle (perfeedback_form_layoutmemory):- Add explicit
<h6 class="text-muted border-bottom pb-1">subsection headers: Primary Endpoint and Backup Endpoint. - Move Failover Retry Count inside the Backup subsection (it only applies when backup is enabled).
- Site field stays first; read-only in edit mode; preselected & disabled when
?siteId=is passed on create.
- Add explicit
Files to modify
src/ScadaLink.CentralUI/Components/Pages/Admin/DataConnections.razor
- Add primary route
@page "/admin/connections"and secondary legacy@page "/admin/data-connections". - Inject
IJSRuntimeonly if needed (search doesn't need it; no sessionStorage). - Add toolbar row above the tree:
- Search input (
@bind="_searchText" @bind:event="oninput" @bind:after="OnSearchChanged") - btn-group with: + Connection (disabled-bind to
!HasSiteSelected), Refresh, Expand, Collapse.
- Search input (
- TreeView wiring:
- Add
@ref="_tree"and use_tree?.ExpandAll()/CollapseAll(). - Set
Selectable="true"andSelectedKeyChanged="OnTreeNodeSelected". Keep selected key in_selectedKey(in-memory only).
- Add
- Search dim:
- Recompute a
HashSet<string> _matchKeysof keys whose own label or any descendant's label contains the search text. - In
NodeContent, wrap the label<span>withstyle="opacity: 0.4"if a search is active and the node is not in_matchKeys.
- Recompute a
- Always-show-empty sites: current code already creates a Site node per Site regardless of children — keep as-is.
- Site context menu: add an item "Add Connection here" that navigates to
/admin/connections/create?siteId=@node.SiteId. - Connection context menu: keep Edit + Delete; update the Edit href to the new
/admin/connections/{id}/editpath.
src/ScadaLink.CentralUI/Components/Pages/Admin/DataConnectionForm.razor
- Add primary routes:
@page "/admin/connections/create" @page "/admin/connections/{Id:int}/edit" @page "/admin/data-connections/create" @page "/admin/data-connections/{Id:int}/edit" - Add
[SupplyParameterFromQuery] public int? SiteId { get; set; }. - On
OnInitializedAsync, ifIdis null andSiteIdhas a value, set_formSiteId = SiteId.Valueand render the Site field as a disabled<input>(same pattern as edit mode) — also set_siteNamefor display. - Reorganize fields to subsections per
SiteForm.razorreference:- Site (already first), Name, Protocol.
<h6 class="text-muted border-bottom pb-1">Primary Endpoint</h6>then Primary Endpoint Configuration.<h6 class="text-muted border-bottom pb-1">Backup Endpoint</h6>— collapsed (Add Backup Endpoint button) by default; when toggled on, render: Backup Configuration, Failover Retry Count, Remove Backup button.
GoBack()→NavigationManager.NavigateTo("/admin/connections").
src/ScadaLink.CentralUI/Components/Layout/NavMenu.razor
- Change
<NavLink class="nav-link" href="/admin/data-connections">Data Connections</NavLink>to:<NavLink class="nav-link" href="/admin/connections">Connections</NavLink>
tests/ScadaLink.CentralUI.PlaywrightTests/NavigationTests.cs
- Update the AdminNavLinks theory:
[InlineData("Data Connections", "/admin/data-connections")]→[InlineData("Connections", "/admin/connections")].
New tests
tests/ScadaLink.CentralUI.Tests/DataConnectionsPageTests.cs (new)
bUnit rendering tests, modeled after TopologyPageTests:
Renders_EmptyState_WhenNoSites— no sites configured.Renders_EmptySite_AsTopLevelNode— site with no connections still appears.Renders_SiteConnection_Nesting— connection nested under site after click-expand.Search_DimsNonMatches_PreservesShape— typing in search dims unmatched siblings.AddConnectionButton_DisabledUntilSiteSelected— toolbar+ Connectionisdisabledinitially, becomes enabled after clicking a site row.LegacyDataConnectionsRoute_IsDeclaredOnListPage— both/admin/connectionsand/admin/data-connectionsroutes are present (reflection check).
JSInterop stubs (TreeView calls treeviewStorage.load/save even when StorageKey isn't supplied — verify):
JSInterop.Setup<string?>("treeviewStorage.load", _ => true).SetResult(null);JSInterop.SetupVoid("treeviewStorage.save", _ => true);
Out of scope
- Moving connections between sites (would require new service method + binding consequences).
- Connection status indicators (live state) — DCL connection state isn't surfaced in this page; deferred.
- Drag-and-drop reorder.
- Selection persistence across page reloads.
Verification
dotnet buildclean.dotnet test tests/ScadaLink.CentralUI.Tests/ScadaLink.CentralUI.Tests.csproj— all green incl. new tests.- Existing Playwright NavigationTests pass with the updated label/URL.
- Browser smoke (after
bash docker/deploy.sh):/admin/data-connections(legacy bookmark) loads the same page as/admin/connections.-
- Connection disabled until a site is selected; then navigates with
?siteId=N; Site field is locked in the form.
- Connection disabled until a site is selected; then navigates with
- Right-click on an empty site → "Add Connection here" works.
- Search "OPC" dims non-matching connections (label-based search, case-insensitive).
- Expand / Collapse buttons work; Refresh re-fetches from repos.
- Form sections "Primary Endpoint" / "Backup Endpoint" render with the SiteForm-style headers; Failover Retry Count appears inside the Backup section only when backup is enabled.
Critical files
src/ScadaLink.CentralUI/Components/Pages/Admin/DataConnections.razorsrc/ScadaLink.CentralUI/Components/Pages/Admin/DataConnectionForm.razorsrc/ScadaLink.CentralUI/Components/Layout/NavMenu.razortests/ScadaLink.CentralUI.PlaywrightTests/NavigationTests.cstests/ScadaLink.CentralUI.Tests/DataConnectionsPageTests.cs(new)
Reference patterns
- TreeView usage with toolbar/search:
src/ScadaLink.CentralUI/Components/Pages/Deployment/Topology.razor - Form layout convention:
src/ScadaLink.CentralUI/Components/Pages/Admin/SiteForm.razor - bUnit harness for tree page:
tests/ScadaLink.CentralUI.Tests/TopologyPageTests.cs