insforge 1.3.0 → 1.4.8

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 (269) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/auth/package.json +5 -3
  3. package/auth/src/lib/broadcastService.ts +115 -117
  4. package/auth/src/lib/insforge.ts +8 -0
  5. package/auth/src/main.tsx +2 -4
  6. package/auth/src/pages/SignInPage.tsx +60 -60
  7. package/auth/src/pages/SignUpPage.tsx +60 -60
  8. package/auth/src/pages/VerifyEmailPage.tsx +18 -0
  9. package/auth/tsconfig.json +2 -1
  10. package/backend/package.json +10 -6
  11. package/backend/src/api/middlewares/rate-limiters.ts +127 -127
  12. package/backend/src/api/routes/ai/index.routes.ts +475 -468
  13. package/backend/src/api/routes/auth/index.routes.ts +85 -32
  14. package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
  15. package/backend/src/api/routes/database/index.routes.ts +2 -0
  16. package/backend/src/api/routes/database/records.routes.ts +39 -175
  17. package/backend/src/api/routes/database/rpc.routes.ts +69 -0
  18. package/backend/src/api/routes/deployments/index.routes.ts +192 -0
  19. package/backend/src/api/routes/docs/index.routes.ts +3 -2
  20. package/backend/src/api/routes/email/index.routes.ts +35 -35
  21. package/backend/src/api/routes/functions/index.routes.ts +3 -3
  22. package/backend/src/api/routes/metadata/index.routes.ts +26 -0
  23. package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
  24. package/backend/src/infra/database/database.manager.ts +0 -10
  25. package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
  26. package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
  27. package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
  28. package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
  29. package/backend/src/infra/security/token.manager.ts +1 -4
  30. package/backend/src/providers/ai/openrouter.provider.ts +12 -3
  31. package/backend/src/providers/database/base.provider.ts +39 -0
  32. package/backend/src/providers/database/cloud.provider.ts +159 -0
  33. package/backend/src/providers/deployments/vercel.provider.ts +516 -0
  34. package/backend/src/server.ts +19 -7
  35. package/backend/src/services/ai/ai-config.service.ts +6 -6
  36. package/backend/src/services/ai/ai-model.service.ts +60 -60
  37. package/backend/src/services/ai/ai-usage.service.ts +7 -7
  38. package/backend/src/services/ai/chat-completion.service.ts +415 -220
  39. package/backend/src/services/ai/helpers.ts +64 -64
  40. package/backend/src/services/ai/index.ts +13 -13
  41. package/backend/src/services/auth/auth-config.service.ts +4 -4
  42. package/backend/src/services/auth/auth-otp.service.ts +6 -6
  43. package/backend/src/services/auth/auth.service.ts +134 -74
  44. package/backend/src/services/auth/index.ts +4 -4
  45. package/backend/src/services/auth/oauth-config.service.ts +12 -12
  46. package/backend/src/services/database/database-advance.service.ts +19 -55
  47. package/backend/src/services/database/database-table.service.ts +38 -85
  48. package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
  49. package/backend/src/services/deployments/deployment.service.ts +693 -0
  50. package/backend/src/services/functions/function.service.ts +61 -41
  51. package/backend/src/services/logs/audit.service.ts +10 -10
  52. package/backend/src/services/secrets/secret.service.ts +101 -27
  53. package/backend/src/services/storage/storage.service.ts +30 -30
  54. package/backend/src/services/usage/usage.service.ts +6 -6
  55. package/backend/src/types/ai.ts +8 -0
  56. package/backend/src/types/auth.ts +5 -1
  57. package/backend/src/types/database.ts +2 -0
  58. package/backend/src/types/deployments.ts +33 -0
  59. package/backend/src/types/storage.ts +1 -1
  60. package/backend/src/types/webhooks.ts +45 -0
  61. package/backend/src/utils/cookies.ts +34 -35
  62. package/backend/src/utils/environment.ts +0 -14
  63. package/backend/src/utils/s3-config-loader.ts +64 -64
  64. package/backend/src/utils/seed.ts +334 -301
  65. package/backend/src/utils/sql-parser.ts +126 -0
  66. package/backend/src/utils/utils.ts +114 -114
  67. package/backend/src/utils/validations.ts +10 -10
  68. package/backend/tests/local/test-rpc.sh +141 -0
  69. package/backend/tests/local/test-secrets.sh +1 -1
  70. package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
  71. package/backend/tests/manual/test-rawsql-modes.sh +24 -24
  72. package/backend/tests/unit/database-advance.test.ts +326 -0
  73. package/backend/tests/unit/helpers.test.ts +2 -2
  74. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
  75. package/docker-compose.prod.yml +1 -1
  76. package/docker-compose.yml +1 -1
  77. package/docs/agent-docs/deployment.md +79 -0
  78. package/docs/changelog.mdx +165 -72
  79. package/docs/core-concepts/ai/architecture.mdx +1 -23
  80. package/docs/core-concepts/ai/sdk.mdx +26 -1
  81. package/docs/core-concepts/authentication/architecture.mdx +6 -8
  82. package/docs/core-concepts/authentication/sdk.mdx +387 -91
  83. package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
  84. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
  85. package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
  86. package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
  87. package/docs/core-concepts/database/architecture.mdx +58 -21
  88. package/docs/core-concepts/database/pgvector.mdx +138 -0
  89. package/docs/core-concepts/database/sdk.mdx +17 -17
  90. package/docs/core-concepts/deployments/architecture.mdx +152 -0
  91. package/docs/core-concepts/email/architecture.mdx +4 -2
  92. package/docs/core-concepts/functions/architecture.mdx +1 -1
  93. package/docs/core-concepts/functions/sdk.mdx +0 -1
  94. package/docs/core-concepts/realtime/architecture.mdx +1 -1
  95. package/docs/core-concepts/storage/architecture.mdx +1 -1
  96. package/docs/core-concepts/storage/sdk.mdx +25 -25
  97. package/docs/docs.json +14 -6
  98. package/docs/favicon.png +0 -0
  99. package/docs/favicon.svg +3 -18
  100. package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
  101. package/docs/images/changelog/dec-2025/moreModels.png +0 -0
  102. package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
  103. package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
  104. package/docs/images/changelog/dec-2025/realtime2.png +0 -0
  105. package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
  106. package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
  107. package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
  108. package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
  109. package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
  110. package/docs/images/mcp-setup/claude-code-connect.png +0 -0
  111. package/docs/images/mcp-setup/cline-1.png +0 -0
  112. package/docs/images/mcp-setup/cline-2.png +0 -0
  113. package/docs/images/mcp-setup/cline-3.png +0 -0
  114. package/docs/images/mcp-setup/connect-project.png +0 -0
  115. package/docs/images/mcp-setup/copilot-1.png +0 -0
  116. package/docs/images/mcp-setup/copilot-2.png +0 -0
  117. package/docs/images/mcp-setup/copilot-3.png +0 -0
  118. package/docs/images/mcp-setup/mcp-json-1.png +0 -0
  119. package/docs/images/mcp-setup/mcp-json-2.png +0 -0
  120. package/docs/images/mcp-setup/qoder-1.png +0 -0
  121. package/docs/images/mcp-setup/qoder-2.png +0 -0
  122. package/docs/images/mcp-setup/roocode-1.png +0 -0
  123. package/docs/images/mcp-setup/roocode-2.png +0 -0
  124. package/docs/images/mcp-setup/trae-1.png +0 -0
  125. package/docs/images/mcp-setup/trae-2.png +0 -0
  126. package/docs/images/mcp-setup/trae-3.png +0 -0
  127. package/docs/images/mcp-setup/trae-4.png +0 -0
  128. package/docs/images/mcp-setup/trae-5.png +0 -0
  129. package/docs/images/mcp-setup/windsurf-1.png +0 -0
  130. package/docs/images/mcp-setup/windsurf-2.png +0 -0
  131. package/docs/insforge-instructions-sdk.md +7 -3
  132. package/docs/introduction.mdx +9 -8
  133. package/docs/mcp-setup.mdx +332 -0
  134. package/docs/oauth-server.mdx +563 -0
  135. package/docs/partnership.mdx +79 -10
  136. package/docs/quickstart.mdx +1 -1
  137. package/docs/vscode-extension.mdx +74 -0
  138. package/eslint.config.js +1 -0
  139. package/examples/response-examples.md +1 -1
  140. package/frontend/package.json +1 -1
  141. package/frontend/src/App.tsx +8 -3
  142. package/frontend/src/assets/logos/antigravity.svg +1 -0
  143. package/frontend/src/assets/logos/copilot.svg +10 -0
  144. package/frontend/src/assets/logos/deepseek.svg +139 -0
  145. package/frontend/src/assets/logos/kiro.svg +9 -0
  146. package/frontend/src/assets/logos/qoder.svg +4 -0
  147. package/frontend/src/assets/logos/qwen.svg +15 -0
  148. package/frontend/src/components/CodeBlock.tsx +2 -2
  149. package/frontend/src/components/ConnectCTA.tsx +3 -2
  150. package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
  151. package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
  152. package/frontend/src/components/datagrid/index.ts +1 -1
  153. package/frontend/src/components/index.ts +0 -1
  154. package/frontend/src/components/layout/AppHeader.tsx +4 -27
  155. package/frontend/src/components/layout/AppSidebar.tsx +85 -100
  156. package/frontend/src/components/layout/Layout.tsx +34 -32
  157. package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
  158. package/frontend/src/components/radix/Select.tsx +151 -151
  159. package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
  160. package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
  161. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
  162. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
  163. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
  164. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
  165. package/frontend/src/features/ai/components/index.ts +6 -6
  166. package/frontend/src/features/ai/helpers.ts +147 -141
  167. package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
  168. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
  169. package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
  170. package/frontend/src/features/auth/components/index.ts +5 -5
  171. package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
  172. package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
  173. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
  174. package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
  175. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
  176. package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
  177. package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
  178. package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
  179. package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
  180. package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
  181. package/frontend/src/features/database/constants.ts +16 -28
  182. package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
  183. package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
  184. package/frontend/src/features/database/hooks/useTables.ts +5 -7
  185. package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
  186. package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
  187. package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
  188. package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
  189. package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
  190. package/frontend/src/features/database/services/advance.service.ts +1 -15
  191. package/frontend/src/features/database/services/record.service.ts +4 -20
  192. package/frontend/src/features/database/services/table.service.ts +1 -4
  193. package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
  194. package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
  195. package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
  196. package/frontend/src/features/database/templates/notion-clone.ts +8 -8
  197. package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
  198. package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
  199. package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
  200. package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
  201. package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
  202. package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
  203. package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
  204. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
  205. package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
  206. package/frontend/src/features/functions/components/index.ts +5 -5
  207. package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
  208. package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
  209. package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
  210. package/frontend/src/features/functions/services/function.service.ts +8 -25
  211. package/frontend/src/features/functions/services/secret.service.ts +23 -41
  212. package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
  213. package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
  214. package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
  215. package/frontend/src/features/logs/components/index.ts +1 -0
  216. package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
  217. package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
  218. package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
  219. package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
  220. package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
  221. package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
  222. package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
  223. package/frontend/src/features/onboard/components/index.ts +9 -4
  224. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
  225. package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
  226. package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
  227. package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
  228. package/frontend/src/features/onboard/index.ts +17 -13
  229. package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
  230. package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
  231. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
  232. package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
  233. package/frontend/src/index.css +249 -249
  234. package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
  235. package/frontend/src/lib/hooks/useMetadata.ts +45 -1
  236. package/frontend/src/lib/hooks/useModal.tsx +2 -0
  237. package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
  238. package/frontend/src/lib/services/metadata.service.ts +20 -3
  239. package/frontend/src/lib/utils/menuItems.ts +223 -207
  240. package/frontend/src/lib/utils/utils.ts +196 -196
  241. package/functions/server.ts +315 -315
  242. package/functions/worker-template.js +1 -1
  243. package/openapi/ai.yaml +115 -5
  244. package/openapi/auth.yaml +97 -17
  245. package/openapi/logs.yaml +0 -2
  246. package/openapi/metadata.yaml +0 -2
  247. package/openapi/records.yaml +21 -21
  248. package/openapi/tables.yaml +1 -2
  249. package/package.json +1 -1
  250. package/shared-schemas/package.json +1 -1
  251. package/shared-schemas/src/ai-api.schema.ts +251 -143
  252. package/shared-schemas/src/ai.schema.ts +63 -63
  253. package/shared-schemas/src/auth-api.schema.ts +34 -6
  254. package/shared-schemas/src/auth.schema.ts +17 -10
  255. package/shared-schemas/src/cloud-events.schema.ts +26 -0
  256. package/shared-schemas/src/deployments-api.schema.ts +55 -0
  257. package/shared-schemas/src/deployments.schema.ts +30 -0
  258. package/shared-schemas/src/docs.schema.ts +8 -2
  259. package/shared-schemas/src/email-api.schema.ts +30 -30
  260. package/shared-schemas/src/functions-api.schema.ts +13 -4
  261. package/shared-schemas/src/functions.schema.ts +1 -1
  262. package/shared-schemas/src/index.ts +22 -18
  263. package/shared-schemas/src/metadata.schema.ts +30 -4
  264. package/shared-schemas/src/secrets-api.schema.ts +44 -0
  265. package/shared-schemas/src/secrets.schema.ts +15 -0
  266. package/zeabur/README.md +13 -0
  267. package/zeabur/template.yml +20 -51
  268. package/backend/src/types/profile.ts +0 -55
  269. package/frontend/src/components/ProjectInfoModal.tsx +0 -128
@@ -1,275 +1,275 @@
1
- import { useState, useCallback, useMemo } from 'react';
2
- import { MoreHorizontal, Plus, Trash2, Pencil, Mail, ChevronDown } from 'lucide-react';
3
- import { OAuthConfigDialog, AuthPreview } from '@/features/auth/components';
4
- import { useOAuthConfig } from '@/features/auth/hooks/useOAuthConfig';
5
- import { useConfirm } from '@/lib/hooks/useConfirm';
6
- import {
7
- Button,
8
- ConfirmDialog,
9
- CopyButton,
10
- DropdownMenu,
11
- DropdownMenuContent,
12
- DropdownMenuItem,
13
- DropdownMenuTrigger,
14
- DropdownMenuSeparator,
15
- } from '@/components';
16
- import type { OAuthProvidersSchema } from '@insforge/shared-schemas';
17
- import {
18
- oauthProviders,
19
- type OAuthProviderInfo,
20
- getAuthImplementationPrompt,
21
- } from '@/features/auth/helpers';
22
- import { getBackendUrl } from '@/lib/utils/utils';
23
-
24
- export default function AuthMethodsPage() {
25
- const [selectedProvider, setSelectedProvider] = useState<OAuthProviderInfo>();
26
- const [isDialogOpen, setIsDialogOpen] = useState(false);
27
- const { confirm, confirmDialogProps } = useConfirm();
28
- const {
29
- configs,
30
- isLoadingConfigs,
31
- deleteConfig,
32
- refetchConfigs,
33
- getProviderConfig,
34
- isProviderConfigured,
35
- } = useOAuthConfig();
36
-
37
- const handleConfigureProvider = (provider: OAuthProviderInfo) => {
38
- setSelectedProvider(provider);
39
- setIsDialogOpen(true);
40
- };
41
-
42
- const deleteOAuthConfig = async (providerId: OAuthProvidersSchema, providerName: string) => {
43
- const shouldDelete = await confirm({
44
- title: `Delete ${providerName} OAuth`,
45
- description: `Are you sure you want to delete the ${providerName} configuration? This action cannot be undone.`,
46
- confirmText: 'Delete',
47
- cancelText: 'Cancel',
48
- destructive: true,
49
- });
50
-
51
- if (shouldDelete) {
52
- deleteConfig(providerId);
53
- }
54
- };
55
-
56
- const handleCloseDialog = () => {
57
- setIsDialogOpen(false);
58
- setSelectedProvider(undefined);
59
- };
60
-
61
- const hasAuthMethods = useMemo(() => {
62
- return !!configs.length;
63
- }, [configs]);
64
-
65
- const enabledProviders = useMemo(() => {
66
- const enabled: Record<OAuthProvidersSchema, boolean> = {} as Record<
67
- OAuthProvidersSchema,
68
- boolean
69
- >;
70
- oauthProviders.forEach((provider) => {
71
- enabled[provider.id] = isProviderConfigured(provider.id);
72
- });
73
- return enabled;
74
- }, [isProviderConfigured]);
75
-
76
- // Check if all providers are enabled
77
- const allProvidersEnabled = useMemo(() => {
78
- return oauthProviders.every((provider) => enabledProviders[provider.id]);
79
- }, [enabledProviders]);
80
-
81
- const handleSuccess = useCallback(() => {
82
- // Refresh configuration after successful update
83
- void refetchConfigs();
84
- }, [refetchConfigs]);
85
-
86
- if (isLoadingConfigs) {
87
- return (
88
- <div className="h-full bg-slate-50 dark:bg-neutral-800 flex flex-col overflow-hidden">
89
- <div className="flex-1 flex items-center justify-center">
90
- <div className="text-center">
91
- <div className="text-sm text-gray-500 dark:text-zinc-400">
92
- Loading OAuth configuration...
93
- </div>
94
- </div>
95
- </div>
96
- </div>
97
- );
98
- }
99
-
100
- return (
101
- <div className="h-full flex flex-col overflow-hidden">
102
- {/* Two column layout */}
103
- <div className="h-full flex overflow-hidden">
104
- {/* Left Section - Auth Methods List */}
105
- <div className="flex-1 bg-slate-50 dark:bg-[#2d2d2d] flex flex-col overflow-hidden">
106
- {/* Header */}
107
- <div className="flex items-center justify-between px-4 py-6 gap-3">
108
- <h2 className="px-4 text-xl font-semibold text-gray-900 dark:text-white tracking-tight">
109
- Auth Methods
110
- </h2>
111
- {!allProvidersEnabled && (
112
- <DropdownMenu>
113
- <DropdownMenuTrigger asChild>
114
- <Button className="h-8 px-2 py-0 gap-2 bg-black text-white dark:bg-neutral-600 dark:text-white hover:bg-gray-800 dark:hover:bg-neutral-500 text-sm font-medium rounded">
115
- <Plus className="w-5 h-5" />
116
- Add Provider
117
- <ChevronDown className="w-4 h-4" />
118
- </Button>
119
- </DropdownMenuTrigger>
120
- <DropdownMenuContent align="end" className="w-80">
121
- {/* Available providers (not enabled) */}
122
- {oauthProviders
123
- .filter((provider) => !enabledProviders[provider.id])
124
- .map((provider) => (
125
- <DropdownMenuItem
126
- key={provider.id}
127
- onClick={() => handleConfigureProvider(provider)}
128
- className="py-2 px-3 flex items-center gap-3 cursor-pointer"
129
- >
130
- {provider.icon}
131
- <span className="text-sm">{provider.name}</span>
132
- </DropdownMenuItem>
133
- ))}
134
-
135
- {/* Separator if there are both enabled and disabled providers */}
136
- {oauthProviders.some((p) => enabledProviders[p.id]) &&
137
- oauthProviders.some((p) => !enabledProviders[p.id]) && (
138
- <DropdownMenuSeparator />
139
- )}
140
-
141
- {/* Enabled providers (disabled from selection) */}
142
- {oauthProviders
143
- .filter((provider) => enabledProviders[provider.id])
144
- .map((provider) => (
145
- <DropdownMenuItem
146
- key={provider.id}
147
- disabled
148
- className="py-2 px-3 flex items-center justify-between gap-3 opacity-50 cursor-not-allowed"
149
- >
150
- <div className="flex items-center gap-3">
151
- {provider.icon}
152
- <span className="text-sm">{provider.name}</span>
153
- </div>
154
- <span className="text-xs px-2 py-0.5 bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400 rounded border border-emerald-300 dark:border-emerald-700">
155
- Enabled
156
- </span>
157
- </DropdownMenuItem>
158
- ))}
159
- </DropdownMenuContent>
160
- </DropdownMenu>
161
- )}
162
- </div>
163
-
164
- {/* Auth Methods List */}
165
- <div className="flex-1 overflow-y-auto p-4">
166
- <div className="flex flex-col gap-3">
167
- {/* Email Auth Card */}
168
- <div className="flex items-center justify-between px-6 py-4 bg-white dark:bg-neutral-800 rounded-lg border border-gray-200 dark:border-transparent">
169
- <div className="flex items-center gap-3">
170
- <Mail className="w-6 h-6 text-gray-700 dark:text-white" />
171
- <div className="text-sm font-medium text-black dark:text-white">Email Auth</div>
172
- </div>
173
- </div>
174
-
175
- {/* OAuth Providers */}
176
- {hasAuthMethods &&
177
- oauthProviders.map((provider) => {
178
- const providerConfig = getProviderConfig(provider.id);
179
- if (!providerConfig) {
180
- return null;
181
- }
182
-
183
- return (
184
- <div
185
- key={provider.id}
186
- className="flex items-center justify-between px-6 py-4 bg-white dark:bg-neutral-800 rounded-lg border border-gray-200 dark:border-transparent"
187
- >
188
- <div className="flex items-center gap-3">
189
- {provider.icon}
190
- <div className="text-sm font-medium text-black dark:text-white">
191
- {provider.name}
192
- </div>
193
- </div>
194
-
195
- <div className="flex items-center gap-3">
196
- {providerConfig.useSharedKey && (
197
- <span className="px-2 py-0.5 text-xs font-medium text-neutral-500 dark:text-neutral-400 border border-neutral-500 dark:border-neutral-400 rounded">
198
- Shared Keys
199
- </span>
200
- )}
201
-
202
- <DropdownMenu>
203
- <DropdownMenuTrigger asChild>
204
- <Button
205
- className="h-7 w-7 p-1 text-gray-500 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-700"
206
- variant="ghost"
207
- size="sm"
208
- >
209
- <MoreHorizontal className="w-5 h-5" />
210
- </Button>
211
- </DropdownMenuTrigger>
212
- <DropdownMenuContent align="end" className="w-40 py-1 px-2">
213
- <DropdownMenuItem
214
- onClick={() => handleConfigureProvider(provider)}
215
- className="py-2 px-3 flex items-center gap-3 cursor-pointer"
216
- >
217
- <Pencil className="w-5 h-5" />
218
- Edit
219
- </DropdownMenuItem>
220
- <DropdownMenuItem
221
- onClick={() => void deleteOAuthConfig(provider.id, provider.name)}
222
- className="py-2 px-3 flex items-center gap-3 cursor-pointer text-red-600 dark:text-red-400"
223
- >
224
- <Trash2 className="w-5 h-5" />
225
- Delete
226
- </DropdownMenuItem>
227
- </DropdownMenuContent>
228
- </DropdownMenu>
229
- </div>
230
- </div>
231
- );
232
- })}
233
- </div>
234
- </div>
235
- </div>
236
-
237
- {/* Right Section - Preview */}
238
- <div className="w-[688px] bg-slate-50 dark:bg-[#2d2d2d] p-3 flex flex-col overflow-hidden">
239
- <div className="h-full bg-gray-200 dark:bg-neutral-700 rounded-xl overflow-hidden flex flex-col">
240
- {/* Preview Header */}
241
- <div className="flex items-center justify-end px-6 py-3 gap-3">
242
- <p className="text-sm font-medium text-gray-700 dark:text-white">
243
- Integrate Authentication to Your Application
244
- </p>
245
- <CopyButton
246
- text={getAuthImplementationPrompt(getBackendUrl())}
247
- copyText="Copy Prompt"
248
- variant="primary"
249
- className="w-34"
250
- />
251
- </div>
252
-
253
- {/* Preview Content */}
254
- <div className="flex-1 overflow-y-auto py-8 flex flex-col items-center justify-center gap-4">
255
- <AuthPreview />
256
- <p className="text-xs text-gray-500 dark:text-neutral-400 text-center">
257
- Preview Mode
258
- </p>
259
- </div>
260
- </div>
261
- </div>
262
- </div>
263
-
264
- <OAuthConfigDialog
265
- provider={selectedProvider}
266
- isOpen={isDialogOpen}
267
- onClose={handleCloseDialog}
268
- onSuccess={handleSuccess}
269
- />
270
-
271
- {/* Confirm Dialog */}
272
- <ConfirmDialog {...confirmDialogProps} />
273
- </div>
274
- );
275
- }
1
+ import { useState, useCallback, useMemo } from 'react';
2
+ import { MoreHorizontal, Plus, Trash2, Pencil, Mail, ChevronDown } from 'lucide-react';
3
+ import { OAuthConfigDialog, AuthPreview } from '@/features/auth/components';
4
+ import { useOAuthConfig } from '@/features/auth/hooks/useOAuthConfig';
5
+ import { useConfirm } from '@/lib/hooks/useConfirm';
6
+ import {
7
+ Button,
8
+ ConfirmDialog,
9
+ CopyButton,
10
+ DropdownMenu,
11
+ DropdownMenuContent,
12
+ DropdownMenuItem,
13
+ DropdownMenuTrigger,
14
+ DropdownMenuSeparator,
15
+ } from '@/components';
16
+ import type { OAuthProvidersSchema } from '@insforge/shared-schemas';
17
+ import {
18
+ oauthProviders,
19
+ type OAuthProviderInfo,
20
+ getAuthImplementationPrompt,
21
+ } from '@/features/auth/helpers';
22
+ import { getBackendUrl } from '@/lib/utils/utils';
23
+
24
+ export default function AuthMethodsPage() {
25
+ const [selectedProvider, setSelectedProvider] = useState<OAuthProviderInfo>();
26
+ const [isDialogOpen, setIsDialogOpen] = useState(false);
27
+ const { confirm, confirmDialogProps } = useConfirm();
28
+ const {
29
+ configs,
30
+ isLoadingConfigs,
31
+ deleteConfig,
32
+ refetchConfigs,
33
+ getProviderConfig,
34
+ isProviderConfigured,
35
+ } = useOAuthConfig();
36
+
37
+ const handleConfigureProvider = (provider: OAuthProviderInfo) => {
38
+ setSelectedProvider(provider);
39
+ setIsDialogOpen(true);
40
+ };
41
+
42
+ const deleteOAuthConfig = async (providerId: OAuthProvidersSchema, providerName: string) => {
43
+ const shouldDelete = await confirm({
44
+ title: `Delete ${providerName} OAuth`,
45
+ description: `Are you sure you want to delete the ${providerName} configuration? This action cannot be undone.`,
46
+ confirmText: 'Delete',
47
+ cancelText: 'Cancel',
48
+ destructive: true,
49
+ });
50
+
51
+ if (shouldDelete) {
52
+ deleteConfig(providerId);
53
+ }
54
+ };
55
+
56
+ const handleCloseDialog = () => {
57
+ setIsDialogOpen(false);
58
+ setSelectedProvider(undefined);
59
+ };
60
+
61
+ const hasAuthMethods = useMemo(() => {
62
+ return !!configs.length;
63
+ }, [configs]);
64
+
65
+ const enabledProviders = useMemo(() => {
66
+ const enabled: Record<OAuthProvidersSchema, boolean> = {} as Record<
67
+ OAuthProvidersSchema,
68
+ boolean
69
+ >;
70
+ oauthProviders.forEach((provider) => {
71
+ enabled[provider.id] = isProviderConfigured(provider.id);
72
+ });
73
+ return enabled;
74
+ }, [isProviderConfigured]);
75
+
76
+ // Check if all providers are enabled
77
+ const allProvidersEnabled = useMemo(() => {
78
+ return oauthProviders.every((provider) => enabledProviders[provider.id]);
79
+ }, [enabledProviders]);
80
+
81
+ const handleSuccess = useCallback(() => {
82
+ // Refresh configuration after successful update
83
+ void refetchConfigs();
84
+ }, [refetchConfigs]);
85
+
86
+ if (isLoadingConfigs) {
87
+ return (
88
+ <div className="h-full bg-slate-50 dark:bg-neutral-800 flex flex-col overflow-hidden">
89
+ <div className="flex-1 flex items-center justify-center">
90
+ <div className="text-center">
91
+ <div className="text-sm text-gray-500 dark:text-zinc-400">
92
+ Loading OAuth configuration...
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ );
98
+ }
99
+
100
+ return (
101
+ <div className="h-full flex flex-col overflow-hidden">
102
+ {/* Two column layout */}
103
+ <div className="h-full flex overflow-hidden">
104
+ {/* Left Section - Auth Methods List */}
105
+ <div className="flex-1 bg-slate-50 dark:bg-[#2d2d2d] flex flex-col overflow-hidden">
106
+ {/* Header */}
107
+ <div className="flex items-center justify-between px-4 py-6 gap-3">
108
+ <h2 className="px-4 text-xl font-semibold text-gray-900 dark:text-white tracking-tight">
109
+ Auth Methods
110
+ </h2>
111
+ {!allProvidersEnabled && (
112
+ <DropdownMenu>
113
+ <DropdownMenuTrigger asChild>
114
+ <Button className="h-8 px-2 py-0 gap-2 bg-black text-white dark:bg-neutral-600 dark:text-white hover:bg-gray-800 dark:hover:bg-neutral-500 text-sm font-medium rounded">
115
+ <Plus className="w-5 h-5" />
116
+ Add Provider
117
+ <ChevronDown className="w-4 h-4" />
118
+ </Button>
119
+ </DropdownMenuTrigger>
120
+ <DropdownMenuContent align="end" className="w-80">
121
+ {/* Available providers (not enabled) */}
122
+ {oauthProviders
123
+ .filter((provider) => !enabledProviders[provider.id])
124
+ .map((provider) => (
125
+ <DropdownMenuItem
126
+ key={provider.id}
127
+ onClick={() => handleConfigureProvider(provider)}
128
+ className="py-2 px-3 flex items-center gap-3 cursor-pointer"
129
+ >
130
+ {provider.icon}
131
+ <span className="text-sm">{provider.name}</span>
132
+ </DropdownMenuItem>
133
+ ))}
134
+
135
+ {/* Separator if there are both enabled and disabled providers */}
136
+ {oauthProviders.some((p) => enabledProviders[p.id]) &&
137
+ oauthProviders.some((p) => !enabledProviders[p.id]) && (
138
+ <DropdownMenuSeparator />
139
+ )}
140
+
141
+ {/* Enabled providers (disabled from selection) */}
142
+ {oauthProviders
143
+ .filter((provider) => enabledProviders[provider.id])
144
+ .map((provider) => (
145
+ <DropdownMenuItem
146
+ key={provider.id}
147
+ disabled
148
+ className="py-2 px-3 flex items-center justify-between gap-3 opacity-50 cursor-not-allowed"
149
+ >
150
+ <div className="flex items-center gap-3">
151
+ {provider.icon}
152
+ <span className="text-sm">{provider.name}</span>
153
+ </div>
154
+ <span className="text-xs px-2 py-0.5 bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400 rounded border border-emerald-300 dark:border-emerald-700">
155
+ Enabled
156
+ </span>
157
+ </DropdownMenuItem>
158
+ ))}
159
+ </DropdownMenuContent>
160
+ </DropdownMenu>
161
+ )}
162
+ </div>
163
+
164
+ {/* Auth Methods List */}
165
+ <div className="flex-1 overflow-y-auto p-4">
166
+ <div className="flex flex-col gap-3">
167
+ {/* Email Auth Card */}
168
+ <div className="flex items-center justify-between px-6 py-4 bg-white dark:bg-neutral-800 rounded-lg border border-gray-200 dark:border-transparent">
169
+ <div className="flex items-center gap-3">
170
+ <Mail className="w-6 h-6 text-gray-700 dark:text-white" />
171
+ <div className="text-sm font-medium text-black dark:text-white">Email Auth</div>
172
+ </div>
173
+ </div>
174
+
175
+ {/* OAuth Providers */}
176
+ {hasAuthMethods &&
177
+ oauthProviders.map((provider) => {
178
+ const providerConfig = getProviderConfig(provider.id);
179
+ if (!providerConfig) {
180
+ return null;
181
+ }
182
+
183
+ return (
184
+ <div
185
+ key={provider.id}
186
+ className="flex items-center justify-between px-6 py-4 bg-white dark:bg-neutral-800 rounded-lg border border-gray-200 dark:border-transparent"
187
+ >
188
+ <div className="flex items-center gap-3">
189
+ {provider.icon}
190
+ <div className="text-sm font-medium text-black dark:text-white">
191
+ {provider.name}
192
+ </div>
193
+ </div>
194
+
195
+ <div className="flex items-center gap-3">
196
+ {providerConfig.useSharedKey && (
197
+ <span className="px-2 py-0.5 text-xs font-medium text-neutral-500 dark:text-neutral-400 border border-neutral-500 dark:border-neutral-400 rounded">
198
+ Shared Keys
199
+ </span>
200
+ )}
201
+
202
+ <DropdownMenu>
203
+ <DropdownMenuTrigger asChild>
204
+ <Button
205
+ className="h-7 w-7 p-1 text-gray-500 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-700"
206
+ variant="ghost"
207
+ size="sm"
208
+ >
209
+ <MoreHorizontal className="w-5 h-5" />
210
+ </Button>
211
+ </DropdownMenuTrigger>
212
+ <DropdownMenuContent align="end" className="w-40 py-1 px-2">
213
+ <DropdownMenuItem
214
+ onClick={() => handleConfigureProvider(provider)}
215
+ className="py-2 px-3 flex items-center gap-3 cursor-pointer"
216
+ >
217
+ <Pencil className="w-5 h-5" />
218
+ Edit
219
+ </DropdownMenuItem>
220
+ <DropdownMenuItem
221
+ onClick={() => void deleteOAuthConfig(provider.id, provider.name)}
222
+ className="py-2 px-3 flex items-center gap-3 cursor-pointer text-red-600 dark:text-red-400"
223
+ >
224
+ <Trash2 className="w-5 h-5" />
225
+ Delete
226
+ </DropdownMenuItem>
227
+ </DropdownMenuContent>
228
+ </DropdownMenu>
229
+ </div>
230
+ </div>
231
+ );
232
+ })}
233
+ </div>
234
+ </div>
235
+ </div>
236
+
237
+ {/* Right Section - Preview */}
238
+ <div className="w-[688px] bg-slate-50 dark:bg-[#2d2d2d] p-3 flex flex-col overflow-hidden">
239
+ <div className="h-full bg-gray-200 dark:bg-neutral-700 rounded-xl overflow-hidden flex flex-col">
240
+ {/* Preview Header */}
241
+ <div className="flex items-center justify-end px-6 py-3 gap-3">
242
+ <p className="text-sm font-medium text-gray-700 dark:text-white">
243
+ Integrate Authentication to Your Application
244
+ </p>
245
+ <CopyButton
246
+ text={getAuthImplementationPrompt(getBackendUrl())}
247
+ copyText="Copy Prompt"
248
+ variant="primary"
249
+ className="w-34"
250
+ />
251
+ </div>
252
+
253
+ {/* Preview Content */}
254
+ <div className="flex-1 overflow-y-auto py-8 flex flex-col items-center justify-center gap-4">
255
+ <AuthPreview />
256
+ <p className="text-xs text-gray-500 dark:text-neutral-400 text-center">
257
+ Preview Mode
258
+ </p>
259
+ </div>
260
+ </div>
261
+ </div>
262
+ </div>
263
+
264
+ <OAuthConfigDialog
265
+ provider={selectedProvider}
266
+ isOpen={isDialogOpen}
267
+ onClose={handleCloseDialog}
268
+ onSuccess={handleSuccess}
269
+ />
270
+
271
+ {/* Confirm Dialog */}
272
+ <ConfirmDialog {...confirmDialogProps} />
273
+ </div>
274
+ );
275
+ }
@@ -19,7 +19,7 @@ export default function DashboardPage() {
19
19
  const { totalUsers } = useUsers();
20
20
  const { records } = useMcpUsage();
21
21
 
22
- const authCount = auth?.oauths.length ?? 0;
22
+ const authCount = auth?.oAuthProviders.length ?? 0;
23
23
  const tableCount = tables?.length ?? 0;
24
24
  const showBanner = location.state?.showSuccessBanner === true;
25
25
 
@@ -225,10 +225,8 @@ export function convertSchemaToColumns(
225
225
  onJumpToTable={onJumpToTable}
226
226
  />
227
227
  );
228
- // Note: editable is set in the column definition above
229
228
  } else if (col.columnName === primaryKeyColumn) {
230
229
  column.renderCell = cellRenderers.id;
231
- // Note: editable is set in the column definition above
232
230
  } else if (col.type === ColumnType.BOOLEAN) {
233
231
  column.renderCell = cellRenderers.boolean;
234
232
  column.renderEditCell = (props: RenderEditCellProps<DatabaseDataGridRow>) => (