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,76 @@
1
+ import {
2
+ Dialog,
3
+ DialogContent,
4
+ DialogHeader,
5
+ DialogTitle,
6
+ DialogFooter,
7
+ } from '@/components/radix/Dialog';
8
+ import { Button } from '@/components/radix/Button';
9
+ import {
10
+ AIConfigurationWithUsageSchema,
11
+ CreateAIConfigurationRequest,
12
+ UpdateAIConfigurationRequest,
13
+ } from '@insforge/shared-schemas';
14
+ import { AIConfigForm } from './AIConfigForm';
15
+
16
+ interface AIConfigDialogProps {
17
+ open: boolean;
18
+ onOpenChange: (open: boolean) => void;
19
+ mode: 'create' | 'edit';
20
+ editingConfig?: AIConfigurationWithUsageSchema;
21
+ onSuccess?: (config: CreateAIConfigurationRequest | UpdateAIConfigurationRequest) => void;
22
+ }
23
+
24
+ export function AIConfigDialog({
25
+ open,
26
+ onOpenChange,
27
+ mode,
28
+ editingConfig,
29
+ onSuccess,
30
+ }: AIConfigDialogProps) {
31
+ const handleFormSubmit = (data: CreateAIConfigurationRequest | UpdateAIConfigurationRequest) => {
32
+ onSuccess?.(data);
33
+ onOpenChange(false);
34
+ };
35
+
36
+ const handleCancel = () => {
37
+ onOpenChange(false);
38
+ };
39
+
40
+ return (
41
+ <Dialog open={open} onOpenChange={onOpenChange}>
42
+ <DialogContent
43
+ aria-describedby={undefined}
44
+ className="max-w-[640px] p-0 border-zinc-200 shadow-[0px_1px_3px_0px_rgba(0,0,0,0.1)]"
45
+ >
46
+ <div className="flex flex-col">
47
+ <DialogHeader className="px-6 py-3 flex flex-col gap-1 justify-start border-b border-zinc-200 dark:border-neutral-700">
48
+ <DialogTitle className="text-lg font-semibold text-zinc-950 dark:text-white">
49
+ {mode === 'create' ? 'New AI Integration' : 'Edit System Prompt'}
50
+ </DialogTitle>
51
+ </DialogHeader>
52
+
53
+ <AIConfigForm mode={mode} editingConfig={editingConfig} onSubmit={handleFormSubmit} />
54
+
55
+ <DialogFooter className="p-6 gap-3 border-t border-zinc-200 dark:border-neutral-700">
56
+ <Button
57
+ type="button"
58
+ variant="outline"
59
+ onClick={handleCancel}
60
+ className="h-9 px-3 py-2 rounded-sm text-sm font-medium dark:bg-neutral-600 dark:text-zinc-300 dark:border-neutral-600 dark:hover:bg-neutral-700"
61
+ >
62
+ Cancel
63
+ </Button>
64
+ <Button
65
+ type="submit"
66
+ form="ai-config-form"
67
+ className="h-9 px-3 py-2 rounded-sm text-sm font-medium bg-zinc-950 text-white hover:bg-zinc-800 disabled:opacity-40 dark:bg-emerald-300 dark:text-zinc-950 dark:hover:bg-emerald-400"
68
+ >
69
+ {mode === 'create' ? 'Add Integration' : 'Save'}
70
+ </Button>
71
+ </DialogFooter>
72
+ </div>
73
+ </DialogContent>
74
+ </Dialog>
75
+ );
76
+ }
@@ -0,0 +1,222 @@
1
+ import { useState, useEffect, useMemo, useCallback } from 'react';
2
+ import { useForm } from 'react-hook-form';
3
+ import { zodResolver } from '@hookform/resolvers/zod';
4
+ import { useAIConfigs } from '../hooks/useAIConfigs';
5
+ import {
6
+ AIConfigurationWithUsageSchema,
7
+ createAIConfigurationRequestSchema,
8
+ updateAIConfigurationRequestSchema,
9
+ CreateAIConfigurationRequest,
10
+ UpdateAIConfigurationRequest,
11
+ ModalitySchema,
12
+ } from '@insforge/shared-schemas';
13
+ import { useToast } from '@/lib/hooks/useToast';
14
+ import { ModalityField } from './fields/ModalityField';
15
+ import { ModelSelectionField } from './fields/ModelSelectionField';
16
+ import { SystemPromptField } from './fields/SystemPromptField';
17
+
18
+ interface AIConfigFormProps {
19
+ mode: 'create' | 'edit';
20
+ editingConfig?: AIConfigurationWithUsageSchema;
21
+ onSubmit: (data: CreateAIConfigurationRequest | UpdateAIConfigurationRequest) => void;
22
+ }
23
+
24
+ export function AIConfigForm({ mode, editingConfig, onSubmit }: AIConfigFormProps) {
25
+ const { allConfiguredModels, configurations, getFilteredModels } = useAIConfigs();
26
+ const { showToast } = useToast();
27
+ const isCreateMode = mode === 'create';
28
+
29
+ // State for create mode
30
+ const [selectedInputModality, setSelectedInputModality] = useState<ModalitySchema[]>(
31
+ isCreateMode ? ['text'] : []
32
+ );
33
+ const [selectedOutputModality, setSelectedOutputModality] = useState<ModalitySchema[]>(
34
+ isCreateMode ? ['text'] : []
35
+ );
36
+
37
+ // Initialize form based on mode
38
+ const getInitialValues = useCallback(():
39
+ | CreateAIConfigurationRequest
40
+ | UpdateAIConfigurationRequest => {
41
+ if (isCreateMode) {
42
+ return {
43
+ inputModality: ['text'],
44
+ outputModality: ['text'],
45
+ provider: 'openrouter',
46
+ modelId: '',
47
+ systemPrompt: undefined,
48
+ };
49
+ } else {
50
+ return {
51
+ systemPrompt: editingConfig?.systemPrompt ?? null,
52
+ };
53
+ }
54
+ }, [isCreateMode, editingConfig?.systemPrompt]);
55
+
56
+ // Create form instances
57
+ const createForm = useForm<CreateAIConfigurationRequest>({
58
+ resolver: zodResolver(createAIConfigurationRequestSchema),
59
+ defaultValues: isCreateMode ? (getInitialValues() as CreateAIConfigurationRequest) : undefined,
60
+ });
61
+
62
+ const editForm = useForm<UpdateAIConfigurationRequest>({
63
+ resolver: zodResolver(updateAIConfigurationRequestSchema),
64
+ defaultValues: !isCreateMode ? (getInitialValues() as UpdateAIConfigurationRequest) : undefined,
65
+ });
66
+
67
+ const form = isCreateMode ? createForm : editForm;
68
+
69
+ // Get filtered models for create mode
70
+ const filteredModels = useMemo(() => {
71
+ if (!isCreateMode) {
72
+ return [];
73
+ }
74
+ return getFilteredModels(selectedInputModality, selectedOutputModality);
75
+ }, [isCreateMode, getFilteredModels, selectedInputModality, selectedOutputModality]);
76
+
77
+ // Initialize form values
78
+ useEffect(() => {
79
+ const initialValues = getInitialValues();
80
+ if (isCreateMode) {
81
+ const createValues = initialValues as CreateAIConfigurationRequest;
82
+ setSelectedInputModality(createValues.inputModality);
83
+ setSelectedOutputModality(createValues.outputModality);
84
+ createForm.reset(createValues);
85
+ } else {
86
+ editForm.reset(initialValues as UpdateAIConfigurationRequest);
87
+ }
88
+ }, [isCreateMode, getInitialValues, createForm, editForm]);
89
+
90
+ // Reset model selection when modalities change (create mode only)
91
+ useEffect(() => {
92
+ if (isCreateMode) {
93
+ createForm.setValue('modelId', '');
94
+ }
95
+ }, [selectedInputModality, selectedOutputModality, isCreateMode, createForm]);
96
+
97
+ // Check if a model is already configured (create mode only)
98
+ const isModelConfigured = useCallback(
99
+ (modelId: string) => {
100
+ if (!isCreateMode || !configurations) {
101
+ return false;
102
+ }
103
+
104
+ return configurations.some((config) => config.modelId === modelId);
105
+ },
106
+ [isCreateMode, configurations]
107
+ );
108
+
109
+ // Check if model selection should be disabled (create mode only)
110
+ const isModelSelectionDisabled = useMemo(() => {
111
+ if (!isCreateMode) {
112
+ return true;
113
+ }
114
+ return selectedInputModality.length === 0 || selectedOutputModality.length === 0;
115
+ }, [isCreateMode, selectedInputModality.length, selectedOutputModality.length]);
116
+ const selectedModelId = createForm.watch('modelId');
117
+
118
+ const handleModelChange = useCallback(
119
+ (modelId: string) => {
120
+ createForm.setValue('modelId', modelId);
121
+ },
122
+ [createForm]
123
+ );
124
+
125
+ const handleFormSubmit = useCallback(
126
+ (data: CreateAIConfigurationRequest | UpdateAIConfigurationRequest) => {
127
+ if (isCreateMode) {
128
+ const createData = data as CreateAIConfigurationRequest;
129
+
130
+ // Find the selected model to get its actual architecture
131
+ const selectedModel = allConfiguredModels.find((model) => model.id === createData.modelId);
132
+
133
+ if (!selectedModel) {
134
+ showToast('Selected model not found', 'error');
135
+ return;
136
+ }
137
+
138
+ // Filter to only supported modalities (text and image)
139
+ const supportedModalities: ModalitySchema[] = ['text', 'image'];
140
+ const rawInputModality = selectedModel.architecture?.inputModalities || ['text'];
141
+ const rawOutputModality = selectedModel.architecture?.outputModalities || ['text'];
142
+
143
+ // Filter out unsupported modalities
144
+ const filteredInputModality = rawInputModality.filter(
145
+ (modality): modality is ModalitySchema =>
146
+ supportedModalities.includes(modality as ModalitySchema)
147
+ );
148
+ const filteredOutputModality = rawOutputModality.filter(
149
+ (modality): modality is ModalitySchema =>
150
+ supportedModalities.includes(modality as ModalitySchema)
151
+ );
152
+
153
+ const finalCreateData: CreateAIConfigurationRequest = {
154
+ ...createData,
155
+ inputModality: filteredInputModality,
156
+ outputModality: filteredOutputModality,
157
+ };
158
+
159
+ onSubmit(finalCreateData);
160
+ } else {
161
+ // Edit mode - just pass the data as is
162
+ onSubmit(data as UpdateAIConfigurationRequest);
163
+ }
164
+ },
165
+ [isCreateMode, onSubmit, allConfiguredModels, showToast]
166
+ );
167
+
168
+ return (
169
+ <form
170
+ id="ai-config-form"
171
+ onSubmit={(e) => {
172
+ e.preventDefault();
173
+ void form.handleSubmit(handleFormSubmit)();
174
+ }}
175
+ className="flex flex-col"
176
+ >
177
+ <div className="flex flex-col gap-6 p-6">
178
+ <div className="flex flex-col gap-6 w-full items-stretch">
179
+ {isCreateMode ? (
180
+ <>
181
+ {/* Input modality field */}
182
+ <ModalityField
183
+ fieldType="input"
184
+ value={selectedInputModality}
185
+ onChange={setSelectedInputModality}
186
+ />
187
+
188
+ {/* Output modality field */}
189
+ <ModalityField
190
+ fieldType="output"
191
+ value={selectedOutputModality}
192
+ onChange={setSelectedOutputModality}
193
+ />
194
+
195
+ {/* Model selection field */}
196
+ <ModelSelectionField
197
+ models={filteredModels}
198
+ selectedModelId={selectedModelId}
199
+ onModelChange={handleModelChange}
200
+ isModelConfigured={isModelConfigured}
201
+ disabled={isModelSelectionDisabled}
202
+ />
203
+ </>
204
+ ) : null}
205
+
206
+ {/* System prompt field */}
207
+ {isCreateMode ? (
208
+ <SystemPromptField<CreateAIConfigurationRequest>
209
+ register={createForm.register}
210
+ error={createForm.formState.errors.systemPrompt}
211
+ />
212
+ ) : (
213
+ <SystemPromptField<UpdateAIConfigurationRequest>
214
+ register={editForm.register}
215
+ error={editForm.formState.errors.systemPrompt}
216
+ />
217
+ )}
218
+ </div>
219
+ </div>
220
+ </form>
221
+ );
222
+ }
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { Box } from 'lucide-react';
3
+
4
+ const AIEmptyState: React.FC = () => {
5
+ return (
6
+ <div className="flex flex-col items-center justify-center py-8 text-center gap-3 rounded-[8px] bg-neutral-100 dark:bg-[#333333]">
7
+ <Box size={40} className="text-neutral-400 dark:text-neutral-600" />
8
+ <div className="flex flex-col items-center justify-center gap-1">
9
+ <p className="text-sm font-medium text-zinc-950 dark:text-white">No AI Integration Yet</p>
10
+ <p className="text-neutral-500 dark:text-neutral-400 text-xs">
11
+ Add your first integration to get started
12
+ </p>
13
+ </div>
14
+ </div>
15
+ );
16
+ };
17
+
18
+ export default AIEmptyState;
@@ -0,0 +1,87 @@
1
+ import { Label } from '@/components/radix/Label';
2
+ import { Checkbox } from '@/components/Checkbox';
3
+ import { getModalityIcon } from '../../helpers';
4
+ import { ModalitySchema } from '@insforge/shared-schemas';
5
+
6
+ interface ModalityFieldProps {
7
+ fieldType: 'input' | 'output';
8
+ value: ModalitySchema[];
9
+ onChange: (value: ModalitySchema[]) => void;
10
+ isReadOnly?: boolean;
11
+ }
12
+
13
+ const modalityOptions: Array<{
14
+ value: ModalitySchema;
15
+ label: string;
16
+ icon: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
17
+ }> = [
18
+ {
19
+ value: 'text',
20
+ label: 'Text',
21
+ icon: getModalityIcon('text'),
22
+ },
23
+ {
24
+ value: 'image',
25
+ label: 'Image',
26
+ icon: getModalityIcon('image'),
27
+ },
28
+ ];
29
+
30
+ export function ModalityField({
31
+ fieldType,
32
+ value,
33
+ onChange,
34
+ isReadOnly = false,
35
+ }: ModalityFieldProps) {
36
+ const label = fieldType.charAt(0).toUpperCase() + fieldType.slice(1);
37
+
38
+ const handleCheckboxChange = (modalityValue: ModalitySchema, checked: boolean) => {
39
+ if (checked) {
40
+ onChange([...value, modalityValue]);
41
+ } else {
42
+ onChange(value.filter((v) => v !== modalityValue));
43
+ }
44
+ };
45
+
46
+ if (isReadOnly) {
47
+ return (
48
+ <div className="flex flex-row gap-10 items-center">
49
+ <Label className="w-34 text-sm font-normal text-zinc-950 dark:text-neutral-50">
50
+ {label} <span className="text-red-500">*</span>
51
+ </Label>
52
+ <div className="w-full flex items-center h-9 px-3 py-2 text-sm bg-zinc-50 dark:bg-neutral-900 border border-zinc-200 dark:border-neutral-700 rounded-md text-zinc-600 dark:text-zinc-400">
53
+ {value.length > 0 ? value.join(', ') : 'None selected'}
54
+ </div>
55
+ </div>
56
+ );
57
+ }
58
+
59
+ return (
60
+ <div className="flex flex-row gap-10 items-center">
61
+ <Label className="w-34 text-sm font-normal text-zinc-950 dark:text-neutral-50">
62
+ {label} <span className="text-red-500">*</span>
63
+ </Label>
64
+ <div className="w-full flex flex-row gap-10">
65
+ {modalityOptions.map((option) => {
66
+ const isChecked = value.includes(option.value);
67
+
68
+ return (
69
+ <div key={option.value} className="flex items-center space-x-2">
70
+ <Checkbox
71
+ checked={isChecked}
72
+ onChange={(checked: boolean) => handleCheckboxChange(option.value, checked)}
73
+ className="data-[state=checked]:bg-zinc-950 data-[state=checked]:border-zinc-950 dark:data-[state=checked]:bg-emerald-300 dark:data-[state=checked]:border-emerald-300"
74
+ />
75
+ <Label
76
+ className="flex items-center gap-2 text-sm font-normal text-zinc-950 dark:text-neutral-50 cursor-pointer"
77
+ onClick={() => handleCheckboxChange(option.value, !isChecked)}
78
+ >
79
+ {option.label}
80
+ </Label>
81
+ </div>
82
+ );
83
+ })}
84
+ </div>
85
+ </div>
86
+ );
87
+ }
@@ -0,0 +1,134 @@
1
+ import { Label } from '@/components/radix/Label';
2
+ import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/radix/Select';
3
+ import { ModelOption } from '../../helpers';
4
+
5
+ interface ModelSelectionFieldProps {
6
+ models: ModelOption[];
7
+ selectedModelId?: string;
8
+ onModelChange: (modelId: string) => void;
9
+ isReadOnly?: boolean;
10
+ readOnlyModelId?: string;
11
+ isModelConfigured?: (modelId: string) => boolean;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ export function ModelSelectionField({
16
+ models,
17
+ selectedModelId,
18
+ onModelChange,
19
+ isReadOnly = false,
20
+ readOnlyModelId,
21
+ isModelConfigured,
22
+ disabled = false,
23
+ }: ModelSelectionFieldProps) {
24
+ const hasModels = models.length > 0;
25
+
26
+ if (isReadOnly) {
27
+ return (
28
+ <div className="flex flex-row gap-10 items-center">
29
+ <Label className="w-34 text-sm font-normal text-zinc-950 dark:text-neutral-50">
30
+ AI Model <span className="text-red-500">*</span>
31
+ </Label>
32
+ <div className="w-full flex items-center h-9 px-3 py-2 text-sm bg-zinc-50 dark:bg-neutral-900 border border-zinc-200 dark:border-neutral-700 rounded-md text-zinc-600 dark:text-zinc-400">
33
+ {readOnlyModelId}
34
+ </div>
35
+ </div>
36
+ );
37
+ }
38
+
39
+ return (
40
+ <div className="flex flex-row gap-10 items-center">
41
+ <Label className="w-34 text-sm font-normal text-zinc-950 dark:text-neutral-50">
42
+ AI Model <span className="text-red-500">*</span>
43
+ </Label>
44
+ <Select
45
+ value={selectedModelId || ''}
46
+ onValueChange={(value) => {
47
+ if (value) {
48
+ onModelChange(value);
49
+ }
50
+ }}
51
+ disabled={!hasModels || disabled}
52
+ >
53
+ <SelectTrigger
54
+ id="model"
55
+ className="w-full h-9 bg-transparent dark:bg-neutral-900 dark:border-neutral-700 dark:text-white"
56
+ >
57
+ <div className="flex items-center justify-between w-full">
58
+ {selectedModelId ? (
59
+ (() => {
60
+ const selectedModel = models.find((m) => m.value === selectedModelId);
61
+ if (selectedModel) {
62
+ return (
63
+ <>
64
+ <div className="flex items-center gap-2">
65
+ {selectedModel.logo ? (
66
+ <selectedModel.logo className="w-5 h-5" />
67
+ ) : (
68
+ <div className="w-5 h-5 bg-gray-500 rounded flex items-center justify-center text-white text-xs font-bold">
69
+ {selectedModel.company.slice(0, 1).toUpperCase()}
70
+ </div>
71
+ )}
72
+ <span className="truncate">{selectedModel.label}</span>
73
+ </div>
74
+ <div className={`text-xs font-medium ${selectedModel.priceColor}`}>
75
+ {selectedModel.priceLevel}
76
+ </div>
77
+ </>
78
+ );
79
+ }
80
+ return <span className="text-zinc-500 dark:text-zinc-400">{selectedModelId}</span>;
81
+ })()
82
+ ) : (
83
+ <span className="text-zinc-500 dark:text-zinc-400">
84
+ {hasModels ? 'Select model' : 'No models available'}
85
+ </span>
86
+ )}
87
+ </div>
88
+ </SelectTrigger>
89
+ <SelectContent className="dark:bg-neutral-900 dark:border-neutral-700">
90
+ {hasModels ? (
91
+ models.map((modelOption, index) => {
92
+ const isConfigured = isModelConfigured?.(modelOption.value) ?? false;
93
+ return (
94
+ <SelectItem
95
+ key={`${modelOption.value}-${index}`}
96
+ value={modelOption.value}
97
+ disabled={isConfigured}
98
+ className={
99
+ isConfigured
100
+ ? 'dark:text-zinc-500 text-zinc-400 cursor-not-allowed'
101
+ : 'dark:text-white dark:hover:bg-neutral-700'
102
+ }
103
+ >
104
+ <div className="flex items-center justify-between w-full">
105
+ <div className="flex items-center gap-2">
106
+ {modelOption.logo ? (
107
+ <modelOption.logo className="w-5 h-5" />
108
+ ) : (
109
+ <span className="w-5 h-5 bg-gray-500 rounded flex items-center justify-center text-white text-xs font-bold">
110
+ {modelOption.company.slice(0, 1).toUpperCase()}
111
+ </span>
112
+ )}
113
+ <span className="truncate flex-1">
114
+ {modelOption.label}
115
+ {isConfigured && <span className="text-sm"> (Already configured)</span>}
116
+ </span>
117
+ </div>
118
+ <span className={`items-end text-xs font-medium ${modelOption.priceColor}`}>
119
+ {modelOption.priceLevel}
120
+ </span>
121
+ </div>
122
+ </SelectItem>
123
+ );
124
+ })
125
+ ) : (
126
+ <SelectItem value="no-models" disabled className="dark:text-zinc-400">
127
+ No models available for selected input/output combination
128
+ </SelectItem>
129
+ )}
130
+ </SelectContent>
131
+ </Select>
132
+ </div>
133
+ );
134
+ }
@@ -0,0 +1,33 @@
1
+ import { UseFormRegister, FieldError, FieldValues, Path } from 'react-hook-form';
2
+ import { Label } from '@/components/radix/Label';
3
+ import { Textarea } from '@/components/radix/Textarea';
4
+
5
+ interface SystemPromptFieldProps<T extends FieldValues> {
6
+ register: UseFormRegister<T>;
7
+ error?: FieldError;
8
+ }
9
+
10
+ export function SystemPromptField<T extends FieldValues>({
11
+ register,
12
+ error,
13
+ }: SystemPromptFieldProps<T>) {
14
+ return (
15
+ <div className="flex flex-row gap-10 items-start">
16
+ <Label
17
+ htmlFor="systemPrompt"
18
+ className="text-sm font-normal text-zinc-950 dark:text-neutral-50 whitespace-nowrap"
19
+ >
20
+ System Prompt
21
+ </Label>
22
+ <div className="flex flex-col gap-1 w-full">
23
+ <Textarea
24
+ id="systemPrompt"
25
+ {...register('systemPrompt' as Path<T>)}
26
+ placeholder="Enter system prompt..."
27
+ className="w-full min-h-[160px] resize-none bg-transparent dark:bg-neutral-900 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
28
+ />
29
+ {error && <p className="text-sm text-red-600 dark:text-red-500">{error.message}</p>}
30
+ </div>
31
+ </div>
32
+ );
33
+ }