spine-framework 0.1.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/.framework/README.md +129 -0
- package/.framework/cli/bin.cjs +14 -0
- package/.framework/cli/commands/agents.ts +153 -0
- package/.framework/cli/commands/auth.ts +94 -0
- package/.framework/cli/commands/create-app.ts +185 -0
- package/.framework/cli/commands/dev.ts +295 -0
- package/.framework/cli/commands/doctor.ts +442 -0
- package/.framework/cli/commands/generate.ts +332 -0
- package/.framework/cli/commands/init.ts +272 -0
- package/.framework/cli/commands/install-app.ts +391 -0
- package/.framework/cli/commands/items.ts +253 -0
- package/.framework/cli/commands/migrations.ts +141 -0
- package/.framework/cli/commands/pipelines.ts +166 -0
- package/.framework/cli/commands/status.ts +197 -0
- package/.framework/cli/commands/system.ts +184 -0
- package/.framework/cli/commands/test.ts +227 -0
- package/.framework/cli/commands/uninstall-app.ts +166 -0
- package/.framework/cli/context.ts +268 -0
- package/.framework/cli/env-loader.ts +36 -0
- package/.framework/cli/index.ts +106 -0
- package/.framework/cli/welcome.cjs +45 -0
- package/.framework/docs/API.md +384 -0
- package/.framework/docs/STABILITY.md +52 -0
- package/.framework/docs/admin-routes.md +76 -0
- package/.framework/docs/api-docs-progress.md +38 -0
- package/.framework/docs/api-governance.md +146 -0
- package/.framework/docs/api-testing-results.md +212 -0
- package/.framework/docs/apis/admin-configs.md +567 -0
- package/.framework/docs/apis/admin-data.md +272 -0
- package/.framework/docs/apis/index.md +231 -0
- package/.framework/docs/apis/internal.md +295 -0
- package/.framework/docs/apis/runtime.md +537 -0
- package/.framework/docs/assembly-launch-guide.md +138 -0
- package/.framework/docs/audit-results.md +590 -0
- package/.framework/docs/authorization-model.md +170 -0
- package/.framework/docs/db-api-inventory.md +95 -0
- package/.framework/docs/examples/custom-app/README.md +77 -0
- package/.framework/docs/examples/custom-function/README.md +27 -0
- package/.framework/docs/examples/custom-function/handler.ts +48 -0
- package/.framework/docs/examples/custom-webhook/README.md +68 -0
- package/.framework/docs/gap-remediation-backlog.md +103 -0
- package/.framework/docs/guides/cli-guide.md +224 -0
- package/.framework/docs/guides/getting-started.md +103 -0
- package/.framework/docs/guides/import-guide.md +193 -0
- package/.framework/docs/guides/testing-guide.md +229 -0
- package/.framework/docs/permission-examples.md +326 -0
- package/.framework/docs/ui-adoption-verification.md +111 -0
- package/.framework/docs/ui-api-coverage.md +84 -0
- package/.framework/docs/v2-compatibility-audit.md +228 -0
- package/.framework/functions/.gitkeep +1 -0
- package/.framework/functions/_shared/agent-runner.ts +1097 -0
- package/.framework/functions/_shared/app-manifest.ts +184 -0
- package/.framework/functions/_shared/audit.ts +150 -0
- package/.framework/functions/_shared/db.ts +174 -0
- package/.framework/functions/_shared/index.ts +382 -0
- package/.framework/functions/_shared/middleware.ts +490 -0
- package/.framework/functions/_shared/permissions.ts +1325 -0
- package/.framework/functions/_shared/pipeline-runner.ts +731 -0
- package/.framework/functions/_shared/principal.ts +760 -0
- package/.framework/functions/_shared/schema-utils.ts +967 -0
- package/.framework/functions/_shared/testing.ts +258 -0
- package/.framework/functions/_shared/trigger-engine.ts +425 -0
- package/.framework/functions/_shared/webhook-registration.ts +168 -0
- package/.framework/functions/_shared/webhook-registry.ts +129 -0
- package/.framework/functions/account-nodes.ts +111 -0
- package/.framework/functions/admin-data.ts +606 -0
- package/.framework/functions/ai-agents.ts +323 -0
- package/.framework/functions/api-keys.ts +376 -0
- package/.framework/functions/apps.ts +483 -0
- package/.framework/functions/auth.ts +196 -0
- package/.framework/functions/debug-auth.ts +107 -0
- package/.framework/functions/embeddings.ts +556 -0
- package/.framework/functions/integration-routes.ts +523 -0
- package/.framework/functions/integrations.ts +319 -0
- package/.framework/functions/item-progress.ts +272 -0
- package/.framework/functions/logs.ts +438 -0
- package/.framework/functions/observability.ts +275 -0
- package/.framework/functions/pipeline-executions.ts +494 -0
- package/.framework/functions/pipelines.ts +485 -0
- package/.framework/functions/prompt-configs.ts +339 -0
- package/.framework/functions/roles.ts +387 -0
- package/.framework/functions/system-cron.ts +742 -0
- package/.framework/functions/system.ts +323 -0
- package/.framework/functions/tests.ts +119 -0
- package/.framework/functions/timers.ts +357 -0
- package/.framework/functions/triggers.ts +563 -0
- package/.framework/functions/types.ts +604 -0
- package/.framework/migrations/000_foundation.sql +1256 -0
- package/.framework/migrations/001_seed.sql +92 -0
- package/.framework/migrations/002_seed_constraints.sql +13 -0
- package/.framework/migrations/003_auth_user_trigger.sql +59 -0
- package/.framework/src/App.tsx +126 -0
- package/.framework/src/apps/admin/index.tsx +173 -0
- package/.framework/src/components/AppWrapper.tsx +56 -0
- package/.framework/src/components/CustomAppLoader.tsx +116 -0
- package/.framework/src/components/admin/AdminListPage.tsx +151 -0
- package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
- package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
- package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
- package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
- package/.framework/src/components/app-sidebar.tsx +228 -0
- package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
- package/.framework/src/components/layout/AppShell.tsx +91 -0
- package/.framework/src/components/layout/Header.tsx +88 -0
- package/.framework/src/components/layout/Layout.tsx +95 -0
- package/.framework/src/components/layout/Sidebar.tsx +329 -0
- package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
- package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
- package/.framework/src/components/runtime/DataFilters.tsx +91 -0
- package/.framework/src/components/runtime/DataHeader.tsx +68 -0
- package/.framework/src/components/runtime/DataListPage.tsx +124 -0
- package/.framework/src/components/runtime/DataStats.tsx +70 -0
- package/.framework/src/components/runtime/DataTable.tsx +174 -0
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
- package/.framework/src/components/runtime/index.ts +18 -0
- package/.framework/src/components/search-form.tsx +29 -0
- package/.framework/src/components/shared/AgentView.tsx +213 -0
- package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
- package/.framework/src/components/shared/SchemaFields.tsx +226 -0
- package/.framework/src/components/ui/DataTable.tsx +343 -0
- package/.framework/src/components/ui/Form.tsx +281 -0
- package/.framework/src/components/ui/ItemCard.tsx +296 -0
- package/.framework/src/components/ui/ItemListView.tsx +308 -0
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
- package/.framework/src/components/ui/Modal.tsx +61 -0
- package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
- package/.framework/src/components/ui/accordion.tsx +82 -0
- package/.framework/src/components/ui/alert-dialog.tsx +197 -0
- package/.framework/src/components/ui/alert.tsx +76 -0
- package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
- package/.framework/src/components/ui/avatar.tsx +110 -0
- package/.framework/src/components/ui/badge.tsx +49 -0
- package/.framework/src/components/ui/breadcrumb.tsx +122 -0
- package/.framework/src/components/ui/button-group.tsx +83 -0
- package/.framework/src/components/ui/button.tsx +65 -0
- package/.framework/src/components/ui/calendar.tsx +222 -0
- package/.framework/src/components/ui/card.tsx +100 -0
- package/.framework/src/components/ui/carousel.tsx +240 -0
- package/.framework/src/components/ui/chart.tsx +373 -0
- package/.framework/src/components/ui/checkbox.tsx +31 -0
- package/.framework/src/components/ui/collapsible.tsx +33 -0
- package/.framework/src/components/ui/combobox.tsx +299 -0
- package/.framework/src/components/ui/command.tsx +193 -0
- package/.framework/src/components/ui/context-menu.tsx +261 -0
- package/.framework/src/components/ui/dialog.tsx +165 -0
- package/.framework/src/components/ui/direction.tsx +22 -0
- package/.framework/src/components/ui/drawer.tsx +132 -0
- package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
- package/.framework/src/components/ui/empty.tsx +104 -0
- package/.framework/src/components/ui/field.tsx +238 -0
- package/.framework/src/components/ui/hover-card.tsx +42 -0
- package/.framework/src/components/ui/input-group.tsx +153 -0
- package/.framework/src/components/ui/input-otp.tsx +87 -0
- package/.framework/src/components/ui/input.tsx +19 -0
- package/.framework/src/components/ui/item.tsx +196 -0
- package/.framework/src/components/ui/kbd.tsx +26 -0
- package/.framework/src/components/ui/label.tsx +22 -0
- package/.framework/src/components/ui/menubar.tsx +277 -0
- package/.framework/src/components/ui/native-select.tsx +61 -0
- package/.framework/src/components/ui/navigation-menu.tsx +164 -0
- package/.framework/src/components/ui/pagination.tsx +129 -0
- package/.framework/src/components/ui/popover.tsx +87 -0
- package/.framework/src/components/ui/progress.tsx +31 -0
- package/.framework/src/components/ui/radio-group.tsx +42 -0
- package/.framework/src/components/ui/resizable.tsx +50 -0
- package/.framework/src/components/ui/scroll-area.tsx +53 -0
- package/.framework/src/components/ui/select.tsx +195 -0
- package/.framework/src/components/ui/separator.tsx +26 -0
- package/.framework/src/components/ui/sheet.tsx +145 -0
- package/.framework/src/components/ui/sidebar.tsx +706 -0
- package/.framework/src/components/ui/skeleton.tsx +13 -0
- package/.framework/src/components/ui/slider.tsx +59 -0
- package/.framework/src/components/ui/sonner.tsx +47 -0
- package/.framework/src/components/ui/spinner.tsx +10 -0
- package/.framework/src/components/ui/switch.tsx +33 -0
- package/.framework/src/components/ui/table-primitives.tsx +141 -0
- package/.framework/src/components/ui/table.tsx +114 -0
- package/.framework/src/components/ui/tabs.tsx +90 -0
- package/.framework/src/components/ui/textarea.tsx +18 -0
- package/.framework/src/components/ui/toggle-group.tsx +89 -0
- package/.framework/src/components/ui/toggle.tsx +45 -0
- package/.framework/src/components/ui/tooltip.tsx +57 -0
- package/.framework/src/contexts/AppContext.tsx +133 -0
- package/.framework/src/contexts/AuthContext.tsx +371 -0
- package/.framework/src/hooks/use-mobile.ts +19 -0
- package/.framework/src/hooks/useApi.ts +526 -0
- package/.framework/src/hooks/useApps.ts +114 -0
- package/.framework/src/hooks/useEntityList.ts +190 -0
- package/.framework/src/hooks/useEntityRecord.ts +308 -0
- package/.framework/src/hooks/useForm.ts +307 -0
- package/.framework/src/hooks/useListSchema.ts +264 -0
- package/.framework/src/hooks/useSchemaRecord.ts +223 -0
- package/.framework/src/index.css +128 -0
- package/.framework/src/lib/api.ts +156 -0
- package/.framework/src/lib/supabase.ts +94 -0
- package/.framework/src/lib/utils.ts +317 -0
- package/.framework/src/main.tsx +27 -0
- package/.framework/src/pages/DashboardPage.tsx +181 -0
- package/.framework/src/pages/NotFoundPage.tsx +39 -0
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
- package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
- package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
- package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
- package/.framework/src/pages/admin/AppsPage.tsx +355 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
- package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
- package/.framework/src/pages/admin/LogsPage.tsx +283 -0
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
- package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
- package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
- package/.framework/src/pages/admin/RolesPage.tsx +292 -0
- package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
- package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
- package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
- package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
- package/.framework/src/pages/admin/TimersPage.tsx +376 -0
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
- package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
- package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
- package/.framework/src/pages/admin/TypesPage.tsx +295 -0
- package/.framework/src/pages/auth/LoginPage.tsx +188 -0
- package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
- package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
- package/.framework/src/types/auth.ts +125 -0
- package/.framework/src/types/types.ts +407 -0
- package/STRUCTURE.md +150 -0
- package/config/components.json +25 -0
- package/config/deno.lock +108 -0
- package/config/package-lock.json +17183 -0
- package/config/postcss.config.cjs +10 -0
- package/config/tailwind.config.cjs +78 -0
- package/config/tsconfig.build.json +32 -0
- package/config/tsconfig.cli.json +18 -0
- package/config/tsconfig.json +41 -0
- package/config/tsconfig.node.json +17 -0
- package/config/tsconfig.node.tsbuildinfo +1 -0
- package/config/tsconfig.tsbuildinfo +1 -0
- package/config/typedoc.json +16 -0
- package/config/vite.config.d.ts +2 -0
- package/config/vite.config.ts +72 -0
- package/dist/cli/commands/agents.d.ts +39 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/auth.d.ts +36 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/create-app.d.ts +23 -0
- package/dist/cli/commands/create-app.d.ts.map +1 -0
- package/dist/cli/commands/dev.d.ts +39 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/doctor.d.ts +42 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/generate.d.ts +36 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts +30 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/install-app.d.ts +30 -0
- package/dist/cli/commands/install-app.d.ts.map +1 -0
- package/dist/cli/commands/items.d.ts +45 -0
- package/dist/cli/commands/items.d.ts.map +1 -0
- package/dist/cli/commands/migrations.d.ts +41 -0
- package/dist/cli/commands/migrations.d.ts.map +1 -0
- package/dist/cli/commands/pipelines.d.ts +40 -0
- package/dist/cli/commands/pipelines.d.ts.map +1 -0
- package/dist/cli/commands/status.d.ts +23 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/system.d.ts +29 -0
- package/dist/cli/commands/system.d.ts.map +1 -0
- package/dist/cli/commands/test.d.ts +46 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/uninstall-app.d.ts +23 -0
- package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
- package/dist/cli/context.d.ts +88 -0
- package/dist/cli/context.d.ts.map +1 -0
- package/dist/cli/env-loader.d.ts +14 -0
- package/dist/cli/env-loader.d.ts.map +1 -0
- package/dist/cli/index.d.ts +41 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/functions/_shared/agent-runner.d.ts +156 -0
- package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
- package/dist/functions/_shared/app-manifest.d.ts +68 -0
- package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
- package/dist/functions/_shared/audit.d.ts +91 -0
- package/dist/functions/_shared/audit.d.ts.map +1 -0
- package/dist/functions/_shared/db.d.ts +125 -0
- package/dist/functions/_shared/db.d.ts.map +1 -0
- package/dist/functions/_shared/index.d.ts +298 -0
- package/dist/functions/_shared/index.d.ts.map +1 -0
- package/dist/functions/_shared/middleware.d.ts +315 -0
- package/dist/functions/_shared/middleware.d.ts.map +1 -0
- package/dist/functions/_shared/permissions.d.ts +626 -0
- package/dist/functions/_shared/permissions.d.ts.map +1 -0
- package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
- package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
- package/dist/functions/_shared/principal.d.ts +284 -0
- package/dist/functions/_shared/principal.d.ts.map +1 -0
- package/dist/functions/_shared/schema-utils.d.ts +181 -0
- package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
- package/dist/functions/_shared/testing.d.ts +172 -0
- package/dist/functions/_shared/testing.d.ts.map +1 -0
- package/dist/functions/_shared/trigger-engine.d.ts +140 -0
- package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
- package/dist/functions/_shared/webhook-registration.d.ts +81 -0
- package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
- package/dist/functions/_shared/webhook-registry.d.ts +57 -0
- package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
- package/dist/functions/account-nodes.d.ts +48 -0
- package/dist/functions/account-nodes.d.ts.map +1 -0
- package/dist/functions/admin-data.d.ts +178 -0
- package/dist/functions/admin-data.d.ts.map +1 -0
- package/dist/functions/ai-agents.d.ts +125 -0
- package/dist/functions/ai-agents.d.ts.map +1 -0
- package/dist/functions/api-keys.d.ts +140 -0
- package/dist/functions/api-keys.d.ts.map +1 -0
- package/dist/functions/apps.d.ts +163 -0
- package/dist/functions/apps.d.ts.map +1 -0
- package/dist/functions/auth.d.ts +74 -0
- package/dist/functions/auth.d.ts.map +1 -0
- package/dist/functions/debug-auth.d.ts +33 -0
- package/dist/functions/debug-auth.d.ts.map +1 -0
- package/dist/functions/embeddings.d.ts +205 -0
- package/dist/functions/embeddings.d.ts.map +1 -0
- package/dist/functions/integration-routes.d.ts +45 -0
- package/dist/functions/integration-routes.d.ts.map +1 -0
- package/dist/functions/integrations.d.ts +124 -0
- package/dist/functions/integrations.d.ts.map +1 -0
- package/dist/functions/item-progress.d.ts +41 -0
- package/dist/functions/item-progress.d.ts.map +1 -0
- package/dist/functions/logs.d.ts +162 -0
- package/dist/functions/logs.d.ts.map +1 -0
- package/dist/functions/observability.d.ts +123 -0
- package/dist/functions/observability.d.ts.map +1 -0
- package/dist/functions/pipeline-executions.d.ts +190 -0
- package/dist/functions/pipeline-executions.d.ts.map +1 -0
- package/dist/functions/pipelines.d.ts +171 -0
- package/dist/functions/pipelines.d.ts.map +1 -0
- package/dist/functions/prompt-configs.d.ts +125 -0
- package/dist/functions/prompt-configs.d.ts.map +1 -0
- package/dist/functions/roles.d.ts +118 -0
- package/dist/functions/roles.d.ts.map +1 -0
- package/dist/functions/system-cron.d.ts +65 -0
- package/dist/functions/system-cron.d.ts.map +1 -0
- package/dist/functions/system.d.ts +29 -0
- package/dist/functions/system.d.ts.map +1 -0
- package/dist/functions/tests.d.ts +28 -0
- package/dist/functions/tests.d.ts.map +1 -0
- package/dist/functions/timers.d.ts +139 -0
- package/dist/functions/timers.d.ts.map +1 -0
- package/dist/functions/triggers.d.ts +203 -0
- package/dist/functions/triggers.d.ts.map +1 -0
- package/dist/functions/types.d.ts +151 -0
- package/dist/functions/types.d.ts.map +1 -0
- package/dist/src/types/types.d.ts +364 -0
- package/dist/src/types/types.d.ts.map +1 -0
- package/package.json +192 -0
- package/scripts/app-install-cli.ts +286 -0
- package/scripts/assemble-frontend.sh +79 -0
- package/scripts/assemble-functions.sh +62 -0
- package/scripts/assemble.sh +35 -0
- package/scripts/boundary-check.sh +106 -0
- package/scripts/build-manifest.sh +80 -0
- package/scripts/check-core-integrity.sh +82 -0
- package/scripts/ingest-chunks.cjs +202 -0
- package/scripts/kb-chunk-parser.cjs +312 -0
- package/scripts/kb-chunk-parser.ts +330 -0
- package/scripts/load-test-app-install.ts +484 -0
- package/scripts/netlify-dev-wrapper.sh +22 -0
- package/scripts/verify-integrity.sh +69 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module src/pages/admin/SimpleDashboard
|
|
3
|
+
* @audience installer
|
|
4
|
+
* @layer frontend-page
|
|
5
|
+
* @stability testing
|
|
6
|
+
*
|
|
7
|
+
* A simple dashboard that works within the existing admin layout.
|
|
8
|
+
* No layout conflicts - just content.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useState } from 'react'
|
|
12
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../components/ui/card'
|
|
13
|
+
import { Button } from '../../components/ui/button'
|
|
14
|
+
import { Input } from '../../components/ui/input'
|
|
15
|
+
import { Badge } from '../../components/ui/badge'
|
|
16
|
+
import {
|
|
17
|
+
Select,
|
|
18
|
+
SelectContent,
|
|
19
|
+
SelectItem,
|
|
20
|
+
SelectTrigger,
|
|
21
|
+
SelectValue,
|
|
22
|
+
} from '../../components/ui/select'
|
|
23
|
+
import { Switch } from '../../components/ui/switch'
|
|
24
|
+
import {
|
|
25
|
+
Tabs,
|
|
26
|
+
TabsContent,
|
|
27
|
+
TabsList,
|
|
28
|
+
TabsTrigger,
|
|
29
|
+
} from '../../components/ui/tabs'
|
|
30
|
+
import { Alert, AlertDescription, AlertTitle } from '../../components/ui/alert'
|
|
31
|
+
import {
|
|
32
|
+
Plus,
|
|
33
|
+
Users,
|
|
34
|
+
FileText,
|
|
35
|
+
BarChart3,
|
|
36
|
+
Search,
|
|
37
|
+
Filter,
|
|
38
|
+
Download,
|
|
39
|
+
Eye,
|
|
40
|
+
ChevronRight,
|
|
41
|
+
Database,
|
|
42
|
+
Shield,
|
|
43
|
+
CheckCircle,
|
|
44
|
+
AlertTriangle,
|
|
45
|
+
TrendingUp,
|
|
46
|
+
Activity,
|
|
47
|
+
Settings
|
|
48
|
+
} from 'lucide-react'
|
|
49
|
+
|
|
50
|
+
export function SimpleDashboard() {
|
|
51
|
+
const [selectedTab, setSelectedTab] = useState('overview')
|
|
52
|
+
const [searchQuery, setSearchQuery] = useState('')
|
|
53
|
+
const [notifications, setNotifications] = useState(true)
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="space-y-6">
|
|
57
|
+
{/* Page Header */}
|
|
58
|
+
<div className="flex items-center justify-between">
|
|
59
|
+
<div>
|
|
60
|
+
<h2 className="text-3xl font-bold tracking-tight">Dashboard</h2>
|
|
61
|
+
<p className="text-muted-foreground">
|
|
62
|
+
Monitor your system performance and key metrics
|
|
63
|
+
</p>
|
|
64
|
+
</div>
|
|
65
|
+
<div className="flex items-center gap-2">
|
|
66
|
+
<Badge variant="outline" className="bg-green-50 text-green-700 border-green-200 dark:bg-green-900/20 dark:text-green-400 dark:border-green-800">
|
|
67
|
+
<CheckCircle className="w-3 h-3 mr-1" />
|
|
68
|
+
System Healthy
|
|
69
|
+
</Badge>
|
|
70
|
+
<Button>
|
|
71
|
+
<Plus className="w-4 h-4 mr-2" />
|
|
72
|
+
New Project
|
|
73
|
+
</Button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
{/* Search and Filter Bar */}
|
|
78
|
+
<Card>
|
|
79
|
+
<CardContent className="pt-6">
|
|
80
|
+
<div className="flex flex-col gap-4 sm:flex-row sm:items-center">
|
|
81
|
+
<div className="relative flex-1">
|
|
82
|
+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
83
|
+
<Input
|
|
84
|
+
placeholder="Search projects, users, or data..."
|
|
85
|
+
value={searchQuery}
|
|
86
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
87
|
+
className="pl-10"
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
<div className="flex gap-2">
|
|
91
|
+
<Button variant="outline" size="sm">
|
|
92
|
+
<Filter className="h-4 w-4 mr-2" />
|
|
93
|
+
Filter
|
|
94
|
+
</Button>
|
|
95
|
+
<Button variant="outline" size="sm">
|
|
96
|
+
<Download className="h-4 w-4 mr-2" />
|
|
97
|
+
Export
|
|
98
|
+
</Button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</CardContent>
|
|
102
|
+
</Card>
|
|
103
|
+
|
|
104
|
+
{/* Stats Cards */}
|
|
105
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
106
|
+
<Card className="relative overflow-hidden">
|
|
107
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
108
|
+
<CardTitle className="text-sm font-medium">Total Users</CardTitle>
|
|
109
|
+
<Users className="h-4 w-4 text-muted-foreground" />
|
|
110
|
+
</CardHeader>
|
|
111
|
+
<CardContent>
|
|
112
|
+
<div className="text-2xl font-bold">2,847</div>
|
|
113
|
+
<p className="text-xs text-muted-foreground flex items-center">
|
|
114
|
+
<TrendingUp className="w-3 h-3 mr-1 text-green-600" />
|
|
115
|
+
+12% from last month
|
|
116
|
+
</p>
|
|
117
|
+
</CardContent>
|
|
118
|
+
<div className="absolute top-0 right-0 h-16 w-16 bg-gradient-to-br from-blue-500/10 to-transparent rounded-bl-2xl"></div>
|
|
119
|
+
</Card>
|
|
120
|
+
|
|
121
|
+
<Card className="relative overflow-hidden">
|
|
122
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
123
|
+
<CardTitle className="text-sm font-medium">Active Projects</CardTitle>
|
|
124
|
+
<FileText className="h-4 w-4 text-muted-foreground" />
|
|
125
|
+
</CardHeader>
|
|
126
|
+
<CardContent>
|
|
127
|
+
<div className="text-2xl font-bold">142</div>
|
|
128
|
+
<p className="text-xs text-muted-foreground flex items-center">
|
|
129
|
+
<TrendingUp className="w-3 h-3 mr-1 text-green-600" />
|
|
130
|
+
+5% from last month
|
|
131
|
+
</p>
|
|
132
|
+
</CardContent>
|
|
133
|
+
<div className="absolute top-0 right-0 h-16 w-16 bg-gradient-to-br from-green-500/10 to-transparent rounded-bl-2xl"></div>
|
|
134
|
+
</Card>
|
|
135
|
+
|
|
136
|
+
<Card className="relative overflow-hidden">
|
|
137
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
138
|
+
<CardTitle className="text-sm font-medium">Data Processed</CardTitle>
|
|
139
|
+
<Database className="h-4 w-4 text-muted-foreground" />
|
|
140
|
+
</CardHeader>
|
|
141
|
+
<CardContent>
|
|
142
|
+
<div className="text-2xl font-bold">1.2M</div>
|
|
143
|
+
<p className="text-xs text-muted-foreground flex items-center">
|
|
144
|
+
<TrendingUp className="w-3 h-3 mr-1 text-green-600" />
|
|
145
|
+
+18% from last month
|
|
146
|
+
</p>
|
|
147
|
+
</CardContent>
|
|
148
|
+
<div className="absolute top-0 right-0 h-16 w-16 bg-gradient-to-br from-purple-500/10 to-transparent rounded-bl-2xl"></div>
|
|
149
|
+
</Card>
|
|
150
|
+
|
|
151
|
+
<Card className="relative overflow-hidden">
|
|
152
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
153
|
+
<CardTitle className="text-sm font-medium">System Health</CardTitle>
|
|
154
|
+
<Activity className="h-4 w-4 text-muted-foreground" />
|
|
155
|
+
</CardHeader>
|
|
156
|
+
<CardContent>
|
|
157
|
+
<div className="text-2xl font-bold">98.5%</div>
|
|
158
|
+
<p className="text-xs text-muted-foreground flex items-center">
|
|
159
|
+
<AlertTriangle className="w-3 h-3 mr-1 text-yellow-600" />
|
|
160
|
+
-0.5% from last month
|
|
161
|
+
</p>
|
|
162
|
+
</CardContent>
|
|
163
|
+
<div className="absolute top-0 right-0 h-16 w-16 bg-gradient-to-br from-orange-500/10 to-transparent rounded-bl-2xl"></div>
|
|
164
|
+
</Card>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
{/* Main Content Tabs */}
|
|
168
|
+
<Tabs value={selectedTab} onValueChange={setSelectedTab} className="space-y-4">
|
|
169
|
+
<TabsList className="grid w-full grid-cols-4">
|
|
170
|
+
<TabsTrigger value="overview">Overview</TabsTrigger>
|
|
171
|
+
<TabsTrigger value="analytics">Analytics</TabsTrigger>
|
|
172
|
+
<TabsTrigger value="reports">Reports</TabsTrigger>
|
|
173
|
+
<TabsTrigger value="settings">Settings</TabsTrigger>
|
|
174
|
+
</TabsList>
|
|
175
|
+
|
|
176
|
+
<TabsContent value="overview" className="space-y-4">
|
|
177
|
+
<div className="grid gap-6 lg:grid-cols-3">
|
|
178
|
+
{/* Recent Activity */}
|
|
179
|
+
<Card className="lg:col-span-2">
|
|
180
|
+
<CardHeader>
|
|
181
|
+
<CardTitle>Recent Activity</CardTitle>
|
|
182
|
+
<CardDescription>
|
|
183
|
+
Latest system events and user actions
|
|
184
|
+
</CardDescription>
|
|
185
|
+
</CardHeader>
|
|
186
|
+
<CardContent>
|
|
187
|
+
<div className="space-y-4">
|
|
188
|
+
<div className="flex items-center gap-4 p-4 rounded-lg border border-border/50 bg-card/50 hover:bg-card transition-colors">
|
|
189
|
+
<div className="h-10 w-10 rounded-full bg-primary/10 flex items-center justify-center">
|
|
190
|
+
<Users className="h-5 w-5 text-primary" />
|
|
191
|
+
</div>
|
|
192
|
+
<div className="flex-1 min-w-0">
|
|
193
|
+
<p className="font-medium truncate">New user registration</p>
|
|
194
|
+
<p className="text-sm text-muted-foreground">John Doe joined 2 minutes ago</p>
|
|
195
|
+
</div>
|
|
196
|
+
<ChevronRight className="h-4 w-4 text-muted-foreground flex-shrink-0" />
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<div className="flex items-center gap-4 p-4 rounded-lg border border-border/50 bg-card/50 hover:bg-card transition-colors">
|
|
200
|
+
<div className="h-10 w-10 rounded-full bg-secondary/10 flex items-center justify-center">
|
|
201
|
+
<FileText className="h-5 w-5 text-secondary-foreground" />
|
|
202
|
+
</div>
|
|
203
|
+
<div className="flex-1 min-w-0">
|
|
204
|
+
<p className="font-medium truncate">Report generated</p>
|
|
205
|
+
<p className="text-sm text-muted-foreground">Monthly analytics report completed</p>
|
|
206
|
+
</div>
|
|
207
|
+
<ChevronRight className="h-4 w-4 text-muted-foreground flex-shrink-0" />
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div className="flex items-center gap-4 p-4 rounded-lg border border-border/50 bg-card/50 hover:bg-card transition-colors">
|
|
211
|
+
<div className="h-10 w-10 rounded-full bg-destructive/10 flex items-center justify-center">
|
|
212
|
+
<AlertTriangle className="h-5 w-5 text-destructive" />
|
|
213
|
+
</div>
|
|
214
|
+
<div className="flex-1 min-w-0">
|
|
215
|
+
<p className="font-medium truncate">System alert</p>
|
|
216
|
+
<p className="text-sm text-muted-foreground">High memory usage detected</p>
|
|
217
|
+
</div>
|
|
218
|
+
<ChevronRight className="h-4 w-4 text-muted-foreground flex-shrink-0" />
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
</CardContent>
|
|
222
|
+
</Card>
|
|
223
|
+
|
|
224
|
+
{/* Quick Actions */}
|
|
225
|
+
<Card>
|
|
226
|
+
<CardHeader>
|
|
227
|
+
<CardTitle>Quick Actions</CardTitle>
|
|
228
|
+
<CardDescription>
|
|
229
|
+
Common tasks and shortcuts
|
|
230
|
+
</CardDescription>
|
|
231
|
+
</CardHeader>
|
|
232
|
+
<CardContent className="space-y-3">
|
|
233
|
+
<Button className="w-full justify-start gap-2">
|
|
234
|
+
<Plus className="h-4 w-4" />
|
|
235
|
+
Create New Project
|
|
236
|
+
</Button>
|
|
237
|
+
<Button variant="outline" className="w-full justify-start gap-2">
|
|
238
|
+
<Users className="h-4 w-4" />
|
|
239
|
+
Invite Team Member
|
|
240
|
+
</Button>
|
|
241
|
+
<Button variant="outline" className="w-full justify-start gap-2">
|
|
242
|
+
<Download className="h-4 w-4" />
|
|
243
|
+
Export Report
|
|
244
|
+
</Button>
|
|
245
|
+
<Button variant="outline" className="w-full justify-start gap-2">
|
|
246
|
+
<Settings className="h-4 w-4" />
|
|
247
|
+
System Settings
|
|
248
|
+
</Button>
|
|
249
|
+
</CardContent>
|
|
250
|
+
</Card>
|
|
251
|
+
</div>
|
|
252
|
+
</TabsContent>
|
|
253
|
+
|
|
254
|
+
<TabsContent value="analytics" className="space-y-4">
|
|
255
|
+
<Card>
|
|
256
|
+
<CardHeader>
|
|
257
|
+
<CardTitle>Analytics Dashboard</CardTitle>
|
|
258
|
+
<CardDescription>
|
|
259
|
+
System performance and usage metrics
|
|
260
|
+
</CardDescription>
|
|
261
|
+
</CardHeader>
|
|
262
|
+
<CardContent>
|
|
263
|
+
<div className="h-64 flex items-center justify-center border-2 border-dashed border-border rounded-lg bg-muted/20">
|
|
264
|
+
<div className="text-center">
|
|
265
|
+
<BarChart3 className="h-12 w-12 text-muted-foreground mx-auto mb-4" />
|
|
266
|
+
<p className="text-muted-foreground">Analytics charts would be displayed here</p>
|
|
267
|
+
<p className="text-sm text-muted-foreground mt-2">Integration with charting library needed</p>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
</CardContent>
|
|
271
|
+
</Card>
|
|
272
|
+
</TabsContent>
|
|
273
|
+
|
|
274
|
+
<TabsContent value="reports" className="space-y-4">
|
|
275
|
+
<Card>
|
|
276
|
+
<CardHeader>
|
|
277
|
+
<CardTitle>Reports</CardTitle>
|
|
278
|
+
<CardDescription>
|
|
279
|
+
Generated reports and documentation
|
|
280
|
+
</CardDescription>
|
|
281
|
+
</CardHeader>
|
|
282
|
+
<CardContent>
|
|
283
|
+
<div className="space-y-4">
|
|
284
|
+
{[
|
|
285
|
+
{ name: 'Monthly Analytics', date: '2024-01-15', status: 'completed' },
|
|
286
|
+
{ name: 'User Activity Report', date: '2024-01-14', status: 'completed' },
|
|
287
|
+
{ name: 'System Performance', date: '2024-01-13', status: 'processing' },
|
|
288
|
+
].map((report, index) => (
|
|
289
|
+
<div key={index} className="flex items-center justify-between p-4 border border-border/50 rounded-lg bg-card/50">
|
|
290
|
+
<div className="flex items-center gap-3">
|
|
291
|
+
<FileText className="h-5 w-5 text-muted-foreground" />
|
|
292
|
+
<div className="min-w-0 flex-1">
|
|
293
|
+
<p className="font-medium truncate">{report.name}</p>
|
|
294
|
+
<p className="text-sm text-muted-foreground">{report.date}</p>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
<div className="flex items-center gap-2">
|
|
298
|
+
<Badge variant={report.status === 'completed' ? 'default' : 'secondary'}>
|
|
299
|
+
{report.status}
|
|
300
|
+
</Badge>
|
|
301
|
+
<Button variant="ghost" size="sm">
|
|
302
|
+
<Eye className="h-4 w-4" />
|
|
303
|
+
</Button>
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
))}
|
|
307
|
+
</div>
|
|
308
|
+
</CardContent>
|
|
309
|
+
</Card>
|
|
310
|
+
</TabsContent>
|
|
311
|
+
|
|
312
|
+
<TabsContent value="settings" className="space-y-4">
|
|
313
|
+
<div className="grid gap-6 lg:grid-cols-2">
|
|
314
|
+
<Card>
|
|
315
|
+
<CardHeader>
|
|
316
|
+
<CardTitle>Preferences</CardTitle>
|
|
317
|
+
<CardDescription>
|
|
318
|
+
Customize your experience
|
|
319
|
+
</CardDescription>
|
|
320
|
+
</CardHeader>
|
|
321
|
+
<CardContent className="space-y-6">
|
|
322
|
+
<div className="flex items-center justify-between">
|
|
323
|
+
<div className="space-y-0.5">
|
|
324
|
+
<label className="text-sm font-medium">Notifications</label>
|
|
325
|
+
<p className="text-sm text-muted-foreground">
|
|
326
|
+
Receive system notifications
|
|
327
|
+
</p>
|
|
328
|
+
</div>
|
|
329
|
+
<Switch
|
|
330
|
+
checked={notifications}
|
|
331
|
+
onCheckedChange={setNotifications}
|
|
332
|
+
/>
|
|
333
|
+
</div>
|
|
334
|
+
|
|
335
|
+
<div className="space-y-2">
|
|
336
|
+
<label className="text-sm font-medium">Theme</label>
|
|
337
|
+
<Select>
|
|
338
|
+
<SelectTrigger>
|
|
339
|
+
<SelectValue placeholder="Select theme" />
|
|
340
|
+
</SelectTrigger>
|
|
341
|
+
<SelectContent>
|
|
342
|
+
<SelectItem value="light">Light</SelectItem>
|
|
343
|
+
<SelectItem value="dark">Dark</SelectItem>
|
|
344
|
+
<SelectItem value="system">System</SelectItem>
|
|
345
|
+
</SelectContent>
|
|
346
|
+
</Select>
|
|
347
|
+
</div>
|
|
348
|
+
</CardContent>
|
|
349
|
+
</Card>
|
|
350
|
+
|
|
351
|
+
<Card>
|
|
352
|
+
<CardHeader>
|
|
353
|
+
<CardTitle>Security</CardTitle>
|
|
354
|
+
<CardDescription>
|
|
355
|
+
Manage your security settings
|
|
356
|
+
</CardDescription>
|
|
357
|
+
</CardHeader>
|
|
358
|
+
<CardContent className="space-y-6">
|
|
359
|
+
<Alert>
|
|
360
|
+
<Shield className="h-4 w-4" />
|
|
361
|
+
<AlertTitle>Two-factor authentication</AlertTitle>
|
|
362
|
+
<AlertDescription>
|
|
363
|
+
Add an extra layer of security to your account
|
|
364
|
+
</AlertDescription>
|
|
365
|
+
</Alert>
|
|
366
|
+
|
|
367
|
+
<div className="space-y-4">
|
|
368
|
+
<div className="space-y-2">
|
|
369
|
+
<label className="text-sm font-medium">Current Password</label>
|
|
370
|
+
<Input type="password" />
|
|
371
|
+
</div>
|
|
372
|
+
|
|
373
|
+
<div className="space-y-2">
|
|
374
|
+
<label className="text-sm font-medium">New Password</label>
|
|
375
|
+
<Input type="password" />
|
|
376
|
+
</div>
|
|
377
|
+
|
|
378
|
+
<Button className="w-full">Update Password</Button>
|
|
379
|
+
</div>
|
|
380
|
+
</CardContent>
|
|
381
|
+
</Card>
|
|
382
|
+
</div>
|
|
383
|
+
</TabsContent>
|
|
384
|
+
</Tabs>
|
|
385
|
+
</div>
|
|
386
|
+
)
|
|
387
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module src/pages/admin/TestRunDetailPage
|
|
3
|
+
*/
|
|
4
|
+
import { useState, useEffect } from 'react'
|
|
5
|
+
import { useParams, useNavigate } from 'react-router-dom'
|
|
6
|
+
import { apiFetch } from '../../lib/api'
|
|
7
|
+
import { Button } from '../../components/ui/button'
|
|
8
|
+
import { Input } from '../../components/ui/input'
|
|
9
|
+
import { Textarea } from '../../components/ui/textarea'
|
|
10
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select'
|
|
11
|
+
import { Checkbox } from '../../components/ui/checkbox'
|
|
12
|
+
import { Label } from '../../components/ui/label'
|
|
13
|
+
import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card'
|
|
14
|
+
import { Skeleton } from '../../components/ui/skeleton'
|
|
15
|
+
import { Alert, AlertDescription, AlertTitle } from '../../components/ui/alert'
|
|
16
|
+
import { Badge } from '../../components/ui/badge'
|
|
17
|
+
import { DataTable } from '../../components/ui/DataTable'
|
|
18
|
+
import { ArrowLeft, Beaker, AlertCircle } from 'lucide-react'
|
|
19
|
+
import { formatDateTime } from '../../lib/utils'
|
|
20
|
+
|
|
21
|
+
interface TestRun {
|
|
22
|
+
id: string
|
|
23
|
+
name: string
|
|
24
|
+
description?: string
|
|
25
|
+
test_type: 'unit' | 'integration' | 'e2e' | 'performance'
|
|
26
|
+
status: 'pending' | 'running' | 'passed' | 'failed' | 'skipped'
|
|
27
|
+
started_at?: string
|
|
28
|
+
completed_at?: string
|
|
29
|
+
duration_ms?: number
|
|
30
|
+
results: Array<{ name: string; status: string; message?: string; duration_ms?: number }>
|
|
31
|
+
config: Record<string, any>
|
|
32
|
+
created_at: string
|
|
33
|
+
updated_at: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const TEST_TYPES = [
|
|
37
|
+
{ value: 'unit', label: 'Unit Test' },
|
|
38
|
+
{ value: 'integration', label: 'Integration Test' },
|
|
39
|
+
{ value: 'e2e', label: 'End-to-End Test' },
|
|
40
|
+
{ value: 'performance', label: 'Performance Test' }
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
const STATUSES = [
|
|
44
|
+
{ value: 'pending', label: 'Pending' },
|
|
45
|
+
{ value: 'running', label: 'Running' },
|
|
46
|
+
{ value: 'passed', label: 'Passed' },
|
|
47
|
+
{ value: 'failed', label: 'Failed' },
|
|
48
|
+
{ value: 'skipped', label: 'Skipped' }
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
export function TestRunDetailPage() {
|
|
52
|
+
const { id } = useParams<{ id: string }>()
|
|
53
|
+
const navigate = useNavigate()
|
|
54
|
+
const isCreateMode = !id || id === 'new'
|
|
55
|
+
const [testRun, setTestRun] = useState<TestRun | null>(null)
|
|
56
|
+
const [loading, setLoading] = useState(true)
|
|
57
|
+
const [error, setError] = useState<string | null>(null)
|
|
58
|
+
const [isEditing, setIsEditing] = useState(isCreateMode)
|
|
59
|
+
const [formData, setFormData] = useState({
|
|
60
|
+
name: '', description: '', test_type: 'unit' as const, config: '{}', status: 'pending' as const
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (isCreateMode) {
|
|
65
|
+
setLoading(false)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
setLoading(true)
|
|
69
|
+
const fetchTestRun = async () => {
|
|
70
|
+
try {
|
|
71
|
+
const response = await apiFetch(`/api/test-runs?action=get&id=${id}`)
|
|
72
|
+
if (!response.ok) throw new Error('Failed to fetch test run')
|
|
73
|
+
const result = await response.json()
|
|
74
|
+
const data = result.data
|
|
75
|
+
setTestRun(data)
|
|
76
|
+
setFormData({
|
|
77
|
+
name: data.name, description: data.description || '', test_type: data.test_type, status: data.status,
|
|
78
|
+
config: JSON.stringify(data.config || {}, null, 2)
|
|
79
|
+
})
|
|
80
|
+
} catch (err) {
|
|
81
|
+
setError(err instanceof Error ? err.message : 'Failed to load test run')
|
|
82
|
+
} finally {
|
|
83
|
+
setLoading(false)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
fetchTestRun()
|
|
87
|
+
}, [id, isCreateMode])
|
|
88
|
+
|
|
89
|
+
const handleSave = async () => {
|
|
90
|
+
try {
|
|
91
|
+
let parsedConfig = {}
|
|
92
|
+
try { parsedConfig = JSON.parse(formData.config) } catch {}
|
|
93
|
+
const url = isCreateMode ? '/api/test-runs?action=create' : `/api/test-runs?action=update&id=${id}`
|
|
94
|
+
const method = isCreateMode ? 'POST' : 'PATCH'
|
|
95
|
+
const response = await apiFetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...formData, config: parsedConfig }) })
|
|
96
|
+
if (!response.ok) throw new Error('Failed to save test run')
|
|
97
|
+
if (isCreateMode) {
|
|
98
|
+
const result = await response.json()
|
|
99
|
+
navigate(`/spine-framework/admin/configs/test-runs/${result.data?.id || result.id}`)
|
|
100
|
+
} else setIsEditing(false)
|
|
101
|
+
} catch (err) {
|
|
102
|
+
setError(err instanceof Error ? err.message : 'Failed to save')
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (loading) return (
|
|
107
|
+
<div className="space-y-6">
|
|
108
|
+
<Skeleton className="h-8 w-48" />
|
|
109
|
+
<Card><CardHeader><Skeleton className="h-6 w-32" /></CardHeader><CardContent className="space-y-4"><Skeleton className="h-4 w-full" /><Skeleton className="h-4 w-2/3" /></CardContent></Card>
|
|
110
|
+
</div>
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if (error && !isCreateMode) return (
|
|
114
|
+
<Alert variant="destructive"><AlertCircle className="h-4 w-4" /><AlertTitle>Error</AlertTitle><AlertDescription>{error}</AlertDescription></Alert>
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const resultColumns = [
|
|
118
|
+
{ key: 'name' as keyof any, title: 'Test' },
|
|
119
|
+
{ key: 'status' as keyof any, title: 'Status', render: (v: string) => <Badge variant={v === 'passed' ? 'default' : v === 'failed' ? 'destructive' : 'outline'}>{v}</Badge> },
|
|
120
|
+
{ key: 'duration_ms' as keyof any, title: 'Duration', render: (v?: number) => v ? `${v}ms` : '—' },
|
|
121
|
+
{ key: 'message' as keyof any, title: 'Message' }
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div className="space-y-6">
|
|
126
|
+
<div className="flex items-center justify-between">
|
|
127
|
+
<div className="flex items-center gap-4">
|
|
128
|
+
<Button variant="ghost" onClick={() => isCreateMode ? navigate('/spine-framework/admin/configs/testing') : navigate(-1)}><ArrowLeft className="h-5 w-5" /></Button>
|
|
129
|
+
<div>
|
|
130
|
+
<h1 className="text-2xl font-bold">{isCreateMode ? 'Create Test Run' : testRun?.name}</h1>
|
|
131
|
+
{testRun && <Badge variant={testRun.status === 'passed' ? 'default' : testRun.status === 'failed' ? 'destructive' : 'secondary'}>{testRun.status}</Badge>}
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
<div className="flex gap-2">
|
|
135
|
+
{isEditing ? (
|
|
136
|
+
<><Button variant="outline" onClick={() => isCreateMode ? navigate(-1) : setIsEditing(false)}>Cancel</Button><Button onClick={handleSave}>{isCreateMode ? 'Create' : 'Save'}</Button></>
|
|
137
|
+
) : !isCreateMode && <Button onClick={() => setIsEditing(true)}>Edit</Button>}
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<Card><CardContent className="p-6">
|
|
142
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
143
|
+
<div className="space-y-4">
|
|
144
|
+
<h3 className="text-sm font-medium text-muted-foreground">Test Configuration</h3>
|
|
145
|
+
<div className="space-y-2"><Label>Name</Label>{isEditing ? <Input value={formData.name} onChange={e => setFormData({...formData, name: e.target.value})} /> : <div className="text-sm">{testRun?.name}</div>}</div>
|
|
146
|
+
<div className="space-y-2"><Label>Type</Label>{isEditing ? <Select value={formData.test_type} onValueChange={v => setFormData({...formData, test_type: v as any})}><SelectTrigger><SelectValue /></SelectTrigger><SelectContent>{TEST_TYPES.map(t => <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>)}</SelectContent></Select> : <Badge>{testRun?.test_type}</Badge>}</div>
|
|
147
|
+
<div className="space-y-2"><Label>Status</Label>{isEditing ? <Select value={formData.status} onValueChange={v => setFormData({...formData, status: v as any})}><SelectTrigger><SelectValue /></SelectTrigger><SelectContent>{STATUSES.map(s => <SelectItem key={s.value} value={s.value}>{s.label}</SelectItem>)}</SelectContent></Select> : <Badge>{testRun?.status}</Badge>}</div>
|
|
148
|
+
</div>
|
|
149
|
+
<div className="space-y-4">
|
|
150
|
+
<h3 className="text-sm font-medium text-muted-foreground">Execution Info</h3>
|
|
151
|
+
{!isCreateMode && (
|
|
152
|
+
<>
|
|
153
|
+
<div className="flex justify-between"><span className="text-sm text-muted-foreground">Started</span><span className="text-sm">{testRun?.started_at ? formatDateTime(testRun.started_at) : '—'}</span></div>
|
|
154
|
+
<div className="flex justify-between"><span className="text-sm text-muted-foreground">Completed</span><span className="text-sm">{testRun?.completed_at ? formatDateTime(testRun.completed_at) : '—'}</span></div>
|
|
155
|
+
<div className="flex justify-between"><span className="text-sm text-muted-foreground">Duration</span><span className="text-sm">{testRun?.duration_ms ? `${testRun.duration_ms}ms` : '—'}</span></div>
|
|
156
|
+
<div className="flex justify-between"><span className="text-sm text-muted-foreground">Results</span><span className="text-sm">{testRun?.results?.length || 0} tests</span></div>
|
|
157
|
+
</>
|
|
158
|
+
)}
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
<div className="mt-6 space-y-2"><Label>Description</Label>{isEditing ? <Textarea value={formData.description} onChange={e => setFormData({...formData, description: e.target.value})} rows={3} /> : <div className="text-sm">{testRun?.description || '—'}</div>}</div>
|
|
162
|
+
<div className="mt-6 space-y-2"><Label>Config (JSON)</Label>{isEditing ? <Textarea value={formData.config} onChange={e => setFormData({...formData, config: e.target.value})} rows={6} className="font-mono text-sm" /> : <pre className="text-sm bg-muted p-3 rounded">{JSON.stringify(testRun?.config || {}, null, 2)}</pre>}</div>
|
|
163
|
+
</CardContent></Card>
|
|
164
|
+
|
|
165
|
+
{!isCreateMode && testRun?.results && (
|
|
166
|
+
<Card><CardHeader><CardTitle>Results ({testRun.results.length})</CardTitle></CardHeader><CardContent>
|
|
167
|
+
<DataTable data={testRun.results} columns={resultColumns as any} />
|
|
168
|
+
</CardContent></Card>
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
)
|
|
172
|
+
}
|