spine-framework 0.3.124 → 0.3.126

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 (319) hide show
  1. package/.framework/cli/commands/agents.ts +35 -37
  2. package/.framework/cli/commands/auth.ts +35 -34
  3. package/.framework/cli/commands/create-app.ts +104 -40
  4. package/.framework/cli/commands/dev.ts +104 -69
  5. package/.framework/cli/commands/doctor.ts +179 -69
  6. package/.framework/cli/commands/generate.ts +83 -143
  7. package/.framework/cli/commands/init.ts +72 -34
  8. package/.framework/cli/commands/install-app.ts +260 -125
  9. package/.framework/cli/commands/items.ts +33 -44
  10. package/.framework/cli/commands/migrate.ts +122 -40
  11. package/.framework/cli/commands/migrations.ts +33 -40
  12. package/.framework/cli/commands/pipelines.ts +31 -39
  13. package/.framework/cli/commands/status.ts +47 -23
  14. package/.framework/cli/commands/system.ts +47 -37
  15. package/.framework/cli/commands/test.ts +112 -68
  16. package/.framework/cli/commands/validate-app.ts +215 -121
  17. package/.framework/cli/context.ts +112 -130
  18. package/.framework/cli/env-loader.ts +47 -18
  19. package/.framework/cli/index.ts +81 -42
  20. package/.framework/docs/runtime-types.md +1024 -0
  21. package/.framework/functions/_shared/agent-runner.ts +1296 -961
  22. package/.framework/functions/_shared/app-manifest.ts +82 -68
  23. package/.framework/functions/_shared/audit.ts +135 -83
  24. package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
  25. package/.framework/functions/_shared/db.ts +80 -126
  26. package/.framework/functions/_shared/hash-api-key.ts +63 -0
  27. package/.framework/functions/_shared/index.ts +224 -335
  28. package/.framework/functions/_shared/kb.ts +319 -0
  29. package/.framework/functions/_shared/llm.ts +92 -0
  30. package/.framework/functions/_shared/logging.ts +288 -0
  31. package/.framework/functions/_shared/middleware.ts +329 -365
  32. package/.framework/functions/_shared/outcomes.ts +36 -0
  33. package/.framework/functions/_shared/permissions.ts +359 -643
  34. package/.framework/functions/_shared/pipeline-runner.ts +243 -316
  35. package/.framework/functions/_shared/principal.ts +376 -468
  36. package/.framework/functions/_shared/resolve-credentials.ts +102 -0
  37. package/.framework/functions/_shared/resolve-ids.ts +188 -16
  38. package/.framework/functions/_shared/retry-deliveries.ts +104 -0
  39. package/.framework/functions/_shared/schema-utils.ts +611 -373
  40. package/.framework/functions/_shared/testing.ts +207 -137
  41. package/.framework/functions/_shared/tracing.ts +276 -0
  42. package/.framework/functions/_shared/trigger-engine.ts +159 -211
  43. package/.framework/functions/_shared/webhook-registration.ts +95 -81
  44. package/.framework/functions/_shared/webhook-registry.ts +153 -75
  45. package/.framework/functions/account-nodes.ts +31 -53
  46. package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
  47. package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
  48. package/.framework/functions/adapters/openai-outbound.ts +40 -0
  49. package/.framework/functions/admin-data.ts +685 -537
  50. package/.framework/functions/admin-funnel.ts +31 -20
  51. package/.framework/functions/admin-install-funnel.ts +47 -28
  52. package/.framework/functions/admin-signals.ts +47 -29
  53. package/.framework/functions/ai-agents.ts +122 -147
  54. package/.framework/functions/ai-interactions.ts +180 -90
  55. package/.framework/functions/api-keys.ts +250 -192
  56. package/.framework/functions/apps.ts +203 -197
  57. package/.framework/functions/auth.ts +98 -91
  58. package/.framework/functions/cil-agent-ingest.ts +773 -0
  59. package/.framework/functions/cil-agent.ts +592 -0
  60. package/.framework/functions/cil-callmap.ts +1227 -0
  61. package/.framework/functions/cil-config.ts +583 -0
  62. package/.framework/functions/cil-context.ts +445 -0
  63. package/.framework/functions/cil-doc.ts +1752 -0
  64. package/.framework/functions/cil-embeddings.ts +1202 -0
  65. package/.framework/functions/cil-graph.ts +585 -0
  66. package/.framework/functions/cil-ingest.ts +2416 -0
  67. package/.framework/functions/cil-pipeline.ts +318 -0
  68. package/.framework/functions/cil-project.ts +499 -0
  69. package/.framework/functions/cil-validate.ts +469 -0
  70. package/.framework/functions/debug-auth.ts +73 -53
  71. package/.framework/functions/deliveries.ts +117 -0
  72. package/.framework/functions/embeddings.ts +528 -516
  73. package/.framework/functions/eval-harness.ts +158 -106
  74. package/.framework/functions/integration-outbound.ts +311 -0
  75. package/.framework/functions/integration-routes.ts +240 -466
  76. package/.framework/functions/integrations.ts +132 -140
  77. package/.framework/functions/invites.ts +401 -201
  78. package/.framework/functions/item-progress.ts +113 -53
  79. package/.framework/functions/kb.ts +28 -0
  80. package/.framework/functions/logs.ts +239 -222
  81. package/.framework/functions/observability.ts +308 -259
  82. package/.framework/functions/pipeline-executions.ts +179 -235
  83. package/.framework/functions/pipelines.ts +163 -205
  84. package/.framework/functions/prompt-configs.ts +109 -156
  85. package/.framework/functions/roles.ts +97 -147
  86. package/.framework/functions/system-cron.ts +132 -218
  87. package/.framework/functions/system.ts +112 -52
  88. package/.framework/functions/tests.ts +32 -28
  89. package/.framework/functions/timers.ts +162 -210
  90. package/.framework/functions/triggers.ts +282 -346
  91. package/.framework/functions/types.ts +283 -400
  92. package/.framework/migrations/001_core_schema.sql +630 -0
  93. package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
  94. package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
  95. package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
  96. package/.framework/migrations/005_core_observability.sql +598 -0
  97. package/.framework/migrations/006_security_hardening_rls.sql +97 -0
  98. package/.framework/migrations/007_kb_article_list.sql +237 -0
  99. package/.framework/migrations/008_items_target.sql +8 -0
  100. package/.framework/migrations/009_roles_slug_unique.sql +11 -0
  101. package/.framework/public/spine.config.json +91 -0
  102. package/.framework/scripts/app-install-cli.ts +112 -98
  103. package/.framework/src/App.tsx +67 -20
  104. package/.framework/src/apps/admin/index.tsx +97 -27
  105. package/.framework/src/components/AppWrapper.tsx +50 -11
  106. package/.framework/src/components/CustomAppLoader.tsx +131 -22
  107. package/.framework/src/components/admin/AdminListPage.tsx +75 -8
  108. package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
  109. package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
  110. package/.framework/src/components/admin/PageInstructions.tsx +49 -0
  111. package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
  112. package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
  113. package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
  114. package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
  115. package/.framework/src/components/app-sidebar.tsx +50 -3
  116. package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
  117. package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
  118. package/.framework/src/components/kb/KBArticleList.tsx +557 -0
  119. package/.framework/src/components/layout/AppShell.tsx +54 -16
  120. package/.framework/src/components/layout/Header.tsx +50 -38
  121. package/.framework/src/components/layout/Layout.tsx +48 -32
  122. package/.framework/src/components/layout/Sidebar.tsx +167 -16
  123. package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
  124. package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
  125. package/.framework/src/components/runtime/DataFilters.tsx +78 -1
  126. package/.framework/src/components/runtime/DataHeader.tsx +32 -29
  127. package/.framework/src/components/runtime/DataListPage.tsx +161 -2
  128. package/.framework/src/components/runtime/DataStats.tsx +48 -1
  129. package/.framework/src/components/runtime/DataTable.tsx +153 -1
  130. package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
  131. package/.framework/src/components/runtime/index.ts +16 -9
  132. package/.framework/src/components/search-form.tsx +33 -1
  133. package/.framework/src/components/shared/AgentView.tsx +48 -51
  134. package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
  135. package/.framework/src/components/shared/InviteManager.tsx +113 -52
  136. package/.framework/src/components/shared/MemberList.tsx +182 -0
  137. package/.framework/src/components/shared/SchemaFields.tsx +96 -78
  138. package/.framework/src/components/ui/DataTable.tsx +86 -56
  139. package/.framework/src/components/ui/Form.tsx +188 -109
  140. package/.framework/src/components/ui/ItemCard.tsx +86 -58
  141. package/.framework/src/components/ui/ItemListView.tsx +88 -61
  142. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
  143. package/.framework/src/components/ui/Modal.tsx +81 -4
  144. package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
  145. package/.framework/src/components/ui/accordion.tsx +97 -5
  146. package/.framework/src/components/ui/alert-dialog.tsx +225 -13
  147. package/.framework/src/components/ui/alert.tsx +113 -6
  148. package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
  149. package/.framework/src/components/ui/avatar.tsx +129 -7
  150. package/.framework/src/components/ui/badge.tsx +65 -3
  151. package/.framework/src/components/ui/breadcrumb.tsx +145 -8
  152. package/.framework/src/components/ui/button-group.tsx +81 -4
  153. package/.framework/src/components/ui/button.tsx +49 -2
  154. package/.framework/src/components/ui/calendar.tsx +65 -3
  155. package/.framework/src/components/ui/card.tsx +145 -8
  156. package/.framework/src/components/ui/carousel.tsx +129 -7
  157. package/.framework/src/components/ui/chart.tsx +161 -10
  158. package/.framework/src/components/ui/checkbox.tsx +49 -2
  159. package/.framework/src/components/ui/collapsible.tsx +81 -5
  160. package/.framework/src/components/ui/combobox.tsx +305 -20
  161. package/.framework/src/components/ui/command.tsx +177 -11
  162. package/.framework/src/components/ui/context-menu.tsx +273 -17
  163. package/.framework/src/components/ui/dialog.tsx +209 -27
  164. package/.framework/src/components/ui/direction.tsx +64 -4
  165. package/.framework/src/components/ui/drawer.tsx +193 -12
  166. package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
  167. package/.framework/src/components/ui/empty.tsx +145 -9
  168. package/.framework/src/components/ui/field.tsx +209 -14
  169. package/.framework/src/components/ui/hover-card.tsx +81 -4
  170. package/.framework/src/components/ui/input-group.tsx +162 -10
  171. package/.framework/src/components/ui/input-otp.tsx +98 -5
  172. package/.framework/src/components/ui/input.tsx +49 -2
  173. package/.framework/src/components/ui/item.tsx +225 -13
  174. package/.framework/src/components/ui/kbd.tsx +65 -3
  175. package/.framework/src/components/ui/label.tsx +49 -2
  176. package/.framework/src/components/ui/menubar.tsx +289 -17
  177. package/.framework/src/components/ui/native-select.tsx +97 -5
  178. package/.framework/src/components/ui/navigation-menu.tsx +177 -10
  179. package/.framework/src/components/ui/pagination.tsx +161 -9
  180. package/.framework/src/components/ui/popover.tsx +145 -8
  181. package/.framework/src/components/ui/progress.tsx +49 -2
  182. package/.framework/src/components/ui/radio-group.tsx +65 -3
  183. package/.framework/src/components/ui/resizable.tsx +82 -4
  184. package/.framework/src/components/ui/scroll-area.tsx +65 -3
  185. package/.framework/src/components/ui/select.tsx +193 -11
  186. package/.framework/src/components/ui/separator.tsx +49 -2
  187. package/.framework/src/components/ui/sheet.tsx +193 -11
  188. package/.framework/src/components/ui/sidebar.tsx +481 -38
  189. package/.framework/src/components/ui/skeleton.tsx +49 -2
  190. package/.framework/src/components/ui/slider.tsx +49 -2
  191. package/.framework/src/components/ui/sonner.tsx +49 -2
  192. package/.framework/src/components/ui/spinner.tsx +49 -2
  193. package/.framework/src/components/ui/switch.tsx +49 -2
  194. package/.framework/src/components/ui/table-primitives.tsx +160 -33
  195. package/.framework/src/components/ui/table.tsx +161 -9
  196. package/.framework/src/components/ui/tabs.tsx +113 -6
  197. package/.framework/src/components/ui/textarea.tsx +49 -2
  198. package/.framework/src/components/ui/toggle-group.tsx +81 -4
  199. package/.framework/src/components/ui/toggle.tsx +65 -3
  200. package/.framework/src/components/ui/tooltip.tsx +97 -5
  201. package/.framework/src/contexts/AppContext.tsx +129 -45
  202. package/.framework/src/contexts/AuthContext.tsx +187 -144
  203. package/.framework/src/hooks/use-mobile.ts +48 -2
  204. package/.framework/src/hooks/useApi.ts +208 -159
  205. package/.framework/src/hooks/useAppPath.ts +32 -23
  206. package/.framework/src/hooks/useApps.ts +51 -20
  207. package/.framework/src/hooks/useEntityList.ts +32 -78
  208. package/.framework/src/hooks/useEntityRecord.ts +35 -96
  209. package/.framework/src/hooks/useForm.ts +32 -92
  210. package/.framework/src/hooks/useListSchema.ts +49 -78
  211. package/.framework/src/hooks/useSchemaRecord.ts +114 -105
  212. package/.framework/src/lib/api.ts +195 -116
  213. package/.framework/src/lib/supabase.ts +98 -64
  214. package/.framework/src/lib/utils.ts +287 -151
  215. package/.framework/src/main.tsx +49 -3
  216. package/.framework/src/pages/DashboardPage.tsx +52 -29
  217. package/.framework/src/pages/NotFoundPage.tsx +32 -10
  218. package/.framework/src/pages/SetupPage.tsx +32 -12
  219. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
  220. package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
  221. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
  222. package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
  223. package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
  224. package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
  225. package/.framework/src/pages/admin/AppsPage.tsx +49 -2
  226. package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
  227. package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
  228. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
  229. package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
  230. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
  231. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
  232. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
  233. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
  234. package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
  235. package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
  236. package/.framework/src/pages/admin/LogsPage.tsx +422 -75
  237. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
  238. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
  239. package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
  240. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
  241. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
  242. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
  243. package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
  244. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
  245. package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
  246. package/.framework/src/pages/admin/RolesPage.tsx +171 -18
  247. package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
  248. package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
  249. package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
  250. package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
  251. package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
  252. package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
  253. package/.framework/src/pages/admin/TimersPage.tsx +48 -20
  254. package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
  255. package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
  256. package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
  257. package/.framework/src/pages/admin/TypesPage.tsx +48 -20
  258. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
  259. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
  260. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
  261. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
  262. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
  263. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
  264. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
  265. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
  266. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
  267. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  268. package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
  269. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
  270. package/.framework/src/pages/auth/LoginPage.tsx +50 -23
  271. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
  272. package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
  273. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
  274. package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
  275. package/.framework/src/types/auth.ts +128 -71
  276. package/.framework/src/types/types.ts +373 -157
  277. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
  278. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
  279. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
  280. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
  281. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
  282. package/docs/README.md +9 -130
  283. package/netlify.toml +5 -2
  284. package/package.json +13 -25
  285. package/scripts/kb-ingest-docs.ts +203 -0
  286. package/spine.config.json +65 -4
  287. package/.framework/migrations/001_schema.sql +0 -425
  288. package/.framework/migrations/002_rls_and_functions.sql +0 -763
  289. package/.framework/migrations/004_enhancements.sql +0 -43
  290. package/.framework/migrations/005_auth_user_trigger.sql +0 -105
  291. package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
  292. package/.framework/migrations/016_invites.sql +0 -27
  293. package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
  294. package/.framework/migrations/018_apps_required_roles.sql +0 -17
  295. package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
  296. package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
  297. package/.framework/migrations/021_app_domains.sql +0 -112
  298. package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
  299. package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
  300. package/.framework/migrations/024_messages_account_id.sql +0 -9
  301. package/.framework/migrations/025_retype_threads_messages.sql +0 -240
  302. package/.framework/migrations/026_fix_rls_policies.sql +0 -47
  303. package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
  304. package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
  305. package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
  306. package/.framework/migrations/030_messages_updated_by.sql +0 -6
  307. package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
  308. package/docs/APPS.md +0 -232
  309. package/docs/ARCHITECTURE.md +0 -246
  310. package/docs/INSTALL.md +0 -155
  311. package/docs/design-schema-spec.md +0 -1837
  312. package/docs/dev-guides/01-create-an-app.md +0 -183
  313. package/docs/dev-guides/02-create-a-function.md +0 -178
  314. package/docs/dev-guides/03-create-a-component.md +0 -178
  315. package/docs/dev-guides/04-webhook-handlers.md +0 -129
  316. package/docs/dev-guides/05-testing.md +0 -168
  317. package/docs/dev-guides/README.md +0 -40
  318. package/docs/npm-packages-plan.md +0 -288
  319. package/docs/spine-core--api-reference.md +0 -822
@@ -1,48 +1,35 @@
1
- /**
2
- * @module src/components/shared/FieldRenderer
3
- * @audience installer
4
- * @layer frontend-component
5
- * @stability stable
6
- *
7
- * Low-level field rendering primitive. Given a `FieldDefinition` and a
8
- * current value, renders the appropriate input widget (edit mode) or
9
- * display element (read-only mode).
10
- *
11
- * **Render type resolution** (`resolveRenderType`):
12
- * 1. If `displayType` is set (from the view config), it maps to a canonical
13
- * render type first — this lets a view override how a field looks without
14
- * changing the underlying `FieldDefinition`.
15
- * 2. Falls back to `field.data_type`.
16
- *
17
- * **Supported render types:**
18
- * `text`, `textarea`, `email`, `phone`, `url`, `number`, `date`,
19
- * `datetime`, `select`, `multiselect`, `radio`, `checkbox`, `json`,
20
- * `file`, `color`, `range`
21
- *
22
- * **Error display:** when `error` is set, a red helper text is shown below
23
- * the field and `border-red-500` is applied where applicable.
24
- *
25
- * **Label + description:** rendered above / below the input respectively,
26
- * with a red `*` suffix when `field.required` is true.
27
- *
28
- * @seeAlso src/components/shared/SchemaFields.tsx (mounts this component)
29
- * @seeAlso src/types/types.ts (FieldDefinition)
30
- */
31
1
 
2
+
3
+
4
+ // CIL[BEGIN chunk_id="FieldRenderer_module_header_1783927912" type="module_header" identity="module_header" parent="none"]
5
+ // CIL[DOC-MACRO purpose="Import dependencies and define field renderer component interfaces"]
6
+ // CIL[DOC-RESPONSIBILITY responsibility="Manage React imports and field renderer prop types"]
7
+ // CIL[DOC-CONTEXT module="field-renderer" layer="frontend-component" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/src/components/ui/table-primitives.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
8
+ // CIL[DOC-CONTRACT inputs="none" outputs="Imported modules and interface" errors="none" side_effects="none"]
9
+ // CIL[DOC-MICRO logic_summary="Imports React, field types, and defines FieldRendererProps interface" notable_decisions="[]"]
10
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
11
+ // CIL[DOC-STABILITY stability="stable"]
12
+ // CIL[DOC-AUDIENCE audience="developer"]
13
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/components/ui/dialog.tsx, .framework/src/components/ui/table-primitives.tsx, .framework/functions/_shared/schema-utils.ts, \."]
14
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
15
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
16
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
17
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
18
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
32
19
  import React from 'react'
20
+ import DOMPurify from 'dompurify'
21
+ import { marked } from 'marked'
33
22
  import { FieldDefinition } from '../../types/types'
23
+ import { RichTextEditor } from '../ui/RichTextEditor'
24
+
25
+ function toSafeHtml(raw: string | undefined): string {
26
+ const source = (raw ?? '').trim()
27
+ if (!source) return '<p class="text-slate-400 italic">—</p>'
28
+ const likelyHtml = /<\/?(?:h[1-6]|p|div|ul|ol|li|pre|code|br|span|strong|em|a|table|tr|td|th|thead|tbody|blockquote)\b/i.test(source)
29
+ const html = likelyHtml ? source : (marked.parse(source, { async: false }) as string)
30
+ return DOMPurify.sanitize(html)
31
+ }
34
32
 
35
- /**
36
- * Props for `FieldRenderer`.
37
- *
38
- * @prop field - Full field definition including data_type, options, validation
39
- * @prop value - Current controlled value
40
- * @prop onChange - Value change callback (omit or pass `undefined` for read-only)
41
- * @prop onBlur - Optional blur callback for validation triggers
42
- * @prop readonly - If true, renders a display element instead of an input
43
- * @prop error - Validation error message to display below the field
44
- * @prop displayType - View-config widget override (e.g. `'textarea'`, `'select'`)
45
- */
46
33
  interface FieldRendererProps {
47
34
  field: FieldDefinition
48
35
  value: any
@@ -50,27 +37,32 @@ interface FieldRendererProps {
50
37
  onBlur?: () => void
51
38
  readonly?: boolean
52
39
  error?: string
53
- displayType?: string // From view config — controls rendering without polluting field data contract
40
+ displayType?: string
54
41
  }
55
-
56
- /**
57
- * Resolves the canonical render type for a field.
58
- *
59
- * `displayType` (from view config) takes precedence over `field.data_type`
60
- * so view authors can choose a different widget without changing the
61
- * underlying schema.
62
- *
63
- * @param field - Field definition
64
- * @param displayType - Optional view-config widget override
65
- * @returns Canonical render type string (e.g. `'text'`, `'select'`, `'checkbox'`)
66
- */
42
+ // CIL[END chunk_id="FieldRenderer_module_header_1783927912"]
43
+ // CIL[BEGIN chunk_id="FieldRenderer_resolverendertype_1783927912" type="function" identity="resolveRenderType" parent="none"]
44
+ // CIL[DOC-LEARNING topic="runtime-type:generic/field_rendering" content="FieldRenderer maps field.data_type or display_type to a widget: text, textarea, email, phone, url, number, date, datetime, checkbox, select, multiselect, radio, color, file, json. display_type overrides data_type when provided."]
45
+ // CIL[DOC-NOTE type="design_schema_caveat" content="Unknown data_type or display_type silently falls back to text. Select/multiselect fields must define options or the user sees an empty control."]
46
+ // CIL[DOC-MACRO purpose="Resolve canonical render type from field definition and display type"]
47
+ // CIL[DOC-RESPONSIBILITY responsibility="Map display types and data types to render types"]
48
+ // CIL[DOC-CONTEXT module="field-renderer" layer="frontend-component" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/migrations/025_retype_threads_messages.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
49
+ // CIL[DOC-CONTRACT inputs="none" outputs="Render type string" errors="none" side_effects="none"]
50
+ // CIL[DOC-MICRO logic_summary="Display type overrides data type, maps to canonical render types" notable_decisions="[]"]
51
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
52
+ // CIL[DOC-STABILITY stability="stable"]
53
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/migrations/025_retype_threads_messages.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
54
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
55
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
56
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
57
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
58
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
67
59
  function resolveRenderType(field: FieldDefinition, displayType?: string): string {
68
- // displayType from view config overrides data_type for rendering decisions
69
60
  if (displayType) {
70
61
  switch (displayType) {
71
62
  case 'textarea':
72
- case 'rich_text':
73
63
  return 'textarea'
64
+ case 'rich_text':
65
+ return 'rich_text'
74
66
  case 'select':
75
67
  return 'select'
76
68
  case 'multiselect':
@@ -93,11 +85,11 @@ function resolveRenderType(field: FieldDefinition, displayType?: string): string
93
85
  return 'file'
94
86
  }
95
87
  }
96
- // Fall back to data_type
97
88
  switch (field.data_type) {
98
89
  case 'textarea':
99
- case 'rich_text':
100
90
  return 'textarea'
91
+ case 'rich_text':
92
+ return 'rich_text'
101
93
  case 'email':
102
94
  return 'email'
103
95
  case 'phone':
@@ -132,14 +124,21 @@ function resolveRenderType(field: FieldDefinition, displayType?: string): string
132
124
  return 'text'
133
125
  }
134
126
  }
135
-
136
- /**
137
- * Renders a single schema field as an input widget or read-only display.
138
- *
139
- * @param props - `FieldRendererProps`
140
- * @returns Label + field widget + description + error message
141
- * @sideEffects none (delegates changes to `onChange`)
142
- */
127
+ // CIL[END chunk_id="FieldRenderer_resolverendertype_1783927912"]
128
+ // CIL[BEGIN chunk_id="FieldRenderer_fieldrenderer_1783927912" type="function" identity="FieldRenderer" parent="none"]
129
+ // CIL[DOC-MACRO purpose="Render appropriate input widget or display element for field type"]
130
+ // CIL[DOC-RESPONSIBILITY responsibility="Display field as editable input or read-only value based on type"]
131
+ // CIL[DOC-CONTEXT module="field-renderer" layer="frontend-component" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/migrations/025_retype_threads_messages.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
132
+ // CIL[DOC-CONTRACT inputs="none" outputs="Rendered field widget" errors="none" side_effects="Renders UI, calls onChange"]
133
+ // CIL[DOC-MICRO logic_summary="Switches on render type to return appropriate input or display component" notable_decisions="[]"]
134
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
135
+ // CIL[DOC-STABILITY stability="stable"]
136
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/migrations/025_retype_threads_messages.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, \."]
137
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
138
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
139
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
140
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
141
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
143
142
  export function FieldRenderer({ field, value, onChange, readonly = false, error, displayType }: FieldRendererProps) {
144
143
  const renderType = resolveRenderType(field, displayType)
145
144
 
@@ -160,6 +159,24 @@ export function FieldRenderer({ field, value, onChange, readonly = false, error,
160
159
  />
161
160
  )
162
161
 
162
+ case 'rich_text':
163
+ return readonly ? (
164
+ <div
165
+ className={`prose prose-sm dark:prose-invert max-w-none ${error ? 'border-red-500' : ''}`}
166
+ // Sanitize before injecting: `value` may be rich-text HTML or legacy
167
+ // markdown stored in records, and must never execute scripts/handlers
168
+ // for readers (stored-XSS defense).
169
+ dangerouslySetInnerHTML={{ __html: toSafeHtml(value) }}
170
+ />
171
+ ) : (
172
+ <RichTextEditor
173
+ value={value || ''}
174
+ onChange={onChange}
175
+ placeholder={field.placeholder}
176
+ minHeight="200px"
177
+ />
178
+ )
179
+
163
180
  case 'textarea':
164
181
  return readonly ? (
165
182
  <div className={`text-slate-900 whitespace-pre-wrap ${error ? 'border-red-500' : ''}`}>
@@ -355,7 +372,6 @@ export function FieldRenderer({ field, value, onChange, readonly = false, error,
355
372
  try {
356
373
  onChange?.(JSON.parse(e.target.value))
357
374
  } catch {
358
- // Invalid JSON, don't update
359
375
  }
360
376
  }}
361
377
  className={`textarea font-mono text-sm ${error ? 'border-red-500' : ''}`}
@@ -476,3 +492,4 @@ export function FieldRenderer({ field, value, onChange, readonly = false, error,
476
492
  </div>
477
493
  )
478
494
  }
495
+ // CIL[END chunk_id="FieldRenderer_fieldrenderer_1783927912"]
@@ -1,36 +1,28 @@
1
- /**
2
- * @module src/components/shared/InviteManager
3
- * @audience installer
4
- * @layer frontend-component
5
- * @stability stable
6
- *
7
- * Reusable invite and access-request management UI.
8
- * Consumed by Cortex TeamPage, Portal TeamPage, and the Admin InvitesPage.
9
- *
10
- * Layout:
11
- * [ Name input ] [ Email input ] [ Role picker ] [ Generate Link button ]
12
- * ─────────────────────────────────────────────────────────────────────────
13
- * Searchable/sortable invite list table with status + actions
14
- *
15
- * @prop accountId - Scope invites to this account UUID.
16
- * Omit (system_admin only) to show all accounts.
17
- * @prop allowedRoles - Roles the admin may assign. First entry is the default.
18
- * If only one entry, no picker is shown.
19
- * @prop roleSlugsFilter - Comma-separated role slugs to pass to list-invites.
20
- * Limits which people appear in the list.
21
- * @prop scope - 'account' = scoped to one account | 'system' = all accounts
22
- *
23
- * @seeAlso functions/invites.ts (API)
24
- * @seeAlso pages/admin/InvitesPage.tsx
25
- * @seeAlso custom/apps/cortex/pages/team/TeamPage.tsx
26
- * @seeAlso custom/apps/portal/pages/team/TeamPage.tsx
27
- */
28
1
 
2
+
3
+
4
+
5
+
6
+
7
+
8
+ // CIL[BEGIN chunk_id="InviteManager_module_header_1783927912" type="module_header" identity="module_header" parent="none"]
9
+ // CIL[DOC-MACRO purpose="Import dependencies and define invite management component interfaces"]
10
+ // CIL[DOC-RESPONSIBILITY responsibility="Manage React imports and invite component prop types"]
11
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/src/components/ui/table-primitives.tsx\",\"\\\"]"]
12
+ // CIL[DOC-CONTRACT inputs="none" outputs="Imported modules and interfaces" errors="none" side_effects="none"]
13
+ // CIL[DOC-MICRO logic_summary="Imports React hooks and API, defines invite-related types and interfaces" notable_decisions="[]"]
14
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
15
+ // CIL[DOC-STABILITY stability="stable"]
16
+ // CIL[DOC-AUDIENCE audience="developer"]
17
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/components/ui/dialog.tsx, .framework/src/components/ui/table-primitives.tsx, \."]
18
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
19
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
20
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
21
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
22
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
29
23
  import React, { useState, useEffect, useCallback, useMemo } from 'react'
30
24
  import { apiFetch } from '../../lib/api'
31
25
 
32
- // ─── TYPES ────────────────────────────────────────────────────────────────────
33
-
34
26
  export type InviteScope = 'account' | 'system'
35
27
 
36
28
  export interface AllowedRole {
@@ -41,7 +33,7 @@ export interface AllowedRole {
41
33
  export interface InviteManagerProps {
42
34
  accountId?: string
43
35
  allowedRoles: AllowedRole[]
44
- roleSlugsFilter?: string // comma-separated, passed to list-invites
36
+ roleSlugsFilter?: string
45
37
  scope: InviteScope
46
38
  }
47
39
 
@@ -57,9 +49,21 @@ interface InviteRow {
57
49
  account: { id: string; slug: string; display_name: string } | null
58
50
  role: { id: string; slug: string; name: string } | null
59
51
  }
60
-
61
- // ─── HELPERS ──────────────────────────────────────────────────────────────────
62
-
52
+ // CIL[END chunk_id="InviteManager_module_header_1783927912"]
53
+ // CIL[BEGIN chunk_id="InviteManager_callinvitesapi_1783927912" type="function" identity="callInvitesApi" parent="none"]
54
+ // CIL[DOC-MACRO purpose="Make API calls to invites endpoint with proper method handling"]
55
+ // CIL[DOC-RESPONSIBILITY responsibility="Handle GET/POST requests to invites API functions"]
56
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/components/ui/table-primitives.tsx\",\"\\\"]"]
57
+ // CIL[DOC-CONTRACT inputs="none" outputs="API response JSON" errors="API errors" side_effects="Network requests"]
58
+ // CIL[DOC-MICRO logic_summary="Builds query strings for GET, sends JSON for POST to invites endpoint" notable_decisions="[]"]
59
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
60
+ // CIL[DOC-STABILITY stability="stable"]
61
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 1. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/RolesPage.tsx, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/components/ui/table-primitives.tsx, \."]
62
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
63
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
64
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
65
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
66
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
63
67
  async function callInvitesApi(action: string, params: Record<string, any> = {}, method: 'GET' | 'POST' = 'GET') {
64
68
  const base = '/.netlify/functions/invites'
65
69
  if (method === 'GET') {
@@ -74,7 +78,21 @@ async function callInvitesApi(action: string, params: Record<string, any> = {},
74
78
  })
75
79
  return res.json()
76
80
  }
77
-
81
+ // CIL[END chunk_id="InviteManager_callinvitesapi_1783927912"]
82
+ // CIL[BEGIN chunk_id="InviteManager_derivedisplaystatus_1783927912" type="function" identity="deriveDisplayStatus" parent="none"]
83
+ // CIL[DOC-MACRO purpose="Convert invite status to human-readable display text"]
84
+ // CIL[DOC-RESPONSIBILITY responsibility="Map internal status codes to user-friendly labels"]
85
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
86
+ // CIL[DOC-CONTRACT inputs="none" outputs="Display status string" errors="none" side_effects="none"]
87
+ // CIL[DOC-MICRO logic_summary="Handles special cases like expiration, blocking, and invite vs access request" notable_decisions="[]"]
88
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
89
+ // CIL[DOC-STABILITY stability="stable"]
90
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/schema-utils.ts, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
91
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
92
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
93
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
94
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
95
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
78
96
  function deriveDisplayStatus(row: InviteRow): string {
79
97
  if (row.blocked_at) return 'blocked'
80
98
  if (row.status === 'inactive') return 'revoked'
@@ -87,7 +105,21 @@ function deriveDisplayStatus(row: InviteRow): string {
87
105
  }
88
106
  return row.status
89
107
  }
90
-
108
+ // CIL[END chunk_id="InviteManager_derivedisplaystatus_1783927912"]
109
+ // CIL[BEGIN chunk_id="InviteManager_statusclasses_1783927912" type="constant" identity="STATUS_CLASSES" parent="none"]
110
+ // CIL[DOC-MACRO purpose="Define CSS classes for different invite status colors"]
111
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide styling mappings for status badge components"]
112
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
113
+ // CIL[DOC-CONTRACT inputs="none" outputs="CSS class mapping object" errors="none" side_effects="none"]
114
+ // CIL[DOC-MICRO logic_summary="Maps status strings to Tailwind color classes for consistent styling" notable_decisions="[]"]
115
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
116
+ // CIL[DOC-STABILITY stability="stable"]
117
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
118
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
119
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
120
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
121
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
122
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
91
123
  const STATUS_CLASSES: Record<string, string> = {
92
124
  pending: 'bg-yellow-100 text-yellow-800',
93
125
  'pending approval': 'bg-blue-100 text-blue-800',
@@ -97,7 +129,21 @@ const STATUS_CLASSES: Record<string, string> = {
97
129
  blocked: 'bg-red-100 text-red-800',
98
130
  revoked: 'bg-slate-100 text-slate-500',
99
131
  }
100
-
132
+ // CIL[END chunk_id="InviteManager_statusclasses_1783927912"]
133
+ // CIL[BEGIN chunk_id="InviteManager_timeuntil_1783927912" type="function" identity="timeUntil" parent="none"]
134
+ // CIL[DOC-MACRO purpose="Calculate human-readable time until expiration from ISO date"]
135
+ // CIL[DOC-RESPONSIBILITY responsibility="Format time remaining as days or hours until expiry"]
136
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
137
+ // CIL[DOC-CONTRACT inputs="none" outputs="Time remaining string" errors="none" side_effects="none"]
138
+ // CIL[DOC-MICRO logic_summary="Computes time difference, returns days/hours or 'expired' if past" notable_decisions="[]"]
139
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
140
+ // CIL[DOC-STABILITY stability="stable"]
141
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 1. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, \."]
142
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
143
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
144
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
145
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
146
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
101
147
  function timeUntil(iso: string | null): string {
102
148
  if (!iso) return '—'
103
149
  const diff = new Date(iso).getTime() - Date.now()
@@ -107,9 +153,21 @@ function timeUntil(iso: string | null): string {
107
153
  if (days > 0) return `${days}d`
108
154
  return `${hours}h`
109
155
  }
110
-
111
- // ─── COMPONENT ────────────────────────────────────────────────────────────────
112
-
156
+ // CIL[END chunk_id="InviteManager_timeuntil_1783927912"]
157
+ // CIL[BEGIN chunk_id="InviteManager_invitemanager_1783927912" type="function" identity="InviteManager" parent="none"]
158
+ // CIL[DOC-MACRO purpose="Manage invite creation, listing, and actions with searchable table UI"]
159
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide complete invite management interface with form and table"]
160
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[]"]
161
+ // CIL[DOC-CONTRACT inputs="none" outputs="Invite management UI" errors="API errors" side_effects="Renders UI, API calls"]
162
+ // CIL[DOC-MICRO logic_summary="Handles invite generation, listing, searching, sorting, and bulk actions" notable_decisions="[]"]
163
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
164
+ // CIL[DOC-STABILITY stability="stable"]
165
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 0. Direct calls: 0. Related files: none."]
166
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
167
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
168
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
169
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
170
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
113
171
  export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope }: InviteManagerProps) {
114
172
  const [invites, setInvites] = useState<InviteRow[]>([])
115
173
  const [loading, setLoading] = useState(true)
@@ -122,19 +180,15 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
122
180
  const [generateError, setGenerateError] = useState('')
123
181
  const [copiedId, setCopiedId] = useState<string | null>(null)
124
182
 
125
- // Search / sort state
126
183
  const [search, setSearch] = useState('')
127
184
  const [sortKey, setSortKey] = useState<'full_name' | 'email' | 'status' | 'created_at'>('created_at')
128
185
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc')
129
-
130
- // Keep selectedRoleSlug in sync if allowedRoles changes
131
186
  useEffect(() => {
132
187
  if (!allowedRoles.find(r => r.slug === selectedRoleSlug)) {
133
188
  setSelectedRoleSlug(allowedRoles[0]?.slug ?? '')
134
189
  }
135
190
  }, [allowedRoles, selectedRoleSlug])
136
191
 
137
- // ── Load invites ──────────────────────────────────────────────────────────
138
192
  const loadInvites = useCallback(async () => {
139
193
  setLoading(true)
140
194
  setError('')
@@ -153,7 +207,6 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
153
207
 
154
208
  useEffect(() => { loadInvites() }, [loadInvites])
155
209
 
156
- // ── Filtered + sorted list ─────────────────────────────────────────────────
157
210
  const filteredInvites = useMemo(() => {
158
211
  const q = search.toLowerCase()
159
212
  const filtered = q
@@ -185,7 +238,6 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
185
238
  }
186
239
  }
187
240
 
188
- // ── Generate invite ────────────────────────────────────────────────────────
189
241
  const handleGenerate = async (e: React.FormEvent) => {
190
242
  e.preventDefault()
191
243
  if (!newEmail.trim() || !accountId) return
@@ -208,7 +260,6 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
208
260
  return
209
261
  }
210
262
 
211
- // Copy URL to clipboard automatically
212
263
  if (result.data?.invite_url) {
213
264
  navigator.clipboard.writeText(result.data.invite_url).catch(() => {})
214
265
  }
@@ -218,7 +269,6 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
218
269
  await loadInvites()
219
270
  }
220
271
 
221
- // ── Reinvite (issues new token, copies URL) ────────────────────────────────
222
272
  const handleReinvite = async (personId: string) => {
223
273
  const result = await callInvitesApi('reinvite', {
224
274
  person_id: personId,
@@ -236,7 +286,6 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
236
286
  }
237
287
  }
238
288
 
239
- // ── Generic action (revoke, approve, deny, block) ─────────────────────────
240
289
  const handleAction = async (action: string, personId: string) => {
241
290
  const result = await callInvitesApi(action, { person_id: personId }, 'POST')
242
291
  if (result.error) {
@@ -246,7 +295,6 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
246
295
  }
247
296
  }
248
297
 
249
- // ── Render ─────────────────────────────────────────────────────────────────
250
298
  const canGenerate = !!accountId || scope === 'system'
251
299
  const showRolePicker = allowedRoles.length > 1
252
300
 
@@ -508,9 +556,21 @@ export function InviteManager({ accountId, allowedRoles, roleSlugsFilter, scope
508
556
  </div>
509
557
  )
510
558
  }
511
-
512
- // ─── SORT HEADER ──────────────────────────────────────────────────────────────
513
-
559
+ // CIL[END chunk_id="InviteManager_invitemanager_1783927912"]
560
+ // CIL[BEGIN chunk_id="InviteManager_sortth_1783927912" type="function" identity="SortTh" parent="none"]
561
+ // CIL[DOC-MACRO purpose="Render sortable table header with sort direction indicator"]
562
+ // CIL[DOC-RESPONSIBILITY responsibility="Create clickable table header with visual sort state"]
563
+ // CIL[DOC-CONTEXT module="invite-manager" layer="frontend-component" related_files="[]"]
564
+ // CIL[DOC-CONTRACT inputs="none" outputs="Table header element" errors="none" side_effects="Renders UI, calls onSort"]
565
+ // CIL[DOC-MICRO logic_summary="Shows sort arrows and handles click events for column sorting" notable_decisions="[]"]
566
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
567
+ // CIL[DOC-STABILITY stability="stable"]
568
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-component. Direct callers: 0. Direct calls: 0. Related files: none."]
569
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
570
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
571
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
572
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
573
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
514
574
  function SortTh({
515
575
  label, col, current, dir, onSort
516
576
  }: {
@@ -531,3 +591,4 @@ function SortTh({
531
591
  </th>
532
592
  )
533
593
  }
594
+ // CIL[END chunk_id="InviteManager_sortth_1783927912"]