Track HiveGrid Cloud planning reference

This commit is contained in:
david committed 2026-06-26 20:48:01 +02:00
1 parent b3d5ea6764
commit e341c5938a
5784 files changed
+1104929 -3

No files matched your search

@@ -0,0 +1,76 @@
import { describe, expect, it } from "vitest";
import { buttonAdapterNames, buttonAdapters } from "@toolctrl/ui/buttons";
import { layoutAdapterNames, layoutAdapters } from "@toolctrl/ui/layout";
import { navigationAdapterNames, navigationAdapters } from "@toolctrl/ui/navigation";
describe("@toolctrl/ui button adapter contract", () => {
it("exposes the first available button adapter targets without importing React components", () => {
expect(buttonAdapterNames).toEqual(["Button", "buttonVariants"]);
expect(buttonAdapters).toEqual([
expect.objectContaining({
category: "buttons",
name: "Button",
status: "available",
source: "apps/web/app/components/ui/button.tsx",
implementation: "shadcn/radix",
packageExport: "@toolctrl/ui/buttons",
}),
expect.objectContaining({
category: "buttons",
name: "buttonVariants",
status: "available",
source: "apps/web/app/components/ui/button.tsx",
implementation: "shadcn/radix",
packageExport: "@toolctrl/ui/buttons",
}),
]);
});
});
describe("@toolctrl/ui shell and navigation adapter contracts", () => {
it("exposes available layout adapter targets without importing React components", () => {
expect(layoutAdapterNames).toEqual(["ShadcnSidebarLayout", "UiRegistry"]);
expect(layoutAdapters).toEqual([
expect.objectContaining({
category: "layout",
name: "ShadcnSidebarLayout",
status: "available",
source: "apps/web/app/components/layouts/sidebars/shadcn/ShadcnSidebarLayout.tsx",
implementation: "shell-layout",
packageExport: "@toolctrl/ui/layout",
}),
expect.objectContaining({
category: "layout",
name: "UiRegistry",
status: "available",
source: "apps/web/app/application/ui/uiRegistry.ts",
implementation: "agent-registry",
packageExport: "@toolctrl/ui/layout",
}),
]);
});
it("exposes available navigation adapter targets without importing React components", () => {
expect(navigationAdapterNames).toEqual([
"AppSidebar",
"AdminSidebar",
"DocsSidebar",
"NavMain",
"NavSecondary",
"NavQuickLinks",
"NavActions",
"SidebarPrimitives",
]);
expect(navigationAdapters).toEqual([
expect.objectContaining({ name: "AppSidebar", source: "apps/web/app/application/sidebar/AppSidebar.tsx" }),
expect.objectContaining({ name: "AdminSidebar", source: "apps/web/app/application/sidebar/AdminSidebar.tsx" }),
expect.objectContaining({ name: "DocsSidebar", source: "apps/web/app/application/sidebar/DocsSidebar.ts" }),
expect.objectContaining({ name: "NavMain", source: "apps/web/app/components/layouts/sidebars/shadcn/nav-main.tsx" }),
expect.objectContaining({ name: "NavSecondary", source: "apps/web/app/components/layouts/sidebars/shadcn/nav-secondary.tsx" }),
expect.objectContaining({ name: "NavQuickLinks", source: "apps/web/app/components/layouts/sidebars/shadcn/nav-quick-links.tsx" }),
expect.objectContaining({ name: "NavActions", source: "apps/web/app/components/layouts/sidebars/shadcn/nav-actions.tsx" }),
expect.objectContaining({ name: "SidebarPrimitives", source: "apps/web/app/components/ui/sidebar.tsx" }),
]);
expect(navigationAdapters.every((adapter) => adapter.status === "available" && adapter.packageExport === "@toolctrl/ui/navigation")).toBe(true);
});
});
@@ -0,0 +1,182 @@
import fs from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { uiAdapterCategories } from "@toolctrl/ui";
import { layoutAdapters } from "@toolctrl/ui/layout";
import { navigationAdapters } from "@toolctrl/ui/navigation";
import { UI_ACTION_IDS, UI_NAV_IDS, UI_SURFACE_IDS } from "~/application/ui/uiRegistry";
import { readRepoDir, repoPathExists } from "~/utils/testing/repoPaths";
type UiInventoryComponent = {
stableName: string;
path: string;
category: string;
library: string;
status: string;
};
type UiInventory = {
schemaVersion: number;
notes: string[];
components: UiInventoryComponent[];
};
type UiSurfaceMapEntry = {
id: string;
kind: "surface" | "action" | "nav";
label: string;
sourceFiles: string[];
renderer: string;
notes: string[];
};
type UiSurfaceMap = {
schemaVersion: number;
surfaces: UiSurfaceMapEntry[];
};
const inventoryPath = path.join(process.cwd(), "docs/ui-inventory/components.json");
const schemaPath = path.join(process.cwd(), "docs/ui-inventory/schema.json");
const surfacesPath = path.join(process.cwd(), "docs/ui-inventory/surfaces.json");
const surfacesSchemaPath = path.join(process.cwd(), "docs/ui-inventory/surfaces.schema.json");
const inventory = JSON.parse(fs.readFileSync(inventoryPath, "utf8")) as UiInventory;
const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8")) as {
$defs: { component: { properties: { category: { enum: string[] }; status: { enum: string[] } } } };
};
const surfaceMap = JSON.parse(fs.readFileSync(surfacesPath, "utf8")) as UiSurfaceMap;
const surfaceSchema = JSON.parse(fs.readFileSync(surfacesSchemaPath, "utf8")) as {
$defs: { surface: { properties: { kind: { enum: string[] } } } };
};
const allowedCategories = schema.$defs.component.properties.category.enum;
const allowedStatuses = schema.$defs.component.properties.status.enum;
const allowedSurfaceKinds = surfaceSchema.$defs.surface.properties.kind.enum;
function physicalWebPath(sourcePath: string) {
if (sourcePath.startsWith("apps/web/app/")) {
return sourcePath;
}
return sourcePath.startsWith("app/") ? `apps/web/${sourcePath}` : sourcePath;
}
function expectStringArray(value: unknown) {
expect(Array.isArray(value)).toBe(true);
expect((value as unknown[]).every((item) => typeof item === "string")).toBe(true);
}
describe("UI inventory", () => {
it("matches the declared schema shape", () => {
expect(inventory.schemaVersion).toBe(1);
expect(Array.isArray(inventory.notes)).toBe(true);
expect(inventory.components.length).toBeGreaterThan(0);
inventory.components.forEach((component) => {
expect(component.stableName).toEqual(expect.any(String));
expect(component.path).toEqual(expect.any(String));
expect(component.library).toEqual(expect.any(String));
expect(allowedCategories).toContain(component.category);
expect(allowedStatuses).toContain(component.status);
});
});
it("uses the same category names as packages/ui", () => {
expect(new Set(allowedCategories)).toEqual(new Set(uiAdapterCategories));
});
it("contains inventory entries for every available shell/navigation adapter", () => {
const availableAdapterNames = [...layoutAdapters, ...navigationAdapters].map((adapter) => adapter.name);
const inventoryStableNames = new Set(inventory.components.map((component) => component.stableName));
availableAdapterNames.forEach((adapterName) => {
expect(inventoryStableNames.has(adapterName), adapterName).toBe(true);
});
});
it("points every inventory entry at an existing file or directory", () => {
inventory.components.forEach((component) => {
expect(repoPathExists(component.path), component.path).toBe(true);
});
});
it("covers root shadcn/custom UI primitive files", () => {
const inventoryPaths = new Set(inventory.components.map((component) => component.path));
const rootPrimitivePaths = readRepoDir("apps/web/app/components/ui")
.filter((file) => /^[a-z0-9-]+\.tsx$/.test(file))
.map((file) => `apps/web/app/components/ui/${file}`);
rootPrimitivePaths.forEach((primitivePath) => {
expect(inventoryPaths.has(primitivePath), primitivePath).toBe(true);
});
});
it("references every shell/navigation adapter source in the inventory or surface map", () => {
const inventoryPaths = new Set(inventory.components.map((component) => component.path));
const surfaceSourceFiles = new Set(surfaceMap.surfaces.flatMap((surface) => surface.sourceFiles));
const adapterSources = [...layoutAdapters, ...navigationAdapters].map((adapter) => physicalWebPath(adapter.source));
adapterSources.forEach((source) => {
expect(inventoryPaths.has(source) || surfaceSourceFiles.has(source), source).toBe(true);
});
});
});
describe("UI surface map", () => {
it("provides the UI agent playbooks and human-readable surface map", () => {
const requiredDocs = [
"docs/agent-playbooks/ui-changes.md",
"docs/agent-playbooks/ui-adapter-migration.md",
"docs/ui-inventory/surface-map.md",
"docs/ui-inventory/surfaces.json",
"docs/ui-inventory/surfaces.schema.json",
];
requiredDocs.forEach((docPath) => {
expect(fs.existsSync(path.join(process.cwd(), docPath)), docPath).toBe(true);
});
const uiPlaybook = fs.readFileSync(path.join(process.cwd(), "docs/agent-playbooks/ui-changes.md"), "utf8");
const adapterPlaybook = fs.readFileSync(path.join(process.cwd(), "docs/agent-playbooks/ui-adapter-migration.md"), "utf8");
expect(uiPlaybook).toContain("Identify the target by `data-ui-id`");
expect(adapterPlaybook).toContain("@toolctrl/ui/buttons");
});
it("matches the declared surface schema shape", () => {
expect(surfaceMap.schemaVersion).toBe(1);
expect(surfaceMap.surfaces.length).toBeGreaterThan(0);
surfaceMap.surfaces.forEach((surface) => {
expect(surface.id).toMatch(/^ui\.(surface|action|nav)\./);
expect(allowedSurfaceKinds).toContain(surface.kind);
expect(surface.label).toEqual(expect.any(String));
expect(surface.renderer).toEqual(expect.any(String));
expectStringArray(surface.sourceFiles);
expectStringArray(surface.notes);
});
});
it("points every surface map source file at an existing file", () => {
surfaceMap.surfaces.forEach((surface) => {
surface.sourceFiles.forEach((sourceFile) => {
expect(repoPathExists(sourceFile), `${surface.id} -> ${sourceFile}`).toBe(true);
});
});
});
it("maps all stable registry surface, action and nav IDs", () => {
const mappedIds = new Set(surfaceMap.surfaces.map((surface) => surface.id));
const registryIds = [...Object.values(UI_SURFACE_IDS), ...Object.values(UI_ACTION_IDS), ...Object.values(UI_NAV_IDS)];
registryIds.forEach((id) => {
expect(mappedIds.has(id), id).toBe(true);
});
});
it("keeps mapped IDs unique and kind-aligned", () => {
const ids = surfaceMap.surfaces.map((surface) => surface.id);
expect(new Set(ids).size).toBe(ids.length);
surfaceMap.surfaces.forEach((surface) => {
expect(surface.id.startsWith(`ui.${surface.kind}.`), surface.id).toBe(true);
});
});
});
@@ -0,0 +1,8 @@
import { describe, expect, it } from "vitest";
import { UI_NAV_IDS } from "./uiRegistry";
describe("UI_NAV_IDS", () => {
it("exposes the app notification nav id", () => {
expect(UI_NAV_IDS.appNotifications).toBe("ui.nav.app.notifications");
});
});
@@ -0,0 +1,131 @@
import type { SideBarItem } from "~/application/sidebar/SidebarItem";
export type UiLayout = "app" | "admin" | "docs";
export const UI_SURFACE_IDS = {
shell: "ui.surface.shell",
shellInset: "ui.surface.shell.inset",
appSidebar: "ui.surface.app.sidebar",
adminSidebar: "ui.surface.admin.sidebar",
docsSidebar: "ui.surface.docs.sidebar",
shellHeader: "ui.surface.shell.header",
shellBreadcrumb: "ui.surface.shell.breadcrumb",
shellBreadcrumbCurrent: "ui.surface.shell.breadcrumb.current",
shellMain: "ui.surface.shell.main",
shellNavActions: "ui.surface.shell.navActions",
aiAssistantDialog: "ui.surface.shell.aiAssistant.dialog",
feedbackDialog: "ui.surface.shell.feedback.dialog",
commandPalettePortal: "ui.surface.commandPalette.portal",
commandPaletteSearch: "ui.surface.commandPalette.search",
commandPaletteResults: "ui.surface.commandPalette.results",
commandPaletteRow: "ui.surface.commandPalette.row",
} as const;
export const UI_ACTION_IDS = {
sidebarTrigger: "ui.action.shell.sidebarTrigger",
search: "ui.action.shell.search",
aiAssistant: "ui.action.shell.aiAssistant",
aiAssistantExpand: "ui.action.shell.aiAssistant.expand",
aiAssistantClose: "ui.action.shell.aiAssistant.close",
notifications: "ui.action.shell.notifications",
onboarding: "ui.action.shell.onboarding",
feedback: "ui.action.shell.feedback",
chatSupport: "ui.action.shell.chatSupport",
more: "ui.action.shell.more",
profile: "ui.action.shell.profile",
subscription: "ui.action.shell.subscription",
signOut: "ui.action.shell.signOut",
} as const;
export const UI_NAV_IDS = {
appDashboard: "ui.nav.app.dashboard",
appNotifications: "ui.nav.app.notifications",
appCrm: "ui.nav.app.crm",
appEmailMarketing: "ui.nav.app.emailMarketing",
appApi: "ui.nav.app.api",
appWorkflowEngine: "ui.nav.app.workflowEngine",
appCredits: "ui.nav.app.credits",
appSettings: "ui.nav.app.settings",
appSwitchToAdmin: "ui.nav.app.switchToAdmin",
adminDashboard: "ui.nav.admin.dashboard",
adminAccounts: "ui.nav.admin.accounts",
adminAnalytics: "ui.nav.admin.analytics",
adminEntities: "ui.nav.admin.entities",
adminWorkflows: "ui.nav.admin.workflows",
adminApi: "ui.nav.admin.api",
adminEvents: "ui.nav.admin.events",
adminAuditTrails: "ui.nav.admin.auditTrails",
adminNotifications: "ui.nav.admin.notifications",
adminFeatureFlags: "ui.nav.admin.featureFlags",
adminNavigation: "ui.nav.admin.navigation",
adminPortals: "ui.nav.admin.portals",
adminPrompts: "ui.nav.admin.prompts",
adminEmailMarketing: "ui.nav.admin.emailMarketing",
adminMarketing: "ui.nav.admin.marketing",
adminKnowledgeBase: "ui.nav.admin.knowledgeBase",
adminHelpDesk: "ui.nav.admin.helpDesk",
adminOnboarding: "ui.nav.admin.onboarding",
adminMetrics: "ui.nav.admin.metrics",
adminSettings: "ui.nav.admin.settings",
adminSwitchToApp: "ui.nav.admin.switchToApp",
docsIntroduction: "ui.nav.docs.introduction",
} as const;
export const UI_ID_PATTERNS = {
appEntity: "ui.nav.app.entity.{entityName}",
appEntityGroup: "ui.nav.app.entityGroup.{groupSlug}",
appEntityGroupEntity: "ui.nav.app.entityGroup.{groupSlug}.entity.{entityName}",
appSection: "ui.nav.app.section.{sectionName}",
docsRoute: "ui.nav.docs.route.{routeSlug}",
} as const;
export function getSidebarSurfaceId(layout: UiLayout) {
if (layout === "admin") {
return UI_SURFACE_IDS.adminSidebar;
}
if (layout === "docs") {
return UI_SURFACE_IDS.docsSidebar;
}
return UI_SURFACE_IDS.appSidebar;
}
export function uiIdSegment(value: string) {
const words = value
.trim()
.replace(/&/g, "and")
.split(/[^a-zA-Z0-9]+/)
.filter(Boolean);
if (words.length === 0) {
return "untitled";
}
return words
.map((word, index) => {
const normalized = word.toLowerCase();
if (index === 0) {
return normalized;
}
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
})
.join("");
}
export function getUiIdAttributes(item: Pick<SideBarItem, "id" | "uiIdPattern" | "uiIdParams">) {
const attributes: Record<string, string> = {};
if (item.id) {
attributes["data-ui-id"] = item.id;
}
if (item.uiIdPattern) {
attributes["data-ui-id-pattern"] = item.uiIdPattern;
}
if (item.uiIdParams) {
Object.entries(item.uiIdParams).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
const paramName = key.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
attributes[`data-ui-id-param-${paramName}`] = String(value);
}
});
}
return attributes;
}