EPIC-2 Slice I: replaces the static applicationCatalog stub with a live install flow driven by catalyst-catalog (slice L, #1148). UI: - src/lib/catalog.api.ts — typed REST client to catalyst-api proxy. - src/lib/useCatalog.ts — TanStack Query hooks (list, item, version, versions). Mirrors the slice U useComplianceStream pattern (REST baseline; no Zustand). - src/widgets/install/InstallForm.tsx — auto-form generator backed by @rjsf/core + @rjsf/validator-ajv8. Honors x-catalyst-ui-hint extensions per BLUEPRINT-AUTHORING.md §4: password (masked input), domain-picker, application-ref, secret-ref. Unknown hints fall back to the default RJSF widget. - src/widgets/install/installFormSchema.ts — pure helpers (buildUiSchema, extractConfigSchema) lifted out so the component module exports only components (react-refresh/only-export-components). - src/pages/sovereign/InstallPage.tsx — catalog grid → form → submit with preview button + status modal. - Routes: /provision/$deploymentId/install (mothership tree) and /install (chroot consoleLayoutRoute), each with a $blueprintName variant for deep-linking. Server (catalyst-api): - internal/handler/catalog_client.go — narrow REST client to catalyst-catalog. CATALYST_CATALOG_URL is env-overridable (INVIOLABLE-PRINCIPLES #4); defaults to the in-cluster service FQDN. - internal/handler/applications.go — POST /applications creates the Application CR per ADR-0001 §2.7. Validates parameters against Blueprint.spec.configSchema using core/controllers/pkg/validate (santhosh-tekuri/jsonschema/v5). 201/400/403/404/409/503 surface the canonical error vocabulary the UI status modal renders. - internal/handler/applications_preview.go — POST .../preview renders manifests via core/controllers/pkg/render. Pure simulation (no CR write, no Gitea commit). Response shape is forward-compatible with EPIC-2 T topology preview. - GET .../applications/{name}/status (snapshot) and .../stream (SSE). - Route registration in cmd/api/main.go; catalogClient wired from env unconditionally (handlers surface 502/503 with detail when upstream fails). - internal/handler/applications_test.go — 9 paths: 201 happy, 400 invalid params (configSchema), 400 missing field, 403 unauthorized, 404 unknown blueprint, 409 duplicate, 503 unwired catalog, 502 upstream error, status 200/404, preview 200/400. Promoted packages (per slice L's pattern with the Gitea client): - core/controllers/internal/render → core/controllers/pkg/render. - core/controllers/application/internal/validate → core/controllers/pkg/validate. - products/catalyst/bootstrap/api/go.mod adds a `replace` directive pinning to the in-tree controllers module so the renderer the preview emits is byte-identical to the one application-controller ships at install time. Tests: - Vitest: 5 useCatalog tests, 11 InstallForm tests (16 passed). - Playwright (5 snapshots @ 1440x900): I1 catalog grid, I2 form + password mask, I3 submit + status modal, I4 preview modal, I5 install-with-defaults branch. - go test -count=1 -race ./... clean across both modules. Per per-issue-Playwright-verification rule: 5 snapshots in playwright-report/install-i{1..5}-*.png, one per issue surface. Co-authored-by: hatiyildiz <269457768+hatiyildiz@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 lines
2.5 KiB
JSON
83 lines
2.5 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",
|
|
"@rjsf/core": "^5.24.6",
|
|
"@rjsf/utils": "^5.24.6",
|
|
"@rjsf/validator-ajv8": "^5.24.6",
|
|
"@tabler/icons-react": "^3.41.1",
|
|
"@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",
|
|
"d3-drag": "^3.0.0",
|
|
"d3-force": "^3.0.0",
|
|
"d3-selection": "^3.0.0",
|
|
"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/d3-drag": "^3.0.7",
|
|
"@types/d3-force": "^3.0.10",
|
|
"@types/d3-selection": "^3.0.11",
|
|
"@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"
|
|
}
|
|
}
|