feat(webui): expose stable product destinations
Module Package Release / publish-packages (push) Successful in 13s

This commit is contained in:
2026-08-24 18:06:52 +02:00
parent 9a3008002d
commit ac40774785
27 changed files with 532 additions and 68 deletions
+62 -1
View File
@@ -18,7 +18,10 @@ import {
visibleRoutesForProjection
} from "../src/platform/views";
import { groupNavigationItems } from "../src/platform/productAreas";
import { composeProductSurfaces } from "../src/platform/productSurfaces";
import {
composeProductSurfaces,
projectProductNavigation
} from "../src/platform/productSurfaces";
import { hasAnyScope, scopeGrants } from "../src/utils/permissions";
function assert(condition: unknown, message: string): void {
@@ -260,6 +263,64 @@ assert(composedMessages[0]?.entryPath === "/messages", "the composed identity sh
assert(composedMessages[0]?.contributors.map((item) => item.moduleId).join(",") === "mail,postbox", "composition should retain ordered technical provenance");
assert(composedMessages[0]?.aliases.join(",") === "/inbox", "migration aliases should be de-duplicated across owners");
const messageNavigation = projectProductNavigation(
[
{ to: "/dashboard", label: "Dashboard", order: 1 },
{ to: "/mail", label: "Mail", order: 50, anyOf: ["mail:mailbox:read"] },
{ to: "/postbox", label: "Postbox", order: 51, anyOf: ["postbox:message:read"] },
{ to: "/admin", label: "Administration", order: 90, anyOf: ["core:admin:read"] }
],
messageSurfaceModules,
{ scopes: ["mail:mailbox:read", "postbox:message:read"] } as AuthInfo
);
assert(
messageNavigation.primaryItems.map((item) => item.to).join(",") === "/dashboard,/messages",
"ordinary navigation should replace authorized owner routes with one stable product entry"
);
assert(
messageNavigation.primaryItems.find((item) => item.to === "/messages")?.activePaths?.includes("/postbox"),
"the product entry should remain active on an owner route"
);
assert(
messageNavigation.allToolItems.map((item) => item.to).join(",") === "/dashboard,/mail,/postbox",
"the explicit tool catalogue should retain authorized technical routes"
);
const mailOnlyNavigation = projectProductNavigation(
[
{ to: "/mail", label: "Mail", order: 50, anyOf: ["mail:mailbox:read"] },
{ to: "/postbox", label: "Postbox", order: 51, anyOf: ["postbox:message:read"] }
],
messageSurfaceModules,
{ scopes: ["mail:mailbox:read"] } as AuthInfo
);
assert(
mailOnlyNavigation.primaryItems.map((item) => item.to).join(",") === "/messages",
"composition should remain stable when only one optional contributor is authorized"
);
assert(
mailOnlyNavigation.allToolItems.map((item) => item.to).join(",") === "/mail",
"the tool catalogue must not disclose unauthorized owner routes"
);
const focusedMessageNavigation = projectProductNavigation(
[{ to: "/mail", label: "Mail", order: 50, anyOf: ["mail:mailbox:read"] }],
messageSurfaceModules,
{ scopes: ["mail:mailbox:read", "postbox:message:read"] } as AuthInfo,
null,
[
{ to: "/mail", label: "Mail", order: 50, anyOf: ["mail:mailbox:read"] },
{ to: "/postbox", label: "Postbox", order: 51, anyOf: ["postbox:message:read"] }
]
);
assert(
focusedMessageNavigation.primaryItems.map((item) => item.to).join(",") === "/messages",
"a focused View should keep the selected stable product destination"
);
assert(
focusedMessageNavigation.allToolItems.map((item) => item.to).join(",") === "/mail,/postbox",
"All available tools should provide an explicit permission-derived escape from View focus"
);
const viewAwareFiles: PlatformWebModule = {
...files,
navItems: [{ to: "/files", label: "Files", order: 20, anyOf: ["files:file:read"] }],