Adds the Sovereign Dashboard surface at /sovereign/provision/$deploymentId/dashboard rendering a Recharts <Treemap> where box AREA tracks the selected resource limit and box COLOR is a continuous gradient (blue -> green -> red) over a selectable utilisation/health/age metric. Toolbar lets the operator pick Size, Color, and up to 4 nested Layer dimensions (sovereign/cluster/family/namespace/application). Capacity size metrics auto-lock the colour scale to utilisation. Drill-down walks the in-memory tree (no refetch); breadcrumb chips pop back. Hover yields a viewport-clamped tooltip with a deep link to AppDetail. Architecture notes baked into the code: - Module-level callback refs (_onCellHover/_onCellClick/_activeColorFn /_itemsByName) are required because Recharts clones the cell content component without preserving React closures or hooks. - Parent-bounds Map clips child labels under the 24px nested header strip so a tall narrow child can't render under its parent's title. - Cell renderers gate label visibility on width >= 50px / height >= 24px to avoid noisy text on tiny cells. - isAnimationActive=false for perf on 500+ cells. Backend (catalyst-api): - New GET /api/v1/dashboard/treemap?group_by=A,B&color_by=C&size_by=D returning the nested TreemapItem[] shape the UI consumes. - v1 emits a static placeholder shape derived from the canonical Catalyst-Zero family list (20 cells across 6 families). The HTTP schema is the target schema; only the data SOURCE is a placeholder. Replacing it with metrics-server integration is a follow-up. Tests: - 30 colour-gradient + drill-walk unit tests in src/lib/treemap.types.test.ts (0%->blue, 50%->green, 100%->red, interpolation, walk, query string). - 9 controller toolbar tests (add/remove layer caps, capacity-metric auto-lock, dimension exclusion). - 6 Dashboard render tests (toolbar, empty state, total count, breadcrumb root chip). - 6 Go handler tests (default/nested response shape, dimension/colour/ size validation, percentage-in-range invariant). Sidebar gets a Dashboard nav entry. Sidebar.test updated to reflect. Vite dev proxy gains a /sovereign/api passthrough (rewrites to /api) so dev mirrors the production traefik prefix-strip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2.2 KiB
JSON
73 lines
2.2 KiB
JSON
{
|
|
"name": "ui",
|
|
"private": true,
|
|
"version": "0.0.0",
|
|
"type": "module",
|
|
"scripts": {
|
|
"build:catalog": "node scripts/build-catalog.mjs",
|
|
"predev": "npm run build:catalog",
|
|
"prebuild": "npm run build:catalog",
|
|
"dev": "vite",
|
|
"build": "tsc -b && vite build",
|
|
"typecheck": "tsc -b --noEmit",
|
|
"test": "vitest run",
|
|
"test:watch": "vitest",
|
|
"lint": "eslint .",
|
|
"preview": "vite preview"
|
|
},
|
|
"dependencies": {
|
|
"@hookform/resolvers": "^5.2.2",
|
|
"@radix-ui/react-accordion": "^1.2.12",
|
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
"@radix-ui/react-avatar": "^1.1.11",
|
|
"@radix-ui/react-checkbox": "^1.3.3",
|
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
"@radix-ui/react-label": "^2.1.8",
|
|
"@radix-ui/react-popover": "^1.1.15",
|
|
"@radix-ui/react-progress": "^1.1.8",
|
|
"@radix-ui/react-select": "^2.2.6",
|
|
"@radix-ui/react-separator": "^1.1.8",
|
|
"@radix-ui/react-slot": "^1.2.4",
|
|
"@radix-ui/react-switch": "^1.2.6",
|
|
"@radix-ui/react-tabs": "^1.1.13",
|
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
"@tailwindcss/vite": "^4.2.2",
|
|
"@tanstack/react-query": "^5.91.2",
|
|
"@tanstack/react-query-devtools": "^5.91.3",
|
|
"@tanstack/react-router": "^1.167.5",
|
|
"@tanstack/router-devtools": "^1.166.9",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"framer-motion": "^12.38.0",
|
|
"lucide-react": "^0.577.0",
|
|
"react": "^19.2.4",
|
|
"react-dom": "^19.2.4",
|
|
"react-hook-form": "^7.71.2",
|
|
"recharts": "^3.8.1",
|
|
"tailwind-merge": "^3.5.0",
|
|
"tailwindcss": "^4.2.2",
|
|
"zod": "^4.3.6",
|
|
"zustand": "^5.0.12"
|
|
},
|
|
"devDependencies": {
|
|
"@eslint/js": "^9.39.4",
|
|
"@playwright/test": "^1.59.1",
|
|
"@testing-library/jest-dom": "^6.9.1",
|
|
"@testing-library/react": "^16.3.2",
|
|
"@types/node": "^24.12.0",
|
|
"@types/react": "^19.2.14",
|
|
"@types/react-dom": "^19.2.3",
|
|
"@vitejs/plugin-react": "^6.0.1",
|
|
"eslint": "^9.39.4",
|
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
"eslint-plugin-react-refresh": "^0.5.2",
|
|
"globals": "^17.4.0",
|
|
"jsdom": "^29.1.0",
|
|
"typescript": "~5.9.3",
|
|
"typescript-eslint": "^8.57.0",
|
|
"vite": "^8.0.1",
|
|
"vitest": "^4.1.5"
|
|
}
|
|
}
|