Repository navigation
feat(ws7): generic top-bar menus from data + AI menu entries as contributions - #1652
Conversation
…ibutions Slice 3 of design #1645, generalized per maintainer direction: ANY top-bar menu can now be injected as data, not just entries into compiled menus. - UiContribution gains Href (overrides the derived area URL — catalog-style links), Tooltip/TooltipKey, and the TopBar context: a contribution there declares a whole NEW top-bar dropdown — its Area names the menu's context key, Label/Icon/Order/Tooltip style the button, entries are ordinary contributions targeting that key, and the closed gate vocabulary applies to the declaration (an AdminOnly menu disappears wholesale). - The menu renderer's context list now unions the contexts declared by data (snapshot per render via UiContributionCatalog.Current), so $Menu:{key} slots exist for data-declared menus; LayoutAreaView pumps the TopBar stream and subscribes each declared key as it appears; PortalLayoutBase renders one dropdown per declaration after the compiled menus, hidden while it has no visible entries (the GitHub pattern). - The AI menu's six navigation entries (Threads/Models/Tiers/Providers/ Agents/Skills) migrate to seeded UiContribution nodes (AiMenuContributions); only the imperative "New thread" click-action sentinel stays compiled — behavior, which the closed vocabulary deliberately cannot express. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The UiExtensibility page gains the composition-first section: the closed field vocabulary (contexts incl. TopBar, Href/Tooltip, grouping, gates), the security boundary, settings-tab and top-bar-menu semantics, and the seeding pattern; the seams table points menus/settings/top-bar at the data lane first. DocumentationLinkIntegrityTest green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR extends the WS7 UiContribution mechanism to allow data-declared top-bar dropdown menus (via a reserved TopBar context), and migrates the AI menu’s pure navigation entries to seeded UiContribution nodes so plugins and platform content share the same contribution lane.
Changes:
- Add
UiContribution.Href+ tooltip fields and project them intoNodeMenuItemDefinition(withHrefoverriding derived area URLs). - Introduce
TopBaras a reserved contribution context to declare new top-bar dropdowns, and wire the portal to subscribe/render them dynamically. - Move AI menu navigation entries (Threads/Models/Tiers/Providers/Agents/Skills) to seeded
UiContributionnodes; keep only the imperative “New thread” entry compiled.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/MeshWeaver.Graph.Test/UiContributionProjectionTest.cs | Adds projection tests for Href override, tooltip carry-through, and TopBar declarations. |
| test/Memex.Portal.Shared.Test/AiMenuNewThreadTest.cs | Updates AI menu tests for the split between the compiled sentinel and seeded navigation contributions. |
| src/MeshWeaver.Graph/Configuration/UiContributionProjection.cs | Projects Href/tooltips into NodeMenuItemDefinition and supports explicit navigation links. |
| src/MeshWeaver.Graph/Configuration/UiContributionNodeType.cs | Extends UiContribution with TopBar context and new Href/tooltip fields. |
| src/MeshWeaver.Graph/Configuration/UiContributionCatalog.cs | Adds a synchronous Current snapshot for render-time context enumeration. |
| src/MeshWeaver.Graph/Configuration/NodeMenuItemsExtensions.cs | Unions menu contexts declared by UiContribution data (including TopBar-declared menu keys). |
| src/MeshWeaver.Blazor/Components/LayoutAreaView.razor.cs | Subscribes to TopBar declarations and dynamically subscribes each declared menu key’s entry stream. |
| src/MeshWeaver.Blazor.Portal/Layout/PortalLayoutBase.razor.css | Styles contributed top-bar menu icons (emoji/img) to match Fluent sizing/contrast. |
| src/MeshWeaver.Blazor.Portal/Layout/PortalLayoutBase.razor.cs | Tracks and renders contributed top-bar menus and their per-key subscriptions. |
| src/MeshWeaver.Blazor.Portal/Layout/PortalLayoutBase.razor | Renders one top-bar dropdown per declaration, hidden when its entry list is empty. |
| memex/Memex.Portal.Shared/MemexConfiguration.cs | Removes compiled AI navigation items; wires AddAiMenuContributions(). |
| memex/Memex.Portal.Shared/AiMenuContributions.cs | Adds seeded UiContribution nodes for AI menu navigation entries. |
Suppressed comments (1)
src/MeshWeaver.Graph/Configuration/UiContributionNodeType.cs:79
- The Context documentation lists
AiMenu, but the actual AI-menu context value used elsewhere is"AI"(see NodeMenuItemsExtensions.AiMenuContext). Also, now that TopBar is a reserved context, it should be included in this summary so plugin authors don’t discover it only by reading other docs.
/// <summary>
/// Which menu the entry contributes to: <c>Node</c>, <c>Mesh</c>, <c>Settings</c>,
/// <c>AiMenu</c> or <c>SidePanel</c>. Unset ⇒ <c>Node</c>.
/// </summary>
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results (shard 0)913 tests 912 ✅ 11m 20s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Test Results (shard 5)1 367 tests 1 366 ✅ 6m 5s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Test Results (shard 4)1 541 tests 1 535 ✅ 7m 27s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Test Results (shard 3) 11 files 11 suites 5m 54s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Test Results (shard 2)2 366 tests 2 362 ✅ 7m 55s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Test Results (shard 1)2 178 tests 2 075 ✅ 6m 54s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Test Results 65 files 65 suites 45m 38s ⏱️ Results for commit a153f37. ♻️ This comment has been updated with latest results. |
Href is mesh data reaching NavigationManager: schemes (javascript:, https:) and protocol-relative //host forms are an XSS/phishing surface the closed vocabulary must not open. The compiled gate accepts only single-slash-rooted paths; anything else falls back to the derived area URL. Pinned with a 4-case theory; external links stay a compiled concern until an explicit allowlist vocabulary exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Slice 3 of #1645, generalized per the maintainer's direction: any top-bar menu can be injected as data, not just entries into the compiled menus.
The generic mechanism
UiContributiongainsHref(overrides the derived area URL — catalog-style absolute links),Tooltip/TooltipKey, and a reservedTopBarcontext: a contribution there declares a whole NEW top-bar dropdown. ItsAreanames the menu's own context key;Label/Icon/Order/Tooltipstyle the button; its entries are ordinary contributions targeting that key. The closed gate vocabulary applies to the declaration itself — anAdminOnlymenu disappears wholesale for non-admins, and a menu with no visible entries renders nothing.UiContributionCatalog.Current), so$Menu:{key}slots exist for data-declared menus.LayoutAreaViewpumps the TopBar stream and subscribes each declared key the first time it appears (registered on the area stream, same teardown as the fixed menus).PortalLayoutBaserenders one dropdown per declaration after the compiled menus, hidden while empty (the GitHub-menu pattern), with string icons (emoji/svg) sized to match the Fluent buttons.The AI menu migration
The six navigation entries (Threads / Models / Tiers / Providers / Agents / Skills) become seeded
UiContributionnodes (AiMenuContributions,Admin/UiContribution/*) — pure links, so they ride the same lane a plugin's AI-menu entry arrives through. Only the imperative New thread click-action sentinel stays compiled (AiMenuItems): its destination resolves from the circuit's viewer identity at click time — behavior, which the closed vocabulary deliberately cannot express. The side panel's three entries (new-chat/history/fullscreen) are likewise behavior sentinels and stay compiled; plugins can already contributeSidePanel-context entries through the generic lane.No visible change for users: the AI menu renders identically (labels, icons, order, tooltips, localization keys all pre-existing — no i18n catalog change, no react mirror change). Anonymous viewers never saw these menus (the block is inside
AuthorizeView), so the contribution permission floor changes nothing.Verification
MeshWeaver.Graph,MeshWeaver.Blazor.Portal,Memex.Portal.Shared,Memex.Portal.Monolithbuild clean-c Release -warnaserror.MeshWeaver.Graph.Test1162/1162 (new pins: Href override + tooltip carry-through; TopBar declaration projects only in the TopBar context and honors AdminOnly),Memex.Portal.Shared.Test361/361 (AiMenuNewThreadTest repointed: single compiled entry, seeds all Href-navigating + localized, uniqueness spans both lists).No What's New entry: platform capability for plugin authors; the rendered UI is unchanged (same precedent as #1646/#1648).
🤖 Generated with Claude Code