insforge 0.3.1

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 (395) hide show
  1. package/.dockerignore +58 -0
  2. package/.env.example +49 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +11 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +79 -0
  6. package/.github/copilot-instructions.md +147 -0
  7. package/.github/workflows/build-image.yml +65 -0
  8. package/.github/workflows/ci-premerge-check.yml +24 -0
  9. package/.github/workflows/deploy-aws.yml +130 -0
  10. package/.github/workflows/lint-and-format.yml +33 -0
  11. package/.prettierignore +65 -0
  12. package/.prettierrc +9 -0
  13. package/CHANGELOG.md +3 -0
  14. package/CONTRIBUTING.md +126 -0
  15. package/Dockerfile +27 -0
  16. package/GITHUB_OAUTH_SETUP.md +49 -0
  17. package/GOOGLE_OAUTH_SETUP.md +148 -0
  18. package/LICENSE +201 -0
  19. package/README.md +134 -0
  20. package/assets/Dark.svg +23 -0
  21. package/assets/archDiagram.png +0 -0
  22. package/assets/banner.png +0 -0
  23. package/assets/mcpInstallv2.png +0 -0
  24. package/assets/sampleResponse.png +0 -0
  25. package/assets/signin.png +0 -0
  26. package/assets/userflow.png +0 -0
  27. package/backend/migrations/000_create-base-tables.sql +142 -0
  28. package/backend/migrations/001_create-helper-functions.sql +41 -0
  29. package/backend/migrations/002_rename-auth-tables.sql +30 -0
  30. package/backend/migrations/003_create-users-table.sql +56 -0
  31. package/backend/migrations/004_add-reload-postgrest-func.sql +24 -0
  32. package/backend/migrations/005_enable-project-admin-modify-users.sql +30 -0
  33. package/backend/migrations/006_modify-ai-usage-table.sql +25 -0
  34. package/backend/migrations/007_drop-metadata-table.sql +2 -0
  35. package/backend/migrations/008_add-system-tables.sql +77 -0
  36. package/backend/migrations/009_add-function-secrets.sql +24 -0
  37. package/backend/migrations/010_modify-ai-config-modalities.sql +93 -0
  38. package/backend/migrations/011_refactor-secrets-table.sql +15 -0
  39. package/backend/migrations/012_add-storage-uploaded-by.sql +8 -0
  40. package/backend/package.json +75 -0
  41. package/backend/src/api/middleware/auth.ts +240 -0
  42. package/backend/src/api/middleware/error.ts +231 -0
  43. package/backend/src/api/middleware/upload.ts +59 -0
  44. package/backend/src/api/routes/agent.ts +29 -0
  45. package/backend/src/api/routes/ai.ts +472 -0
  46. package/backend/src/api/routes/auth.oauth.ts +482 -0
  47. package/backend/src/api/routes/auth.ts +386 -0
  48. package/backend/src/api/routes/database.advance.ts +275 -0
  49. package/backend/src/api/routes/database.records.ts +246 -0
  50. package/backend/src/api/routes/database.tables.ts +161 -0
  51. package/backend/src/api/routes/docs.ts +66 -0
  52. package/backend/src/api/routes/functions.ts +183 -0
  53. package/backend/src/api/routes/logs.ts +150 -0
  54. package/backend/src/api/routes/metadata.ts +160 -0
  55. package/backend/src/api/routes/openapi.ts +82 -0
  56. package/backend/src/api/routes/secrets.ts +199 -0
  57. package/backend/src/api/routes/storage.ts +547 -0
  58. package/backend/src/api/routes/usage.ts +96 -0
  59. package/backend/src/core/ai/chat.ts +207 -0
  60. package/backend/src/core/ai/client.ts +242 -0
  61. package/backend/src/core/ai/config.ts +187 -0
  62. package/backend/src/core/ai/image.ts +156 -0
  63. package/backend/src/core/ai/model.ts +117 -0
  64. package/backend/src/core/ai/usage.ts +290 -0
  65. package/backend/src/core/auth/auth.ts +781 -0
  66. package/backend/src/core/auth/oauth.ts +398 -0
  67. package/backend/src/core/database/advance.ts +1074 -0
  68. package/backend/src/core/database/manager.ts +178 -0
  69. package/backend/src/core/database/table.ts +772 -0
  70. package/backend/src/core/documentation/agent.ts +689 -0
  71. package/backend/src/core/documentation/openapi.ts +856 -0
  72. package/backend/src/core/functions/functions.ts +310 -0
  73. package/backend/src/core/logs/analytics.ts +76 -0
  74. package/backend/src/core/logs/audit.ts +255 -0
  75. package/backend/src/core/logs/providers/base.provider.ts +83 -0
  76. package/backend/src/core/logs/providers/cloudwatch.provider.ts +510 -0
  77. package/backend/src/core/logs/providers/localdb.provider.ts +246 -0
  78. package/backend/src/core/secrets/encryption.ts +58 -0
  79. package/backend/src/core/secrets/secrets.ts +410 -0
  80. package/backend/src/core/socket/socket.ts +388 -0
  81. package/backend/src/core/socket/types.ts +79 -0
  82. package/backend/src/core/storage/storage.ts +923 -0
  83. package/backend/src/server.ts +288 -0
  84. package/backend/src/types/ai.ts +46 -0
  85. package/backend/src/types/auth.ts +90 -0
  86. package/backend/src/types/database.ts +136 -0
  87. package/backend/src/types/error-constants.ts +86 -0
  88. package/backend/src/types/logs.ts +47 -0
  89. package/backend/src/types/profile.ts +55 -0
  90. package/backend/src/types/storage.ts +23 -0
  91. package/backend/src/utils/cloud-token.ts +39 -0
  92. package/backend/src/utils/constants.ts +1 -0
  93. package/backend/src/utils/environment.ts +35 -0
  94. package/backend/src/utils/helpers.ts +49 -0
  95. package/backend/src/utils/logger.ts +13 -0
  96. package/backend/src/utils/response.ts +62 -0
  97. package/backend/src/utils/seed.ts +205 -0
  98. package/backend/src/utils/sql-parser.ts +63 -0
  99. package/backend/src/utils/uuid.ts +9 -0
  100. package/backend/src/utils/validations.ts +129 -0
  101. package/backend/tests/README.md +134 -0
  102. package/backend/tests/cleanup-all-test-data.sh +231 -0
  103. package/backend/tests/cloud/test-s3-multitenant.sh +132 -0
  104. package/backend/tests/local/comprehensive-curl-tests.sh +156 -0
  105. package/backend/tests/local/test-auth-router.sh +144 -0
  106. package/backend/tests/local/test-database-router.sh +222 -0
  107. package/backend/tests/local/test-e2e.sh +241 -0
  108. package/backend/tests/local/test-fk-errors.sh +97 -0
  109. package/backend/tests/local/test-id-field.sh +201 -0
  110. package/backend/tests/local/test-public-bucket.sh +265 -0
  111. package/backend/tests/local/test-secrets.sh +248 -0
  112. package/backend/tests/local/test-serverless-functions.sh.disabled +325 -0
  113. package/backend/tests/local/test-traditional-rest.sh +209 -0
  114. package/backend/tests/manual/README.md +51 -0
  115. package/backend/tests/manual/create-large-table-simple.sql +11 -0
  116. package/backend/tests/manual/seed-large-table.sql +101 -0
  117. package/backend/tests/manual/setup-large-table-extras.sql +34 -0
  118. package/backend/tests/manual/test-better-auth.sh +303 -0
  119. package/backend/tests/manual/test-bulk-upsert.sh +410 -0
  120. package/backend/tests/manual/test-database-advance.sh +297 -0
  121. package/backend/tests/manual/test-postgrest-stability.sh +192 -0
  122. package/backend/tests/manual/test-rawsql-export-import.sh +412 -0
  123. package/backend/tests/manual/test-universal-storage.sh +264 -0
  124. package/backend/tests/manual/test-users.sql +18 -0
  125. package/backend/tests/run-all-tests.sh +140 -0
  126. package/backend/tests/setup.ts +22 -0
  127. package/backend/tests/test-config.sh +303 -0
  128. package/backend/tsconfig.json +23 -0
  129. package/backend/tsup.config.ts +18 -0
  130. package/backend/vitest.config.ts +22 -0
  131. package/docker-compose.prod.yml +145 -0
  132. package/docker-compose.yml +167 -0
  133. package/docker-init/db/db-init.sql +125 -0
  134. package/docker-init/db/jwt.sql +5 -0
  135. package/docker-init/db/logs.sql +9 -0
  136. package/docker-init/db/postgresql.conf +17 -0
  137. package/docs/deprecated/insforge-auth-api.md +215 -0
  138. package/docs/deprecated/insforge-auth-sdk.md +100 -0
  139. package/docs/deprecated/insforge-db-api.md +359 -0
  140. package/docs/deprecated/insforge-db-sdk.md +140 -0
  141. package/docs/deprecated/insforge-debug-sdk.md +157 -0
  142. package/docs/deprecated/insforge-debug.md +65 -0
  143. package/docs/deprecated/insforge-instructions.md +124 -0
  144. package/docs/deprecated/insforge-project.md +118 -0
  145. package/docs/deprecated/insforge-storage-api.md +279 -0
  146. package/docs/deprecated/insforge-storage-sdk.md +159 -0
  147. package/docs/insforge-instructions-sdk.md +407 -0
  148. package/eslint.config.js +317 -0
  149. package/examples/oauth/frontend-oauth-example.html +251 -0
  150. package/examples/response-examples.md +444 -0
  151. package/frontend/README.md +112 -0
  152. package/frontend/components.json +17 -0
  153. package/frontend/index.html +13 -0
  154. package/frontend/package.json +63 -0
  155. package/frontend/public/favicon.ico +0 -0
  156. package/frontend/src/App.tsx +106 -0
  157. package/frontend/src/assets/icons/checkbox_checked.svg +6 -0
  158. package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -0
  159. package/frontend/src/assets/icons/checked.svg +3 -0
  160. package/frontend/src/assets/icons/error.svg +3 -0
  161. package/frontend/src/assets/icons/pencil.svg +4 -0
  162. package/frontend/src/assets/icons/refresh.svg +4 -0
  163. package/frontend/src/assets/icons/step_active.svg +3 -0
  164. package/frontend/src/assets/icons/step_inactive.svg +11 -0
  165. package/frontend/src/assets/icons/warning.svg +3 -0
  166. package/frontend/src/assets/logos/amazon.svg +1 -0
  167. package/frontend/src/assets/logos/claude_code.svg +3 -0
  168. package/frontend/src/assets/logos/cline.svg +6 -0
  169. package/frontend/src/assets/logos/cursor.svg +20 -0
  170. package/frontend/src/assets/logos/discord.svg +9 -0
  171. package/frontend/src/assets/logos/gemini.svg +19 -0
  172. package/frontend/src/assets/logos/github.svg +5 -0
  173. package/frontend/src/assets/logos/google.svg +13 -0
  174. package/frontend/src/assets/logos/grok.svg +10 -0
  175. package/frontend/src/assets/logos/insforge_dark.svg +15 -0
  176. package/frontend/src/assets/logos/insforge_light.svg +15 -0
  177. package/frontend/src/assets/logos/openai.svg +10 -0
  178. package/frontend/src/assets/logos/roo_code.svg +9 -0
  179. package/frontend/src/assets/logos/trae.svg +3 -0
  180. package/frontend/src/assets/logos/windsurf.svg +10 -0
  181. package/frontend/src/components/ButtonWithLoading.tsx +27 -0
  182. package/frontend/src/components/Checkbox.tsx +61 -0
  183. package/frontend/src/components/CodeBlock.tsx +32 -0
  184. package/frontend/src/components/ConfirmDialog.tsx +96 -0
  185. package/frontend/src/components/CopyButton.tsx +69 -0
  186. package/frontend/src/components/DeleteActionButton.tsx +42 -0
  187. package/frontend/src/components/EmptyState.tsx +41 -0
  188. package/frontend/src/components/ErrorState.tsx +35 -0
  189. package/frontend/src/components/FeatureSidebar.tsx +126 -0
  190. package/frontend/src/components/FeatureSidebarItem.tsx +101 -0
  191. package/frontend/src/components/JsonHighlight.tsx +61 -0
  192. package/frontend/src/components/LoadingState.tsx +16 -0
  193. package/frontend/src/components/PaginationControls.tsx +54 -0
  194. package/frontend/src/components/PromptDialog.tsx +68 -0
  195. package/frontend/src/components/SearchInput.tsx +90 -0
  196. package/frontend/src/components/SelectionClearButton.tsx +26 -0
  197. package/frontend/src/components/Stepper.tsx +139 -0
  198. package/frontend/src/components/ThemeToggle.tsx +58 -0
  199. package/frontend/src/components/TypeBadge.tsx +20 -0
  200. package/frontend/src/components/datagrid/DataGrid.tsx +264 -0
  201. package/frontend/src/components/datagrid/DefaultCellRenderer.tsx +114 -0
  202. package/frontend/src/components/datagrid/IdCell.tsx +44 -0
  203. package/frontend/src/components/datagrid/SortableHeader.tsx +74 -0
  204. package/frontend/src/components/datagrid/cell-editors/BooleanCellEditor.tsx +54 -0
  205. package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +483 -0
  206. package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +362 -0
  207. package/frontend/src/components/datagrid/cell-editors/TextCellEditor.tsx +38 -0
  208. package/frontend/src/components/datagrid/cell-editors/index.ts +14 -0
  209. package/frontend/src/components/datagrid/cell-editors/types.ts +43 -0
  210. package/frontend/src/components/datagrid/datagridTypes.tsx +72 -0
  211. package/frontend/src/components/datagrid/index.tsx +20 -0
  212. package/frontend/src/components/index.ts +39 -0
  213. package/frontend/src/components/layout/AppHeader.tsx +146 -0
  214. package/frontend/src/components/layout/AppSidebar.tsx +190 -0
  215. package/frontend/src/components/layout/CloudLayout.tsx +95 -0
  216. package/frontend/src/components/layout/Layout.tsx +43 -0
  217. package/frontend/src/components/radix/Alert.tsx +45 -0
  218. package/frontend/src/components/radix/AlertDialog.tsx +115 -0
  219. package/frontend/src/components/radix/Avatar.tsx +45 -0
  220. package/frontend/src/components/radix/Badge.tsx +33 -0
  221. package/frontend/src/components/radix/Button.tsx +50 -0
  222. package/frontend/src/components/radix/Card.tsx +58 -0
  223. package/frontend/src/components/radix/Dialog.tsx +98 -0
  224. package/frontend/src/components/radix/DropdownMenu.tsx +185 -0
  225. package/frontend/src/components/radix/Form.tsx +167 -0
  226. package/frontend/src/components/radix/Input.tsx +22 -0
  227. package/frontend/src/components/radix/Label.tsx +19 -0
  228. package/frontend/src/components/radix/Popover.tsx +29 -0
  229. package/frontend/src/components/radix/ScrollArea.tsx +44 -0
  230. package/frontend/src/components/radix/Select.tsx +151 -0
  231. package/frontend/src/components/radix/Separator.tsx +26 -0
  232. package/frontend/src/components/radix/Sheet.tsx +119 -0
  233. package/frontend/src/components/radix/Skeleton.tsx +7 -0
  234. package/frontend/src/components/radix/Switch.tsx +29 -0
  235. package/frontend/src/components/radix/Tabs.tsx +50 -0
  236. package/frontend/src/components/radix/Textarea.tsx +21 -0
  237. package/frontend/src/components/radix/Tooltip.tsx +28 -0
  238. package/frontend/src/features/ai/components/AIConfigCard.tsx +154 -0
  239. package/frontend/src/features/ai/components/AIConfigDialog.tsx +76 -0
  240. package/frontend/src/features/ai/components/AIConfigForm.tsx +222 -0
  241. package/frontend/src/features/ai/components/AIEmptyState.tsx +18 -0
  242. package/frontend/src/features/ai/components/fields/ModalityField.tsx +87 -0
  243. package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +134 -0
  244. package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +33 -0
  245. package/frontend/src/features/ai/helpers.ts +155 -0
  246. package/frontend/src/features/ai/hooks/useAIConfigs.ts +221 -0
  247. package/frontend/src/features/ai/hooks/useAIUsage.ts +77 -0
  248. package/frontend/src/features/ai/page/AIPage.tsx +178 -0
  249. package/frontend/src/features/ai/services/ai.service.ts +148 -0
  250. package/frontend/src/features/auth/components/AddOAuthDialog.tsx +106 -0
  251. package/frontend/src/features/auth/components/AuthMethodTab.tsx +238 -0
  252. package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +303 -0
  253. package/frontend/src/features/auth/components/OAuthEmptyState.tsx +15 -0
  254. package/frontend/src/features/auth/components/UserFormDialog.tsx +248 -0
  255. package/frontend/src/features/auth/components/UsersDataGrid.tsx +183 -0
  256. package/frontend/src/features/auth/components/UsersTab.tsx +114 -0
  257. package/frontend/src/features/auth/hooks/useOAuthConfig.ts +129 -0
  258. package/frontend/src/features/auth/hooks/useUsers.ts +57 -0
  259. package/frontend/src/features/auth/index.ts +9 -0
  260. package/frontend/src/features/auth/page/AuthenticationPage.tsx +169 -0
  261. package/frontend/src/features/auth/services/auth.service.ts +112 -0
  262. package/frontend/src/features/auth/services/oauth.service.ts +49 -0
  263. package/frontend/src/features/dashboard/page/DashboardPage.tsx +194 -0
  264. package/frontend/src/features/database/components/ColumnTypeSelect.tsx +64 -0
  265. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +282 -0
  266. package/frontend/src/features/database/components/ForeignKeyCell.tsx +187 -0
  267. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +378 -0
  268. package/frontend/src/features/database/components/LinkRecordModal.tsx +288 -0
  269. package/frontend/src/features/database/components/RecordFormDialog.tsx +164 -0
  270. package/frontend/src/features/database/components/RecordFormField.tsx +568 -0
  271. package/frontend/src/features/database/components/TableEmptyState.tsx +21 -0
  272. package/frontend/src/features/database/components/TableForm.tsx +656 -0
  273. package/frontend/src/features/database/components/TableFormColumn.tsx +137 -0
  274. package/frontend/src/features/database/components/TableListSkeleton.tsx +9 -0
  275. package/frontend/src/features/database/components/TableSidebar.tsx +47 -0
  276. package/frontend/src/features/database/constants.ts +26 -0
  277. package/frontend/src/features/database/helpers.ts +125 -0
  278. package/frontend/src/features/database/hooks/UseLinkModal.tsx +78 -0
  279. package/frontend/src/features/database/index.ts +12 -0
  280. package/frontend/src/features/database/page/DatabasePage.tsx +626 -0
  281. package/frontend/src/features/database/schema.ts +25 -0
  282. package/frontend/src/features/database/services/database.service.ts +216 -0
  283. package/frontend/src/features/functions/components/FunctionEmptyState.tsx +15 -0
  284. package/frontend/src/features/functions/components/FunctionRow.tsx +71 -0
  285. package/frontend/src/features/functions/components/FunctionViewer.tsx +46 -0
  286. package/frontend/src/features/functions/components/FunctionsContent.tsx +88 -0
  287. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -0
  288. package/frontend/src/features/functions/components/SecretEmptyState.tsx +23 -0
  289. package/frontend/src/features/functions/components/SecretRow.tsx +68 -0
  290. package/frontend/src/features/functions/components/SecretsContent.tsx +120 -0
  291. package/frontend/src/features/functions/hooks/useFunctions.ts +106 -0
  292. package/frontend/src/features/functions/page/FunctionsPage.tsx +28 -0
  293. package/frontend/src/features/functions/services/functions.service.ts +48 -0
  294. package/frontend/src/features/login/components/AuthErrorBoundary.tsx +87 -0
  295. package/frontend/src/features/login/components/PrivateRoute.tsx +24 -0
  296. package/frontend/src/features/login/page/CloudLoginPage.tsx +93 -0
  297. package/frontend/src/features/login/page/LoginPage.tsx +174 -0
  298. package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +313 -0
  299. package/frontend/src/features/logs/components/LogsTable.tsx +199 -0
  300. package/frontend/src/features/logs/hooks/useAuditLogs.ts +39 -0
  301. package/frontend/src/features/logs/index.ts +5 -0
  302. package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +530 -0
  303. package/frontend/src/features/logs/page/AuditsPage.tsx +192 -0
  304. package/frontend/src/features/logs/services/log.service.ts +171 -0
  305. package/frontend/src/features/metadata/hooks/useMetadata.ts +53 -0
  306. package/frontend/src/features/metadata/index.ts +0 -0
  307. package/frontend/src/features/metadata/page/MetadataPage.tsx +136 -0
  308. package/frontend/src/features/metadata/services/metadata.service.ts +17 -0
  309. package/frontend/src/features/onboard/components/CompletionCard.tsx +41 -0
  310. package/frontend/src/features/onboard/components/OnboardButton.tsx +84 -0
  311. package/frontend/src/features/onboard/components/StepContent.tsx +91 -0
  312. package/frontend/src/features/onboard/components/TestConnectionStep.tsx +53 -0
  313. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +35 -0
  314. package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +144 -0
  315. package/frontend/src/features/onboard/components/mcp/index.ts +4 -0
  316. package/frontend/src/features/onboard/components/mcp/mcp-helper.tsx +98 -0
  317. package/frontend/src/features/onboard/index.ts +3 -0
  318. package/frontend/src/features/onboard/page/OnBoardPage.tsx +104 -0
  319. package/frontend/src/features/onboard/types.ts +8 -0
  320. package/frontend/src/features/secrets/hooks/useSecrets.ts +139 -0
  321. package/frontend/src/features/secrets/services/secrets.service.ts +57 -0
  322. package/frontend/src/features/storage/components/BucketEmptyState.tsx +19 -0
  323. package/frontend/src/features/storage/components/BucketFormDialog.tsx +194 -0
  324. package/frontend/src/features/storage/components/BucketListSkeleton.tsx +17 -0
  325. package/frontend/src/features/storage/components/FilePreviewDialog.tsx +287 -0
  326. package/frontend/src/features/storage/components/StorageDataGrid.tsx +239 -0
  327. package/frontend/src/features/storage/components/StorageManager.tsx +236 -0
  328. package/frontend/src/features/storage/components/StorageSidebar.tsx +44 -0
  329. package/frontend/src/features/storage/components/UploadToast.tsx +46 -0
  330. package/frontend/src/features/storage/index.ts +3 -0
  331. package/frontend/src/features/storage/page/StoragePage.tsx +553 -0
  332. package/frontend/src/features/storage/services/storage.service.ts +144 -0
  333. package/frontend/src/features/visualizer/components/AuthNode.tsx +107 -0
  334. package/frontend/src/features/visualizer/components/BucketNode.tsx +34 -0
  335. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +359 -0
  336. package/frontend/src/features/visualizer/components/TableNode.tsx +152 -0
  337. package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +24 -0
  338. package/frontend/src/features/visualizer/components/index.ts +5 -0
  339. package/frontend/src/features/visualizer/page/VisualizerPage.tsx +127 -0
  340. package/frontend/src/index.css +248 -0
  341. package/frontend/src/lib/api/client.ts +163 -0
  342. package/frontend/src/lib/contexts/AuthContext.tsx +157 -0
  343. package/frontend/src/lib/contexts/OnboardStepContext.tsx +68 -0
  344. package/frontend/src/lib/contexts/SocketContext.tsx +303 -0
  345. package/frontend/src/lib/contexts/ThemeContext.tsx +125 -0
  346. package/frontend/src/lib/hooks/useAuth.ts +4 -0
  347. package/frontend/src/lib/hooks/useConfirm.ts +55 -0
  348. package/frontend/src/lib/hooks/useInterval.ts +27 -0
  349. package/frontend/src/lib/hooks/useMediaQuery.ts +59 -0
  350. package/frontend/src/lib/hooks/useOnboardingCompletion.ts +29 -0
  351. package/frontend/src/lib/hooks/usePagination.ts +27 -0
  352. package/frontend/src/lib/hooks/useTimeout.ts +27 -0
  353. package/frontend/src/lib/hooks/useToast.tsx +229 -0
  354. package/frontend/src/lib/utils/constants.ts +38 -0
  355. package/frontend/src/lib/utils/utils.ts +165 -0
  356. package/frontend/src/lib/utils/validation-schemas.ts +126 -0
  357. package/frontend/src/main.tsx +16 -0
  358. package/frontend/src/rdg.css +194 -0
  359. package/frontend/src/vite-env.d.ts +12 -0
  360. package/frontend/tailwind.config.js +97 -0
  361. package/frontend/tsconfig.json +26 -0
  362. package/frontend/tsconfig.node.json +10 -0
  363. package/frontend/vite.config.ts +37 -0
  364. package/frontend/vitest.config.ts +36 -0
  365. package/functions/deno.json +25 -0
  366. package/functions/server.ts +290 -0
  367. package/functions/worker-template.js +126 -0
  368. package/openapi/ai.yaml +689 -0
  369. package/openapi/auth.yaml +563 -0
  370. package/openapi/functions.yaml +476 -0
  371. package/openapi/health.yaml +30 -0
  372. package/openapi/logs.yaml +224 -0
  373. package/openapi/metadata.yaml +178 -0
  374. package/openapi/records.yaml +382 -0
  375. package/openapi/secrets.yaml +371 -0
  376. package/openapi/storage.yaml +876 -0
  377. package/openapi/tables.yaml +464 -0
  378. package/package.json +88 -0
  379. package/shared-schemas/package.json +31 -0
  380. package/shared-schemas/src/ai-api.schema.ts +167 -0
  381. package/shared-schemas/src/ai.schema.ts +54 -0
  382. package/shared-schemas/src/auth-api.schema.ts +193 -0
  383. package/shared-schemas/src/auth.schema.ts +94 -0
  384. package/shared-schemas/src/database-api.schema.ts +259 -0
  385. package/shared-schemas/src/database.schema.ts +69 -0
  386. package/shared-schemas/src/functions-api.schema.ts +25 -0
  387. package/shared-schemas/src/functions.schema.ts +16 -0
  388. package/shared-schemas/src/index.ts +13 -0
  389. package/shared-schemas/src/logs-api.schema.ts +49 -0
  390. package/shared-schemas/src/logs.schema.ts +14 -0
  391. package/shared-schemas/src/metadata.schema.ts +56 -0
  392. package/shared-schemas/src/storage-api.schema.ts +65 -0
  393. package/shared-schemas/src/storage.schema.ts +19 -0
  394. package/shared-schemas/tsconfig.json +21 -0
  395. package/tsconfig.json +8 -0
@@ -0,0 +1,68 @@
1
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/radix/Dialog';
2
+ import { CopyButton } from '@/components/CopyButton';
3
+ import { cn } from '@/lib/utils/utils';
4
+
5
+ interface PromptDialogProps {
6
+ open: boolean;
7
+ onOpenChange: (open: boolean) => void;
8
+ title?: string;
9
+ subtitle?: string;
10
+ prompt: string;
11
+ additionalAction?: React.ReactNode;
12
+ }
13
+
14
+ export function PromptDialog({
15
+ open,
16
+ onOpenChange,
17
+ title = 'Integrate with your application',
18
+ subtitle = 'Paste the prompt below into your cloud agent',
19
+ prompt,
20
+ additionalAction,
21
+ }: PromptDialogProps) {
22
+ return (
23
+ <Dialog open={open} onOpenChange={onOpenChange}>
24
+ <DialogContent className="max-w-4xl p-0 bg-white border border-zinc-200 shadow-[0px_1px_3px_0px_rgba(0,0,0,0.1)] dark:bg-neutral-800 dark:border-neutral-700">
25
+ <div className="flex flex-col">
26
+ <DialogHeader className="px-6 py-3 flex flex-col gap-1 justify-start border-b border-zinc-200 dark:border-neutral-700">
27
+ <DialogTitle className="text-lg font-semibold text-zinc-950 dark:text-white">
28
+ {title}
29
+ </DialogTitle>
30
+ </DialogHeader>
31
+ {/* Content */}
32
+ <div className="p-6 flex flex-col gap-4">
33
+ <p className="text-sm text-zinc-500 font-normal leading-5 dark:text-neutral-400">
34
+ {subtitle}
35
+ </p>
36
+ {/* Prompt display */}
37
+ <div className="relative">
38
+ <pre
39
+ className={cn(
40
+ 'px-6 py-4 font-mono text-sm leading-5 overflow-auto whitespace-pre-wrap break-all rounded',
41
+ 'max-h-96',
42
+ 'bg-zinc-50 text-zinc-900 dark:bg-neutral-700 dark:text-white',
43
+ 'border border-zinc-200 dark:border-neutral-700'
44
+ )}
45
+ >
46
+ {prompt}
47
+ </pre>
48
+ </div>
49
+
50
+ {/* Action buttons */}
51
+ <div className="flex items-center justify-end gap-2.5">
52
+ {additionalAction}
53
+ <CopyButton
54
+ text={prompt}
55
+ variant="default"
56
+ size="default"
57
+ showText={true}
58
+ className="h-9 pl-2 pr-3 py-2 text-sm font-medium"
59
+ copyText="Copy Prompt"
60
+ copiedText="Copied!"
61
+ />
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </DialogContent>
66
+ </Dialog>
67
+ );
68
+ }
@@ -0,0 +1,90 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { Search, X } from 'lucide-react';
3
+ import { Input } from '@/components/radix/Input';
4
+ import { Button } from '@/components/radix/Button';
5
+
6
+ interface SearchInputProps {
7
+ value: string;
8
+ onChange: (value: string) => void;
9
+ placeholder?: string;
10
+ className?: string;
11
+ /** Debounce delay in milliseconds. Set to 0 to disable debouncing. Default: 500ms */
12
+ debounceTime?: number;
13
+ /** Callback fired immediately when input changes (before debounce) */
14
+ onImmediateChange?: (value: string) => void;
15
+ }
16
+
17
+ export function SearchInput({
18
+ value,
19
+ onChange,
20
+ placeholder = 'Search...',
21
+ className,
22
+ debounceTime = 500,
23
+ onImmediateChange,
24
+ }: SearchInputProps) {
25
+ const [internalValue, setInternalValue] = useState(value);
26
+
27
+ // Sync internal value with external value prop
28
+ useEffect(() => {
29
+ setInternalValue(value);
30
+ }, [value]);
31
+
32
+ // Handle debounced onChange
33
+ useEffect(() => {
34
+ if (debounceTime === 0) {
35
+ // No debouncing, call onChange immediately
36
+ onChange(internalValue);
37
+ return;
38
+ }
39
+
40
+ // Set up debounce timer
41
+ const handler = setTimeout(() => {
42
+ onChange(internalValue);
43
+ }, debounceTime);
44
+
45
+ // Cleanup timer on value change
46
+ return () => {
47
+ clearTimeout(handler);
48
+ };
49
+ }, [internalValue, debounceTime, onChange]);
50
+
51
+ const handleInputChange = (newValue: string) => {
52
+ setInternalValue(newValue);
53
+ // Call immediate change callback if provided
54
+ onImmediateChange?.(newValue);
55
+ };
56
+
57
+ const handleClear = () => {
58
+ setInternalValue('');
59
+ onImmediateChange?.('');
60
+ // If no debouncing, clear immediately
61
+ if (debounceTime === 0) {
62
+ onChange('');
63
+ }
64
+ };
65
+
66
+ return (
67
+ <div
68
+ className={`relative bg-white dark:bg-neutral-900 overflow-hidden rounded-md ${className || ''}`}
69
+ >
70
+ <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground dark:text-zinc-300" />
71
+ <Input
72
+ type="text"
73
+ placeholder={placeholder}
74
+ value={internalValue}
75
+ onChange={(e) => handleInputChange(e.target.value)}
76
+ className="pl-9 pr-9 h-10 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
77
+ />
78
+ {internalValue && (
79
+ <Button
80
+ variant="ghost"
81
+ size="icon"
82
+ onClick={handleClear}
83
+ className="absolute right-1 top-1/2 h-7 w-7 -translate-y-1/2"
84
+ >
85
+ <X className="h-3 w-3" />
86
+ </Button>
87
+ )}
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,26 @@
1
+ import { X } from 'lucide-react';
2
+
3
+ interface SelectionClearButtonProps {
4
+ selectedCount: number;
5
+ itemType: string;
6
+ onClear: () => void;
7
+ }
8
+
9
+ export function SelectionClearButton({
10
+ selectedCount,
11
+ itemType,
12
+ onClear,
13
+ }: SelectionClearButtonProps) {
14
+ const isPlural = selectedCount > 1;
15
+ const displayText = `${selectedCount} ${isPlural ? `${itemType}s` : itemType} selected`;
16
+
17
+ return (
18
+ <button
19
+ className="flex items-center gap-1.5 h-10 px-3 rounded-[6px] bg-white border border-border-gray hover:bg-gray-50 dark:bg-neutral-600 dark:border-neutral-600 dark:hover:bg-neutral-700 transition-colors"
20
+ onClick={onClear}
21
+ >
22
+ <p className="text-zinc-950 dark:text-white text-sm">{displayText}</p>
23
+ <X className="h-4 w-4 text-gray-500 dark:text-neutral-400" />
24
+ </button>
25
+ );
26
+ }
@@ -0,0 +1,139 @@
1
+ import { cn } from '@/lib/utils/utils';
2
+
3
+ interface CircularStepperProps {
4
+ isActive: boolean;
5
+ currentStep: number;
6
+ totalSteps: number;
7
+ size?: number;
8
+ }
9
+
10
+ export function CircularStepper({
11
+ isActive,
12
+ currentStep,
13
+ totalSteps,
14
+ size = 40,
15
+ }: CircularStepperProps) {
16
+ const radius = (size - 2) / 2;
17
+ const circumference = 2 * Math.PI * radius;
18
+ const progress = (currentStep / totalSteps) * circumference;
19
+
20
+ return (
21
+ <div className="relative [&_svg]:w-full [&_svg]:h-full" style={{ width: size, height: size }}>
22
+ {/* Background circle */}
23
+ <svg className="absolute inset-0 transform">
24
+ <circle
25
+ cx={size / 2}
26
+ cy={size / 2}
27
+ r={radius}
28
+ stroke="currentColor"
29
+ strokeWidth="2"
30
+ fill="none"
31
+ className={cn(
32
+ 'transition-all duration-300',
33
+ isActive ? 'text-zinc-50' : 'text-zinc-200 dark:text-zinc-500'
34
+ )}
35
+ />
36
+ {/* Progress circle */}
37
+ <circle
38
+ cx={size / 2}
39
+ cy={size / 2}
40
+ r={radius}
41
+ stroke="currentColor"
42
+ strokeWidth="2"
43
+ fill="none"
44
+ strokeDasharray={circumference}
45
+ strokeDashoffset={circumference - progress}
46
+ className={cn(
47
+ 'transition-all duration-300',
48
+ isActive ? 'text-zinc-400 dark:text-zinc-800' : 'text-zinc-950 dark:text-emerald-300'
49
+ )}
50
+ strokeLinecap="round"
51
+ />
52
+ </svg>
53
+ {/* Step number */}
54
+ <div className="absolute inset-0 flex items-center justify-center">
55
+ <span
56
+ className={cn(
57
+ 'transition-all duration-300',
58
+ isActive ? 'text-zinc-200 dark:text-zinc-800' : 'text-zinc-950 dark:text-white'
59
+ )}
60
+ >
61
+ {currentStep}/{totalSteps}
62
+ </span>
63
+ </div>
64
+ </div>
65
+ );
66
+ }
67
+
68
+ import ActiveStep from '@/assets/icons/step_active.svg?react';
69
+ import InactiveStep from '@/assets/icons/step_inactive.svg?react';
70
+ import CheckedIcon from '@/assets/icons/checked.svg?react';
71
+
72
+ interface LinearStepperProps {
73
+ currentStep: number;
74
+ totalSteps: number;
75
+ stepLabels: readonly string[];
76
+ className?: string;
77
+ isCompleted: boolean;
78
+ }
79
+
80
+ export function LinearStepper({
81
+ currentStep,
82
+ totalSteps,
83
+ stepLabels,
84
+ className,
85
+ isCompleted,
86
+ }: LinearStepperProps) {
87
+ // Calculate progress percentage
88
+ const progressPercentage = isCompleted
89
+ ? 100
90
+ : Math.min(((currentStep - 1) / totalSteps) * 100 + currentStep, 100);
91
+
92
+ return (
93
+ <div className={cn('w-full space-y-3', className)}>
94
+ {/* Progress Bar */}
95
+ <div className="relative w-full h-2 bg-zinc-200 dark:bg-zinc-600 rounded-full overflow-hidden">
96
+ <div
97
+ className="absolute top-0 left-0 h-full bg-zinc-950 dark:bg-white transition-all duration-500 ease-in-out"
98
+ style={{ width: `${progressPercentage}%` }}
99
+ />
100
+ </div>
101
+
102
+ {/* Step Labels */}
103
+ <div className="flex justify-start items-center gap-6 w-full">
104
+ {stepLabels.map((label, index) => {
105
+ const stepNumber = index + 1;
106
+ const stepIsCompleted = stepNumber < currentStep || isCompleted;
107
+ const isCurrent = stepNumber === currentStep;
108
+
109
+ return (
110
+ <div key={stepNumber} className="flex flex-row items-start justify-start gap-1 w-full">
111
+ {/* Step Number */}
112
+ <div className="w-5 h-5 flex items-center justify-center">
113
+ {stepIsCompleted ? (
114
+ <CheckedIcon className="w-5 h-5" />
115
+ ) : isCurrent ? (
116
+ <ActiveStep className="w-5 h-5 dark:text-white" />
117
+ ) : (
118
+ <InactiveStep className="w-5 h-5 dark:text-neutral-400" />
119
+ )}
120
+ </div>
121
+
122
+ {/* Step Label */}
123
+ <span
124
+ className={cn(
125
+ 'text-sm text-center transition-colors duration-300',
126
+ stepIsCompleted || isCurrent
127
+ ? 'text-zinc-950 dark:text-white'
128
+ : 'text-zinc-500 dark:text-neutral-400'
129
+ )}
130
+ >
131
+ {label}
132
+ </span>
133
+ </div>
134
+ );
135
+ })}
136
+ </div>
137
+ </div>
138
+ );
139
+ }
@@ -0,0 +1,58 @@
1
+ import { Sun, Moon, Monitor } from 'lucide-react';
2
+ import { useTheme } from '@/lib/contexts/ThemeContext';
3
+ import {
4
+ DropdownMenu,
5
+ DropdownMenuContent,
6
+ DropdownMenuItem,
7
+ DropdownMenuTrigger,
8
+ } from '@/components/radix/DropdownMenu';
9
+ import { Button } from '@/components/radix/Button';
10
+
11
+ export function ThemeToggle() {
12
+ const { theme, resolvedTheme, setTheme } = useTheme();
13
+
14
+ return (
15
+ <DropdownMenu>
16
+ <DropdownMenuTrigger asChild>
17
+ <Button
18
+ variant="ghost"
19
+ size="icon"
20
+ className="h-9 w-9 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800"
21
+ aria-label="Toggle theme"
22
+ >
23
+ {resolvedTheme === 'light' ? (
24
+ <Sun className="h-5 w-5 text-gray-600 dark:text-gray-400" />
25
+ ) : (
26
+ <Moon className="h-5 w-5 text-gray-600 dark:text-gray-400" />
27
+ )}
28
+ </Button>
29
+ </DropdownMenuTrigger>
30
+ <DropdownMenuContent align="end" className="w-36">
31
+ <DropdownMenuItem
32
+ onClick={() => setTheme('light')}
33
+ className="flex items-center gap-2 cursor-pointer"
34
+ >
35
+ <Sun className="h-4 w-4" />
36
+ <span>Light</span>
37
+ {theme === 'light' && <span className="ml-auto text-xs">✓</span>}
38
+ </DropdownMenuItem>
39
+ <DropdownMenuItem
40
+ onClick={() => setTheme('dark')}
41
+ className="flex items-center gap-2 cursor-pointer"
42
+ >
43
+ <Moon className="h-4 w-4" />
44
+ <span>Dark</span>
45
+ {theme === 'dark' && <span className="ml-auto text-xs">✓</span>}
46
+ </DropdownMenuItem>
47
+ <DropdownMenuItem
48
+ onClick={() => setTheme('system')}
49
+ className="flex items-center gap-2 cursor-pointer"
50
+ >
51
+ <Monitor className="h-4 w-4" />
52
+ <span>System</span>
53
+ {theme === 'system' && <span className="ml-auto text-xs">✓</span>}
54
+ </DropdownMenuItem>
55
+ </DropdownMenuContent>
56
+ </DropdownMenu>
57
+ );
58
+ }
@@ -0,0 +1,20 @@
1
+ import { cn } from '@/lib/utils/utils';
2
+
3
+ interface TypeBadgeProps {
4
+ type: string;
5
+ className?: string;
6
+ }
7
+
8
+ export function TypeBadge({ type, className }: TypeBadgeProps) {
9
+ return (
10
+ <div
11
+ className={cn(
12
+ 'inline-flex items-center justify-center px-1.5 py-0.5 rounded',
13
+ 'bg-white border border-zinc-200 dark:bg-neutral-900 dark:border-neutral-700',
14
+ className
15
+ )}
16
+ >
17
+ <span className="text-xs font-normal text-zinc-500 dark:text-neutral-400">{type}</span>
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,264 @@
1
+ import '@/rdg.css';
2
+ import { useMemo, useCallback } from 'react';
3
+ import ReactDataGrid, {
4
+ type Column,
5
+ type SortColumn,
6
+ SelectColumn,
7
+ SELECT_COLUMN_KEY,
8
+ type CellClickArgs,
9
+ type CellMouseEvent,
10
+ type RenderCellProps,
11
+ } from 'react-data-grid';
12
+ import { cn } from '@/lib/utils/utils';
13
+ import { PaginationControls } from '../PaginationControls';
14
+ import { Checkbox } from '../Checkbox';
15
+ import { useTheme } from '@/lib/contexts/ThemeContext';
16
+ import type { DataGridColumn, DataGridRow, DataGridRowType } from './datagridTypes';
17
+ import SortableHeaderRenderer from './SortableHeader';
18
+
19
+ // Generic DataGrid props
20
+ export interface DataGridProps<TRow extends DataGridRowType = DataGridRow> {
21
+ data: TRow[];
22
+ columns: DataGridColumn<TRow>[];
23
+ loading?: boolean;
24
+ isSorting?: boolean;
25
+ isRefreshing?: boolean;
26
+ selectedRows?: Set<string>;
27
+ onSelectedRowsChange?: (selectedRows: Set<string>) => void;
28
+ sortColumns?: SortColumn[];
29
+ onSortColumnsChange?: (sortColumns: SortColumn[]) => void;
30
+ onCellClick?: (args: CellClickArgs<TRow>, event: CellMouseEvent) => void;
31
+ currentPage?: number;
32
+ totalPages?: number;
33
+ pageSize?: number;
34
+ totalRecords?: number;
35
+ onPageChange?: (page: number) => void;
36
+ emptyStateTitle?: string;
37
+ emptyStateActionText?: string;
38
+ onEmptyStateAction?: () => void;
39
+ rowKeyGetter?: (row: TRow) => string;
40
+ className?: string;
41
+ showSelection?: boolean;
42
+ showPagination?: boolean;
43
+ showTypeBadge?: boolean;
44
+ }
45
+
46
+ // Main DataGrid component
47
+ export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
48
+ data,
49
+ columns,
50
+ loading = false,
51
+ isSorting = false,
52
+ isRefreshing = false,
53
+ selectedRows,
54
+ onSelectedRowsChange,
55
+ sortColumns,
56
+ onSortColumnsChange,
57
+ onCellClick,
58
+ currentPage,
59
+ totalPages,
60
+ pageSize,
61
+ totalRecords,
62
+ onPageChange,
63
+ emptyStateTitle = 'No data available',
64
+ emptyStateActionText,
65
+ onEmptyStateAction,
66
+ rowKeyGetter,
67
+ className,
68
+ showSelection = false,
69
+ showPagination = true,
70
+ showTypeBadge = true,
71
+ }: DataGridProps<TRow>) {
72
+ const { resolvedTheme } = useTheme();
73
+ // Convert columns to react-data-grid format
74
+ const gridColumns = useMemo(() => {
75
+ const cols: Column<TRow>[] = [];
76
+
77
+ // Add selection column if enabled and not hidden
78
+ if (showSelection && selectedRows !== undefined && onSelectedRowsChange) {
79
+ cols.push({
80
+ ...SelectColumn,
81
+ key: SELECT_COLUMN_KEY,
82
+ frozen: true,
83
+ width: 45,
84
+ minWidth: 45,
85
+ maxWidth: 45,
86
+ resizable: false,
87
+ renderCell: ({ row, tabIndex }) => (
88
+ <Checkbox
89
+ checked={selectedRows.has(String(row.id))}
90
+ onChange={(checked) => {
91
+ const newSelectedRows = new Set(selectedRows);
92
+ if (checked) {
93
+ newSelectedRows.add(String(row.id));
94
+ } else {
95
+ newSelectedRows.delete(String(row.id));
96
+ }
97
+ onSelectedRowsChange(newSelectedRows);
98
+ }}
99
+ tabIndex={tabIndex}
100
+ />
101
+ ),
102
+ renderHeaderCell: () => {
103
+ const selectedCount = data.filter((row) => selectedRows.has(String(row.id))).length;
104
+ const totalCount = data.length;
105
+ const isAllSelected = totalCount > 0 && selectedCount === totalCount;
106
+ const isPartiallySelected = selectedCount > 0 && selectedCount < totalCount;
107
+
108
+ return (
109
+ <Checkbox
110
+ checked={isAllSelected}
111
+ indeterminate={isPartiallySelected}
112
+ onChange={(checked) => {
113
+ const newSelectedRows = new Set(selectedRows);
114
+ if (checked) {
115
+ // Select all
116
+ data.forEach((row) => newSelectedRows.add(String(row.id)));
117
+ } else {
118
+ // Unselect all
119
+ data.forEach((row) => newSelectedRows.delete(String(row.id)));
120
+ }
121
+ onSelectedRowsChange(newSelectedRows);
122
+ }}
123
+ />
124
+ );
125
+ },
126
+ });
127
+ }
128
+
129
+ // Add data columns
130
+ columns.forEach((col) => {
131
+ const currentSort = sortColumns?.find((sort) => sort.columnKey === col.key);
132
+ const sortDirection = currentSort?.direction;
133
+
134
+ const gridColumn: Column<TRow> = {
135
+ ...col,
136
+ key: col.key,
137
+ name: col.name,
138
+ width: col.width,
139
+ minWidth: col.minWidth || 80,
140
+ maxWidth: col.maxWidth,
141
+ resizable: col.resizable !== false,
142
+ sortable: col.sortable !== false,
143
+ sortDescendingFirst: col.sortDescendingFirst ?? true,
144
+ editable: col.editable && !col.isPrimaryKey,
145
+ renderCell:
146
+ col.renderCell ||
147
+ (({ row, column }: RenderCellProps<TRow>) => {
148
+ const value = row[column.key];
149
+ const displayValue = String(value ?? '');
150
+ return (
151
+ <div className="w-full h-full flex items-center">
152
+ <span className="truncate dark:text-zinc-300" title={displayValue}>
153
+ {displayValue}
154
+ </span>
155
+ </div>
156
+ );
157
+ }),
158
+ renderEditCell: col.renderEditCell,
159
+ renderHeaderCell:
160
+ col.renderHeaderCell ||
161
+ (() => (
162
+ <SortableHeaderRenderer<TRow>
163
+ column={col}
164
+ sortDirection={sortDirection}
165
+ columnType={col.type}
166
+ showTypeBadge={showTypeBadge}
167
+ />
168
+ )),
169
+ };
170
+
171
+ cols.push(gridColumn);
172
+ });
173
+
174
+ return cols;
175
+ }, [
176
+ columns,
177
+ selectedRows,
178
+ onSelectedRowsChange,
179
+ data,
180
+ sortColumns,
181
+ showSelection,
182
+ showTypeBadge,
183
+ ]);
184
+
185
+ // Default row key getter
186
+ const defaultRowKeyGetter = useCallback((row: TRow) => row.id || Math.random().toString(), []);
187
+ const keyGetter = rowKeyGetter || defaultRowKeyGetter;
188
+
189
+ // Loading state - only show full loading screen if not sorting
190
+ if (loading && !isSorting) {
191
+ return (
192
+ <div className="h-full flex items-center justify-center bg-white dark:bg-neutral-800">
193
+ <div className="text-gray-500 dark:text-zinc-400">Loading...</div>
194
+ </div>
195
+ );
196
+ }
197
+
198
+ return (
199
+ <div
200
+ className={cn(
201
+ 'h-full flex flex-col bg-bg-gray dark:bg-neutral-800 overflow-hidden',
202
+ className
203
+ )}
204
+ >
205
+ <div className="flex-1 overflow-hidden relative mx-3 border border-border-gray dark:border-0">
206
+ <ReactDataGrid
207
+ columns={gridColumns}
208
+ rows={isRefreshing ? [] : data}
209
+ rowKeyGetter={keyGetter}
210
+ onRowsChange={() => {}}
211
+ selectedRows={selectedRows}
212
+ onSelectedRowsChange={onSelectedRowsChange}
213
+ sortColumns={sortColumns || []}
214
+ onSortColumnsChange={onSortColumnsChange}
215
+ onCellClick={onCellClick}
216
+ className={`h-full fill-grid ${resolvedTheme === 'dark' ? 'rdg-dark' : 'rdg-light'}`}
217
+ headerRowHeight={36}
218
+ rowHeight={36}
219
+ enableVirtualization={true}
220
+ renderers={{
221
+ noRowsFallback: (
222
+ <div className="absolute inset-x-0 top-0 mt-13 py-8 flex items-center justify-center bg-white dark:bg-neutral-800">
223
+ <div className="flex flex-col gap-1 items-center">
224
+ <div className="flex flex-row gap-2.5 items-center">
225
+ <div className="text-sm text-zinc-500 dark:text-zinc-400">
226
+ {emptyStateTitle}
227
+ </div>
228
+ {emptyStateActionText && onEmptyStateAction && (
229
+ <button
230
+ onClick={onEmptyStateAction}
231
+ className="inline-flex items-center text-sm font-medium text-chart-blue-dark focus:outline-none focus:ring-0 dark:text-zinc-400"
232
+ >
233
+ {emptyStateActionText}
234
+ </button>
235
+ )}
236
+ </div>
237
+ </div>
238
+ </div>
239
+ ),
240
+ }}
241
+ />
242
+
243
+ {/* Loading mask overlay */}
244
+ {isRefreshing && (
245
+ <div className="absolute inset-0 bg-white dark:bg-neutral-800 flex items-center justify-center z-50 mt-9">
246
+ <div className="flex items-center gap-1">
247
+ <div className="w-5 h-5 border-2 border-zinc-500 dark:border-neutral-700 border-t-transparent rounded-full animate-spin" />
248
+ <span className="text-sm text-zinc-500 dark:text-zinc-400">Loading</span>
249
+ </div>
250
+ </div>
251
+ )}
252
+ </div>
253
+ {showPagination && onPageChange && (
254
+ <PaginationControls
255
+ currentPage={currentPage}
256
+ totalPages={totalPages}
257
+ onPageChange={onPageChange}
258
+ totalRecords={totalRecords}
259
+ pageSize={pageSize}
260
+ />
261
+ )}
262
+ </div>
263
+ );
264
+ }