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.
- package/.framework/cli/commands/agents.ts +35 -37
- package/.framework/cli/commands/auth.ts +35 -34
- package/.framework/cli/commands/create-app.ts +104 -40
- package/.framework/cli/commands/dev.ts +104 -69
- package/.framework/cli/commands/doctor.ts +179 -69
- package/.framework/cli/commands/generate.ts +83 -143
- package/.framework/cli/commands/init.ts +72 -34
- package/.framework/cli/commands/install-app.ts +260 -125
- package/.framework/cli/commands/items.ts +33 -44
- package/.framework/cli/commands/migrate.ts +122 -40
- package/.framework/cli/commands/migrations.ts +33 -40
- package/.framework/cli/commands/pipelines.ts +31 -39
- package/.framework/cli/commands/status.ts +47 -23
- package/.framework/cli/commands/system.ts +47 -37
- package/.framework/cli/commands/test.ts +112 -68
- package/.framework/cli/commands/validate-app.ts +215 -121
- package/.framework/cli/context.ts +112 -130
- package/.framework/cli/env-loader.ts +47 -18
- package/.framework/cli/index.ts +81 -42
- package/.framework/docs/runtime-types.md +1024 -0
- package/.framework/functions/_shared/agent-runner.ts +1296 -961
- package/.framework/functions/_shared/app-manifest.ts +82 -68
- package/.framework/functions/_shared/audit.ts +135 -83
- package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +224 -335
- package/.framework/functions/_shared/kb.ts +319 -0
- package/.framework/functions/_shared/llm.ts +92 -0
- package/.framework/functions/_shared/logging.ts +288 -0
- package/.framework/functions/_shared/middleware.ts +329 -365
- package/.framework/functions/_shared/outcomes.ts +36 -0
- package/.framework/functions/_shared/permissions.ts +359 -643
- package/.framework/functions/_shared/pipeline-runner.ts +243 -316
- package/.framework/functions/_shared/principal.ts +376 -468
- package/.framework/functions/_shared/resolve-credentials.ts +102 -0
- package/.framework/functions/_shared/resolve-ids.ts +188 -16
- package/.framework/functions/_shared/retry-deliveries.ts +104 -0
- package/.framework/functions/_shared/schema-utils.ts +611 -373
- package/.framework/functions/_shared/testing.ts +207 -137
- package/.framework/functions/_shared/tracing.ts +276 -0
- package/.framework/functions/_shared/trigger-engine.ts +159 -211
- package/.framework/functions/_shared/webhook-registration.ts +95 -81
- package/.framework/functions/_shared/webhook-registry.ts +153 -75
- package/.framework/functions/account-nodes.ts +31 -53
- package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
- package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
- package/.framework/functions/adapters/openai-outbound.ts +40 -0
- package/.framework/functions/admin-data.ts +685 -537
- package/.framework/functions/admin-funnel.ts +31 -20
- package/.framework/functions/admin-install-funnel.ts +47 -28
- package/.framework/functions/admin-signals.ts +47 -29
- package/.framework/functions/ai-agents.ts +122 -147
- package/.framework/functions/ai-interactions.ts +180 -90
- package/.framework/functions/api-keys.ts +250 -192
- package/.framework/functions/apps.ts +203 -197
- package/.framework/functions/auth.ts +98 -91
- package/.framework/functions/cil-agent-ingest.ts +773 -0
- package/.framework/functions/cil-agent.ts +592 -0
- package/.framework/functions/cil-callmap.ts +1227 -0
- package/.framework/functions/cil-config.ts +583 -0
- package/.framework/functions/cil-context.ts +445 -0
- package/.framework/functions/cil-doc.ts +1752 -0
- package/.framework/functions/cil-embeddings.ts +1202 -0
- package/.framework/functions/cil-graph.ts +585 -0
- package/.framework/functions/cil-ingest.ts +2416 -0
- package/.framework/functions/cil-pipeline.ts +318 -0
- package/.framework/functions/cil-project.ts +499 -0
- package/.framework/functions/cil-validate.ts +469 -0
- package/.framework/functions/debug-auth.ts +73 -53
- package/.framework/functions/deliveries.ts +117 -0
- package/.framework/functions/embeddings.ts +528 -516
- package/.framework/functions/eval-harness.ts +158 -106
- package/.framework/functions/integration-outbound.ts +311 -0
- package/.framework/functions/integration-routes.ts +240 -466
- package/.framework/functions/integrations.ts +132 -140
- package/.framework/functions/invites.ts +401 -201
- package/.framework/functions/item-progress.ts +113 -53
- package/.framework/functions/kb.ts +28 -0
- package/.framework/functions/logs.ts +239 -222
- package/.framework/functions/observability.ts +308 -259
- package/.framework/functions/pipeline-executions.ts +179 -235
- package/.framework/functions/pipelines.ts +163 -205
- package/.framework/functions/prompt-configs.ts +109 -156
- package/.framework/functions/roles.ts +97 -147
- package/.framework/functions/system-cron.ts +132 -218
- package/.framework/functions/system.ts +112 -52
- package/.framework/functions/tests.ts +32 -28
- package/.framework/functions/timers.ts +162 -210
- package/.framework/functions/triggers.ts +282 -346
- package/.framework/functions/types.ts +283 -400
- package/.framework/migrations/001_core_schema.sql +630 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
- package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
- package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
- package/.framework/migrations/005_core_observability.sql +598 -0
- package/.framework/migrations/006_security_hardening_rls.sql +97 -0
- package/.framework/migrations/007_kb_article_list.sql +237 -0
- package/.framework/migrations/008_items_target.sql +8 -0
- package/.framework/migrations/009_roles_slug_unique.sql +11 -0
- package/.framework/public/spine.config.json +91 -0
- package/.framework/scripts/app-install-cli.ts +112 -98
- package/.framework/src/App.tsx +67 -20
- package/.framework/src/apps/admin/index.tsx +97 -27
- package/.framework/src/components/AppWrapper.tsx +50 -11
- package/.framework/src/components/CustomAppLoader.tsx +131 -22
- package/.framework/src/components/admin/AdminListPage.tsx +75 -8
- package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
- package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
- package/.framework/src/components/admin/PageInstructions.tsx +49 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
- package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
- package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
- package/.framework/src/components/app-sidebar.tsx +50 -3
- package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
- package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
- package/.framework/src/components/kb/KBArticleList.tsx +557 -0
- package/.framework/src/components/layout/AppShell.tsx +54 -16
- package/.framework/src/components/layout/Header.tsx +50 -38
- package/.framework/src/components/layout/Layout.tsx +48 -32
- package/.framework/src/components/layout/Sidebar.tsx +167 -16
- package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
- package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
- package/.framework/src/components/runtime/DataFilters.tsx +78 -1
- package/.framework/src/components/runtime/DataHeader.tsx +32 -29
- package/.framework/src/components/runtime/DataListPage.tsx +161 -2
- package/.framework/src/components/runtime/DataStats.tsx +48 -1
- package/.framework/src/components/runtime/DataTable.tsx +153 -1
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
- package/.framework/src/components/runtime/index.ts +16 -9
- package/.framework/src/components/search-form.tsx +33 -1
- package/.framework/src/components/shared/AgentView.tsx +48 -51
- package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
- package/.framework/src/components/shared/InviteManager.tsx +113 -52
- package/.framework/src/components/shared/MemberList.tsx +182 -0
- package/.framework/src/components/shared/SchemaFields.tsx +96 -78
- package/.framework/src/components/ui/DataTable.tsx +86 -56
- package/.framework/src/components/ui/Form.tsx +188 -109
- package/.framework/src/components/ui/ItemCard.tsx +86 -58
- package/.framework/src/components/ui/ItemListView.tsx +88 -61
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
- package/.framework/src/components/ui/Modal.tsx +81 -4
- package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
- package/.framework/src/components/ui/accordion.tsx +97 -5
- package/.framework/src/components/ui/alert-dialog.tsx +225 -13
- package/.framework/src/components/ui/alert.tsx +113 -6
- package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
- package/.framework/src/components/ui/avatar.tsx +129 -7
- package/.framework/src/components/ui/badge.tsx +65 -3
- package/.framework/src/components/ui/breadcrumb.tsx +145 -8
- package/.framework/src/components/ui/button-group.tsx +81 -4
- package/.framework/src/components/ui/button.tsx +49 -2
- package/.framework/src/components/ui/calendar.tsx +65 -3
- package/.framework/src/components/ui/card.tsx +145 -8
- package/.framework/src/components/ui/carousel.tsx +129 -7
- package/.framework/src/components/ui/chart.tsx +161 -10
- package/.framework/src/components/ui/checkbox.tsx +49 -2
- package/.framework/src/components/ui/collapsible.tsx +81 -5
- package/.framework/src/components/ui/combobox.tsx +305 -20
- package/.framework/src/components/ui/command.tsx +177 -11
- package/.framework/src/components/ui/context-menu.tsx +273 -17
- package/.framework/src/components/ui/dialog.tsx +209 -27
- package/.framework/src/components/ui/direction.tsx +64 -4
- package/.framework/src/components/ui/drawer.tsx +193 -12
- package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
- package/.framework/src/components/ui/empty.tsx +145 -9
- package/.framework/src/components/ui/field.tsx +209 -14
- package/.framework/src/components/ui/hover-card.tsx +81 -4
- package/.framework/src/components/ui/input-group.tsx +162 -10
- package/.framework/src/components/ui/input-otp.tsx +98 -5
- package/.framework/src/components/ui/input.tsx +49 -2
- package/.framework/src/components/ui/item.tsx +225 -13
- package/.framework/src/components/ui/kbd.tsx +65 -3
- package/.framework/src/components/ui/label.tsx +49 -2
- package/.framework/src/components/ui/menubar.tsx +289 -17
- package/.framework/src/components/ui/native-select.tsx +97 -5
- package/.framework/src/components/ui/navigation-menu.tsx +177 -10
- package/.framework/src/components/ui/pagination.tsx +161 -9
- package/.framework/src/components/ui/popover.tsx +145 -8
- package/.framework/src/components/ui/progress.tsx +49 -2
- package/.framework/src/components/ui/radio-group.tsx +65 -3
- package/.framework/src/components/ui/resizable.tsx +82 -4
- package/.framework/src/components/ui/scroll-area.tsx +65 -3
- package/.framework/src/components/ui/select.tsx +193 -11
- package/.framework/src/components/ui/separator.tsx +49 -2
- package/.framework/src/components/ui/sheet.tsx +193 -11
- package/.framework/src/components/ui/sidebar.tsx +481 -38
- package/.framework/src/components/ui/skeleton.tsx +49 -2
- package/.framework/src/components/ui/slider.tsx +49 -2
- package/.framework/src/components/ui/sonner.tsx +49 -2
- package/.framework/src/components/ui/spinner.tsx +49 -2
- package/.framework/src/components/ui/switch.tsx +49 -2
- package/.framework/src/components/ui/table-primitives.tsx +160 -33
- package/.framework/src/components/ui/table.tsx +161 -9
- package/.framework/src/components/ui/tabs.tsx +113 -6
- package/.framework/src/components/ui/textarea.tsx +49 -2
- package/.framework/src/components/ui/toggle-group.tsx +81 -4
- package/.framework/src/components/ui/toggle.tsx +65 -3
- package/.framework/src/components/ui/tooltip.tsx +97 -5
- package/.framework/src/contexts/AppContext.tsx +129 -45
- package/.framework/src/contexts/AuthContext.tsx +187 -144
- package/.framework/src/hooks/use-mobile.ts +48 -2
- package/.framework/src/hooks/useApi.ts +208 -159
- package/.framework/src/hooks/useAppPath.ts +32 -23
- package/.framework/src/hooks/useApps.ts +51 -20
- package/.framework/src/hooks/useEntityList.ts +32 -78
- package/.framework/src/hooks/useEntityRecord.ts +35 -96
- package/.framework/src/hooks/useForm.ts +32 -92
- package/.framework/src/hooks/useListSchema.ts +49 -78
- package/.framework/src/hooks/useSchemaRecord.ts +114 -105
- package/.framework/src/lib/api.ts +195 -116
- package/.framework/src/lib/supabase.ts +98 -64
- package/.framework/src/lib/utils.ts +287 -151
- package/.framework/src/main.tsx +49 -3
- package/.framework/src/pages/DashboardPage.tsx +52 -29
- package/.framework/src/pages/NotFoundPage.tsx +32 -10
- package/.framework/src/pages/SetupPage.tsx +32 -12
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
- package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
- package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
- package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
- package/.framework/src/pages/admin/AppsPage.tsx +49 -2
- package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
- package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
- package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
- package/.framework/src/pages/admin/LogsPage.tsx +422 -75
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
- package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
- package/.framework/src/pages/admin/RolesPage.tsx +171 -18
- package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
- package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
- package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
- package/.framework/src/pages/admin/TimersPage.tsx +48 -20
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
- package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
- package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
- package/.framework/src/pages/admin/TypesPage.tsx +48 -20
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
- package/.framework/src/pages/auth/LoginPage.tsx +50 -23
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
- package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
- package/.framework/src/types/auth.ts +128 -71
- package/.framework/src/types/types.ts +373 -157
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
- package/docs/README.md +9 -130
- package/netlify.toml +5 -2
- package/package.json +13 -25
- package/scripts/kb-ingest-docs.ts +203 -0
- package/spine.config.json +65 -4
- package/.framework/migrations/001_schema.sql +0 -425
- package/.framework/migrations/002_rls_and_functions.sql +0 -763
- package/.framework/migrations/004_enhancements.sql +0 -43
- package/.framework/migrations/005_auth_user_trigger.sql +0 -105
- package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
- package/.framework/migrations/016_invites.sql +0 -27
- package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
- package/.framework/migrations/018_apps_required_roles.sql +0 -17
- package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
- package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
- package/.framework/migrations/021_app_domains.sql +0 -112
- package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
- package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
- package/.framework/migrations/024_messages_account_id.sql +0 -9
- package/.framework/migrations/025_retype_threads_messages.sql +0 -240
- package/.framework/migrations/026_fix_rls_policies.sql +0 -47
- package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
- package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
- package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
- package/.framework/migrations/030_messages_updated_by.sql +0 -6
- package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
- package/docs/APPS.md +0 -232
- package/docs/ARCHITECTURE.md +0 -246
- package/docs/INSTALL.md +0 -155
- package/docs/design-schema-spec.md +0 -1837
- package/docs/dev-guides/01-create-an-app.md +0 -183
- package/docs/dev-guides/02-create-a-function.md +0 -178
- package/docs/dev-guides/03-create-a-component.md +0 -178
- package/docs/dev-guides/04-webhook-handlers.md +0 -129
- package/docs/dev-guides/05-testing.md +0 -168
- package/docs/dev-guides/README.md +0 -40
- package/docs/npm-packages-plan.md +0 -288
- package/docs/spine-core--api-reference.md +0 -822
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// CIL[BEGIN chunk_id="useapps_module_header_1783719596" type="module_header" identity="module_header" parent="none"]
|
|
5
|
+
// CIL[DOC-MACRO purpose="Define types and interfaces for app management"]
|
|
6
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Type definitions for AppRecord and UseAppsResult"]
|
|
7
|
+
// CIL[DOC-CONTEXT module="useApps" layer="frontend-hook" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
|
|
8
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Type definitions" errors="none" side_effects="Type declarations"]
|
|
9
|
+
// CIL[DOC-MICRO logic_summary="Exports AppRecord interface with app metadata and UseAppsResult 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-hook. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/migrations/015_simplify_apps_table.sql, .framework/functions/_shared/principal.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"]
|
|
1
19
|
import { useState, useEffect } from 'react'
|
|
2
20
|
import { apiFetch } from '../lib/api'
|
|
3
21
|
import { useAuth } from '../contexts/AuthContext'
|
|
@@ -14,8 +32,8 @@ export interface AppRecord {
|
|
|
14
32
|
source: string
|
|
15
33
|
config: Record<string, any>
|
|
16
34
|
nav_items: any[]
|
|
17
|
-
min_role?: string
|
|
18
|
-
required_roles?: string[]
|
|
35
|
+
min_role?: string
|
|
36
|
+
required_roles?: string[]
|
|
19
37
|
is_active: boolean
|
|
20
38
|
is_system: boolean
|
|
21
39
|
route_prefix: string | null
|
|
@@ -30,12 +48,21 @@ interface UseAppsResult {
|
|
|
30
48
|
error: string | null
|
|
31
49
|
refetch: () => void
|
|
32
50
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
// CIL[END chunk_id="useapps_module_header_1783719596"]
|
|
52
|
+
// CIL[BEGIN chunk_id="useapps_useapps_1783719596" type="function" identity="useApps" parent="none"]
|
|
53
|
+
// CIL[DOC-MACRO purpose="Fetch and filter apps based on user roles and domain"]
|
|
54
|
+
// CIL[DOC-RESPONSIBILITY responsibility="App fetching, role-based filtering, domain matching"]
|
|
55
|
+
// CIL[DOC-CONTEXT module="useApps" layer="frontend-hook" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
|
|
56
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="UseAppsResult with apps, loading, error, refetch" errors="Network errors, auth errors" side_effects="React state updates, API calls"]
|
|
57
|
+
// CIL[DOC-MICRO logic_summary="Fetches apps, filters by active status, domain, and user roles with system_admin override" notable_decisions="[]"]
|
|
58
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
59
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
60
|
+
// CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 1. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, .framework/migrations/015_simplify_apps_table.sql, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
|
|
61
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
|
|
62
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
63
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
64
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
65
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
39
66
|
export function useApps(): UseAppsResult {
|
|
40
67
|
const { user } = useAuth()
|
|
41
68
|
const [apps, setApps] = useState<AppRecord[]>([])
|
|
@@ -73,30 +100,22 @@ export function useApps(): UseAppsResult {
|
|
|
73
100
|
const appMatchesDomain = (app: AppRecord): boolean => {
|
|
74
101
|
const domain = environment === 'preview' ? app.preview_domain : app.prod_domain
|
|
75
102
|
if (!domain) return true
|
|
76
|
-
// Accept both "hostname.com" and "https://hostname.com" formats
|
|
77
103
|
const hostname = domain.includes('://') ? new URL(domain).hostname : domain.split(':')[0]
|
|
78
104
|
return currentHost === hostname
|
|
79
105
|
}
|
|
80
106
|
|
|
81
|
-
// Filter by user's roles: include app if user has any of the required_roles,
|
|
82
|
-
// or if app has no role restrictions
|
|
83
107
|
const accessible = allApps.filter(app => {
|
|
84
108
|
if (!app.is_active) return false
|
|
85
109
|
if (!appMatchesDomain(app)) return false
|
|
86
110
|
|
|
87
|
-
// Support both new required_roles array and legacy min_role
|
|
88
111
|
const requiredRoles = app.required_roles || (app.min_role ? [app.min_role] : [])
|
|
89
112
|
|
|
90
|
-
// No role restriction = accessible to all
|
|
91
113
|
if (requiredRoles.length === 0) return true
|
|
92
114
|
|
|
93
|
-
// User has no roles = no access (unless no restriction)
|
|
94
115
|
if (!user.roles || user.roles.length === 0) return false
|
|
95
116
|
|
|
96
|
-
// system_admin can access everything
|
|
97
117
|
if (user.roles.includes('system_admin')) return true
|
|
98
118
|
|
|
99
|
-
// Check if user has any of the required roles
|
|
100
119
|
return requiredRoles.some(role => user.roles!.includes(role))
|
|
101
120
|
})
|
|
102
121
|
|
|
@@ -115,10 +134,21 @@ export function useApps(): UseAppsResult {
|
|
|
115
134
|
|
|
116
135
|
return { apps, loading, error, refetch: fetchApps }
|
|
117
136
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
137
|
+
// CIL[END chunk_id="useapps_useapps_1783719596"]
|
|
138
|
+
// CIL[BEGIN chunk_id="useapps_useroutableapps_1783719596" type="function" identity="useRoutableApps" parent="none"]
|
|
139
|
+
// CIL[DOC-MACRO purpose="Filter apps to only those with routing capabilities"]
|
|
140
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Route filtering for navigation-ready apps"]
|
|
141
|
+
// CIL[DOC-CONTEXT module="useApps" layer="frontend-hook" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\"\\\"]"]
|
|
142
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="UseAppsResult filtered to routable apps" errors="none" side_effects="React state updates via useApps hook"]
|
|
143
|
+
// CIL[DOC-MICRO logic_summary="Wraps useApps and filters results to apps with route_prefix and not 'none' renderer" notable_decisions="[]"]
|
|
144
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
145
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
146
|
+
// CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/migrations/015_simplify_apps_table.sql, \."]
|
|
147
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
148
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
149
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
150
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
151
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
122
152
|
export function useRoutableApps() {
|
|
123
153
|
const result = useApps()
|
|
124
154
|
return {
|
|
@@ -126,3 +156,4 @@ export function useRoutableApps() {
|
|
|
126
156
|
apps: result.apps.filter(app => app.route_prefix != null && app.renderer !== 'none')
|
|
127
157
|
}
|
|
128
158
|
}
|
|
159
|
+
// CIL[END chunk_id="useapps_useroutableapps_1783719596"]
|
|
@@ -1,43 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module src/hooks/useEntityList
|
|
3
|
-
* @audience installer
|
|
4
|
-
* @layer frontend-hook
|
|
5
|
-
* @stability stable
|
|
6
|
-
*
|
|
7
|
-
* Schema-driven list data hook. Given an entity name and a minimal
|
|
8
|
-
* `MinimalEntityListConfig`, fetches a paginated, filtered, and sorted list
|
|
9
|
-
* from the API and exposes controls for filters, sort, and pagination.
|
|
10
|
-
*
|
|
11
|
-
* **How it works:**
|
|
12
|
-
* 1. Builds query params from `entity`, `config.api`, filters, sort, and pagination
|
|
13
|
-
* 2. Calls `apiFetch('/api/<endpoint>?action=list&...')` via `useApi`
|
|
14
|
-
* 3. Re-fetches when `config` arrives (async schema load), or when filters change
|
|
15
|
-
* (which also resets page to 1)
|
|
16
|
-
*
|
|
17
|
-
* **Auth retry:** `useApi` re-executes on route navigation, which naturally
|
|
18
|
-
* retries after the auth session hydrates on the next tick.
|
|
19
|
-
*
|
|
20
|
-
* @seeAlso src/hooks/useApi.ts (useApi — underlying fetch + abort primitive)
|
|
21
|
-
* @seeAlso src/lib/api.ts (apiFetch)
|
|
22
|
-
* @seeAlso src/components/runtime/DataListPage.tsx (primary consumer)
|
|
23
|
-
* @seeAlso functions/admin-data.ts (API endpoint for list action)
|
|
24
|
-
*/
|
|
25
1
|
|
|
2
|
+
|
|
3
|
+
// CIL[BEGIN chunk_id="useentitylist_module_header_1783719596" type="module_header" identity="module_header" parent="none"]
|
|
4
|
+
// CIL[DOC-MACRO purpose="Define entity list hook types and interfaces"]
|
|
5
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Type definitions for entity list management"]
|
|
6
|
+
// CIL[DOC-CONTEXT module="useEntityList" layer="frontend-hook" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
7
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="MinimalEntityListConfig and UseEntityListReturn interfaces" errors="none" side_effects="Type declarations"]
|
|
8
|
+
// CIL[DOC-MICRO logic_summary="Exports interfaces for list configuration, return values, and pagination controls" notable_decisions="[]"]
|
|
9
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
10
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
11
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
12
|
+
// CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, \."]
|
|
13
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
14
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
15
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
16
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
17
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
26
18
|
import { useState, useEffect, useCallback } from 'react'
|
|
27
19
|
import { useApi } from './useApi'
|
|
28
20
|
import { apiFetch } from '../lib/api'
|
|
29
21
|
|
|
30
|
-
// ─── TYPES ───────────────────────────────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Minimal configuration shape consumed by `useEntityList`.
|
|
34
|
-
*
|
|
35
|
-
* @prop entity - Entity name (used as fallback endpoint, filter param)
|
|
36
|
-
* @prop typeSlug - Optional type slug; appended as `type_slug` param if present
|
|
37
|
-
* @prop api.endpoint - Netlify function base path (e.g. `'admin-data'`)
|
|
38
|
-
* @prop api.listAction - Action string; defaults to `'list'`
|
|
39
|
-
* @prop list.defaultSort - Initial sort field and direction
|
|
40
|
-
*/
|
|
41
22
|
interface MinimalEntityListConfig {
|
|
42
23
|
entity: string
|
|
43
24
|
typeSlug?: string
|
|
@@ -50,19 +31,6 @@ interface MinimalEntityListConfig {
|
|
|
50
31
|
}
|
|
51
32
|
}
|
|
52
33
|
|
|
53
|
-
/**
|
|
54
|
-
* Return value of `useEntityList`.
|
|
55
|
-
*
|
|
56
|
-
* @prop data - Fetched records array (empty while loading or on error)
|
|
57
|
-
* @prop loading - True while fetching
|
|
58
|
-
* @prop error - Error message or null
|
|
59
|
-
* @prop refetch - Re-execute the current query
|
|
60
|
-
* @prop filters - Active filter values keyed by param name
|
|
61
|
-
* @prop setFilters - Replace the active filters (resets page to 1)
|
|
62
|
-
* @prop sort - Current sort field and direction
|
|
63
|
-
* @prop setSort - Update sort (does not auto-reset page)
|
|
64
|
-
* @prop pagination - page/setPage/pageSize/setPageSize/total controls
|
|
65
|
-
*/
|
|
66
34
|
interface UseEntityListReturn {
|
|
67
35
|
data: any[]
|
|
68
36
|
loading: boolean
|
|
@@ -80,28 +48,21 @@ interface UseEntityListReturn {
|
|
|
80
48
|
total: number
|
|
81
49
|
}
|
|
82
50
|
}
|
|
83
|
-
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
* @calledBy DataListPage.tsx
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```tsx
|
|
102
|
-
* const { data, loading, setFilters } = useEntityList('accounts', config)
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
51
|
+
// CIL[END chunk_id="useentitylist_module_header_1783719596"]
|
|
52
|
+
// CIL[BEGIN chunk_id="useentitylist_useentitylist_1783719596" type="function" identity="useEntityList" parent="none"]
|
|
53
|
+
// CIL[DOC-MACRO purpose="Fetch and manage paginated, filtered, sorted entity lists"]
|
|
54
|
+
// CIL[DOC-RESPONSIBILITY responsibility="List fetching, pagination, filtering, sorting, state management"]
|
|
55
|
+
// CIL[DOC-CONTEXT module="useEntityList" layer="frontend-hook" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
|
|
56
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="UseEntityListReturn with data, controls, pagination" errors="Network errors, API errors" side_effects="React state updates, API calls via apiFetch"]
|
|
57
|
+
// CIL[DOC-MICRO logic_summary="Builds query params from config, filters, sort, pagination; fetches via useApi; manages state" notable_decisions="[]"]
|
|
58
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
59
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
60
|
+
// CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 3. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/components/ui/dialog.tsx, .framework/src/pages/admin/RolesPage.tsx, \."]
|
|
61
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 3. Total affected: 3."]
|
|
62
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
63
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
64
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
65
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
105
66
|
export function useEntityList(
|
|
106
67
|
entity: string,
|
|
107
68
|
config: MinimalEntityListConfig | null
|
|
@@ -116,33 +77,27 @@ export function useEntityList(
|
|
|
116
77
|
|
|
117
78
|
const params = new URLSearchParams()
|
|
118
79
|
|
|
119
|
-
// Support new endpoint-based API pattern
|
|
120
80
|
const endpoint = config.api.endpoint || entity
|
|
121
81
|
const action = config.api.listAction || 'list'
|
|
122
82
|
params.append('action', action)
|
|
123
83
|
|
|
124
|
-
// Add entity parameter for unified admin-data endpoint
|
|
125
84
|
if (config.api.endpoint) {
|
|
126
85
|
params.append('entity', entity)
|
|
127
86
|
}
|
|
128
87
|
|
|
129
|
-
// Add type_slug for schema-driven filtering if available
|
|
130
88
|
if (config.typeSlug) {
|
|
131
89
|
params.append('type_slug', config.typeSlug)
|
|
132
90
|
}
|
|
133
91
|
|
|
134
|
-
// Add filters
|
|
135
92
|
Object.entries(filters).forEach(([key, value]) => {
|
|
136
93
|
if (value !== undefined && value !== '' && value !== 'all') {
|
|
137
94
|
params.append(key, value.toString())
|
|
138
95
|
}
|
|
139
96
|
})
|
|
140
97
|
|
|
141
|
-
// Add sort
|
|
142
98
|
params.append('sort_field', sort.field)
|
|
143
99
|
params.append('sort_direction', sort.direction)
|
|
144
100
|
|
|
145
|
-
// Add pagination
|
|
146
101
|
params.append('limit', pageSize.toString())
|
|
147
102
|
params.append('offset', ((page - 1) * pageSize).toString())
|
|
148
103
|
|
|
@@ -160,12 +115,10 @@ export function useEntityList(
|
|
|
160
115
|
immediate: true
|
|
161
116
|
})
|
|
162
117
|
|
|
163
|
-
// Re-fetch when config arrives (schema was not ready on initial mount)
|
|
164
118
|
useEffect(() => {
|
|
165
119
|
if (config) execute()
|
|
166
120
|
}, [config?.api.endpoint, config?.api.listAction, config?.typeSlug])
|
|
167
121
|
|
|
168
|
-
// Reset page when filters change
|
|
169
122
|
useEffect(() => {
|
|
170
123
|
setPage(1)
|
|
171
124
|
}, [filters])
|
|
@@ -188,3 +141,4 @@ export function useEntityList(
|
|
|
188
141
|
}
|
|
189
142
|
}
|
|
190
143
|
}
|
|
144
|
+
// CIL[END chunk_id="useentitylist_useentitylist_1783719596"]
|
|
@@ -1,58 +1,29 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module src/hooks/useEntityRecord
|
|
3
|
-
* @audience installer
|
|
4
|
-
* @layer frontend-hook
|
|
5
|
-
* @stability stable
|
|
6
|
-
*
|
|
7
|
-
* Schema-driven single-record hook. Fetches a record by ID, exposes its
|
|
8
|
-
* design schema, computes field-level read/write permissions for the
|
|
9
|
-
* current principal, and provides save and delete mutations.
|
|
10
|
-
*
|
|
11
|
-
* **Field permission model:**
|
|
12
|
-
* - `system_admin` role always gets `{ read: true, write: true }` on all fields
|
|
13
|
-
* - Other principals: permissions are read from `design_schema.fields[n].permissions`
|
|
14
|
-
* as role arrays; defaults to `true` if absent
|
|
15
|
-
*
|
|
16
|
-
* **Save routing:**
|
|
17
|
-
* - Fields marked `fieldDef.system = true` go to top-level record columns
|
|
18
|
-
* - All other fields are nested under the `data` JSONB column
|
|
19
|
-
*
|
|
20
|
-
* **Delete:** sends a `DELETE` request with the configured `deleteAction`;
|
|
21
|
-
* hard vs. soft delete is determined by the API handler (`config.softDelete`
|
|
22
|
-
* signals intent to the handler).
|
|
23
|
-
*
|
|
24
|
-
* @seeAlso src/hooks/useApi.ts (useApi + useMutation primitives)
|
|
25
|
-
* @seeAlso src/hooks/useSchemaRecord.ts (companion for schema-driven form data)
|
|
26
|
-
* @seeAlso src/components/runtime/DataDetailPage.tsx (primary consumer)
|
|
27
|
-
* @seeAlso functions/admin-data.ts (API endpoint handling get/update/delete)
|
|
28
|
-
*/
|
|
29
1
|
|
|
2
|
+
|
|
3
|
+
// CIL[BEGIN chunk_id="useentityrecord_module_header_1783719596" type="module_header" identity="module_header" parent="none"]
|
|
4
|
+
// CIL[DOC-MACRO purpose="Define entity record hook types and interfaces"]
|
|
5
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Type definitions for entity record management"]
|
|
6
|
+
// CIL[DOC-CONTEXT module="useEntityRecord" layer="frontend-hook" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"\\\"]"]
|
|
7
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="FieldPermissions, MinimalEntityConfig, UseEntityRecordReturn interfaces" errors="none" side_effects="Type declarations"]
|
|
8
|
+
// CIL[DOC-MICRO logic_summary="Exports interfaces for field permissions, entity config, and record management" notable_decisions="[]"]
|
|
9
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
10
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
11
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
12
|
+
// CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, \."]
|
|
13
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
14
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
15
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
16
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
17
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
30
18
|
import { useCallback } from 'react'
|
|
31
19
|
import { useApi, useMutation } from './useApi'
|
|
32
20
|
import { apiFetch } from '../lib/api'
|
|
33
21
|
import { useAuth } from '../contexts/AuthContext'
|
|
34
22
|
|
|
35
|
-
// ─── TYPES ───────────────────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Per-field read/write permission map keyed by field name.
|
|
39
|
-
* Computed from `design_schema.fields[n].permissions` and the current user's roles.
|
|
40
|
-
*/
|
|
41
23
|
interface FieldPermissions {
|
|
42
24
|
[key: string]: { read: boolean; write: boolean }
|
|
43
25
|
}
|
|
44
26
|
|
|
45
|
-
/**
|
|
46
|
-
* Minimal entity configuration consumed by `useEntityRecord`.
|
|
47
|
-
*
|
|
48
|
-
* @prop entity - Entity table name
|
|
49
|
-
* @prop typeSlug - Optional type slug for schema resolution
|
|
50
|
-
* @prop icon - Icon identifier (used by detail page header)
|
|
51
|
-
* @prop displayField - Field name used as the record title
|
|
52
|
-
* @prop api.endpoint - Netlify function base path
|
|
53
|
-
* @prop api.*Action - Action strings for get/create/update/delete
|
|
54
|
-
* @prop softDelete - Hint for the API handler (true = set is_active=false)
|
|
55
|
-
*/
|
|
56
27
|
interface MinimalEntityConfig {
|
|
57
28
|
entity: string
|
|
58
29
|
typeSlug?: string
|
|
@@ -68,19 +39,6 @@ interface MinimalEntityConfig {
|
|
|
68
39
|
softDelete?: boolean
|
|
69
40
|
}
|
|
70
41
|
|
|
71
|
-
/**
|
|
72
|
-
* Return value of `useEntityRecord`.
|
|
73
|
-
*
|
|
74
|
-
* @prop record - Fetched record or null
|
|
75
|
-
* @prop schema - `design_schema` extracted from the record (or nested type)
|
|
76
|
-
* @prop fieldPermissions - Per-field `{ read, write }` map for the current user
|
|
77
|
-
* @prop loading - True while fetching
|
|
78
|
-
* @prop error - Error message or null
|
|
79
|
-
* @prop refetch - Re-fetch the record
|
|
80
|
-
* @prop save - Trigger the save mutation (create or update based on `id`)
|
|
81
|
-
* @prop delete - Trigger the delete mutation
|
|
82
|
-
* @prop saving / deleting - Mutation loading flags
|
|
83
|
-
*/
|
|
84
42
|
interface UseEntityRecordReturn {
|
|
85
43
|
record: any
|
|
86
44
|
schema: any
|
|
@@ -93,30 +51,23 @@ interface UseEntityRecordReturn {
|
|
|
93
51
|
saving: boolean
|
|
94
52
|
deleting: boolean
|
|
95
53
|
}
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```tsx
|
|
116
|
-
* const { record, save, saving, fieldPermissions } =
|
|
117
|
-
* useEntityRecord('accounts', id, config)
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
54
|
+
// CIL[END chunk_id="useentityrecord_module_header_1783719596"]
|
|
55
|
+
// CIL[BEGIN chunk_id="useentityrecord_useentityrecord_1783719596" type="function" identity="useEntityRecord" parent="none"]
|
|
56
|
+
// CIL[DOC-LEARNING topic="runtime-type:generic/entity_record" content="useEntityRecord splits a record into system fields (field.system=true, stored on the row) and data fields (stored in record.data) using record.design_schema.fields. It applies field-level permissions before saving and uses the design_schema to build the update payload."]
|
|
57
|
+
// CIL[DOC-NOTE type="design_schema_caveat" content="If record.design_schema is not stamped or fields is empty, all values may be treated as data and silently dropped by row-level validation or security policies."]
|
|
58
|
+
// CIL[DOC-MACRO purpose="Fetch, save, and delete single entity records with permissions"]
|
|
59
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Record CRUD operations, field permissions, schema extraction"]
|
|
60
|
+
// CIL[DOC-CONTEXT module="useEntityRecord" layer="frontend-hook" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
|
|
61
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="UseEntityRecordReturn with record, permissions, mutations" errors="Network errors, permission errors" side_effects="React state updates, API calls via apiFetch"]
|
|
62
|
+
// CIL[DOC-MICRO logic_summary="Fetches record, calculates field permissions from schema, handles create/update/delete with system/custom field separation" notable_decisions="[]"]
|
|
63
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
64
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
65
|
+
// CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 3. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
|
|
66
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 3. Total affected: 3."]
|
|
67
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
68
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
69
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
70
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
120
71
|
export function useEntityRecord(
|
|
121
72
|
entity: string,
|
|
122
73
|
id: string | undefined,
|
|
@@ -124,14 +75,12 @@ export function useEntityRecord(
|
|
|
124
75
|
): UseEntityRecordReturn {
|
|
125
76
|
const { user } = useAuth()
|
|
126
77
|
|
|
127
|
-
// Get API configuration with safe defaults
|
|
128
78
|
const endpoint = config?.api?.endpoint || entity
|
|
129
79
|
const getAction = config?.api?.getAction || 'get'
|
|
130
80
|
const createAction = config?.api?.createAction || 'create'
|
|
131
81
|
const updateAction = config?.api?.updateAction || 'update'
|
|
132
82
|
const deleteAction = config?.api?.deleteAction || 'delete'
|
|
133
83
|
|
|
134
|
-
// Fetch record - always call useCallback to maintain hook order
|
|
135
84
|
const fetchRecord = useCallback(async () => {
|
|
136
85
|
if (!id) return null
|
|
137
86
|
|
|
@@ -154,17 +103,13 @@ export function useEntityRecord(
|
|
|
154
103
|
immediate: !!id
|
|
155
104
|
})
|
|
156
105
|
|
|
157
|
-
// Extract schema from record (accounts have it at root level, items/types have it nested)
|
|
158
106
|
const schema = record?.design_schema || record?.type?.design_schema || {}
|
|
159
107
|
|
|
160
|
-
// Calculate field permissions from record's schema
|
|
161
108
|
const calculatePermissions = (): FieldPermissions => {
|
|
162
109
|
const permissions: FieldPermissions = {}
|
|
163
110
|
|
|
164
|
-
// System admin gets full access
|
|
165
111
|
const isSystemAdmin = user?.roles?.includes('system_admin')
|
|
166
112
|
|
|
167
|
-
// Get all fields from record's schema
|
|
168
113
|
const recordSchema = record?.design_schema?.fields
|
|
169
114
|
if (!recordSchema) return permissions
|
|
170
115
|
|
|
@@ -172,7 +117,6 @@ export function useEntityRecord(
|
|
|
172
117
|
if (isSystemAdmin) {
|
|
173
118
|
permissions[fieldName] = { read: true, write: true }
|
|
174
119
|
} else {
|
|
175
|
-
// Check field-level permissions from schema
|
|
176
120
|
const fieldPerms = fieldSchema?.permissions || {}
|
|
177
121
|
|
|
178
122
|
const canRead = fieldPerms.read?.some((role: string) =>
|
|
@@ -192,10 +136,8 @@ export function useEntityRecord(
|
|
|
192
136
|
|
|
193
137
|
const fieldPermissions = calculatePermissions()
|
|
194
138
|
|
|
195
|
-
// Save mutation
|
|
196
139
|
const saveMutation = useMutation(
|
|
197
140
|
async (data: any) => {
|
|
198
|
-
// Separate system fields from custom fields
|
|
199
141
|
const systemData: Record<string, any> = {}
|
|
200
142
|
const customData: Record<string, any> = {}
|
|
201
143
|
|
|
@@ -208,14 +150,12 @@ export function useEntityRecord(
|
|
|
208
150
|
}
|
|
209
151
|
})
|
|
210
152
|
|
|
211
|
-
// Combine system fields with custom data in data field
|
|
212
153
|
const saveData = {
|
|
213
154
|
...systemData,
|
|
214
155
|
data: Object.keys(customData).length > 0 ? customData : undefined
|
|
215
156
|
}
|
|
216
157
|
|
|
217
158
|
if (id) {
|
|
218
|
-
// Update
|
|
219
159
|
const params = new URLSearchParams()
|
|
220
160
|
params.append('action', updateAction)
|
|
221
161
|
params.append('entity', entity)
|
|
@@ -236,8 +176,7 @@ export function useEntityRecord(
|
|
|
236
176
|
|
|
237
177
|
return response.json()
|
|
238
178
|
} else {
|
|
239
|
-
|
|
240
|
-
const createData = { entity, ...saveData }
|
|
179
|
+
const createData = { entity, type_slug: config?.typeSlug, ...saveData }
|
|
241
180
|
|
|
242
181
|
const params = new URLSearchParams()
|
|
243
182
|
params.append('action', createAction)
|
|
@@ -268,7 +207,6 @@ export function useEntityRecord(
|
|
|
268
207
|
}
|
|
269
208
|
)
|
|
270
209
|
|
|
271
|
-
// Delete mutation
|
|
272
210
|
const deleteMutation = useMutation(
|
|
273
211
|
async () => {
|
|
274
212
|
if (!id) throw new Error('Cannot delete: no ID provided')
|
|
@@ -306,3 +244,4 @@ export function useEntityRecord(
|
|
|
306
244
|
deleting: deleteMutation.loading
|
|
307
245
|
}
|
|
308
246
|
}
|
|
247
|
+
// CIL[END chunk_id="useentityrecord_useentityrecord_1783719596"]
|