@yss123/cage-cli 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -3
- package/bin/cage.js +5 -0
- package/bin/create-cage-app.js +5 -0
- package/dist/analyze.d.ts +16 -0
- package/dist/analyze.js +20 -2
- package/dist/analyze.js.map +1 -1
- package/dist/baseline.d.ts +8 -0
- package/dist/baseline.js +13 -0
- package/dist/baseline.js.map +1 -1
- package/dist/bootstrap.d.ts +20 -0
- package/dist/bootstrap.js +75 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/budget.d.ts +7 -0
- package/dist/budget.js +49 -5
- package/dist/budget.js.map +1 -1
- package/dist/capabilities.d.ts +38 -0
- package/dist/capabilities.js +133 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/config.d.ts +33 -4
- package/dist/config.js +22 -1
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +86 -0
- package/dist/context.js +235 -0
- package/dist/context.js.map +1 -0
- package/dist/create-prompt.d.ts +12 -0
- package/dist/create-prompt.js +62 -0
- package/dist/create-prompt.js.map +1 -0
- package/dist/create.d.ts +38 -1
- package/dist/create.js +52 -13
- package/dist/create.js.map +1 -1
- package/dist/derive.d.ts +23 -0
- package/dist/derive.js +40 -0
- package/dist/derive.js.map +1 -1
- package/dist/dev.d.ts +6 -0
- package/dist/dev.js +23 -51
- package/dist/dev.js.map +1 -1
- package/dist/doctor.d.ts +98 -0
- package/dist/doctor.js +93 -0
- package/dist/doctor.js.map +1 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +11 -0
- package/dist/env.js.map +1 -1
- package/dist/findings.d.ts +27 -0
- package/dist/findings.js +20 -0
- package/dist/findings.js.map +1 -1
- package/dist/gen/contracts.d.ts +28 -0
- package/dist/gen/contracts.js +81 -20
- package/dist/gen/contracts.js.map +1 -1
- package/dist/gen/index.d.ts +26 -0
- package/dist/gen/index.js +112 -4
- package/dist/gen/index.js.map +1 -1
- package/dist/gen/zod-code.d.ts +43 -1
- package/dist/gen/zod-code.js +180 -16
- package/dist/gen/zod-code.js.map +1 -1
- package/dist/graph-approvals.d.ts +60 -0
- package/dist/graph-approvals.js +80 -0
- package/dist/graph-approvals.js.map +1 -0
- package/dist/graph-business.d.ts +135 -0
- package/dist/graph-business.js +404 -0
- package/dist/graph-business.js.map +1 -0
- package/dist/graph-command.d.ts +28 -0
- package/dist/graph-command.js +88 -0
- package/dist/graph-command.js.map +1 -0
- package/dist/graph-model.d.ts +65 -0
- package/dist/graph-model.js +134 -0
- package/dist/graph-model.js.map +1 -0
- package/dist/graph-presentation.d.ts +27 -0
- package/dist/graph-presentation.js +34 -0
- package/dist/graph-presentation.js.map +1 -0
- package/dist/graph-query.d.ts +266 -0
- package/dist/graph-query.js +304 -0
- package/dist/graph-query.js.map +1 -0
- package/dist/graph-relations.d.ts +34 -0
- package/dist/graph-relations.js +172 -0
- package/dist/graph-relations.js.map +1 -0
- package/dist/graph-search.d.ts +56 -0
- package/dist/graph-search.js +99 -0
- package/dist/graph-search.js.map +1 -0
- package/dist/graph-snapshot.d.ts +28 -4
- package/dist/graph-snapshot.js +32 -20
- package/dist/graph-snapshot.js.map +1 -1
- package/dist/graph.d.ts +13 -2
- package/dist/graph.js +78 -5
- package/dist/graph.js.map +1 -1
- package/dist/impact.d.ts +56 -0
- package/dist/impact.js +90 -18
- package/dist/impact.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +18 -0
- package/dist/init.js +146 -0
- package/dist/init.js.map +1 -0
- package/dist/load.d.ts +10 -0
- package/dist/load.js +15 -0
- package/dist/load.js.map +1 -1
- package/dist/main.d.ts +6 -0
- package/dist/main.js +170 -37
- package/dist/main.js.map +1 -1
- package/dist/migrate.d.ts +15 -6
- package/dist/migrate.js +31 -53
- package/dist/migrate.js.map +1 -1
- package/dist/ontology.d.ts +69 -2
- package/dist/ontology.js +101 -4
- package/dist/ontology.js.map +1 -1
- package/dist/process-rules.d.ts +21 -0
- package/dist/process-rules.js +100 -0
- package/dist/process-rules.js.map +1 -0
- package/dist/process.d.ts +32 -0
- package/dist/process.js +32 -0
- package/dist/process.js.map +1 -1
- package/dist/project-structure.d.ts +13 -0
- package/dist/project-structure.js +104 -0
- package/dist/project-structure.js.map +1 -0
- package/dist/registration.d.ts +16 -0
- package/dist/registration.js +56 -0
- package/dist/registration.js.map +1 -0
- package/dist/rules.d.ts +52 -0
- package/dist/rules.js +58 -0
- package/dist/rules.js.map +1 -1
- package/dist/runtime-diagnostics.d.ts +27 -0
- package/dist/runtime-diagnostics.js +60 -0
- package/dist/runtime-diagnostics.js.map +1 -0
- package/dist/snapshots.d.ts +40 -0
- package/dist/snapshots.js +62 -0
- package/dist/snapshots.js.map +1 -0
- package/dist/static-check.d.ts +33 -0
- package/dist/static-check.js +38 -5
- package/dist/static-check.js.map +1 -1
- package/dist/sync.d.ts +11 -0
- package/dist/sync.js +139 -10
- package/dist/sync.js.map +1 -1
- package/dist/upgrade.d.ts +16 -0
- package/dist/upgrade.js +21 -0
- package/dist/upgrade.js.map +1 -1
- package/dist/verify.d.ts +14 -0
- package/dist/verify.js +19 -0
- package/dist/verify.js.map +1 -1
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -1
- package/graph-ui/app.js +367 -35
- package/graph-ui/approval-flow.js +165 -0
- package/graph-ui/business.css +985 -0
- package/graph-ui/business.js +549 -0
- package/graph-ui/flowchart-interaction.js +177 -0
- package/graph-ui/flowchart.js +1059 -0
- package/graph-ui/graph-approvals.js +79 -0
- package/graph-ui/graph-business.js +403 -0
- package/graph-ui/graph-model.js +133 -0
- package/graph-ui/graph-relations.js +171 -0
- package/graph-ui/graph-search.js +98 -0
- package/graph-ui/index.html +26 -12
- package/graph-ui/model.js +47 -77
- package/graph-ui/relations.js +6 -125
- package/graph-ui/structure.js +48 -1
- package/graph-ui/style.css +33 -0
- package/package.json +10 -8
- package/templates/app/.dockerignore +2 -0
- package/templates/app/.env.example +68 -14
- package/templates/app/AGENTS.md +135 -12
- package/templates/app/Dockerfile +2 -0
- package/templates/app/README.md +49 -16
- package/templates/app/_gitignore +9 -0
- package/templates/app/apps/api/package.json +2 -2
- package/templates/app/apps/api/src/main.ts +5 -1
- package/templates/app/apps/api/src/worker.ts +3 -0
- package/templates/app/apps/web/index.html +1 -0
- package/templates/app/apps/web/package.json +7 -3
- package/templates/app/apps/web/src/app/app.tsx +128 -0
- package/templates/app/apps/web/src/{style.css → app/styles/global.css} +88 -8
- package/templates/app/apps/web/src/app/use-session.ts +43 -0
- package/templates/app/apps/web/src/app/workspace-layout.tsx +109 -0
- package/templates/app/apps/web/src/main.tsx +9 -543
- package/templates/app/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +31 -0
- package/templates/app/apps/web/src/modules/approval/index.ts +6 -0
- package/templates/app/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +73 -0
- package/templates/app/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/app/apps/web/src/modules/auth/pages/login-page.tsx +71 -0
- package/templates/app/apps/web/src/modules/inventory/index.ts +5 -0
- package/templates/app/apps/web/src/modules/inventory/pages/inventory-page.tsx +102 -0
- package/templates/app/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
- package/templates/app/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
- package/templates/app/apps/web/src/modules/purchase/components/purchase-order-form.tsx +82 -0
- package/templates/app/apps/web/src/modules/purchase/index.ts +7 -0
- package/templates/app/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
- package/templates/app/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +240 -0
- package/templates/app/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/app/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
- package/templates/app/apps/web/src/shared/hooks/use-command.ts +42 -0
- package/templates/app/apps/web/src/shared/lib/error-message.ts +24 -0
- package/templates/app/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/app/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
- package/templates/app/apps/web/src/shared/ui/assistant-panel.css +134 -0
- package/templates/app/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
- package/templates/app/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
- package/templates/app/apps/web/src/shared/ui/attachment-upload.css +28 -0
- package/templates/app/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
- package/templates/app/apps/web/src/shared/ui/notice.tsx +20 -0
- package/templates/app/apps/web/src/shared/ui/page-heading.tsx +35 -0
- package/templates/app/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/app/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/app/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/app/apps/web/vite.config.ts +8 -0
- package/templates/app/cage.config.json +10 -1
- package/templates/app/db/migrations/0002_draft.sql +12 -0
- package/templates/app/db/migrations/0003_draft.sql +8 -0
- package/templates/app/deploy/nginx.conf +52 -0
- package/templates/app/docs/ai/README.md +98 -0
- package/templates/app/docs/ai/architecture.md +148 -0
- package/templates/app/docs/ai/commenting.md +203 -0
- package/templates/app/docs/ai/diagnostics.md +80 -0
- package/templates/app/docs/ai/files.md +93 -0
- package/templates/app/docs/ai/intelligence.md +348 -0
- package/templates/app/docs/ai/ontology-context.md +172 -0
- package/templates/app/docs/ai/primitives.md +282 -0
- package/templates/app/docs/ai/project-structure.md +128 -0
- package/templates/app/docs/ai/purchase-example.md +111 -0
- package/templates/app/docs/ai/recipes.md +89 -0
- package/templates/app/docs/ai/relations.md +160 -0
- package/templates/app/docs/ai/routing.md +86 -0
- package/templates/app/docs/ai/transfers.md +92 -0
- package/templates/app/docs/ai/troubleshooting.md +65 -0
- package/templates/app/docs/ai/workflow.md +152 -0
- package/templates/app/docs/errors/CAGE-AI-001.md +61 -0
- package/templates/app/docs/errors/CAGE-APPR-001.md +48 -0
- package/templates/app/docs/errors/CAGE-APPR-002.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-003.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-004.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-005.md +47 -0
- package/templates/app/docs/errors/CAGE-APPR-006.md +53 -0
- package/templates/app/docs/errors/CAGE-APPR-007.md +50 -0
- package/templates/app/docs/errors/CAGE-APPR-010.md +48 -0
- package/templates/app/docs/errors/CAGE-AUDIT-001.md +53 -0
- package/templates/app/docs/errors/CAGE-AUTH-001.md +47 -0
- package/templates/app/docs/errors/CAGE-BIZ-001.md +51 -0
- package/templates/app/docs/errors/CAGE-BIZ-002.md +49 -0
- package/templates/app/docs/errors/CAGE-BUDGET-001.md +47 -0
- package/templates/app/docs/errors/CAGE-BUDGET-002.md +47 -0
- package/templates/app/docs/errors/CAGE-BUDGET-003.md +47 -0
- package/templates/app/docs/errors/CAGE-CMD-002.md +47 -0
- package/templates/app/docs/errors/CAGE-CMD-003.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-001.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-002.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-003.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-004.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-005.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-006.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-007.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-008.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-009.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-010.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-011.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-012.md +47 -0
- package/templates/app/docs/errors/CAGE-CONN-013.md +49 -0
- package/templates/app/docs/errors/CAGE-CONN-014.md +48 -0
- package/templates/app/docs/errors/CAGE-CONN-015.md +49 -0
- package/templates/app/docs/errors/CAGE-CREATE-001.md +53 -0
- package/templates/app/docs/errors/CAGE-DECL-001.md +48 -0
- package/templates/app/docs/errors/CAGE-DECL-002.md +48 -0
- package/templates/app/docs/errors/CAGE-DECL-003.md +47 -0
- package/templates/app/docs/errors/CAGE-DECL-004.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-001.md +48 -0
- package/templates/app/docs/errors/CAGE-DEP-002.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-003.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-004.md +47 -0
- package/templates/app/docs/errors/CAGE-DEP-005.md +47 -0
- package/templates/app/docs/errors/CAGE-DIAG-001.md +53 -0
- package/templates/app/docs/errors/CAGE-DLQ-001.md +48 -0
- package/templates/app/docs/errors/CAGE-ENV-001.md +52 -0
- package/templates/app/docs/errors/CAGE-ENV-002.md +51 -0
- package/templates/app/docs/errors/CAGE-ENV-003.md +48 -0
- package/templates/app/docs/errors/CAGE-EVENT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-EVENT-002.md +50 -0
- package/templates/app/docs/errors/CAGE-FIELD-001.md +47 -0
- package/templates/app/docs/errors/CAGE-FIELD-002.md +47 -0
- package/templates/app/docs/errors/CAGE-FIELD-003.md +47 -0
- package/templates/app/docs/errors/CAGE-FIELD-004.md +47 -0
- package/templates/app/docs/errors/CAGE-FILE-001.md +56 -0
- package/templates/app/docs/errors/CAGE-GEN-001.md +48 -0
- package/templates/app/docs/errors/CAGE-GEN-002.md +47 -0
- package/templates/app/docs/errors/CAGE-GEN-003.md +53 -0
- package/templates/app/docs/errors/CAGE-GRANT-001.md +49 -0
- package/templates/app/docs/errors/CAGE-GRANT-002.md +48 -0
- package/templates/app/docs/errors/CAGE-GRANT-003.md +48 -0
- package/templates/app/docs/errors/CAGE-IMPACT-001.md +48 -0
- package/templates/app/docs/errors/CAGE-IMPACT-002.md +52 -0
- package/templates/app/docs/errors/CAGE-INIT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-INIT-002.md +49 -0
- package/templates/app/docs/errors/CAGE-INIT-003.md +48 -0
- package/templates/app/docs/errors/CAGE-INIT-004.md +48 -0
- package/templates/app/docs/errors/CAGE-INIT-005.md +52 -0
- package/templates/app/docs/errors/CAGE-JOB-001.md +47 -0
- package/templates/app/docs/errors/CAGE-JOB-002.md +47 -0
- package/templates/app/docs/errors/CAGE-JOB-003.md +47 -0
- package/templates/app/docs/errors/CAGE-LINT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-MIG-001.md +47 -0
- package/templates/app/docs/errors/CAGE-MIG-002.md +47 -0
- package/templates/app/docs/errors/CAGE-MIG-003.md +5 -0
- package/templates/app/docs/errors/CAGE-MIG-004.md +5 -0
- package/templates/app/docs/errors/CAGE-MIG-005.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-001.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-002.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-003.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-004.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-005.md +47 -0
- package/templates/app/docs/errors/CAGE-NAME-006.md +47 -0
- package/templates/app/docs/errors/CAGE-ORG-001.md +50 -0
- package/templates/app/docs/errors/CAGE-PAIR-002.md +51 -0
- package/templates/app/docs/errors/CAGE-QUERY-001.md +47 -0
- package/templates/app/docs/errors/CAGE-QUERY-002.md +47 -0
- package/templates/app/docs/errors/CAGE-QUERY-003.md +50 -0
- package/templates/app/docs/errors/CAGE-REACT-001.md +47 -0
- package/templates/app/docs/errors/CAGE-REACT-002.md +47 -0
- package/templates/app/docs/errors/CAGE-REACT-003.md +50 -0
- package/templates/app/docs/errors/CAGE-READS-001.md +50 -0
- package/templates/app/docs/errors/CAGE-REG-001.md +54 -0
- package/templates/app/docs/errors/CAGE-REG-002.md +49 -0
- package/templates/app/docs/errors/CAGE-REG-003.md +47 -0
- package/templates/app/docs/errors/CAGE-REL-001.md +64 -0
- package/templates/app/docs/errors/CAGE-ROUTE-001.md +48 -0
- package/templates/app/docs/errors/CAGE-SCOPE-001.md +47 -0
- package/templates/app/docs/errors/CAGE-SCOPE-002.md +47 -0
- package/templates/app/docs/errors/CAGE-SECRET-001.md +48 -0
- package/templates/app/docs/errors/CAGE-SECRET-002.md +47 -0
- package/templates/app/docs/errors/CAGE-SENS-001.md +48 -0
- package/templates/app/docs/errors/CAGE-SQL-001.md +47 -0
- package/templates/app/docs/errors/CAGE-SQL-002.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-001.md +49 -0
- package/templates/app/docs/errors/CAGE-STATE-002.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-003.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-004.md +47 -0
- package/templates/app/docs/errors/CAGE-STATE-005.md +49 -0
- package/templates/app/docs/errors/CAGE-STATE-010.md +48 -0
- package/templates/app/docs/errors/CAGE-STATE-011.md +48 -0
- package/templates/app/docs/errors/CAGE-STRUCT-001.md +51 -0
- package/templates/app/docs/errors/CAGE-STRUCT-002.md +51 -0
- package/templates/app/docs/errors/CAGE-SYNC-001.md +49 -0
- package/templates/app/docs/errors/CAGE-TEST-001.md +47 -0
- package/templates/app/docs/errors/CAGE-TEST-002.md +50 -0
- package/templates/app/docs/errors/CAGE-TEST-003.md +52 -0
- package/templates/app/docs/errors/CAGE-UNSAFE-001.md +49 -0
- package/templates/app/docs/errors/CAGE-UPGRADE-001.md +48 -0
- package/templates/app/docs/errors/CAGE-WORKER-001.md +48 -0
- package/templates/app/docs/errors/CAGE-WORKER-002.md +50 -0
- package/templates/app/docs/errors/CAGE-WORKER-003.md +48 -0
- package/templates/app/docs/errors/README.md +357 -0
- package/templates/app/docs/errors/runtime.md +50 -0
- package/templates/app/package.json +4 -7
- package/templates/app/packages/contracts/package.json +1 -1
- package/templates/app/packages/contracts/src/{dept.ts → aggregates/dept/index.ts} +11 -11
- package/templates/app/packages/contracts/src/{inventory.ts → aggregates/inventory/index.ts} +6 -6
- package/templates/app/packages/contracts/src/{inventory-lock.ts → aggregates/inventory-lock/index.ts} +5 -5
- package/templates/app/packages/contracts/src/aggregates/purchase-order/index.ts +86 -0
- package/templates/app/packages/contracts/src/{role.ts → aggregates/role/index.ts} +16 -16
- package/templates/app/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/app/packages/contracts/src/index.ts +20 -14
- package/templates/app/packages/contracts/src/{queries.ts → queries/index.ts} +2 -2
- package/templates/app/packages/domain/package.json +5 -4
- package/templates/app/packages/domain/src/index.ts +8 -7
- package/templates/app/packages/domain/src/{erp.ts → integrations/erp.ts} +16 -1
- package/templates/app/packages/domain/src/integrations/intelligence.ts +20 -0
- package/templates/app/packages/domain/src/modules/inventory/index.ts +3 -0
- package/templates/app/packages/domain/src/{inventory.ts → modules/inventory/inventory.ts} +12 -0
- package/templates/app/packages/domain/src/modules/purchase/approvals.ts +39 -0
- package/templates/app/packages/domain/src/modules/purchase/index.ts +7 -0
- package/templates/app/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
- package/templates/app/packages/domain/src/{jobs.ts → modules/purchase/jobs.ts} +5 -0
- package/templates/app/packages/domain/src/{purchase-order.test.ts → modules/purchase/purchase-order.test.ts} +11 -2
- package/templates/app/packages/domain/src/modules/purchase/purchase-order.ts +192 -0
- package/templates/app/packages/domain/src/{queries.ts → modules/purchase/queries.ts} +5 -0
- package/templates/app/packages/domain/src/{reactions.ts → workflows/purchase-inventory.ts} +8 -2
- package/templates/app/packages/domain/src/workflows/purchase-process.ts +42 -0
- package/templates/blank/.dockerignore +12 -0
- package/templates/blank/.env.example +71 -0
- package/templates/blank/.github/workflows/cage.yml +44 -0
- package/templates/blank/AGENTS.md +136 -0
- package/templates/blank/Dockerfile +25 -0
- package/templates/blank/README.md +40 -0
- package/templates/blank/_gitignore +9 -0
- package/templates/blank/apps/api/package.json +15 -0
- package/templates/blank/apps/api/src/main.ts +14 -0
- package/templates/blank/apps/api/src/worker.ts +10 -0
- package/templates/blank/apps/api/tsconfig.json +5 -0
- package/templates/blank/apps/web/index.html +14 -0
- package/templates/blank/apps/web/package.json +26 -0
- package/templates/blank/apps/web/src/app/app.tsx +106 -0
- package/templates/blank/apps/web/src/app/styles/global.css +606 -0
- package/templates/blank/apps/web/src/app/use-session.ts +43 -0
- package/templates/blank/apps/web/src/app/workspace-layout.tsx +95 -0
- package/templates/blank/apps/web/src/main.tsx +18 -0
- package/templates/blank/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/blank/apps/web/src/modules/auth/pages/login-page.tsx +104 -0
- package/templates/blank/apps/web/src/modules/directory/index.ts +7 -0
- package/templates/blank/apps/web/src/modules/directory/pages/user-detail-page.tsx +78 -0
- package/templates/blank/apps/web/src/modules/directory/pages/users-page.tsx +93 -0
- package/templates/blank/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/blank/apps/web/src/modules/workspace/pages/home-page.tsx +62 -0
- package/templates/blank/apps/web/src/shared/lib/error-message.ts +22 -0
- package/templates/blank/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/blank/apps/web/src/shared/ui/brand.tsx +19 -0
- package/templates/blank/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/blank/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/blank/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/blank/apps/web/tsconfig.json +11 -0
- package/templates/blank/apps/web/vite.config.ts +24 -0
- package/templates/blank/cage.config.json +14 -0
- package/templates/blank/db/migrations/0001_init.sql +63 -0
- package/templates/blank/deploy/nginx.conf +52 -0
- package/templates/blank/docs/ai/README.md +98 -0
- package/templates/blank/docs/ai/architecture.md +148 -0
- package/templates/blank/docs/ai/commenting.md +203 -0
- package/templates/blank/docs/ai/diagnostics.md +80 -0
- package/templates/blank/docs/ai/files.md +93 -0
- package/templates/blank/docs/ai/intelligence.md +348 -0
- package/templates/blank/docs/ai/ontology-context.md +172 -0
- package/templates/blank/docs/ai/primitives.md +282 -0
- package/templates/blank/docs/ai/project-structure.md +128 -0
- package/templates/blank/docs/ai/purchase-example.md +111 -0
- package/templates/blank/docs/ai/recipes.md +89 -0
- package/templates/blank/docs/ai/relations.md +160 -0
- package/templates/blank/docs/ai/routing.md +86 -0
- package/templates/blank/docs/ai/transfers.md +92 -0
- package/templates/blank/docs/ai/troubleshooting.md +65 -0
- package/templates/blank/docs/ai/workflow.md +152 -0
- package/templates/blank/docs/errors/CAGE-AI-001.md +61 -0
- package/templates/blank/docs/errors/CAGE-APPR-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-APPR-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-APPR-006.md +53 -0
- package/templates/blank/docs/errors/CAGE-APPR-007.md +50 -0
- package/templates/blank/docs/errors/CAGE-APPR-010.md +48 -0
- package/templates/blank/docs/errors/CAGE-AUDIT-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-AUTH-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-BIZ-001.md +51 -0
- package/templates/blank/docs/errors/CAGE-BIZ-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-BUDGET-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-CMD-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-CMD-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-006.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-007.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-008.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-009.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-010.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-011.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-012.md +47 -0
- package/templates/blank/docs/errors/CAGE-CONN-013.md +49 -0
- package/templates/blank/docs/errors/CAGE-CONN-014.md +48 -0
- package/templates/blank/docs/errors/CAGE-CONN-015.md +49 -0
- package/templates/blank/docs/errors/CAGE-CREATE-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-DECL-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-DECL-002.md +48 -0
- package/templates/blank/docs/errors/CAGE-DECL-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-DECL-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-DEP-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-DEP-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-DIAG-001.md +53 -0
- package/templates/blank/docs/errors/CAGE-DLQ-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-ENV-001.md +52 -0
- package/templates/blank/docs/errors/CAGE-ENV-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-ENV-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-EVENT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-EVENT-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-FIELD-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-FIELD-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-FIELD-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-FIELD-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-FILE-001.md +56 -0
- package/templates/blank/docs/errors/CAGE-GEN-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-GEN-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-GEN-003.md +53 -0
- package/templates/blank/docs/errors/CAGE-GRANT-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-GRANT-002.md +48 -0
- package/templates/blank/docs/errors/CAGE-GRANT-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-IMPACT-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-IMPACT-002.md +52 -0
- package/templates/blank/docs/errors/CAGE-INIT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-INIT-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-INIT-003.md +48 -0
- package/templates/blank/docs/errors/CAGE-INIT-004.md +48 -0
- package/templates/blank/docs/errors/CAGE-INIT-005.md +52 -0
- package/templates/blank/docs/errors/CAGE-JOB-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-JOB-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-JOB-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-LINT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-MIG-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-MIG-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-MIG-003.md +5 -0
- package/templates/blank/docs/errors/CAGE-MIG-004.md +5 -0
- package/templates/blank/docs/errors/CAGE-MIG-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-005.md +47 -0
- package/templates/blank/docs/errors/CAGE-NAME-006.md +47 -0
- package/templates/blank/docs/errors/CAGE-ORG-001.md +50 -0
- package/templates/blank/docs/errors/CAGE-PAIR-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-QUERY-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-QUERY-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-QUERY-003.md +50 -0
- package/templates/blank/docs/errors/CAGE-REACT-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-REACT-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-REACT-003.md +50 -0
- package/templates/blank/docs/errors/CAGE-READS-001.md +50 -0
- package/templates/blank/docs/errors/CAGE-REG-001.md +54 -0
- package/templates/blank/docs/errors/CAGE-REG-002.md +49 -0
- package/templates/blank/docs/errors/CAGE-REG-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-REL-001.md +64 -0
- package/templates/blank/docs/errors/CAGE-ROUTE-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-SCOPE-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-SCOPE-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-SECRET-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-SECRET-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-SENS-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-SQL-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-SQL-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-STATE-002.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-003.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-004.md +47 -0
- package/templates/blank/docs/errors/CAGE-STATE-005.md +49 -0
- package/templates/blank/docs/errors/CAGE-STATE-010.md +48 -0
- package/templates/blank/docs/errors/CAGE-STATE-011.md +48 -0
- package/templates/blank/docs/errors/CAGE-STRUCT-001.md +51 -0
- package/templates/blank/docs/errors/CAGE-STRUCT-002.md +51 -0
- package/templates/blank/docs/errors/CAGE-SYNC-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-TEST-001.md +47 -0
- package/templates/blank/docs/errors/CAGE-TEST-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-TEST-003.md +52 -0
- package/templates/blank/docs/errors/CAGE-UNSAFE-001.md +49 -0
- package/templates/blank/docs/errors/CAGE-UPGRADE-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-WORKER-001.md +48 -0
- package/templates/blank/docs/errors/CAGE-WORKER-002.md +50 -0
- package/templates/blank/docs/errors/CAGE-WORKER-003.md +48 -0
- package/templates/blank/docs/errors/README.md +357 -0
- package/templates/blank/docs/errors/runtime.md +50 -0
- package/templates/blank/docs/examples/purchase-admin/README.md +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/main.ts +14 -0
- package/templates/blank/docs/examples/purchase-admin/apps/api/src/worker.ts +17 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/app.tsx +128 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/styles/global.css +743 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/use-session.ts +43 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/app/workspace-layout.tsx +109 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/main.tsx +18 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/hooks/use-approval-tasks.ts +31 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/index.ts +6 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/approval/pages/approval-tasks-page.tsx +73 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/auth/pages/login-page.tsx +71 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/inventory/pages/inventory-page.tsx +102 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/approval-history.tsx +32 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/order-attachments.tsx +29 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-assistant-context.tsx +17 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.css +6 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/components/purchase-order-form.tsx +82 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/index.ts +7 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/lib/presentation.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-intelligence.css +15 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-order-detail-page.tsx +154 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/purchase/pages/purchase-orders-page.tsx +240 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/index.ts +5 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/modules/workspace/pages/home-page.tsx +44 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/hooks/use-command.ts +42 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/error-message.ts +24 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/lib/navigation.ts +21 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-markdown.tsx +19 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.css +134 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-panel.tsx +200 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/assistant-scope.tsx +72 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.css +28 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/attachment-upload.tsx +163 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/notice.tsx +20 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-heading.tsx +35 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.css +47 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/page-state.tsx +76 -0
- package/templates/blank/docs/examples/purchase-admin/apps/web/src/shared/ui/require-capability.tsx +34 -0
- package/templates/blank/docs/examples/purchase-admin/cage.config.json +123 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/dept/index.ts +74 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory/index.ts +57 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/inventory-lock/index.ts +52 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/purchase-order/index.ts +86 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/role/index.ts +85 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/index.ts +87 -0
- package/templates/blank/docs/examples/purchase-admin/packages/contracts/src/queries/index.ts +17 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/index.ts +10 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/erp.ts +51 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/integrations/intelligence.ts +20 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/index.ts +3 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/inventory/inventory.ts +55 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/approvals.ts +39 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/index.ts +7 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/intelligence.test.ts +62 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/jobs.ts +18 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.test.ts +146 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/purchase-order.ts +192 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/modules/purchase/queries.ts +15 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-inventory.ts +30 -0
- package/templates/blank/docs/examples/purchase-admin/packages/domain/src/workflows/purchase-process.ts +42 -0
- package/templates/blank/package.json +22 -0
- package/templates/blank/packages/contracts/package.json +16 -0
- package/templates/blank/packages/contracts/src/aggregates/dept/index.ts +74 -0
- package/templates/blank/packages/contracts/src/aggregates/role/index.ts +85 -0
- package/templates/blank/packages/contracts/src/aggregates/user/index.ts +89 -0
- package/templates/blank/packages/contracts/src/index.ts +55 -0
- package/templates/blank/packages/contracts/src/queries/index.ts +13 -0
- package/templates/blank/packages/contracts/tsconfig.json +5 -0
- package/templates/blank/packages/domain/package.json +24 -0
- package/templates/blank/packages/domain/src/index.ts +5 -0
- package/templates/blank/packages/domain/tsconfig.json +5 -0
- package/templates/blank/pnpm-workspace.yaml +10 -0
- package/templates/blank/renovate.json +5 -0
- package/templates/blank/tsconfig.base.json +8 -0
- package/dist/database.d.ts +0 -5
- package/dist/database.js +0 -70
- package/dist/database.js.map +0 -1
- package/managed/errors/CAGE-APPR-001.md +0 -32
- package/managed/errors/CAGE-APPR-002.md +0 -32
- package/managed/errors/CAGE-APPR-003.md +0 -32
- package/managed/errors/CAGE-APPR-004.md +0 -32
- package/managed/errors/CAGE-APPR-005.md +0 -32
- package/managed/errors/CAGE-APPR-006.md +0 -32
- package/managed/errors/CAGE-APPR-007.md +0 -32
- package/managed/errors/CAGE-APPR-010.md +0 -32
- package/managed/errors/CAGE-AUTH-001.md +0 -32
- package/managed/errors/CAGE-BUDGET-001.md +0 -32
- package/managed/errors/CAGE-BUDGET-002.md +0 -32
- package/managed/errors/CAGE-BUDGET-003.md +0 -32
- package/managed/errors/CAGE-CMD-002.md +0 -32
- package/managed/errors/CAGE-CMD-003.md +0 -34
- package/managed/errors/CAGE-CONN-001.md +0 -32
- package/managed/errors/CAGE-CONN-002.md +0 -32
- package/managed/errors/CAGE-CONN-003.md +0 -32
- package/managed/errors/CAGE-CONN-004.md +0 -32
- package/managed/errors/CAGE-CONN-005.md +0 -32
- package/managed/errors/CAGE-CONN-006.md +0 -32
- package/managed/errors/CAGE-CONN-007.md +0 -32
- package/managed/errors/CAGE-CONN-008.md +0 -32
- package/managed/errors/CAGE-CONN-009.md +0 -32
- package/managed/errors/CAGE-CONN-010.md +0 -32
- package/managed/errors/CAGE-CONN-011.md +0 -32
- package/managed/errors/CAGE-CONN-012.md +0 -32
- package/managed/errors/CAGE-CREATE-001.md +0 -32
- package/managed/errors/CAGE-DECL-001.md +0 -34
- package/managed/errors/CAGE-DECL-002.md +0 -34
- package/managed/errors/CAGE-DECL-003.md +0 -34
- package/managed/errors/CAGE-DECL-004.md +0 -34
- package/managed/errors/CAGE-DEP-001.md +0 -34
- package/managed/errors/CAGE-DEP-002.md +0 -34
- package/managed/errors/CAGE-DEP-003.md +0 -34
- package/managed/errors/CAGE-DEP-004.md +0 -34
- package/managed/errors/CAGE-DEP-005.md +0 -34
- package/managed/errors/CAGE-DLQ-001.md +0 -32
- package/managed/errors/CAGE-ENV-001.md +0 -32
- package/managed/errors/CAGE-EVENT-001.md +0 -32
- package/managed/errors/CAGE-EVENT-002.md +0 -32
- package/managed/errors/CAGE-FIELD-001.md +0 -32
- package/managed/errors/CAGE-FIELD-002.md +0 -32
- package/managed/errors/CAGE-FIELD-003.md +0 -32
- package/managed/errors/CAGE-FIELD-004.md +0 -32
- package/managed/errors/CAGE-GEN-001.md +0 -33
- package/managed/errors/CAGE-GEN-002.md +0 -33
- package/managed/errors/CAGE-GRANT-001.md +0 -32
- package/managed/errors/CAGE-GRANT-002.md +0 -32
- package/managed/errors/CAGE-GRANT-003.md +0 -32
- package/managed/errors/CAGE-IMPACT-001.md +0 -32
- package/managed/errors/CAGE-JOB-001.md +0 -32
- package/managed/errors/CAGE-JOB-002.md +0 -32
- package/managed/errors/CAGE-JOB-003.md +0 -32
- package/managed/errors/CAGE-LINT-001.md +0 -32
- package/managed/errors/CAGE-MIG-001.md +0 -32
- package/managed/errors/CAGE-MIG-002.md +0 -32
- package/managed/errors/CAGE-MIG-003.md +0 -32
- package/managed/errors/CAGE-MIG-004.md +0 -32
- package/managed/errors/CAGE-MIG-005.md +0 -32
- package/managed/errors/CAGE-NAME-001.md +0 -32
- package/managed/errors/CAGE-NAME-002.md +0 -32
- package/managed/errors/CAGE-NAME-003.md +0 -32
- package/managed/errors/CAGE-NAME-004.md +0 -32
- package/managed/errors/CAGE-NAME-005.md +0 -32
- package/managed/errors/CAGE-NAME-006.md +0 -32
- package/managed/errors/CAGE-ORG-001.md +0 -32
- package/managed/errors/CAGE-PAIR-002.md +0 -33
- package/managed/errors/CAGE-QUERY-001.md +0 -32
- package/managed/errors/CAGE-QUERY-002.md +0 -32
- package/managed/errors/CAGE-QUERY-003.md +0 -32
- package/managed/errors/CAGE-REACT-001.md +0 -32
- package/managed/errors/CAGE-REACT-002.md +0 -32
- package/managed/errors/CAGE-READS-001.md +0 -32
- package/managed/errors/CAGE-REG-001.md +0 -32
- package/managed/errors/CAGE-REG-002.md +0 -32
- package/managed/errors/CAGE-REG-003.md +0 -32
- package/managed/errors/CAGE-ROUTE-001.md +0 -32
- package/managed/errors/CAGE-SCOPE-001.md +0 -32
- package/managed/errors/CAGE-SCOPE-002.md +0 -32
- package/managed/errors/CAGE-SECRET-001.md +0 -32
- package/managed/errors/CAGE-SECRET-002.md +0 -32
- package/managed/errors/CAGE-SENS-001.md +0 -32
- package/managed/errors/CAGE-SQL-001.md +0 -32
- package/managed/errors/CAGE-SQL-002.md +0 -32
- package/managed/errors/CAGE-STATE-001.md +0 -32
- package/managed/errors/CAGE-STATE-002.md +0 -32
- package/managed/errors/CAGE-STATE-003.md +0 -32
- package/managed/errors/CAGE-STATE-004.md +0 -32
- package/managed/errors/CAGE-STATE-005.md +0 -32
- package/managed/errors/CAGE-STATE-010.md +0 -32
- package/managed/errors/CAGE-STATE-011.md +0 -32
- package/managed/errors/CAGE-SYNC-001.md +0 -35
- package/managed/errors/CAGE-TEST-001.md +0 -33
- package/managed/errors/CAGE-UNSAFE-001.md +0 -32
- package/managed/errors/CAGE-UPGRADE-001.md +0 -32
- package/managed/errors/README.md +0 -99
- package/templates/app/compose.yaml +0 -39
- package/templates/app/packages/contracts/src/purchase-order.ts +0 -72
- package/templates/app/packages/contracts/src/user.ts +0 -89
- package/templates/app/packages/domain/src/approvals.ts +0 -18
- package/templates/app/packages/domain/src/purchase-order.ts +0 -122
package/graph-ui/app.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { kinds, nodeLabel,
|
|
1
|
+
import { kinds, nodeLabel, projectGraph, neighborhood, isSystem, layoutGraph, edgePath, NODE_WIDTH, NODE_HEIGHT, } from './model.js';
|
|
2
2
|
import { explainEdge } from './relations.js';
|
|
3
|
+
import { searchGraphNodes as rankGraphNodes } from './graph-search.js';
|
|
4
|
+
import { businessBlocks, businessConstraintLabel, businessJourneys } from './graph-business.js';
|
|
5
|
+
import { renderBusiness, disposeBusiness, sourcePreview } from './business.js';
|
|
3
6
|
import { tableCards, tableOwner, layoutTables, tableEdgePath, fieldType, TABLE_WIDTH, TABLE_HEADER, TABLE_ROW, } from './structure.js';
|
|
4
7
|
// 页面不引入图形框架或远程 CDN。百级声明图使用 SVG,即可保留清晰缩放、
|
|
5
8
|
// 键盘选择和可检查的节点语义;所有数据都由本地 CLI 抽取服务提供。
|
|
9
|
+
/**
|
|
10
|
+
* 获取 index.html 约定的固定 DOM 锚点并标注调用方类型;这些 ID 由静态骨架提供。
|
|
11
|
+
*/
|
|
6
12
|
const element = (id) => document.getElementById(id);
|
|
7
13
|
const svg = document.getElementById('graph');
|
|
8
14
|
const viewport = document.getElementById('viewport');
|
|
@@ -19,7 +25,7 @@ let selectedEdge = null;
|
|
|
19
25
|
let emphasizeSelection = false;
|
|
20
26
|
let aggregate = null;
|
|
21
27
|
let focus = null;
|
|
22
|
-
let mode = '
|
|
28
|
+
let mode = 'business';
|
|
23
29
|
let cards = [];
|
|
24
30
|
let visibleCards = [];
|
|
25
31
|
let searchTarget = null;
|
|
@@ -29,12 +35,18 @@ const businessKinds = Object.keys(kinds).filter((k) => !['field', 'state', 'capa
|
|
|
29
35
|
let enabled = new Set(businessKinds);
|
|
30
36
|
const nodeElements = new Map();
|
|
31
37
|
const edgeElements = new Map();
|
|
38
|
+
/**
|
|
39
|
+
* 创建页面元素并用 textContent 写文本,避免把抽取文案当作 HTML 执行;返回未挂载节点。
|
|
40
|
+
*/
|
|
32
41
|
function html(tag, className = '', text = '') {
|
|
33
42
|
const node = document.createElement(tag);
|
|
34
43
|
node.className = className;
|
|
35
44
|
node.textContent = text;
|
|
36
45
|
return node;
|
|
37
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* 创建 SVG 命名空间元素并设置属性/文本,供节点和连线绘制;不进行布局计算。
|
|
49
|
+
*/
|
|
38
50
|
function vector(tag, attrs = {}, text = '') {
|
|
39
51
|
const node = document.createElementNS(ns, tag);
|
|
40
52
|
for (const [key, value] of Object.entries(attrs))
|
|
@@ -42,9 +54,71 @@ function vector(tag, attrs = {}, text = '') {
|
|
|
42
54
|
node.textContent = text;
|
|
43
55
|
return node;
|
|
44
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* 在当前展示模型按完整 key 查找节点;调用者只传入模型或检索结果中的已知 key。
|
|
59
|
+
*/
|
|
45
60
|
const byKey = (key) => model.nodes.find((n) => n.key === key);
|
|
61
|
+
/**
|
|
62
|
+
* 使用当前快照的中文覆盖获取显示名,保留底层业务 ID。
|
|
63
|
+
*/
|
|
46
64
|
const displayName = (node) => nodeLabel(node, snapshot.presentation.labels);
|
|
65
|
+
/**
|
|
66
|
+
* 按 patch 修改当前查询参数,null 表示移除,并按 replace 决定替换或新增历史。
|
|
67
|
+
* 不自行重渲染;调用方必须同步页面状态,避免地址和视图分离。
|
|
68
|
+
*/
|
|
69
|
+
function address(patch, replace = false) {
|
|
70
|
+
const url = new URL(location.href);
|
|
71
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
72
|
+
if (value === null)
|
|
73
|
+
url.searchParams.delete(key);
|
|
74
|
+
else
|
|
75
|
+
url.searchParams.set(key, value);
|
|
76
|
+
}
|
|
77
|
+
if (url.href !== location.href)
|
|
78
|
+
history[replace ? 'replaceState' : 'pushState'](null, '', url);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 切回业务视图并更新 URL、筛选及画布;仅换场景时滚到入口,窄屏选步骤时滚到详情。
|
|
82
|
+
*/
|
|
83
|
+
function navigateBusiness(patch) {
|
|
84
|
+
const previousScene = element('business-view').dataset.scene;
|
|
85
|
+
mode = 'business';
|
|
86
|
+
selectedEdge = null;
|
|
87
|
+
address({ view: 'business', node: null, object: null, ...patch });
|
|
88
|
+
renderFilters();
|
|
89
|
+
renderGraph();
|
|
90
|
+
if (previousScene !== element('business-view').dataset.scene)
|
|
91
|
+
element('explorer').scrollIntoView({ block: 'start' });
|
|
92
|
+
if (patch.step && matchMedia('(max-width: 800px)').matches)
|
|
93
|
+
element('business-view').querySelector('.business-detail')?.scrollIntoView({ block: 'start' });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 从 URL 恢复可用视图、选中对象与系统开关,删除或无效节点不被强行选中。
|
|
97
|
+
* 清除临时聚焦和边选择,供首次加载及浏览器前进后退复用。
|
|
98
|
+
*/
|
|
99
|
+
function restoreAddress() {
|
|
100
|
+
const params = new URLSearchParams(location.search);
|
|
101
|
+
const view = params.get('view');
|
|
102
|
+
mode = view === 'structure' || view === 'all' ? view : 'business';
|
|
103
|
+
const node = params.get('node');
|
|
104
|
+
if (node && byKey(node))
|
|
105
|
+
selected = node;
|
|
106
|
+
if (mode === 'structure' && selected)
|
|
107
|
+
selected =
|
|
108
|
+
tableOwner(cards, selected)?.node.key ?? cards.find((card) => !isSystem(card.node))?.node.key ?? null;
|
|
109
|
+
const object = params.get('object');
|
|
110
|
+
aggregate = model.nodes.some((n) => n.kind === 'aggregate' && n.id === object) ? object : null;
|
|
111
|
+
showSystem = params.get('system') === '1';
|
|
112
|
+
if (selected && mode !== 'business')
|
|
113
|
+
showSystem ||= isSystem(byKey(selected));
|
|
114
|
+
focus = null;
|
|
115
|
+
selectedEdge = null;
|
|
116
|
+
enabled = new Set(mode === 'all' ? Object.keys(kinds) : businessKinds);
|
|
117
|
+
}
|
|
47
118
|
// 中文字符约占两个半角字宽,不能沿用英文按字符数截断,否则标题会溢出卡片。
|
|
119
|
+
/**
|
|
120
|
+
* 按半角/中文近似宽度截断画布短标题,超限添加省略号;不是精确字体测量。
|
|
121
|
+
*/
|
|
48
122
|
function shortName(text, width = 23) {
|
|
49
123
|
let result = '', used = 0;
|
|
50
124
|
for (const char of text) {
|
|
@@ -55,16 +129,26 @@ function shortName(text, width = 23) {
|
|
|
55
129
|
}
|
|
56
130
|
return result;
|
|
57
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* 将详情中的业务标识转换为可读名称;可指定类型消歧,未命中节点时尝试显示覆盖,最终保留原始值。
|
|
134
|
+
*/
|
|
58
135
|
const named = (id, kind) => {
|
|
59
136
|
const node = model.nodes.find((n) => n.id === id && (!kind || n.kind === kind));
|
|
60
137
|
return node
|
|
61
138
|
? displayName(node)
|
|
62
139
|
: ((kind ? snapshot.presentation.labels[`${kind}:${id}`] : undefined) ?? String(id));
|
|
63
140
|
};
|
|
141
|
+
/**
|
|
142
|
+
* 更新页面状态提示,空文本隐藏区域;不把错误提示写进本体快照。
|
|
143
|
+
*/
|
|
64
144
|
function notify(message) {
|
|
65
145
|
element('notice').textContent = message;
|
|
66
146
|
element('notice').hidden = !message;
|
|
67
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* 读取或重新抽取快照,再重建投影、卡片与详情。
|
|
150
|
+
* refresh 为 true 时调用 POST;期间禁用刷新按钮,失败保留旧图并提示其来源,finally 恢复按钮。
|
|
151
|
+
*/
|
|
68
152
|
async function load(refresh = false) {
|
|
69
153
|
const button = element('refresh');
|
|
70
154
|
button.disabled = true;
|
|
@@ -94,6 +178,8 @@ async function load(refresh = false) {
|
|
|
94
178
|
const commands = (a) => model.nodes.filter((n) => n.kind === 'command' && n.id.startsWith(`${a.id}.`)).length;
|
|
95
179
|
selected = aggregates.sort((a, b) => commands(b) - commands(a))[0]?.key ?? model.nodes[0]?.key ?? null;
|
|
96
180
|
}
|
|
181
|
+
if (!refresh)
|
|
182
|
+
restoreAddress();
|
|
97
183
|
renderSummary();
|
|
98
184
|
renderFilters();
|
|
99
185
|
renderGraph();
|
|
@@ -114,6 +200,9 @@ async function load(refresh = false) {
|
|
|
114
200
|
element('loading').hidden = true;
|
|
115
201
|
}
|
|
116
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* 从当前快照更新项目标题、节点统计和规则状态;通过只表示声明规则,不表示业务测试通过。
|
|
205
|
+
*/
|
|
117
206
|
function renderSummary() {
|
|
118
207
|
element('project-name').textContent = snapshot.presentation.title;
|
|
119
208
|
element('project-name').title = snapshot.project;
|
|
@@ -133,13 +222,25 @@ function renderSummary() {
|
|
|
133
222
|
element('show-findings').hidden = !snapshot.findings.length;
|
|
134
223
|
const time = new Date(snapshot.generatedAt).toLocaleTimeString('zh-CN', { hour12: false });
|
|
135
224
|
element('updated').textContent = `最近抽取 ${time}`;
|
|
225
|
+
const health = element('business-health');
|
|
226
|
+
health.replaceChildren(html('span', '', `${element('health').textContent} · 最近抽取 ${time}`));
|
|
227
|
+
if (snapshot.findings.length) {
|
|
228
|
+
const findings = html('button', 'text-button', '查看声明问题 ↗');
|
|
229
|
+
findings.onclick = () => element('findings-dialog').showModal();
|
|
230
|
+
health.append(findings);
|
|
231
|
+
}
|
|
136
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* 按当前视图重建板块/对象与类型筛选,回调更新内存状态并请求重绘,不修改声明。
|
|
235
|
+
*/
|
|
137
236
|
function renderFilters() {
|
|
138
|
-
element('types-heading').hidden = mode
|
|
139
|
-
element('type-filters').hidden = mode
|
|
237
|
+
element('types-heading').hidden = mode !== 'all';
|
|
238
|
+
element('type-filters').hidden = mode !== 'all';
|
|
140
239
|
element('structure-note').hidden = mode !== 'structure';
|
|
141
240
|
const aggregates = model.nodes.filter((n) => n.kind === 'aggregate' && (showSystem || !isSystem(n)));
|
|
142
|
-
|
|
241
|
+
const blocks = businessBlocks(model, snapshot.presentation.labels, showSystem);
|
|
242
|
+
element('objects-heading-label').textContent = mode === 'business' ? '业务板块' : '业务对象';
|
|
243
|
+
element('aggregate-total').textContent = String(mode === 'business' ? blocks.length : aggregates.length);
|
|
143
244
|
const list = element('aggregate-list');
|
|
144
245
|
list.replaceChildren();
|
|
145
246
|
const addAggregate = (id, label, count) => {
|
|
@@ -149,14 +250,42 @@ function renderFilters() {
|
|
|
149
250
|
button.onclick = () => {
|
|
150
251
|
aggregate = id;
|
|
151
252
|
focus = null;
|
|
253
|
+
address({ view: mode, object: id });
|
|
152
254
|
renderFilters();
|
|
153
255
|
renderGraph();
|
|
154
256
|
};
|
|
155
257
|
list.append(button);
|
|
156
258
|
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
259
|
+
if (mode === 'business') {
|
|
260
|
+
const selectedBlock = new URLSearchParams(location.search).get('block');
|
|
261
|
+
for (const block of [{ id: null, title: '全部业务', count: blocks.length }, ...blocks.map(b => ({ id: b.id, title: b.title, count: businessJourneys(b, model).length }))]) {
|
|
262
|
+
const button = html('a', `aggregate-button${selectedBlock === block.id ? ' active' : ''}`);
|
|
263
|
+
const url = new URL(location.href);
|
|
264
|
+
for (const key of ['flow', 'step', 'source', 'tab', 'node', 'object'])
|
|
265
|
+
url.searchParams.delete(key);
|
|
266
|
+
url.searchParams.set('view', 'business');
|
|
267
|
+
if (block.id)
|
|
268
|
+
url.searchParams.set('block', block.id);
|
|
269
|
+
else
|
|
270
|
+
url.searchParams.delete('block');
|
|
271
|
+
button.href = url.pathname + url.search;
|
|
272
|
+
button.append(html('span', '', block.id ? '◇' : '⊞'), html('span', '', block.title), html('b', '', String(block.count)));
|
|
273
|
+
button.onclick = (event) => {
|
|
274
|
+
if (event.button || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey)
|
|
275
|
+
return;
|
|
276
|
+
event.preventDefault();
|
|
277
|
+
navigateBusiness({ block: block.id, flow: null, step: null, tab: null, source: null });
|
|
278
|
+
element('sidebar').classList.remove('open');
|
|
279
|
+
element('toggle-sidebar').setAttribute('aria-expanded', 'false');
|
|
280
|
+
};
|
|
281
|
+
list.append(button);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
addAggregate(null, '全部业务', aggregates.length);
|
|
286
|
+
for (const a of aggregates)
|
|
287
|
+
addAggregate(a.id, displayName(a), model.nodes.filter((n) => n.id.startsWith(`${a.id}.`)).length);
|
|
288
|
+
}
|
|
160
289
|
const filters = element('type-filters');
|
|
161
290
|
filters.replaceChildren();
|
|
162
291
|
for (const [kind, meta] of Object.entries(kinds)) {
|
|
@@ -189,6 +318,9 @@ function renderFilters() {
|
|
|
189
318
|
}
|
|
190
319
|
/** 选一个聚合时,先纳入它自己的声明,再沿真实关系扩展业务链。
|
|
191
320
|
* 不沿其他聚合的归属边扩散,避免选采购单却展开所有组织管理命令。 */
|
|
321
|
+
/**
|
|
322
|
+
* 围绕指定聚合沿有限三跳显式关系收集相关节点,避免归属虚线扩散为所有组织命令。
|
|
323
|
+
*/
|
|
192
324
|
function aggregateNodes(id) {
|
|
193
325
|
const keys = new Set(model.nodes.filter((n) => n.id === id || n.id.startsWith(`${id}.`)).map((n) => n.key));
|
|
194
326
|
for (let hop = 0; hop < 3; hop++) {
|
|
@@ -202,7 +334,47 @@ function aggregateNodes(id) {
|
|
|
202
334
|
}
|
|
203
335
|
return keys;
|
|
204
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* 按业务、结构或完整模式重建可见画布,应用类型/系统/对象/邻域筛选。
|
|
339
|
+
* resetLayout 决定是否重新排布;切走业务视图先释放专属监听器,绘制不修改语义图。
|
|
340
|
+
*/
|
|
205
341
|
function renderGraph(resetLayout = true) {
|
|
342
|
+
const business = mode === 'business';
|
|
343
|
+
element('explorer').classList.toggle('business-mode', business);
|
|
344
|
+
element('main').classList.toggle('business-page', business);
|
|
345
|
+
element('business-view').hidden = !business;
|
|
346
|
+
element('page-title').textContent = business ? '业务地图' : '本体图谱';
|
|
347
|
+
element('page-description').textContent = business
|
|
348
|
+
? '先理解业务,再沿流程找到实现。'
|
|
349
|
+
: '从声明出发,看见业务如何连接。';
|
|
350
|
+
element('metric-first-label').textContent = business ? '业务板块' : '业务对象';
|
|
351
|
+
element('metric-second-label').textContent = business ? '业务流程' : '声明节点';
|
|
352
|
+
element('metric-third-label').textContent = business ? '业务对象' : '声明关系';
|
|
353
|
+
const blocks = businessBlocks(model, snapshot.presentation.labels, showSystem);
|
|
354
|
+
element('metric-aggregates').textContent = String(business ? blocks.length : cards.length);
|
|
355
|
+
element('metric-nodes').textContent = String(business ? new Set(blocks.flatMap((b) => businessJourneys(b, model).map((n) => n.key))).size : snapshot.graph.nodes.length);
|
|
356
|
+
element('metric-edges').textContent = String(business ? blocks.flatMap((b) => b.objects).length : snapshot.graph.edges.length);
|
|
357
|
+
if (business) {
|
|
358
|
+
renderBusiness(element('business-view'), model, snapshot, {
|
|
359
|
+
showSystem,
|
|
360
|
+
navigate: navigateBusiness,
|
|
361
|
+
inspect: (key, view) => {
|
|
362
|
+
mode = view;
|
|
363
|
+
enabled = new Set(Object.keys(kinds));
|
|
364
|
+
selected = key;
|
|
365
|
+
selectedEdge = null;
|
|
366
|
+
focus = null;
|
|
367
|
+
aggregate = view === 'structure' ? byKey(key).id : null;
|
|
368
|
+
showSystem ||= isSystem(byKey(key));
|
|
369
|
+
address({ view, node: key, object: aggregate, system: showSystem ? '1' : null });
|
|
370
|
+
renderFilters();
|
|
371
|
+
renderGraph();
|
|
372
|
+
renderInspector();
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
disposeBusiness(element('business-view'));
|
|
206
378
|
searchTarget = null;
|
|
207
379
|
const scope = aggregate ? aggregateNodes(aggregate) : null;
|
|
208
380
|
const focused = focus ? neighborhood(model, focus) : null;
|
|
@@ -336,7 +508,7 @@ function renderGraph(resetLayout = true) {
|
|
|
336
508
|
const hiddenRefs = model.edges.filter((e) => e.kind === 'refs' && tableOwner(visibleCards, e.from) && !tableOwner(visibleCards, e.to)).length;
|
|
337
509
|
element('canvas-status').textContent =
|
|
338
510
|
`${visibleEdges.length} 条对象引用${hiddenRefs ? ` · ${hiddenRefs} 条指向隐藏对象` : ''}`;
|
|
339
|
-
element('edge-legend').textContent = '↗
|
|
511
|
+
element('edge-legend').textContent = '↗ 外键引用 ⇄ 集合关系(非主表列) * 必填';
|
|
340
512
|
}
|
|
341
513
|
else {
|
|
342
514
|
element('edge-legend').replaceChildren(html('span', 'legend-line'), document.createTextNode(' 声明关系 '), html('span', 'legend-line dashed'), document.createTextNode(' 视图归属'));
|
|
@@ -346,6 +518,10 @@ function renderGraph(resetLayout = true) {
|
|
|
346
518
|
}
|
|
347
519
|
/** 绿色表头、逐行字段和表名保持在同一 SVG 卡片里。字段是可选择的原始节点,
|
|
348
520
|
* 表头负责拖动卡片,字段点击不会误触画布拖动或把数据结构重新拆散。 */
|
|
521
|
+
/**
|
|
522
|
+
* 为一个真实聚合绘制字段卡片,保留字段身份供点击、键盘和关系解释使用。
|
|
523
|
+
* 卡片尺寸来自字段数量,敏感/可选/关系标记只展示声明事实。
|
|
524
|
+
*/
|
|
349
525
|
function renderTable(card) {
|
|
350
526
|
const { node, fields, height } = card;
|
|
351
527
|
const group = vector('g', {
|
|
@@ -389,15 +565,15 @@ function renderTable(card) {
|
|
|
389
565
|
transform: `translate(0,${TABLE_HEADER + index * TABLE_ROW})`,
|
|
390
566
|
role: 'button',
|
|
391
567
|
tabindex: 0,
|
|
392
|
-
'aria-label': `字段 ${name} ${field.id},${fieldType(field)}${field.attrs.optional ? ',可选' : ',必填'}`,
|
|
568
|
+
'aria-label': `字段 ${name} ${field.id},${fieldType(field)}${field.attrs.virtual ? ',集合关系,不占主表列' : field.attrs.optional ? ',可选' : ',必填'}`,
|
|
393
569
|
});
|
|
394
570
|
row.append(vector('rect', { width: TABLE_WIDTH, height: TABLE_ROW, class: index % 2 ? 'alternate' : '' }));
|
|
395
|
-
row.append(vector('text', { x: 14, y: 24, class: field.attrs.ref ? 'field-ref' : 'field-dot' }, field.attrs.ref ? '↗' : '·'));
|
|
571
|
+
row.append(vector('text', { x: 14, y: 24, class: field.attrs.ref ? 'field-ref' : 'field-dot' }, field.attrs.virtual ? '⇄' : field.attrs.ref ? '↗' : '·'));
|
|
396
572
|
row.append(vector('text', { x: 34, y: 24, class: 'field-code' }, shortName(code, 16)));
|
|
397
|
-
if (!field.attrs.optional)
|
|
573
|
+
if (!field.attrs.optional && !field.attrs.virtual)
|
|
398
574
|
row.append(vector('text', { x: 150, y: 24, class: 'field-required' }, '*'));
|
|
399
575
|
row.append(vector('text', { x: 166, y: 24, class: 'field-name' }, shortName(name, 14)), vector('text', { x: TABLE_WIDTH - 13, y: 24, 'text-anchor': 'end', class: 'field-type' }, fieldType(field)));
|
|
400
|
-
row.append(vector('title', {}, `${name} · ${field.id}\n${fieldType(field)}${field.attrs.optional ? ' · 可选' : ' · 必填'}${field.attrs.ref ? ` ·
|
|
576
|
+
row.append(vector('title', {}, `${name} · ${field.id}\n${fieldType(field)}${field.attrs.virtual ? ' · 集合关系,不占主表列' : field.attrs.optional ? ' · 可选' : ' · 必填'}${field.attrs.ref ? ` · 关联 ${named(field.attrs.ref, 'aggregate')}` : ''}`));
|
|
401
577
|
row.onclick = (event) => {
|
|
402
578
|
event.stopPropagation();
|
|
403
579
|
selectNode(field.key);
|
|
@@ -420,9 +596,16 @@ function renderTable(card) {
|
|
|
420
596
|
nodeLayer.append(group);
|
|
421
597
|
nodeElements.set(node.key, group);
|
|
422
598
|
}
|
|
599
|
+
/**
|
|
600
|
+
* 按当前视图返回节点尺寸:对象卡片使用字段数算出的高度,普通图使用固定节点规格。
|
|
601
|
+
*/
|
|
423
602
|
const nodeSize = (key) => mode === 'structure'
|
|
424
603
|
? { width: TABLE_WIDTH, height: tableOwner(visibleCards, key).height }
|
|
425
604
|
: { width: NODE_WIDTH, height: NODE_HEIGHT };
|
|
605
|
+
/**
|
|
606
|
+
* 将内存节点位置同步到 SVG 并重算连线,随后在候选线段位置选择碰撞较少的标签落点。
|
|
607
|
+
* 标签仍贴近对应线,拖动只变展示坐标,不保存后端数据。
|
|
608
|
+
*/
|
|
426
609
|
function updatePositions() {
|
|
427
610
|
for (const n of visibleNodes) {
|
|
428
611
|
const p = positions.get(n.key);
|
|
@@ -455,6 +638,9 @@ function updatePositions() {
|
|
|
455
638
|
occupied.push(box);
|
|
456
639
|
}
|
|
457
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* 同步节点/边选择高亮及无障碍状态,结构视图保留其他字段的可读对比度。
|
|
643
|
+
*/
|
|
458
644
|
function highlight() {
|
|
459
645
|
const connected = selectedEdge
|
|
460
646
|
? new Set([selectedEdge.from, selectedEdge.to])
|
|
@@ -492,14 +678,41 @@ function highlight() {
|
|
|
492
678
|
path.setAttribute('marker-end', active ? 'url(#arrow-active)' : 'url(#arrow)');
|
|
493
679
|
}
|
|
494
680
|
}
|
|
681
|
+
/**
|
|
682
|
+
* 根据节点选择切到合适业务入口或技术视图,必要时显式解除隐藏筛选再定位。
|
|
683
|
+
* reveal 请求把目标带入视口,不代表执行该节点的业务操作。
|
|
684
|
+
*/
|
|
495
685
|
function selectNode(key, reveal = false) {
|
|
686
|
+
if (mode === 'business') {
|
|
687
|
+
const node = byKey(key);
|
|
688
|
+
const processKey = node.kind === 'stage' ? `process:${node.attrs.process}` : key;
|
|
689
|
+
const blocks = businessBlocks(model, snapshot.presentation.labels, showSystem || isSystem(byKey(key)));
|
|
690
|
+
const block = blocks.find((b) => b.objects.some((n) => n.key === key) || b.flows.some((n) => n.key === key) || b.processes.some(n => n.key === processKey));
|
|
691
|
+
if (block) {
|
|
692
|
+
showSystem ||= block.system;
|
|
693
|
+
navigateBusiness({
|
|
694
|
+
block: block.id,
|
|
695
|
+
flow: node.kind === 'aggregate' ? (businessJourneys(block, model).some(n => n.key === key) ? key : null) : processKey,
|
|
696
|
+
step: node.kind === 'stage' ? key : null,
|
|
697
|
+
branches: node.kind === 'stage' ? '1' : null,
|
|
698
|
+
tab: null,
|
|
699
|
+
source: null,
|
|
700
|
+
system: showSystem ? '1' : null,
|
|
701
|
+
});
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
mode = 'all';
|
|
705
|
+
enabled = new Set(Object.keys(kinds));
|
|
706
|
+
renderFilters();
|
|
707
|
+
renderGraph();
|
|
708
|
+
}
|
|
496
709
|
searchTarget = null;
|
|
497
710
|
selectedEdge = null;
|
|
498
711
|
selected = key;
|
|
499
712
|
emphasizeSelection = true;
|
|
500
713
|
if (mode === 'structure' && !tableOwner(cards, key)) {
|
|
501
|
-
mode =
|
|
502
|
-
enabled = new Set(
|
|
714
|
+
mode = 'all';
|
|
715
|
+
enabled = new Set(Object.keys(kinds));
|
|
503
716
|
aggregate = null;
|
|
504
717
|
focus = null;
|
|
505
718
|
renderFilters();
|
|
@@ -517,6 +730,7 @@ function selectNode(key, reveal = false) {
|
|
|
517
730
|
}
|
|
518
731
|
highlight();
|
|
519
732
|
renderInspector();
|
|
733
|
+
address({ view: mode, node: key, object: aggregate, system: showSystem ? '1' : null });
|
|
520
734
|
if (reveal && mode === 'structure') {
|
|
521
735
|
searchTarget = key;
|
|
522
736
|
requestAnimationFrame(centerSearchResult);
|
|
@@ -524,6 +738,9 @@ function selectNode(key, reveal = false) {
|
|
|
524
738
|
}
|
|
525
739
|
/** 搜索到长画布下方的字段时将该行移入视口。窄屏详情高度变化可能再次触发
|
|
526
740
|
* ResizeObserver,适应画布后仍需保留搜索位置,否则字段会瞬间跳回屏幕外。 */
|
|
741
|
+
/**
|
|
742
|
+
* 把结构视图搜索到的具体字段行移入视口,保留 resize 后的阅读目标;目标已清除则忽略旧帧。
|
|
743
|
+
*/
|
|
527
744
|
function centerSearchResult() {
|
|
528
745
|
// 等待绘制期间切换视图会清除目标,这一帧就不再执行旧的搜索定位。
|
|
529
746
|
if (!searchTarget)
|
|
@@ -538,6 +755,9 @@ function centerSearchResult() {
|
|
|
538
755
|
camera.y = svg.clientHeight / 2 - (position.y + offset) * camera.scale;
|
|
539
756
|
applyCamera();
|
|
540
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* 选中真实关系并确保两端可见;结构模式不能表达的关系切到完整本体,随后刷新解释面板。
|
|
760
|
+
*/
|
|
541
761
|
function selectEdge(edge) {
|
|
542
762
|
searchTarget = null;
|
|
543
763
|
selectedEdge = edge;
|
|
@@ -566,6 +786,9 @@ function selectEdge(edge) {
|
|
|
566
786
|
renderInspector();
|
|
567
787
|
element('inspector').scrollTop = 0;
|
|
568
788
|
}
|
|
789
|
+
/**
|
|
790
|
+
* 渲染连线原因、用途、端点及源码依据,解释复用 CLI 的共享规则,不按布局猜测执行关系。
|
|
791
|
+
*/
|
|
569
792
|
function renderEdgeInspector(panel, edge) {
|
|
570
793
|
const explanation = explainEdge(edge, model, snapshot.presentation.labels);
|
|
571
794
|
const top = html('div', 'inspector-top');
|
|
@@ -602,7 +825,13 @@ function renderEdgeInspector(panel, edge) {
|
|
|
602
825
|
? `${location.file}:${location.line ?? 1}${location !== node ? '(所属业务对象声明)' : ''}`
|
|
603
826
|
: '来自框架包,当前项目未记录源码位置。'));
|
|
604
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* 重建技术详情面板,优先显示选中边,再按节点类型显示字段、规则、实现与关联入口。
|
|
830
|
+
* 业务视图有独立详情故直接返回;所有动态文字通过 DOM 文本节点呈现。
|
|
831
|
+
*/
|
|
605
832
|
function renderInspector() {
|
|
833
|
+
if (mode === 'business')
|
|
834
|
+
return;
|
|
606
835
|
const panel = element('inspector');
|
|
607
836
|
panel.replaceChildren();
|
|
608
837
|
if (selectedEdge) {
|
|
@@ -666,6 +895,31 @@ function renderInspector() {
|
|
|
666
895
|
};
|
|
667
896
|
actions.append(focusButton, copy);
|
|
668
897
|
panel.append(actions);
|
|
898
|
+
// 把当前节点交给编程工具时交付可追溯的文字,而不是让 AI 猜截图中的连线。
|
|
899
|
+
// 入口与 CLI 使用同一上下文构建器,复制失败明确报告,保留原来的节点详情。
|
|
900
|
+
const handoff = html('section', 'context-handoff');
|
|
901
|
+
const contextButton = html('button', 'button secondary', '⌘ 复制 AI 上下文');
|
|
902
|
+
const contextHint = html('p', '', '包含业务链路、连接原因、源码位置和验证候选。基于当前图谱,改代码后先重新抽取。');
|
|
903
|
+
contextButton.onclick = async () => {
|
|
904
|
+
contextButton.disabled = true;
|
|
905
|
+
contextButton.textContent = '正在整理上下文…';
|
|
906
|
+
try {
|
|
907
|
+
const response = await fetch(`/api/context?node=${encodeURIComponent(node.key)}&format=md`);
|
|
908
|
+
if (!response.ok)
|
|
909
|
+
throw new Error((await response.json()).error);
|
|
910
|
+
await navigator.clipboard.writeText(await response.text());
|
|
911
|
+
contextButton.textContent = '✓ 已复制,粘贴给编程工具';
|
|
912
|
+
}
|
|
913
|
+
catch (error) {
|
|
914
|
+
contextButton.textContent = '⌘ 复制 AI 上下文';
|
|
915
|
+
notify(`上下文复制失败:${error.message}`);
|
|
916
|
+
}
|
|
917
|
+
finally {
|
|
918
|
+
contextButton.disabled = false;
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
handoff.append(contextButton, contextHint);
|
|
922
|
+
panel.append(handoff);
|
|
669
923
|
const section = (title, count) => {
|
|
670
924
|
const div = html('section', 'detail-section'), h = html('h3', '', title);
|
|
671
925
|
if (count !== undefined)
|
|
@@ -713,6 +967,9 @@ function renderInspector() {
|
|
|
713
967
|
for (const [key, label] of Object.entries({
|
|
714
968
|
event: '事件',
|
|
715
969
|
command: '调用命令',
|
|
970
|
+
tx: '事务边界',
|
|
971
|
+
order: '同事件执行顺序',
|
|
972
|
+
collection: '有界集合',
|
|
716
973
|
process: '审批流程',
|
|
717
974
|
cron: '调度表达式',
|
|
718
975
|
connector: '连接器',
|
|
@@ -720,6 +977,11 @@ function renderInspector() {
|
|
|
720
977
|
sensitive: '敏感类型',
|
|
721
978
|
kind: '字段类型',
|
|
722
979
|
ref: '引用对象',
|
|
980
|
+
mappedBy: '对方外键',
|
|
981
|
+
through: '自动中间表',
|
|
982
|
+
virtual: '不占主表列',
|
|
983
|
+
readOnly: '只读关联',
|
|
984
|
+
filePolicy: '文件限制',
|
|
723
985
|
optional: '可选字段',
|
|
724
986
|
acquires: '获取资源',
|
|
725
987
|
releases: '释放资源',
|
|
@@ -743,6 +1005,7 @@ function renderInspector() {
|
|
|
743
1005
|
}
|
|
744
1006
|
else
|
|
745
1007
|
source.append(html('p', 'source-note', node.kind === 'entry' ? '由新建命令的迁移关系推导。' : '来自框架包,当前项目未记录源码位置。'));
|
|
1008
|
+
source.append(sourcePreview(node.key, false));
|
|
746
1009
|
const relations = model.edges.filter((e) => e.from === node.key || e.to === node.key);
|
|
747
1010
|
const relationSection = section('关联关系', relations.length);
|
|
748
1011
|
if (relations.length)
|
|
@@ -768,7 +1031,16 @@ function renderInspector() {
|
|
|
768
1031
|
}
|
|
769
1032
|
/** 把会直接影响阅读理解的属性值翻译为业务名称;SQL 表名、cron 和折叠的
|
|
770
1033
|
* 原始元数据仍保持技术原文,方便开发者核对实现。 */
|
|
1034
|
+
/**
|
|
1035
|
+
* 把节点属性转成可读值,特别保留事务、集合上限和资源标签语义;未知值按字符串展示。
|
|
1036
|
+
*/
|
|
771
1037
|
function detailValue(key, value) {
|
|
1038
|
+
if (key === 'collection') {
|
|
1039
|
+
const collection = value;
|
|
1040
|
+
return `最多 ${collection.maxItems} 项,按 ${collection.orderBy} 排序;串行执行,失败遵循事务边界`;
|
|
1041
|
+
}
|
|
1042
|
+
if (key === 'tx')
|
|
1043
|
+
return value === 'same' ? '与触发命令共同提交或回滚' : '异步 outbox';
|
|
772
1044
|
if (typeof value === 'boolean')
|
|
773
1045
|
return value ? '是' : '否';
|
|
774
1046
|
if (key === 'event' || key === 'command')
|
|
@@ -795,6 +1067,8 @@ function detailValue(key, value) {
|
|
|
795
1067
|
boolean: '布尔值',
|
|
796
1068
|
id: '唯一标识',
|
|
797
1069
|
ref: '关联引用',
|
|
1070
|
+
hasMany: '一对多(反查)',
|
|
1071
|
+
manyToMany: '多对多(自动中间表)',
|
|
798
1072
|
list: '列表',
|
|
799
1073
|
json: '结构化数据',
|
|
800
1074
|
date: '日期',
|
|
@@ -806,23 +1080,15 @@ function detailValue(key, value) {
|
|
|
806
1080
|
};
|
|
807
1081
|
return ['kind', 'sensitive'].includes(key) ? (types[String(value)] ?? String(value)) : String(value);
|
|
808
1082
|
}
|
|
1083
|
+
/**
|
|
1084
|
+
* 将约束中文解释委托共享业务规则,保证技术详情和业务地图用同一字段/额度口径。
|
|
1085
|
+
*/
|
|
809
1086
|
function constraintLabel(name, aggregateId) {
|
|
810
|
-
|
|
811
|
-
if (ceiling)
|
|
812
|
-
return `${named(`${aggregateId}.${ceiling[1]}`, 'field')}不超过审批额度`;
|
|
813
|
-
const sod = /^sod\.notSameAs\((.+)\)$/.exec(name);
|
|
814
|
-
if (sod)
|
|
815
|
-
return `审批人与${named(`${aggregateId}.${sod[1]}`, 'field')}不同`;
|
|
816
|
-
const builtins = {
|
|
817
|
-
stepUp: '需要二次认证',
|
|
818
|
-
knownCapability: '能力点必须已声明',
|
|
819
|
-
noEscalation: '不能授予超出自身的能力',
|
|
820
|
-
noWiderScope: '不能授予超出自身的数据范围',
|
|
821
|
-
noEscalationViaRoles: '不能通过分配角色提权',
|
|
822
|
-
};
|
|
823
|
-
return builtins[name] ?? name;
|
|
1087
|
+
return businessConstraintLabel(name, aggregateId, snapshot.presentation.labels);
|
|
824
1088
|
}
|
|
825
1089
|
const descriptions = {
|
|
1090
|
+
process: '引用真实业务声明的完整流程,区分人工下一步、自动触发和等待。',
|
|
1091
|
+
stage: '业务流程中的一个阶段,可展开查看规则、业务对象与实现代码。',
|
|
826
1092
|
aggregate: '统一管理字段、状态、业务操作和数据范围的业务对象。',
|
|
827
1093
|
command: '受权限和状态约束的业务写入入口。',
|
|
828
1094
|
event: '命令产生的领域事件,用于连接后续业务协作。',
|
|
@@ -839,6 +1105,9 @@ const descriptions = {
|
|
|
839
1105
|
capability: '从聚合声明派生的访问能力点。',
|
|
840
1106
|
entry: '新建命令进入初始业务状态的虚拟起点。',
|
|
841
1107
|
};
|
|
1108
|
+
/**
|
|
1109
|
+
* 按当前快照展示规则错误码、原因、修复建议和位置,不自动修复源码。
|
|
1110
|
+
*/
|
|
842
1111
|
function renderFindings() {
|
|
843
1112
|
const list = element('findings-list');
|
|
844
1113
|
list.replaceChildren();
|
|
@@ -852,6 +1121,10 @@ function renderFindings() {
|
|
|
852
1121
|
list.append(item);
|
|
853
1122
|
}
|
|
854
1123
|
}
|
|
1124
|
+
/**
|
|
1125
|
+
* 复用共享排名检索节点并同时检索板块,显示有限候选和命中依据。
|
|
1126
|
+
* 点击候选更新导航并清空搜索框;未命中只提示换关键词,不判定业务不存在。
|
|
1127
|
+
*/
|
|
855
1128
|
function searchNodes() {
|
|
856
1129
|
const query = element('search').value.trim().toLowerCase();
|
|
857
1130
|
const results = element('search-results');
|
|
@@ -859,12 +1132,31 @@ function searchNodes() {
|
|
|
859
1132
|
results.hidden = !query;
|
|
860
1133
|
if (!query)
|
|
861
1134
|
return;
|
|
862
|
-
const matches = model
|
|
863
|
-
|
|
1135
|
+
const matches = rankGraphNodes(model, query, snapshot.presentation.labels, {
|
|
1136
|
+
descriptions: snapshot.presentation.descriptions,
|
|
1137
|
+
});
|
|
1138
|
+
const matchingBlocks = businessBlocks(model, snapshot.presentation.labels, showSystem).filter((block) => block.title.toLowerCase().includes(query) || block.id.toLowerCase().includes(query));
|
|
1139
|
+
for (const block of matchingBlocks.slice(0, 5)) {
|
|
1140
|
+
const button = html('button', 'search-result');
|
|
1141
|
+
const names = html('span', 'search-names');
|
|
1142
|
+
names.append(html('strong', '', block.title), html('span', '', `${businessJourneys(block, model).length} 个业务流程`));
|
|
1143
|
+
button.append(html('small', '', '业务板块'), names);
|
|
1144
|
+
button.onclick = () => {
|
|
1145
|
+
navigateBusiness({ block: block.id, flow: null, step: null, tab: null, source: null });
|
|
1146
|
+
results.hidden = true;
|
|
1147
|
+
element('search').value = '';
|
|
1148
|
+
};
|
|
1149
|
+
results.append(button);
|
|
1150
|
+
}
|
|
1151
|
+
for (const hit of matches.slice(0, 30)) {
|
|
1152
|
+
const n = byKey(hit.key);
|
|
864
1153
|
const button = html('button', 'search-result');
|
|
865
1154
|
const names = html('span', 'search-names');
|
|
866
1155
|
names.append(html('strong', '', displayName(n)), html('span', '', n.id));
|
|
867
1156
|
button.append(html('small', '', kinds[n.kind].label), names);
|
|
1157
|
+
button.title = hit.matches
|
|
1158
|
+
.map((match) => `${match.field}:${match.value}(命中 ${match.terms.join('、')})`)
|
|
1159
|
+
.join('\n');
|
|
868
1160
|
button.onclick = () => {
|
|
869
1161
|
selectNode(n.key, true);
|
|
870
1162
|
results.hidden = true;
|
|
@@ -872,13 +1164,19 @@ function searchNodes() {
|
|
|
872
1164
|
};
|
|
873
1165
|
results.append(button);
|
|
874
1166
|
}
|
|
875
|
-
if (!matches.length)
|
|
876
|
-
results.append(html('div', 'search-empty', '
|
|
1167
|
+
if (!matches.length && !matchingBlocks.length)
|
|
1168
|
+
results.append(html('div', 'search-empty', '没有匹配的业务,试试业务名称、操作或代码标识。'));
|
|
877
1169
|
}
|
|
1170
|
+
/**
|
|
1171
|
+
* 把当前平移和缩放应用到 SVG 并更新百分比显示,节点业务坐标保持不变。
|
|
1172
|
+
*/
|
|
878
1173
|
function applyCamera() {
|
|
879
1174
|
viewport.setAttribute('transform', `translate(${camera.x},${camera.y}) scale(${camera.scale})`);
|
|
880
1175
|
element('zoom-level').textContent = `${Math.round(camera.scale * 100)}%`;
|
|
881
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* 依据可见节点实际尺寸计算居中缩放;结构视图保持字段可读下限并保留搜索行定位。
|
|
1179
|
+
*/
|
|
882
1180
|
function fit() {
|
|
883
1181
|
if (!visibleNodes.length)
|
|
884
1182
|
return;
|
|
@@ -900,6 +1198,9 @@ function fit() {
|
|
|
900
1198
|
if (mode === 'structure' && searchTarget)
|
|
901
1199
|
centerSearchResult();
|
|
902
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* 以屏幕锚点缩放并限制倍率范围,清除临时搜索吸附,避免缩放时图像突然跳到别处。
|
|
1203
|
+
*/
|
|
903
1204
|
function zoom(factor, x = svg.clientWidth / 2, y = svg.clientHeight / 2) {
|
|
904
1205
|
searchTarget = null;
|
|
905
1206
|
const scale = Math.min(2.5, Math.max(0.15, camera.scale * factor));
|
|
@@ -948,6 +1249,9 @@ svg.addEventListener('pointermove', (event) => {
|
|
|
948
1249
|
applyCamera();
|
|
949
1250
|
}
|
|
950
1251
|
});
|
|
1252
|
+
/**
|
|
1253
|
+
* 结束本次指针拖动;只有正常 pointerup 且未移动才按点击选择,取消不触发选择。
|
|
1254
|
+
*/
|
|
951
1255
|
const endDrag = (event) => {
|
|
952
1256
|
if (!drag || drag.id !== event.pointerId)
|
|
953
1257
|
return;
|
|
@@ -972,7 +1276,7 @@ svg.addEventListener('wheel', (event) => {
|
|
|
972
1276
|
zoom(Math.exp(-event.deltaY * 0.0015), event.clientX - rect.left, event.clientY - rect.top);
|
|
973
1277
|
}, { passive: false });
|
|
974
1278
|
new ResizeObserver(() => {
|
|
975
|
-
if (snapshot) {
|
|
1279
|
+
if (snapshot && mode !== 'business') {
|
|
976
1280
|
if (mode === 'structure') {
|
|
977
1281
|
positions = layoutTables(visibleCards, visibleEdges, svg.clientWidth < 680 ? 1 : 2);
|
|
978
1282
|
updatePositions();
|
|
@@ -980,12 +1284,26 @@ new ResizeObserver(() => {
|
|
|
980
1284
|
fit();
|
|
981
1285
|
}
|
|
982
1286
|
}).observe(svg);
|
|
1287
|
+
/**
|
|
1288
|
+
* 恢复业务首页并清除 URL 中板块、流程、步骤及技术选择,保留当前抽取快照。
|
|
1289
|
+
*/
|
|
983
1290
|
function resetView() {
|
|
984
|
-
mode = '
|
|
1291
|
+
mode = 'business';
|
|
985
1292
|
aggregate = null;
|
|
986
1293
|
focus = null;
|
|
987
1294
|
showSystem = false;
|
|
988
1295
|
enabled = new Set(businessKinds);
|
|
1296
|
+
address({
|
|
1297
|
+
view: 'business',
|
|
1298
|
+
block: null,
|
|
1299
|
+
flow: null,
|
|
1300
|
+
step: null,
|
|
1301
|
+
tab: null,
|
|
1302
|
+
source: null,
|
|
1303
|
+
node: null,
|
|
1304
|
+
object: null,
|
|
1305
|
+
system: null,
|
|
1306
|
+
});
|
|
989
1307
|
renderFilters();
|
|
990
1308
|
renderGraph();
|
|
991
1309
|
}
|
|
@@ -1003,6 +1321,7 @@ element('system-toggle').onchange = (event) => {
|
|
|
1003
1321
|
showSystem = event.target.checked;
|
|
1004
1322
|
aggregate = null;
|
|
1005
1323
|
focus = null;
|
|
1324
|
+
address({ system: showSystem ? '1' : null });
|
|
1006
1325
|
renderFilters();
|
|
1007
1326
|
renderGraph();
|
|
1008
1327
|
};
|
|
@@ -1015,11 +1334,24 @@ document.querySelectorAll('[data-mode]').forEach((button) => {
|
|
|
1015
1334
|
if (mode === 'structure' && selected)
|
|
1016
1335
|
selected =
|
|
1017
1336
|
tableOwner(cards, selected)?.node.key ?? cards.find((card) => !isSystem(card.node))?.node.key ?? null;
|
|
1337
|
+
address({
|
|
1338
|
+
view: mode,
|
|
1339
|
+
node: mode === 'business' ? null : selected,
|
|
1340
|
+
object: mode === 'business' ? null : aggregate,
|
|
1341
|
+
});
|
|
1018
1342
|
renderFilters();
|
|
1019
1343
|
renderGraph();
|
|
1020
1344
|
renderInspector();
|
|
1021
1345
|
};
|
|
1022
1346
|
});
|
|
1347
|
+
window.addEventListener('popstate', () => {
|
|
1348
|
+
if (!snapshot)
|
|
1349
|
+
return;
|
|
1350
|
+
restoreAddress();
|
|
1351
|
+
renderFilters();
|
|
1352
|
+
renderGraph();
|
|
1353
|
+
renderInspector();
|
|
1354
|
+
});
|
|
1023
1355
|
element('refresh').onclick = () => void load(true);
|
|
1024
1356
|
element('search').addEventListener('input', searchNodes);
|
|
1025
1357
|
element('search').addEventListener('focus', searchNodes);
|