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.
Files changed (385) hide show
  1. package/.framework/README.md +129 -0
  2. package/.framework/cli/bin.cjs +14 -0
  3. package/.framework/cli/commands/agents.ts +153 -0
  4. package/.framework/cli/commands/auth.ts +94 -0
  5. package/.framework/cli/commands/create-app.ts +185 -0
  6. package/.framework/cli/commands/dev.ts +295 -0
  7. package/.framework/cli/commands/doctor.ts +442 -0
  8. package/.framework/cli/commands/generate.ts +332 -0
  9. package/.framework/cli/commands/init.ts +272 -0
  10. package/.framework/cli/commands/install-app.ts +391 -0
  11. package/.framework/cli/commands/items.ts +253 -0
  12. package/.framework/cli/commands/migrations.ts +141 -0
  13. package/.framework/cli/commands/pipelines.ts +166 -0
  14. package/.framework/cli/commands/status.ts +197 -0
  15. package/.framework/cli/commands/system.ts +184 -0
  16. package/.framework/cli/commands/test.ts +227 -0
  17. package/.framework/cli/commands/uninstall-app.ts +166 -0
  18. package/.framework/cli/context.ts +268 -0
  19. package/.framework/cli/env-loader.ts +36 -0
  20. package/.framework/cli/index.ts +106 -0
  21. package/.framework/cli/welcome.cjs +45 -0
  22. package/.framework/docs/API.md +384 -0
  23. package/.framework/docs/STABILITY.md +52 -0
  24. package/.framework/docs/admin-routes.md +76 -0
  25. package/.framework/docs/api-docs-progress.md +38 -0
  26. package/.framework/docs/api-governance.md +146 -0
  27. package/.framework/docs/api-testing-results.md +212 -0
  28. package/.framework/docs/apis/admin-configs.md +567 -0
  29. package/.framework/docs/apis/admin-data.md +272 -0
  30. package/.framework/docs/apis/index.md +231 -0
  31. package/.framework/docs/apis/internal.md +295 -0
  32. package/.framework/docs/apis/runtime.md +537 -0
  33. package/.framework/docs/assembly-launch-guide.md +138 -0
  34. package/.framework/docs/audit-results.md +590 -0
  35. package/.framework/docs/authorization-model.md +170 -0
  36. package/.framework/docs/db-api-inventory.md +95 -0
  37. package/.framework/docs/examples/custom-app/README.md +77 -0
  38. package/.framework/docs/examples/custom-function/README.md +27 -0
  39. package/.framework/docs/examples/custom-function/handler.ts +48 -0
  40. package/.framework/docs/examples/custom-webhook/README.md +68 -0
  41. package/.framework/docs/gap-remediation-backlog.md +103 -0
  42. package/.framework/docs/guides/cli-guide.md +224 -0
  43. package/.framework/docs/guides/getting-started.md +103 -0
  44. package/.framework/docs/guides/import-guide.md +193 -0
  45. package/.framework/docs/guides/testing-guide.md +229 -0
  46. package/.framework/docs/permission-examples.md +326 -0
  47. package/.framework/docs/ui-adoption-verification.md +111 -0
  48. package/.framework/docs/ui-api-coverage.md +84 -0
  49. package/.framework/docs/v2-compatibility-audit.md +228 -0
  50. package/.framework/functions/.gitkeep +1 -0
  51. package/.framework/functions/_shared/agent-runner.ts +1097 -0
  52. package/.framework/functions/_shared/app-manifest.ts +184 -0
  53. package/.framework/functions/_shared/audit.ts +150 -0
  54. package/.framework/functions/_shared/db.ts +174 -0
  55. package/.framework/functions/_shared/index.ts +382 -0
  56. package/.framework/functions/_shared/middleware.ts +490 -0
  57. package/.framework/functions/_shared/permissions.ts +1325 -0
  58. package/.framework/functions/_shared/pipeline-runner.ts +731 -0
  59. package/.framework/functions/_shared/principal.ts +760 -0
  60. package/.framework/functions/_shared/schema-utils.ts +967 -0
  61. package/.framework/functions/_shared/testing.ts +258 -0
  62. package/.framework/functions/_shared/trigger-engine.ts +425 -0
  63. package/.framework/functions/_shared/webhook-registration.ts +168 -0
  64. package/.framework/functions/_shared/webhook-registry.ts +129 -0
  65. package/.framework/functions/account-nodes.ts +111 -0
  66. package/.framework/functions/admin-data.ts +606 -0
  67. package/.framework/functions/ai-agents.ts +323 -0
  68. package/.framework/functions/api-keys.ts +376 -0
  69. package/.framework/functions/apps.ts +483 -0
  70. package/.framework/functions/auth.ts +196 -0
  71. package/.framework/functions/debug-auth.ts +107 -0
  72. package/.framework/functions/embeddings.ts +556 -0
  73. package/.framework/functions/integration-routes.ts +523 -0
  74. package/.framework/functions/integrations.ts +319 -0
  75. package/.framework/functions/item-progress.ts +272 -0
  76. package/.framework/functions/logs.ts +438 -0
  77. package/.framework/functions/observability.ts +275 -0
  78. package/.framework/functions/pipeline-executions.ts +494 -0
  79. package/.framework/functions/pipelines.ts +485 -0
  80. package/.framework/functions/prompt-configs.ts +339 -0
  81. package/.framework/functions/roles.ts +387 -0
  82. package/.framework/functions/system-cron.ts +742 -0
  83. package/.framework/functions/system.ts +323 -0
  84. package/.framework/functions/tests.ts +119 -0
  85. package/.framework/functions/timers.ts +357 -0
  86. package/.framework/functions/triggers.ts +563 -0
  87. package/.framework/functions/types.ts +604 -0
  88. package/.framework/migrations/000_foundation.sql +1256 -0
  89. package/.framework/migrations/001_seed.sql +92 -0
  90. package/.framework/migrations/002_seed_constraints.sql +13 -0
  91. package/.framework/migrations/003_auth_user_trigger.sql +59 -0
  92. package/.framework/src/App.tsx +126 -0
  93. package/.framework/src/apps/admin/index.tsx +173 -0
  94. package/.framework/src/components/AppWrapper.tsx +56 -0
  95. package/.framework/src/components/CustomAppLoader.tsx +116 -0
  96. package/.framework/src/components/admin/AdminListPage.tsx +151 -0
  97. package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
  98. package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
  99. package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
  100. package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
  101. package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
  102. package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
  103. package/.framework/src/components/app-sidebar.tsx +228 -0
  104. package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
  105. package/.framework/src/components/layout/AppShell.tsx +91 -0
  106. package/.framework/src/components/layout/Header.tsx +88 -0
  107. package/.framework/src/components/layout/Layout.tsx +95 -0
  108. package/.framework/src/components/layout/Sidebar.tsx +329 -0
  109. package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
  110. package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
  111. package/.framework/src/components/runtime/DataFilters.tsx +91 -0
  112. package/.framework/src/components/runtime/DataHeader.tsx +68 -0
  113. package/.framework/src/components/runtime/DataListPage.tsx +124 -0
  114. package/.framework/src/components/runtime/DataStats.tsx +70 -0
  115. package/.framework/src/components/runtime/DataTable.tsx +174 -0
  116. package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
  117. package/.framework/src/components/runtime/index.ts +18 -0
  118. package/.framework/src/components/search-form.tsx +29 -0
  119. package/.framework/src/components/shared/AgentView.tsx +213 -0
  120. package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
  121. package/.framework/src/components/shared/SchemaFields.tsx +226 -0
  122. package/.framework/src/components/ui/DataTable.tsx +343 -0
  123. package/.framework/src/components/ui/Form.tsx +281 -0
  124. package/.framework/src/components/ui/ItemCard.tsx +296 -0
  125. package/.framework/src/components/ui/ItemListView.tsx +308 -0
  126. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
  127. package/.framework/src/components/ui/Modal.tsx +61 -0
  128. package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
  129. package/.framework/src/components/ui/accordion.tsx +82 -0
  130. package/.framework/src/components/ui/alert-dialog.tsx +197 -0
  131. package/.framework/src/components/ui/alert.tsx +76 -0
  132. package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
  133. package/.framework/src/components/ui/avatar.tsx +110 -0
  134. package/.framework/src/components/ui/badge.tsx +49 -0
  135. package/.framework/src/components/ui/breadcrumb.tsx +122 -0
  136. package/.framework/src/components/ui/button-group.tsx +83 -0
  137. package/.framework/src/components/ui/button.tsx +65 -0
  138. package/.framework/src/components/ui/calendar.tsx +222 -0
  139. package/.framework/src/components/ui/card.tsx +100 -0
  140. package/.framework/src/components/ui/carousel.tsx +240 -0
  141. package/.framework/src/components/ui/chart.tsx +373 -0
  142. package/.framework/src/components/ui/checkbox.tsx +31 -0
  143. package/.framework/src/components/ui/collapsible.tsx +33 -0
  144. package/.framework/src/components/ui/combobox.tsx +299 -0
  145. package/.framework/src/components/ui/command.tsx +193 -0
  146. package/.framework/src/components/ui/context-menu.tsx +261 -0
  147. package/.framework/src/components/ui/dialog.tsx +165 -0
  148. package/.framework/src/components/ui/direction.tsx +22 -0
  149. package/.framework/src/components/ui/drawer.tsx +132 -0
  150. package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
  151. package/.framework/src/components/ui/empty.tsx +104 -0
  152. package/.framework/src/components/ui/field.tsx +238 -0
  153. package/.framework/src/components/ui/hover-card.tsx +42 -0
  154. package/.framework/src/components/ui/input-group.tsx +153 -0
  155. package/.framework/src/components/ui/input-otp.tsx +87 -0
  156. package/.framework/src/components/ui/input.tsx +19 -0
  157. package/.framework/src/components/ui/item.tsx +196 -0
  158. package/.framework/src/components/ui/kbd.tsx +26 -0
  159. package/.framework/src/components/ui/label.tsx +22 -0
  160. package/.framework/src/components/ui/menubar.tsx +277 -0
  161. package/.framework/src/components/ui/native-select.tsx +61 -0
  162. package/.framework/src/components/ui/navigation-menu.tsx +164 -0
  163. package/.framework/src/components/ui/pagination.tsx +129 -0
  164. package/.framework/src/components/ui/popover.tsx +87 -0
  165. package/.framework/src/components/ui/progress.tsx +31 -0
  166. package/.framework/src/components/ui/radio-group.tsx +42 -0
  167. package/.framework/src/components/ui/resizable.tsx +50 -0
  168. package/.framework/src/components/ui/scroll-area.tsx +53 -0
  169. package/.framework/src/components/ui/select.tsx +195 -0
  170. package/.framework/src/components/ui/separator.tsx +26 -0
  171. package/.framework/src/components/ui/sheet.tsx +145 -0
  172. package/.framework/src/components/ui/sidebar.tsx +706 -0
  173. package/.framework/src/components/ui/skeleton.tsx +13 -0
  174. package/.framework/src/components/ui/slider.tsx +59 -0
  175. package/.framework/src/components/ui/sonner.tsx +47 -0
  176. package/.framework/src/components/ui/spinner.tsx +10 -0
  177. package/.framework/src/components/ui/switch.tsx +33 -0
  178. package/.framework/src/components/ui/table-primitives.tsx +141 -0
  179. package/.framework/src/components/ui/table.tsx +114 -0
  180. package/.framework/src/components/ui/tabs.tsx +90 -0
  181. package/.framework/src/components/ui/textarea.tsx +18 -0
  182. package/.framework/src/components/ui/toggle-group.tsx +89 -0
  183. package/.framework/src/components/ui/toggle.tsx +45 -0
  184. package/.framework/src/components/ui/tooltip.tsx +57 -0
  185. package/.framework/src/contexts/AppContext.tsx +133 -0
  186. package/.framework/src/contexts/AuthContext.tsx +371 -0
  187. package/.framework/src/hooks/use-mobile.ts +19 -0
  188. package/.framework/src/hooks/useApi.ts +526 -0
  189. package/.framework/src/hooks/useApps.ts +114 -0
  190. package/.framework/src/hooks/useEntityList.ts +190 -0
  191. package/.framework/src/hooks/useEntityRecord.ts +308 -0
  192. package/.framework/src/hooks/useForm.ts +307 -0
  193. package/.framework/src/hooks/useListSchema.ts +264 -0
  194. package/.framework/src/hooks/useSchemaRecord.ts +223 -0
  195. package/.framework/src/index.css +128 -0
  196. package/.framework/src/lib/api.ts +156 -0
  197. package/.framework/src/lib/supabase.ts +94 -0
  198. package/.framework/src/lib/utils.ts +317 -0
  199. package/.framework/src/main.tsx +27 -0
  200. package/.framework/src/pages/DashboardPage.tsx +181 -0
  201. package/.framework/src/pages/NotFoundPage.tsx +39 -0
  202. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
  203. package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
  204. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
  205. package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
  206. package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
  207. package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
  208. package/.framework/src/pages/admin/AppsPage.tsx +355 -0
  209. package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
  210. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
  211. package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
  212. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
  213. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
  214. package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
  215. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
  216. package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
  217. package/.framework/src/pages/admin/LogsPage.tsx +283 -0
  218. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
  219. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
  220. package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
  221. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
  222. package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
  223. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
  224. package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
  225. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
  226. package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
  227. package/.framework/src/pages/admin/RolesPage.tsx +292 -0
  228. package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
  229. package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
  230. package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
  231. package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
  232. package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
  233. package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
  234. package/.framework/src/pages/admin/TimersPage.tsx +376 -0
  235. package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
  236. package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
  237. package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
  238. package/.framework/src/pages/admin/TypesPage.tsx +295 -0
  239. package/.framework/src/pages/auth/LoginPage.tsx +188 -0
  240. package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
  241. package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
  242. package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
  243. package/.framework/src/types/auth.ts +125 -0
  244. package/.framework/src/types/types.ts +407 -0
  245. package/STRUCTURE.md +150 -0
  246. package/config/components.json +25 -0
  247. package/config/deno.lock +108 -0
  248. package/config/package-lock.json +17183 -0
  249. package/config/postcss.config.cjs +10 -0
  250. package/config/tailwind.config.cjs +78 -0
  251. package/config/tsconfig.build.json +32 -0
  252. package/config/tsconfig.cli.json +18 -0
  253. package/config/tsconfig.json +41 -0
  254. package/config/tsconfig.node.json +17 -0
  255. package/config/tsconfig.node.tsbuildinfo +1 -0
  256. package/config/tsconfig.tsbuildinfo +1 -0
  257. package/config/typedoc.json +16 -0
  258. package/config/vite.config.d.ts +2 -0
  259. package/config/vite.config.ts +72 -0
  260. package/dist/cli/commands/agents.d.ts +39 -0
  261. package/dist/cli/commands/agents.d.ts.map +1 -0
  262. package/dist/cli/commands/auth.d.ts +36 -0
  263. package/dist/cli/commands/auth.d.ts.map +1 -0
  264. package/dist/cli/commands/create-app.d.ts +23 -0
  265. package/dist/cli/commands/create-app.d.ts.map +1 -0
  266. package/dist/cli/commands/dev.d.ts +39 -0
  267. package/dist/cli/commands/dev.d.ts.map +1 -0
  268. package/dist/cli/commands/doctor.d.ts +42 -0
  269. package/dist/cli/commands/doctor.d.ts.map +1 -0
  270. package/dist/cli/commands/generate.d.ts +36 -0
  271. package/dist/cli/commands/generate.d.ts.map +1 -0
  272. package/dist/cli/commands/init.d.ts +30 -0
  273. package/dist/cli/commands/init.d.ts.map +1 -0
  274. package/dist/cli/commands/install-app.d.ts +30 -0
  275. package/dist/cli/commands/install-app.d.ts.map +1 -0
  276. package/dist/cli/commands/items.d.ts +45 -0
  277. package/dist/cli/commands/items.d.ts.map +1 -0
  278. package/dist/cli/commands/migrations.d.ts +41 -0
  279. package/dist/cli/commands/migrations.d.ts.map +1 -0
  280. package/dist/cli/commands/pipelines.d.ts +40 -0
  281. package/dist/cli/commands/pipelines.d.ts.map +1 -0
  282. package/dist/cli/commands/status.d.ts +23 -0
  283. package/dist/cli/commands/status.d.ts.map +1 -0
  284. package/dist/cli/commands/system.d.ts +29 -0
  285. package/dist/cli/commands/system.d.ts.map +1 -0
  286. package/dist/cli/commands/test.d.ts +46 -0
  287. package/dist/cli/commands/test.d.ts.map +1 -0
  288. package/dist/cli/commands/uninstall-app.d.ts +23 -0
  289. package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
  290. package/dist/cli/context.d.ts +88 -0
  291. package/dist/cli/context.d.ts.map +1 -0
  292. package/dist/cli/env-loader.d.ts +14 -0
  293. package/dist/cli/env-loader.d.ts.map +1 -0
  294. package/dist/cli/index.d.ts +41 -0
  295. package/dist/cli/index.d.ts.map +1 -0
  296. package/dist/functions/_shared/agent-runner.d.ts +156 -0
  297. package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
  298. package/dist/functions/_shared/app-manifest.d.ts +68 -0
  299. package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
  300. package/dist/functions/_shared/audit.d.ts +91 -0
  301. package/dist/functions/_shared/audit.d.ts.map +1 -0
  302. package/dist/functions/_shared/db.d.ts +125 -0
  303. package/dist/functions/_shared/db.d.ts.map +1 -0
  304. package/dist/functions/_shared/index.d.ts +298 -0
  305. package/dist/functions/_shared/index.d.ts.map +1 -0
  306. package/dist/functions/_shared/middleware.d.ts +315 -0
  307. package/dist/functions/_shared/middleware.d.ts.map +1 -0
  308. package/dist/functions/_shared/permissions.d.ts +626 -0
  309. package/dist/functions/_shared/permissions.d.ts.map +1 -0
  310. package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
  311. package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
  312. package/dist/functions/_shared/principal.d.ts +284 -0
  313. package/dist/functions/_shared/principal.d.ts.map +1 -0
  314. package/dist/functions/_shared/schema-utils.d.ts +181 -0
  315. package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
  316. package/dist/functions/_shared/testing.d.ts +172 -0
  317. package/dist/functions/_shared/testing.d.ts.map +1 -0
  318. package/dist/functions/_shared/trigger-engine.d.ts +140 -0
  319. package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
  320. package/dist/functions/_shared/webhook-registration.d.ts +81 -0
  321. package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
  322. package/dist/functions/_shared/webhook-registry.d.ts +57 -0
  323. package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
  324. package/dist/functions/account-nodes.d.ts +48 -0
  325. package/dist/functions/account-nodes.d.ts.map +1 -0
  326. package/dist/functions/admin-data.d.ts +178 -0
  327. package/dist/functions/admin-data.d.ts.map +1 -0
  328. package/dist/functions/ai-agents.d.ts +125 -0
  329. package/dist/functions/ai-agents.d.ts.map +1 -0
  330. package/dist/functions/api-keys.d.ts +140 -0
  331. package/dist/functions/api-keys.d.ts.map +1 -0
  332. package/dist/functions/apps.d.ts +163 -0
  333. package/dist/functions/apps.d.ts.map +1 -0
  334. package/dist/functions/auth.d.ts +74 -0
  335. package/dist/functions/auth.d.ts.map +1 -0
  336. package/dist/functions/debug-auth.d.ts +33 -0
  337. package/dist/functions/debug-auth.d.ts.map +1 -0
  338. package/dist/functions/embeddings.d.ts +205 -0
  339. package/dist/functions/embeddings.d.ts.map +1 -0
  340. package/dist/functions/integration-routes.d.ts +45 -0
  341. package/dist/functions/integration-routes.d.ts.map +1 -0
  342. package/dist/functions/integrations.d.ts +124 -0
  343. package/dist/functions/integrations.d.ts.map +1 -0
  344. package/dist/functions/item-progress.d.ts +41 -0
  345. package/dist/functions/item-progress.d.ts.map +1 -0
  346. package/dist/functions/logs.d.ts +162 -0
  347. package/dist/functions/logs.d.ts.map +1 -0
  348. package/dist/functions/observability.d.ts +123 -0
  349. package/dist/functions/observability.d.ts.map +1 -0
  350. package/dist/functions/pipeline-executions.d.ts +190 -0
  351. package/dist/functions/pipeline-executions.d.ts.map +1 -0
  352. package/dist/functions/pipelines.d.ts +171 -0
  353. package/dist/functions/pipelines.d.ts.map +1 -0
  354. package/dist/functions/prompt-configs.d.ts +125 -0
  355. package/dist/functions/prompt-configs.d.ts.map +1 -0
  356. package/dist/functions/roles.d.ts +118 -0
  357. package/dist/functions/roles.d.ts.map +1 -0
  358. package/dist/functions/system-cron.d.ts +65 -0
  359. package/dist/functions/system-cron.d.ts.map +1 -0
  360. package/dist/functions/system.d.ts +29 -0
  361. package/dist/functions/system.d.ts.map +1 -0
  362. package/dist/functions/tests.d.ts +28 -0
  363. package/dist/functions/tests.d.ts.map +1 -0
  364. package/dist/functions/timers.d.ts +139 -0
  365. package/dist/functions/timers.d.ts.map +1 -0
  366. package/dist/functions/triggers.d.ts +203 -0
  367. package/dist/functions/triggers.d.ts.map +1 -0
  368. package/dist/functions/types.d.ts +151 -0
  369. package/dist/functions/types.d.ts.map +1 -0
  370. package/dist/src/types/types.d.ts +364 -0
  371. package/dist/src/types/types.d.ts.map +1 -0
  372. package/package.json +192 -0
  373. package/scripts/app-install-cli.ts +286 -0
  374. package/scripts/assemble-frontend.sh +79 -0
  375. package/scripts/assemble-functions.sh +62 -0
  376. package/scripts/assemble.sh +35 -0
  377. package/scripts/boundary-check.sh +106 -0
  378. package/scripts/build-manifest.sh +80 -0
  379. package/scripts/check-core-integrity.sh +82 -0
  380. package/scripts/ingest-chunks.cjs +202 -0
  381. package/scripts/kb-chunk-parser.cjs +312 -0
  382. package/scripts/kb-chunk-parser.ts +330 -0
  383. package/scripts/load-test-app-install.ts +484 -0
  384. package/scripts/netlify-dev-wrapper.sh +22 -0
  385. package/scripts/verify-integrity.sh +69 -0
@@ -0,0 +1,279 @@
1
+ /**
2
+ * @module src/pages/admin/PipelineExecutionsPage
3
+ * @audience installer
4
+ * @layer frontend-page
5
+ * @stability stable
6
+ *
7
+ * Read-only log of pipeline execution history. Fetches execution records
8
+ * via `/api/pipelines?action=executions`, applies client-side search,
9
+ * status filter (`running` | `success` | `failed` | `cancelled`), and
10
+ * sort. Renders inside `AdminListPage` with a sortable table showing
11
+ * pipeline name, status, duration, and timestamps.
12
+ *
13
+ * @seeAlso src/pages/admin/PipelinesPage.tsx
14
+ * @seeAlso src/pages/admin/ObservabilityDashboard.tsx
15
+ */
16
+
17
+ import React, { useState } from 'react'
18
+ import { Play, CheckCircle, XCircle, Clock, RefreshCw, Zap } from 'lucide-react';
19
+ import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
20
+ import { Button } from '../../components/ui/button'
21
+ import { AdminListPage } from '../../components/admin/AdminListPage'
22
+ import { SortableTableHeader } from '../../components/admin/SortableTableHeader'
23
+ import { formatDateTime } from '../../lib/utils'
24
+ import { useApi } from '../../hooks/useApi'
25
+ import { apiFetch } from '../../lib/api'
26
+
27
+ interface PipelineExecution {
28
+ id: string
29
+ pipeline_id: string
30
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
31
+ trigger_data?: Record<string, any>
32
+ result?: Record<string, any>
33
+ error_message?: string
34
+ started_at?: string
35
+ completed_at?: string
36
+ duration_ms?: number
37
+ created_by?: string
38
+ pipeline?: {
39
+ id: string
40
+ name: string
41
+ trigger_type: string
42
+ }
43
+ triggered_by_person?: {
44
+ id: string
45
+ full_name: string
46
+ email: string
47
+ }
48
+ created_at: string
49
+ }
50
+
51
+ export function PipelineExecutionsPage() {
52
+ const [searchTerm, setSearchTerm] = useState('')
53
+ const [selectedStatus, setSelectedStatus] = useState('all')
54
+ const [sortKey, setSortKey] = useState('started_at')
55
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc')
56
+
57
+ const { data: executions, loading, error, refetch } = useApi<PipelineExecution[]>(
58
+ async () => {
59
+ const response = await apiFetch('/api/pipeline-executions?action=list')
60
+ if (!response.ok) throw new Error('Failed to fetch pipeline executions')
61
+ const result = await response.json()
62
+ return (result.data || result) as PipelineExecution[]
63
+ },
64
+ { immediate: true }
65
+ )
66
+
67
+ const { data: stats } = useApi<{ total: number; completed: number; failed: number; running: number }>(
68
+ async () => {
69
+ const response = await apiFetch('/api/pipeline-executions?action=stats')
70
+ if (!response.ok) return null
71
+ const result = await response.json()
72
+ return result.data || result
73
+ },
74
+ { immediate: true }
75
+ )
76
+
77
+ const filteredExecutions = (executions || []).filter(exec => {
78
+ const matchesSearch = exec.pipeline?.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
79
+ exec.error_message?.toLowerCase().includes(searchTerm.toLowerCase()) || false
80
+ const matchesStatus = selectedStatus === 'all' || exec.status === selectedStatus
81
+ return matchesSearch && matchesStatus
82
+ })
83
+
84
+ const handleSort = (key: string) => {
85
+ if (sortKey === key) {
86
+ setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc')
87
+ } else {
88
+ setSortKey(key)
89
+ setSortDirection('asc')
90
+ }
91
+ }
92
+
93
+ const handleRowClick = (exec: PipelineExecution) => {
94
+ window.location.href = `/spine-framework/admin/observability/executions/${exec.id}`
95
+ }
96
+
97
+ const sortedExecutions = [...(filteredExecutions || [])].sort((a, b) => {
98
+ let aValue: any = a[sortKey as keyof PipelineExecution] || ''
99
+ let bValue: any = b[sortKey as keyof PipelineExecution] || ''
100
+
101
+ if (typeof aValue === 'string') {
102
+ return sortDirection === 'asc'
103
+ ? aValue.localeCompare(bValue)
104
+ : bValue.localeCompare(aValue)
105
+ }
106
+
107
+ return 0
108
+ })
109
+
110
+ const getStatusBadge = (status: string) => {
111
+ switch (status) {
112
+ case 'completed':
113
+ return <span className="inline-flex px-2 py-0.5 text-xs font-medium rounded-md bg-green-100 text-green-700">Completed</span>
114
+ case 'running':
115
+ return <span className="inline-flex px-2 py-0.5 text-xs font-medium rounded-md bg-blue-100 text-blue-700">Running</span>
116
+ case 'pending':
117
+ return <span className="inline-flex px-2 py-0.5 text-xs font-medium rounded-md bg-yellow-100 text-yellow-700">Pending</span>
118
+ case 'failed':
119
+ return <span className="inline-flex px-2 py-0.5 text-xs font-medium rounded-md bg-red-100 text-red-700">Failed</span>
120
+ case 'cancelled':
121
+ return <span className="inline-flex px-2 py-0.5 text-xs font-medium rounded-md bg-slate-100 text-slate-600">Cancelled</span>
122
+ default:
123
+ return <span className="inline-flex px-2 py-0.5 text-xs font-medium rounded-md bg-slate-100 text-slate-600">{status}</span>
124
+ }
125
+ }
126
+
127
+ const formatDuration = (ms?: number) => {
128
+ if (!ms) return '—'
129
+ if (ms < 1000) return `${ms}ms`
130
+ return `${(ms / 1000).toFixed(1)}s`
131
+ }
132
+
133
+ const statsCards = [
134
+ {
135
+ title: 'Total Executions',
136
+ value: stats?.total || (executions || []).length,
137
+ icon: Zap,
138
+ iconColor: 'text-blue-500'
139
+ },
140
+ {
141
+ title: 'Completed',
142
+ value: stats?.completed || (executions || []).filter(e => e.status === 'completed').length,
143
+ icon: CheckCircle,
144
+ iconColor: 'text-green-500'
145
+ },
146
+ {
147
+ title: 'Failed',
148
+ value: stats?.failed || (executions || []).filter(e => e.status === 'failed').length,
149
+ icon: XCircle,
150
+ iconColor: 'text-red-500'
151
+ },
152
+ {
153
+ title: 'Running',
154
+ value: stats?.running || (executions || []).filter(e => e.status === 'running').length,
155
+ icon: Play,
156
+ iconColor: 'text-blue-500'
157
+ }
158
+ ]
159
+
160
+ const statusOptions = [
161
+ { value: 'all', label: 'All Status' },
162
+ { value: 'pending', label: 'Pending' },
163
+ { value: 'running', label: 'Running' },
164
+ { value: 'completed', label: 'Completed' },
165
+ { value: 'failed', label: 'Failed' },
166
+ { value: 'cancelled', label: 'Cancelled' }
167
+ ]
168
+
169
+ const filters = [
170
+ {
171
+ label: 'Status',
172
+ value: selectedStatus,
173
+ options: statusOptions,
174
+ onChange: setSelectedStatus
175
+ }
176
+ ]
177
+
178
+ return (
179
+ <AdminListPage
180
+ title="Pipeline Executions"
181
+ description="Monitor and manage pipeline runs"
182
+ statsCards={statsCards}
183
+ searchPlaceholder="Search executions..."
184
+ searchValue={searchTerm}
185
+ onSearchChange={setSearchTerm}
186
+ filters={filters}
187
+ loading={loading}
188
+ error={error}
189
+ emptyMessage="No pipeline executions found"
190
+ emptyIcon={RefreshCw}
191
+ >
192
+ {sortedExecutions.length === 0 ? (
193
+ <div className="p-8 text-center">
194
+ <RefreshCw className="mx-auto h-12 w-12 text-slate-400" />
195
+ <h3 className="mt-2 text-sm font-medium text-slate-900">No executions found</h3>
196
+ <p className="mt-1 text-sm text-slate-500">
197
+ Try adjusting your filters
198
+ </p>
199
+ </div>
200
+ ) : (
201
+ <table className="min-w-full divide-y divide-slate-200">
202
+ <thead className="bg-slate-50">
203
+ <tr>
204
+ <SortableTableHeader
205
+ title="Pipeline"
206
+ sortKey="pipeline"
207
+ currentSortKey={sortKey}
208
+ currentSortDirection={sortDirection}
209
+ onSort={handleSort}
210
+ />
211
+ <SortableTableHeader
212
+ title="Status"
213
+ sortKey="status"
214
+ currentSortKey={sortKey}
215
+ currentSortDirection={sortDirection}
216
+ onSort={handleSort}
217
+ />
218
+ <SortableTableHeader
219
+ title="Started"
220
+ sortKey="started_at"
221
+ currentSortKey={sortKey}
222
+ currentSortDirection={sortDirection}
223
+ onSort={handleSort}
224
+ />
225
+ <SortableTableHeader
226
+ title="Duration"
227
+ sortKey="duration_ms"
228
+ currentSortKey={sortKey}
229
+ currentSortDirection={sortDirection}
230
+ onSort={handleSort}
231
+ />
232
+ <SortableTableHeader
233
+ title="Triggered By"
234
+ sortKey="triggered_by"
235
+ currentSortKey={sortKey}
236
+ currentSortDirection={sortDirection}
237
+ onSort={handleSort}
238
+ />
239
+ <th className="relative px-6 py-3">
240
+ <span className="sr-only">Actions</span>
241
+ </th>
242
+ </tr>
243
+ </thead>
244
+ <tbody className="bg-white divide-y divide-slate-200">
245
+ {sortedExecutions.map((exec) => (
246
+ <tr
247
+ key={exec.id}
248
+ className="hover:bg-slate-50 cursor-pointer transition-colors"
249
+ onClick={() => handleRowClick(exec)}
250
+ >
251
+ <td className="px-6 py-4 whitespace-nowrap">
252
+ <div className="font-medium text-slate-900">
253
+ {exec.pipeline?.name || 'Unknown Pipeline'}
254
+ </div>
255
+ <div className="text-xs text-slate-500 font-mono">{exec.id.slice(0, 8)}</div>
256
+ </td>
257
+ <td className="px-6 py-4 whitespace-nowrap">
258
+ {getStatusBadge(exec.status)}
259
+ </td>
260
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-500">
261
+ {exec.started_at ? formatDateTime(exec.started_at) : 'Not started'}
262
+ </td>
263
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-500">
264
+ {formatDuration(exec.duration_ms)}
265
+ </td>
266
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-500">
267
+ {exec.triggered_by_person?.full_name || exec.created_by || 'System'}
268
+ </td>
269
+ <td className="px-6 py-4 whitespace-nowrap text-right">
270
+ <span className="text-slate-400">→</span>
271
+ </td>
272
+ </tr>
273
+ ))}
274
+ </tbody>
275
+ </table>
276
+ )}
277
+ </AdminListPage>
278
+ )
279
+ }
@@ -0,0 +1,390 @@
1
+ /**
2
+ * @module src/pages/admin/PipelinesPage
3
+ * @audience installer
4
+ * @layer frontend-page
5
+ * @stability stable
6
+ *
7
+ * Admin list page for automation pipelines. Fetches all pipelines via
8
+ * `/api/pipelines?action=list`, applies client-side search, status filter,
9
+ * trigger-type filter, and sort. Renders inside `AdminListPage` with stat
10
+ * cards and a sortable table. Row clicks navigate to
11
+ * `/spine-framework/admin/configs/pipelines/:id`.
12
+ *
13
+ * @seeAlso src/pages/admin/PipelineDetailPage.tsx
14
+ */
15
+
16
+ import React, { useState } from 'react'
17
+ import { useNavigate } from 'react-router-dom'
18
+ import { useApi } from '../../hooks/useApi'
19
+ import { apiFetch } from '../../lib/api'
20
+ import { Plus, Search, Filter, Play, Pause, Pencil, Trash2, Settings, Calendar, User, RefreshCw, CheckCircle, Clock, Cog } from 'lucide-react';
21
+ import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
22
+ import { Button } from '../../components/ui/button'
23
+ import { Badge } from '../../components/ui/badge'
24
+ import { formatDateTime } from '../../lib/utils'
25
+ import { AdminListPage } from '../../components/admin/AdminListPage'
26
+ import { SortableTableHeader } from '../../components/admin/SortableTableHeader'
27
+
28
+ interface Pipeline {
29
+ id: string
30
+ name: string
31
+ description?: string
32
+ trigger_type: string
33
+ trigger_config: Record<string, any>
34
+ stages: Array<{
35
+ name: string
36
+ type: string
37
+ config: Record<string, any>
38
+ order: number
39
+ }>
40
+ is_active: boolean
41
+ created_at: string
42
+ updated_at: string
43
+ created_by: string
44
+ account_id: string
45
+ execution_count: number
46
+ last_execution?: string
47
+ next_execution?: string
48
+ }
49
+
50
+ interface PipelineExecution {
51
+ id: string
52
+ pipeline_id: string
53
+ status: 'pending' | 'running' | 'completed' | 'failed'
54
+ started_at: string
55
+ completed_at?: string
56
+ trigger_data: Record<string, any>
57
+ result?: Record<string, any>
58
+ error?: string
59
+ }
60
+
61
+ export function PipelinesPage() {
62
+ console.log('PipelinesPage rendering...')
63
+ const navigate = useNavigate()
64
+ const [searchTerm, setSearchTerm] = useState('')
65
+ const [selectedTrigger, setSelectedTrigger] = useState('all')
66
+ const [selectedStatus, setSelectedStatus] = useState('all')
67
+ const [selectedPipeline, setSelectedPipeline] = useState<Pipeline | null>(null)
68
+ const [sortKey, setSortKey] = useState('name')
69
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc')
70
+
71
+ // Fetch pipelines from API
72
+ const { data: pipelines, loading, error, refetch } = useApi<Pipeline[]>(
73
+ async ({ signal }: { signal?: AbortSignal }) => {
74
+ try {
75
+ console.log('Fetching pipelines...')
76
+
77
+ // Check authentication using the same method as apiFetch
78
+ const { supabase } = await import('../../lib/supabase')
79
+ const { data: { session } } = await supabase.auth.getSession()
80
+ console.log('Supabase session exists:', !!session)
81
+ console.log('Supabase access token exists:', !!session?.access_token)
82
+ console.log('Supabase access token length:', session?.access_token?.length || 0)
83
+
84
+ // Also check localStorage for comparison
85
+ const localToken = localStorage.getItem('access_token')
86
+ console.log('localStorage token exists:', !!localToken)
87
+ console.log('localStorage token length:', localToken?.length || 0)
88
+
89
+ const response = await apiFetch('/api/pipelines?action=list', { signal })
90
+ console.log('Response status:', response.status)
91
+ console.log('Response headers:', Object.fromEntries(response.headers.entries()))
92
+
93
+ if (!response.ok) {
94
+ console.error('Response not ok:', response.statusText)
95
+ throw new Error(`Failed to fetch pipelines: ${response.statusText}`)
96
+ }
97
+
98
+ const result = await response.json()
99
+ console.log('Raw API result:', result)
100
+ console.log('Result data type:', typeof result.data)
101
+ console.log('Result data is array:', Array.isArray(result.data))
102
+ console.log('Result data length:', result.data?.length || 'N/A')
103
+
104
+ // Handle both nested and direct responses
105
+ const pipelines = result.data || result
106
+ console.log('Pipelines after processing:', pipelines)
107
+ console.log('Pipelines is array:', Array.isArray(pipelines))
108
+ console.log('Pipelines length:', pipelines.length)
109
+
110
+ return pipelines
111
+ } catch (error) {
112
+ console.error('Error in PipelinesPage:', error)
113
+ throw error
114
+ }
115
+ },
116
+ { immediate: true }
117
+ )
118
+
119
+ const triggerOptions = [
120
+ { value: 'all', label: 'All Triggers' },
121
+ { value: 'schedule', label: 'Schedule' },
122
+ { value: 'webhook', label: 'Webhook' },
123
+ { value: 'event', label: 'Event' },
124
+ { value: 'manual', label: 'Manual' },
125
+ ]
126
+
127
+ const statusOptions = [
128
+ { value: 'all', label: 'All Statuses' },
129
+ { value: 'active', label: 'Active' },
130
+ { value: 'inactive', label: 'Inactive' },
131
+ ]
132
+
133
+ const filteredPipelines = (pipelines || []).filter(pipeline => {
134
+ const matchesSearch = pipeline.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
135
+ (pipeline.description && pipeline.description.toLowerCase().includes(searchTerm.toLowerCase()))
136
+ const matchesStatus = selectedStatus === 'all' || pipeline.is_active === (selectedStatus === 'active')
137
+ const matchesTrigger = selectedTrigger === 'all' || pipeline.trigger_type === selectedTrigger
138
+ return matchesSearch && matchesStatus && matchesTrigger
139
+ })
140
+
141
+ const sortedPipelines = [...filteredPipelines].sort((a, b) => {
142
+ const aValue = a[sortKey as keyof Pipeline]
143
+ const bValue = b[sortKey as keyof Pipeline]
144
+
145
+ if (aValue === null || aValue === undefined) return 1
146
+ if (bValue === null || bValue === undefined) return -1
147
+
148
+ if (typeof aValue === 'string') {
149
+ return sortDirection === 'asc'
150
+ ? aValue.localeCompare(bValue as string)
151
+ : (bValue as string).localeCompare(aValue)
152
+ }
153
+
154
+ if (typeof aValue === 'number') {
155
+ return sortDirection === 'asc' ? aValue - (bValue as number) : (bValue as number) - aValue
156
+ }
157
+
158
+ return 0
159
+ })
160
+
161
+ const getTriggerIcon = (triggerType: string) => {
162
+ switch (triggerType) {
163
+ case 'schedule':
164
+ return <Calendar className="h-5 w-5 text-blue-500" />
165
+ case 'webhook':
166
+ return <RefreshCw className="h-5 w-5 text-green-500" />
167
+ case 'user_created':
168
+ return <User className="h-5 w-5 text-purple-500" />
169
+ default:
170
+ return <Settings className="h-5 w-5 text-slate-500" />
171
+ }
172
+ }
173
+
174
+ const getTriggerBadgeColor = (triggerType: string) => {
175
+ switch (triggerType) {
176
+ case 'schedule':
177
+ return 'bg-blue-100 text-blue-800'
178
+ case 'webhook':
179
+ return 'bg-green-100 text-green-800'
180
+ case 'user_created':
181
+ return 'bg-purple-100 text-purple-800'
182
+ case 'item_created':
183
+ return 'bg-orange-100 text-orange-800'
184
+ case 'item_updated':
185
+ return 'bg-yellow-100 text-yellow-800'
186
+ default:
187
+ return 'bg-slate-100 text-slate-800'
188
+ }
189
+ }
190
+
191
+ const getStatusBadgeColor = (isActive: boolean) => {
192
+ return isActive ? 'bg-green-100 text-green-800' : 'bg-slate-100 text-slate-800'
193
+ }
194
+
195
+ const handleTogglePipeline = (pipeline: Pipeline) => {
196
+ console.log('Toggle pipeline:', pipeline.id)
197
+ }
198
+
199
+ const handleExecutePipeline = (pipeline: Pipeline) => {
200
+ console.log('Execute pipeline:', pipeline.id)
201
+ }
202
+
203
+ const handleViewExecutions = (pipeline: Pipeline) => {
204
+ navigate(`/spine-framework/admin/configs/pipelines/${pipeline.id}/executions`)
205
+ }
206
+
207
+ const handleRowClick = (pipeline: Pipeline) => {
208
+ navigate(`/spine-framework/admin/configs/pipelines/${pipeline.id}`)
209
+ }
210
+
211
+ const handleEditPipeline = (pipeline: Pipeline) => {
212
+ navigate(`/spine-framework/admin/configs/pipelines/${pipeline.id}/edit`)
213
+ }
214
+
215
+ const handleSort = (key: string) => {
216
+ if (sortKey === key) {
217
+ setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc')
218
+ } else {
219
+ setSortKey(key)
220
+ setSortDirection('asc')
221
+ }
222
+ }
223
+
224
+ return (
225
+ <AdminListPage
226
+ title="Pipelines"
227
+ description="Manage automated workflows and processes"
228
+ newButtonText="New Pipeline"
229
+ newButtonHref="/spine-framework/admin/configs/pipelines/new"
230
+ statsCards={[
231
+ {
232
+ title: "Total Pipelines",
233
+ value: (pipelines || []).length,
234
+ icon: Play,
235
+ iconColor: "text-blue-600"
236
+ },
237
+ {
238
+ title: "Active",
239
+ value: (pipelines || []).filter(p => p.is_active).length,
240
+ icon: CheckCircle,
241
+ iconColor: "text-green-600"
242
+ },
243
+ {
244
+ title: "Runs Today",
245
+ value: "32",
246
+ icon: Clock,
247
+ iconColor: "text-orange-600"
248
+ }
249
+ ]}
250
+ searchPlaceholder="Search pipelines..."
251
+ searchValue={searchTerm}
252
+ onSearchChange={setSearchTerm}
253
+ filters={[
254
+ {
255
+ label: "Status",
256
+ value: selectedStatus,
257
+ options: statusOptions,
258
+ onChange: setSelectedStatus
259
+ },
260
+ {
261
+ label: "Trigger",
262
+ value: selectedTrigger,
263
+ options: triggerOptions,
264
+ onChange: setSelectedTrigger
265
+ }
266
+ ]}
267
+ loading={loading}
268
+ error={error}
269
+ onRetry={refetch}
270
+ emptyMessage="No pipelines found"
271
+ emptyIcon={Cog}
272
+ >
273
+ {sortedPipelines.length === 0 ? (
274
+ <div className="text-center py-12">
275
+ <Settings className="mx-auto h-12 w-12 text-slate-400" />
276
+ <h3 className="mt-2 text-sm font-medium text-slate-900">No pipelines found</h3>
277
+ <p className="mt-1 text-sm text-slate-500">
278
+ Get started by creating your first automated workflow.
279
+ </p>
280
+ <div className="mt-6">
281
+ <Button onClick={() => navigate('/spine-framework/admin/configs/pipelines/new')}>
282
+ <Plus className="w-4 h-4 mr-2" />
283
+ Create Your First Pipeline
284
+ </Button>
285
+ </div>
286
+ </div>
287
+ ) : (
288
+ <table className="min-w-full divide-y divide-slate-200">
289
+ <thead className="bg-slate-50">
290
+ <tr>
291
+ <SortableTableHeader
292
+ title="Pipeline"
293
+ sortKey="name"
294
+ currentSortKey={sortKey}
295
+ currentSortDirection={sortDirection}
296
+ onSort={handleSort}
297
+ />
298
+ <SortableTableHeader
299
+ title="Trigger"
300
+ sortKey="trigger_type"
301
+ currentSortKey={sortKey}
302
+ currentSortDirection={sortDirection}
303
+ onSort={handleSort}
304
+ />
305
+ <SortableTableHeader
306
+ title="Status"
307
+ sortKey="is_active"
308
+ currentSortKey={sortKey}
309
+ currentSortDirection={sortDirection}
310
+ onSort={handleSort}
311
+ />
312
+ <SortableTableHeader
313
+ title="Executions"
314
+ sortKey="execution_count"
315
+ currentSortKey={sortKey}
316
+ currentSortDirection={sortDirection}
317
+ onSort={handleSort}
318
+ />
319
+ <SortableTableHeader
320
+ title="Last Run"
321
+ sortKey="last_execution"
322
+ currentSortKey={sortKey}
323
+ currentSortDirection={sortDirection}
324
+ onSort={handleSort}
325
+ />
326
+ <th className="relative px-6 py-3">
327
+ <span className="sr-only">Actions</span>
328
+ </th>
329
+ </tr>
330
+ </thead>
331
+ <tbody className="bg-white divide-y divide-slate-200">
332
+ {sortedPipelines.map((pipeline) => (
333
+ <tr
334
+ key={pipeline.id}
335
+ className="hover:bg-slate-50 cursor-pointer transition-colors"
336
+ onClick={() => handleRowClick(pipeline)}
337
+ >
338
+ <td className="px-6 py-4 whitespace-nowrap">
339
+ <div>
340
+ <div className="text-sm font-medium text-slate-900">{pipeline.name}</div>
341
+ {pipeline.description && (
342
+ <div className="text-sm text-slate-500">{pipeline.description}</div>
343
+ )}
344
+ </div>
345
+ </td>
346
+ <td className="px-6 py-4 whitespace-nowrap">
347
+ <div className="flex items-center space-x-2">
348
+ {getTriggerIcon(pipeline.trigger_type)}
349
+ <Badge variant={getTriggerBadgeColor(pipeline.trigger_type) as any}>
350
+ {pipeline.trigger_type.replace('_', ' ')}
351
+ </Badge>
352
+ </div>
353
+ </td>
354
+ <td className="px-6 py-4 whitespace-nowrap">
355
+ <Badge variant={getStatusBadgeColor(pipeline.is_active) as any}>
356
+ {pipeline.is_active ? 'Active' : 'Inactive'}
357
+ </Badge>
358
+ </td>
359
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-900">
360
+ {pipeline.execution_count}
361
+ </td>
362
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-500">
363
+ {pipeline.last_execution ? formatDateTime(pipeline.last_execution) : 'Never'}
364
+ </td>
365
+ <td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
366
+ <div className="flex justify-end space-x-2" onClick={(e) => e.stopPropagation()}>
367
+ <Button
368
+ variant="outline"
369
+ size="sm"
370
+ onClick={() => handleViewExecutions(pipeline)}
371
+ >
372
+ <RefreshCw className="h-4 w-4" />
373
+ </Button>
374
+ <Button
375
+ variant="outline"
376
+ size="sm"
377
+ onClick={() => handleEditPipeline(pipeline)}
378
+ >
379
+ <Pencil className="h-4 w-4" />
380
+ </Button>
381
+ </div>
382
+ </td>
383
+ </tr>
384
+ ))}
385
+ </tbody>
386
+ </table>
387
+ )}
388
+ </AdminListPage>
389
+ )
390
+ }