Point at Gaffer and Navigator from the embedded UI - #5695
Conversation
Projections authored in this UI are click-ops: untracked, unreviewable, and impossible to test before they run in production. Surface Gaffer at the three places someone is most likely to be about to write one by hand. - Projections list: a dense ribbon under the page header, the whole band linking out. Unconditional on the working page, but inside the available-and-leader branch so it never stacks under the "not enabled" or "open projections on the leader" notices, which say something more urgent. - Projection detail: a link beside the Source heading, for user projections only. System projections ship with the server, so there is nothing to author locally and no link to offer. - Tools sidebar: a Gaffer entry below Navigator, opening in a new tab. - KurrentIcons.Gaffer: the logomark ported from Navigator, its "327 34 52 52" source viewBox mapped onto MudIcon's 24x24. - GafferLink: one home for the UTM contract. source/medium and the projections campaign match what Navigator sends for the same links, so both admin surfaces aggregate as one referral channel rather than two. Copy is sentence case per the handbook, and the ribbon reads as a label rather than a sentence so all four verbs fit on one 38px line.
The Tools entry led to a page whose whole content was a sentence, a download link and a screenshot. Replace it with the thing someone wanted from it: hand the browser a connection string for the node they are looking at, so an installed Navigator opens on it, and offer the download only when nothing claims the scheme. Mirrors the Cloud console's connect modal (bespin ui/src/components/modals/connect-modal/utils/openNavigator.ts), with three differences: - No credentials in the connection string. Cloud can assume its own default admin password; this UI never sees the signed-in user's, and a connection string is not the place for one. Navigator prompts instead. - tls=false when the node serves http, or Navigator attempts TLS against an insecure node and fails to connect, which reads as the deep link being broken. - Loss of page focus, not the return value of window.open, as the signal that something claimed the scheme. No browser API reports whether a protocol handler ran, so both are heuristics, but the returned window is truthy either way and never triggers the fallback. The connection string is built from the address the browser reached this node on rather than the node's advertised address, which can be cluster-internal and unreachable from the client. +discover only when gossip reports more than one member. InternalsVisibleTo on the host project so the string building can be tested without making the helpers public; every other project that needs this already declares it.
The embedded UI guide listed Navigator under "Other pages" and described a feature-comparison table, neither of which is true now that the page is gone and the entry opens the app. Split the sidebar's Tools section out from the pages, since these two links leave the UI rather than navigating it, and cover Gaffer alongside.
Deploying eventstore with
|
| Latest commit: |
c2cbbeb
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3a100354.eventstore.pages.dev |
| Branch Preview URL: | https://embedded-ui-tool-links.eventstore.pages.dev |
PR Summary by QodoAdd Gaffer links and Navigator deep-linking from the embedded UI
AI Description
Diagram
High-Level Assessment
Files changed (12)
|
Code Review by Qodo
1.
|
IsSystemProjection tested `Name` with a null-conditional, implying a nullability the route parameter does not have: OnInitializedAsync already dereferences it via Uri.UnescapeDataString, and LeaderUrl escapes it unguarded, so a null would have thrown well before this property was read. Dereference it directly, per the convention against fallbacks for values that are always expected. GafferLink interpolated its campaign and content straight into the query string. No caller passes a reserved character, but one that did would split the query and truncate the attribution silently rather than fail, so escape both. Covered by tests, including that nothing leaks into a new parameter.
Surfaces Gaffer from the projections pages, and turns the Tools sidebar's Navigator entry into a deep link at the node you are viewing.
Sidebar
Projections Overview
Projections detail
Components/Projections/Projections.razor— a dense 38px ribbon under the page header, the whole band linking out. It sits inside the available-and-leader branch so it never stacks under the "not enabled" or "open projections on the leader" notices, which say something more urgent.Components/Projections/ProjectionDetail.razor— a link beside the Source heading, for user projections only. System projections ship with the server, so there is nothing to author locally and no link to offer.Components/Layout/NavMenu.razor— a Gaffer entry in Tools, and Navigator now hands the browser akurrentdb://connection string built from the address the browser actually reached this node on, rather than the node's advertised address, which can be cluster-internal and unreachable from the client.+discoveronly when gossip reports more than one member.Components/Pages/Navigator.razor— deleted, withwwwroot/navigator.png(232K out of the binary). Its content was a sentence, a download link and a screenshot; the sidebar entry does that job directly.Components/Shared/GafferLink.cs,NavigatorLink.cs— outbound URL construction. Gaffer links are UTM-tagged with the same source/medium/campaign Navigator sends, so the two admin surfaces aggregate as one referral channel rather than two. The Navigator connection string deliberately carries no credentials — this UI never sees the signed-in user's password — and addstls=falsefor an http node, without which Navigator attempts TLS against an insecure server and fails to connect.UI/Theme/KurrentIcons.cs— the Gaffer logomark, ported from Navigator with its327 34 52 52source viewBox mapped onto MudIcon's 24x24.KurrentDB.csproj—InternalsVisibleToforKurrentDB.Components.Tests, so the URL building is testable without making the helpers public. Core, Api.V2 and others already declare the same.KurrentDB.Components.Tests: ribbon presence across the page's available, populated and subsystem-disabled states, the detail link's system/user gating, and the Navigator connection string's scheme selection, tls flag and explicit port.