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.
- package/CHANGELOG.md +2 -0
- package/auth/package.json +5 -3
- package/auth/src/lib/broadcastService.ts +115 -117
- package/auth/src/lib/insforge.ts +8 -0
- package/auth/src/main.tsx +2 -4
- package/auth/src/pages/SignInPage.tsx +60 -60
- package/auth/src/pages/SignUpPage.tsx +60 -60
- package/auth/src/pages/VerifyEmailPage.tsx +18 -0
- package/auth/tsconfig.json +2 -1
- package/backend/package.json +10 -6
- package/backend/src/api/middlewares/rate-limiters.ts +127 -127
- package/backend/src/api/routes/ai/index.routes.ts +475 -468
- package/backend/src/api/routes/auth/index.routes.ts +85 -32
- package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
- package/backend/src/api/routes/database/index.routes.ts +2 -0
- package/backend/src/api/routes/database/records.routes.ts +39 -175
- package/backend/src/api/routes/database/rpc.routes.ts +69 -0
- package/backend/src/api/routes/deployments/index.routes.ts +192 -0
- package/backend/src/api/routes/docs/index.routes.ts +3 -2
- package/backend/src/api/routes/email/index.routes.ts +35 -35
- package/backend/src/api/routes/functions/index.routes.ts +3 -3
- package/backend/src/api/routes/metadata/index.routes.ts +26 -0
- package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
- package/backend/src/infra/database/database.manager.ts +0 -10
- package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
- package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
- package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
- package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
- package/backend/src/infra/security/token.manager.ts +1 -4
- package/backend/src/providers/ai/openrouter.provider.ts +12 -3
- package/backend/src/providers/database/base.provider.ts +39 -0
- package/backend/src/providers/database/cloud.provider.ts +159 -0
- package/backend/src/providers/deployments/vercel.provider.ts +516 -0
- package/backend/src/server.ts +19 -7
- package/backend/src/services/ai/ai-config.service.ts +6 -6
- package/backend/src/services/ai/ai-model.service.ts +60 -60
- package/backend/src/services/ai/ai-usage.service.ts +7 -7
- package/backend/src/services/ai/chat-completion.service.ts +415 -220
- package/backend/src/services/ai/helpers.ts +64 -64
- package/backend/src/services/ai/index.ts +13 -13
- package/backend/src/services/auth/auth-config.service.ts +4 -4
- package/backend/src/services/auth/auth-otp.service.ts +6 -6
- package/backend/src/services/auth/auth.service.ts +134 -74
- package/backend/src/services/auth/index.ts +4 -4
- package/backend/src/services/auth/oauth-config.service.ts +12 -12
- package/backend/src/services/database/database-advance.service.ts +19 -55
- package/backend/src/services/database/database-table.service.ts +38 -85
- package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
- package/backend/src/services/deployments/deployment.service.ts +693 -0
- package/backend/src/services/functions/function.service.ts +61 -41
- package/backend/src/services/logs/audit.service.ts +10 -10
- package/backend/src/services/secrets/secret.service.ts +101 -27
- package/backend/src/services/storage/storage.service.ts +30 -30
- package/backend/src/services/usage/usage.service.ts +6 -6
- package/backend/src/types/ai.ts +8 -0
- package/backend/src/types/auth.ts +5 -1
- package/backend/src/types/database.ts +2 -0
- package/backend/src/types/deployments.ts +33 -0
- package/backend/src/types/storage.ts +1 -1
- package/backend/src/types/webhooks.ts +45 -0
- package/backend/src/utils/cookies.ts +34 -35
- package/backend/src/utils/environment.ts +0 -14
- package/backend/src/utils/s3-config-loader.ts +64 -64
- package/backend/src/utils/seed.ts +334 -301
- package/backend/src/utils/sql-parser.ts +126 -0
- package/backend/src/utils/utils.ts +114 -114
- package/backend/src/utils/validations.ts +10 -10
- package/backend/tests/local/test-rpc.sh +141 -0
- package/backend/tests/local/test-secrets.sh +1 -1
- package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
- package/backend/tests/manual/test-rawsql-modes.sh +24 -24
- package/backend/tests/unit/database-advance.test.ts +326 -0
- package/backend/tests/unit/helpers.test.ts +2 -2
- package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
- package/docker-compose.prod.yml +1 -1
- package/docker-compose.yml +1 -1
- package/docs/agent-docs/deployment.md +79 -0
- package/docs/changelog.mdx +165 -72
- package/docs/core-concepts/ai/architecture.mdx +1 -23
- package/docs/core-concepts/ai/sdk.mdx +26 -1
- package/docs/core-concepts/authentication/architecture.mdx +6 -8
- package/docs/core-concepts/authentication/sdk.mdx +387 -91
- package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
- package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
- package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
- package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
- package/docs/core-concepts/database/architecture.mdx +58 -21
- package/docs/core-concepts/database/pgvector.mdx +138 -0
- package/docs/core-concepts/database/sdk.mdx +17 -17
- package/docs/core-concepts/deployments/architecture.mdx +152 -0
- package/docs/core-concepts/email/architecture.mdx +4 -2
- package/docs/core-concepts/functions/architecture.mdx +1 -1
- package/docs/core-concepts/functions/sdk.mdx +0 -1
- package/docs/core-concepts/realtime/architecture.mdx +1 -1
- package/docs/core-concepts/storage/architecture.mdx +1 -1
- package/docs/core-concepts/storage/sdk.mdx +25 -25
- package/docs/docs.json +14 -6
- package/docs/favicon.png +0 -0
- package/docs/favicon.svg +3 -18
- package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
- package/docs/images/changelog/dec-2025/moreModels.png +0 -0
- package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
- package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
- package/docs/images/changelog/dec-2025/realtime2.png +0 -0
- package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
- package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
- package/docs/images/mcp-setup/claude-code-connect.png +0 -0
- package/docs/images/mcp-setup/cline-1.png +0 -0
- package/docs/images/mcp-setup/cline-2.png +0 -0
- package/docs/images/mcp-setup/cline-3.png +0 -0
- package/docs/images/mcp-setup/connect-project.png +0 -0
- package/docs/images/mcp-setup/copilot-1.png +0 -0
- package/docs/images/mcp-setup/copilot-2.png +0 -0
- package/docs/images/mcp-setup/copilot-3.png +0 -0
- package/docs/images/mcp-setup/mcp-json-1.png +0 -0
- package/docs/images/mcp-setup/mcp-json-2.png +0 -0
- package/docs/images/mcp-setup/qoder-1.png +0 -0
- package/docs/images/mcp-setup/qoder-2.png +0 -0
- package/docs/images/mcp-setup/roocode-1.png +0 -0
- package/docs/images/mcp-setup/roocode-2.png +0 -0
- package/docs/images/mcp-setup/trae-1.png +0 -0
- package/docs/images/mcp-setup/trae-2.png +0 -0
- package/docs/images/mcp-setup/trae-3.png +0 -0
- package/docs/images/mcp-setup/trae-4.png +0 -0
- package/docs/images/mcp-setup/trae-5.png +0 -0
- package/docs/images/mcp-setup/windsurf-1.png +0 -0
- package/docs/images/mcp-setup/windsurf-2.png +0 -0
- package/docs/insforge-instructions-sdk.md +7 -3
- package/docs/introduction.mdx +9 -8
- package/docs/mcp-setup.mdx +332 -0
- package/docs/oauth-server.mdx +563 -0
- package/docs/partnership.mdx +79 -10
- package/docs/quickstart.mdx +1 -1
- package/docs/vscode-extension.mdx +74 -0
- package/eslint.config.js +1 -0
- package/examples/response-examples.md +1 -1
- package/frontend/package.json +1 -1
- package/frontend/src/App.tsx +8 -3
- package/frontend/src/assets/logos/antigravity.svg +1 -0
- package/frontend/src/assets/logos/copilot.svg +10 -0
- package/frontend/src/assets/logos/deepseek.svg +139 -0
- package/frontend/src/assets/logos/kiro.svg +9 -0
- package/frontend/src/assets/logos/qoder.svg +4 -0
- package/frontend/src/assets/logos/qwen.svg +15 -0
- package/frontend/src/components/CodeBlock.tsx +2 -2
- package/frontend/src/components/ConnectCTA.tsx +3 -2
- package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
- package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
- package/frontend/src/components/datagrid/index.ts +1 -1
- package/frontend/src/components/index.ts +0 -1
- package/frontend/src/components/layout/AppHeader.tsx +4 -27
- package/frontend/src/components/layout/AppSidebar.tsx +85 -100
- package/frontend/src/components/layout/Layout.tsx +34 -32
- package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
- package/frontend/src/components/radix/Select.tsx +151 -151
- package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
- package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
- package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
- package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
- package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
- package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
- package/frontend/src/features/ai/components/index.ts +6 -6
- package/frontend/src/features/ai/helpers.ts +147 -141
- package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
- package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
- package/frontend/src/features/auth/components/index.ts +5 -5
- package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
- package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
- package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
- package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
- package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
- package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
- package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
- package/frontend/src/features/database/constants.ts +16 -28
- package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
- package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
- package/frontend/src/features/database/hooks/useTables.ts +5 -7
- package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
- package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
- package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
- package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
- package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
- package/frontend/src/features/database/services/advance.service.ts +1 -15
- package/frontend/src/features/database/services/record.service.ts +4 -20
- package/frontend/src/features/database/services/table.service.ts +1 -4
- package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
- package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
- package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
- package/frontend/src/features/database/templates/notion-clone.ts +8 -8
- package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
- package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
- package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
- package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
- package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
- package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
- package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
- package/frontend/src/features/functions/components/index.ts +5 -5
- package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
- package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
- package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
- package/frontend/src/features/functions/services/function.service.ts +8 -25
- package/frontend/src/features/functions/services/secret.service.ts +23 -41
- package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
- package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
- package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
- package/frontend/src/features/logs/components/index.ts +1 -0
- package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
- package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
- package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
- package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
- package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
- package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
- package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
- package/frontend/src/features/onboard/components/index.ts +9 -4
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
- package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
- package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
- package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
- package/frontend/src/features/onboard/index.ts +17 -13
- package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
- package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
- package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
- package/frontend/src/index.css +249 -249
- package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
- package/frontend/src/lib/hooks/useMetadata.ts +45 -1
- package/frontend/src/lib/hooks/useModal.tsx +2 -0
- package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
- package/frontend/src/lib/services/metadata.service.ts +20 -3
- package/frontend/src/lib/utils/menuItems.ts +223 -207
- package/frontend/src/lib/utils/utils.ts +196 -196
- package/functions/server.ts +315 -315
- package/functions/worker-template.js +1 -1
- package/openapi/ai.yaml +115 -5
- package/openapi/auth.yaml +97 -17
- package/openapi/logs.yaml +0 -2
- package/openapi/metadata.yaml +0 -2
- package/openapi/records.yaml +21 -21
- package/openapi/tables.yaml +1 -2
- package/package.json +1 -1
- package/shared-schemas/package.json +1 -1
- package/shared-schemas/src/ai-api.schema.ts +251 -143
- package/shared-schemas/src/ai.schema.ts +63 -63
- package/shared-schemas/src/auth-api.schema.ts +34 -6
- package/shared-schemas/src/auth.schema.ts +17 -10
- package/shared-schemas/src/cloud-events.schema.ts +26 -0
- package/shared-schemas/src/deployments-api.schema.ts +55 -0
- package/shared-schemas/src/deployments.schema.ts +30 -0
- package/shared-schemas/src/docs.schema.ts +8 -2
- package/shared-schemas/src/email-api.schema.ts +30 -30
- package/shared-schemas/src/functions-api.schema.ts +13 -4
- package/shared-schemas/src/functions.schema.ts +1 -1
- package/shared-schemas/src/index.ts +22 -18
- package/shared-schemas/src/metadata.schema.ts +30 -4
- package/shared-schemas/src/secrets-api.schema.ts +44 -0
- package/shared-schemas/src/secrets.schema.ts +15 -0
- package/zeabur/README.md +13 -0
- package/zeabur/template.yml +20 -51
- package/backend/src/types/profile.ts +0 -55
- package/frontend/src/components/ProjectInfoModal.tsx +0 -128
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState, useMemo } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
2
3
|
import { Link2, AlertCircle, X } from 'lucide-react';
|
|
3
4
|
import {
|
|
4
5
|
Button,
|
|
@@ -17,6 +18,9 @@ import { useTables } from '@/features/database/hooks/useTables';
|
|
|
17
18
|
import { useRecords } from '@/features/database/hooks/useRecords';
|
|
18
19
|
import { convertSchemaToColumns } from '@/features/database/components/DatabaseDataGrid';
|
|
19
20
|
import { formatValueForDisplay } from '@/lib/utils/utils';
|
|
21
|
+
import { useQuery } from '@tanstack/react-query';
|
|
22
|
+
import { useUsers } from '@/features/auth/hooks/useUsers';
|
|
23
|
+
import { AUTH_USERS_TABLE, authUsersSchema } from '../constants';
|
|
20
24
|
|
|
21
25
|
interface ForeignKeyCellProps {
|
|
22
26
|
value: string;
|
|
@@ -29,9 +33,16 @@ interface ForeignKeyCellProps {
|
|
|
29
33
|
|
|
30
34
|
export function ForeignKeyCell({ value, foreignKey, onJumpToTable }: ForeignKeyCellProps) {
|
|
31
35
|
const [open, setOpen] = useState(false);
|
|
36
|
+
const navigate = useNavigate();
|
|
32
37
|
const { useTableSchema } = useTables();
|
|
38
|
+
const isAuthUsers = foreignKey.table === AUTH_USERS_TABLE;
|
|
39
|
+
|
|
40
|
+
// Regular table records hook (disabled for auth.users)
|
|
33
41
|
const recordsHook = useRecords(foreignKey.table);
|
|
34
42
|
|
|
43
|
+
// Auth users hook
|
|
44
|
+
const { getUser } = useUsers({ enabled: false });
|
|
45
|
+
|
|
35
46
|
// Helper function to safely render any value type (including JSON objects)
|
|
36
47
|
const renderValue = (val: ConvertedValue): string => {
|
|
37
48
|
return formatValueForDisplay(val);
|
|
@@ -39,16 +50,28 @@ export function ForeignKeyCell({ value, foreignKey, onJumpToTable }: ForeignKeyC
|
|
|
39
50
|
|
|
40
51
|
// Fetch the referenced record when popover opens
|
|
41
52
|
const searchValue = value ? renderValue(value) : '';
|
|
42
|
-
const {
|
|
43
|
-
data: recordData,
|
|
44
|
-
isLoading: _isLoading,
|
|
45
|
-
error,
|
|
46
|
-
} = recordsHook.useRecordByForeignKey(foreignKey.column, searchValue, open && !!value);
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
// For auth.users, fetch user by ID
|
|
55
|
+
const { data: authUserData, error: authUserError } = useQuery({
|
|
56
|
+
queryKey: ['user', searchValue],
|
|
57
|
+
queryFn: () => getUser(searchValue),
|
|
58
|
+
enabled: isAuthUsers && open && !!value,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// For regular tables, fetch by foreign key
|
|
62
|
+
const { data: recordData, error: recordError } = recordsHook.useRecordByForeignKey(
|
|
63
|
+
foreignKey.column,
|
|
64
|
+
searchValue,
|
|
65
|
+
!isAuthUsers && open && !!value
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Use appropriate data source based on table type
|
|
69
|
+
const record = isAuthUsers ? authUserData : recordData;
|
|
70
|
+
const error = isAuthUsers ? authUserError : recordError;
|
|
49
71
|
|
|
50
|
-
// Fetch schema for the referenced table
|
|
51
|
-
const { data:
|
|
72
|
+
// Fetch schema for the referenced table (skip for auth.users)
|
|
73
|
+
const { data: fetchedSchema } = useTableSchema(foreignKey.table, !isAuthUsers && open && !!value);
|
|
74
|
+
const schema = isAuthUsers ? authUsersSchema : fetchedSchema;
|
|
52
75
|
|
|
53
76
|
// Convert schema to columns for the mini DataGrid
|
|
54
77
|
const columns = useMemo(() => {
|
|
@@ -142,18 +165,22 @@ export function ForeignKeyCell({ value, foreignKey, onJumpToTable }: ForeignKeyC
|
|
|
142
165
|
</div>
|
|
143
166
|
|
|
144
167
|
{/* Jump to Table Button */}
|
|
145
|
-
{onJumpToTable && (
|
|
168
|
+
{(onJumpToTable || isAuthUsers) && (
|
|
146
169
|
<div className="flex justify-end p-6 border-t border-border-gray dark:border-neutral-700">
|
|
147
170
|
<Button
|
|
148
171
|
variant="outline"
|
|
149
172
|
size="sm"
|
|
150
173
|
className="h-9 px-3 py-2 text-sm font-medium dark:text-white bg-bg-gray dark:bg-neutral-600"
|
|
151
174
|
onClick={() => {
|
|
152
|
-
|
|
175
|
+
if (isAuthUsers) {
|
|
176
|
+
void navigate('/dashboard/users');
|
|
177
|
+
} else if (onJumpToTable) {
|
|
178
|
+
onJumpToTable(foreignKey.table);
|
|
179
|
+
}
|
|
153
180
|
setOpen(false);
|
|
154
181
|
}}
|
|
155
182
|
>
|
|
156
|
-
Open Table
|
|
183
|
+
{isAuthUsers ? 'Open Users' : 'Open Table'}
|
|
157
184
|
</Button>
|
|
158
185
|
</div>
|
|
159
186
|
)}
|
|
@@ -16,6 +16,7 @@ import { UseFormReturn } from 'react-hook-form';
|
|
|
16
16
|
import { TableFormSchema, TableFormForeignKeySchema } from '../schema';
|
|
17
17
|
import { ColumnSchema, OnDeleteActionSchema, OnUpdateActionSchema } from '@insforge/shared-schemas';
|
|
18
18
|
import { cn } from '@/lib/utils/utils';
|
|
19
|
+
import { AUTH_USERS_TABLE } from '../constants';
|
|
19
20
|
|
|
20
21
|
interface ForeignKeyPopoverProps {
|
|
21
22
|
form: UseFormReturn<TableFormSchema>;
|
|
@@ -69,17 +70,26 @@ export function ForeignKeyPopover({
|
|
|
69
70
|
}
|
|
70
71
|
}, [open, initialValue]);
|
|
71
72
|
|
|
72
|
-
// Get available tables
|
|
73
|
-
const availableTables =
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
// Get available tables (include auth.users as a special option)
|
|
74
|
+
const availableTables = [
|
|
75
|
+
AUTH_USERS_TABLE,
|
|
76
|
+
...tables.filter((tableName) => mode === 'create' || tableName !== editTableName),
|
|
77
|
+
];
|
|
76
78
|
|
|
77
|
-
// Get columns for selected reference table
|
|
78
|
-
const
|
|
79
|
+
// Get columns for selected reference table (skip fetch for auth.users)
|
|
80
|
+
const isAuthUsers = newForeignKey.referenceTable === AUTH_USERS_TABLE;
|
|
81
|
+
const { data: fetchedTableSchema } = useTableSchema(
|
|
79
82
|
newForeignKey.referenceTable || '',
|
|
80
|
-
!!newForeignKey.referenceTable && open
|
|
83
|
+
!!newForeignKey.referenceTable && !isAuthUsers && open
|
|
81
84
|
);
|
|
82
85
|
|
|
86
|
+
// Use hardcoded schema for auth.users, otherwise use fetched schema
|
|
87
|
+
const referenceTableSchema = isAuthUsers
|
|
88
|
+
? {
|
|
89
|
+
columns: [{ columnName: 'id', type: 'uuid', isUnique: true, isNullable: false }],
|
|
90
|
+
}
|
|
91
|
+
: fetchedTableSchema;
|
|
92
|
+
|
|
83
93
|
// Get the type of the selected source column
|
|
84
94
|
const getSourceFieldType = useMemo(() => {
|
|
85
95
|
if (!newForeignKey.columnName) {
|
|
@@ -252,7 +262,7 @@ export function ForeignKeyPopover({
|
|
|
252
262
|
if (!col.isUnique) {
|
|
253
263
|
rightText = 'Not unique';
|
|
254
264
|
} else if (!typesMatch) {
|
|
255
|
-
rightText = '
|
|
265
|
+
rightText = 'Column types mismatch';
|
|
256
266
|
}
|
|
257
267
|
|
|
258
268
|
return (
|
|
@@ -20,9 +20,11 @@ import {
|
|
|
20
20
|
} from '@/components';
|
|
21
21
|
import { useTables } from '@/features/database/hooks/useTables';
|
|
22
22
|
import { useRecords } from '@/features/database/hooks/useRecords';
|
|
23
|
+
import { useUsers } from '@/features/auth/hooks/useUsers';
|
|
23
24
|
import { convertSchemaToColumns } from '@/features/database/components/DatabaseDataGrid';
|
|
24
25
|
import { formatValueForDisplay } from '@/lib/utils/utils';
|
|
25
26
|
import { ColumnType } from '@insforge/shared-schemas';
|
|
27
|
+
import { AUTH_USERS_TABLE, authUsersSchema } from '../constants';
|
|
26
28
|
|
|
27
29
|
const PAGE_SIZE = 50;
|
|
28
30
|
|
|
@@ -45,29 +47,67 @@ export function LinkRecordModal({
|
|
|
45
47
|
const [sortColumns, setSortColumns] = useState<SortColumn[]>([]);
|
|
46
48
|
const [currentPage, setCurrentPage] = useState(1);
|
|
47
49
|
const { useTableSchema } = useTables();
|
|
48
|
-
const
|
|
50
|
+
const isAuthUsers = referenceTable === AUTH_USERS_TABLE;
|
|
49
51
|
|
|
50
|
-
//
|
|
51
|
-
const
|
|
52
|
+
// Regular table records hook (disabled for auth.users)
|
|
53
|
+
const recordsHook = useRecords(isAuthUsers ? '' : referenceTable);
|
|
52
54
|
|
|
53
|
-
//
|
|
55
|
+
// Auth users hook
|
|
56
|
+
const {
|
|
57
|
+
users,
|
|
58
|
+
totalUsers,
|
|
59
|
+
isLoading: isLoadingUsers,
|
|
60
|
+
setCurrentPage: setUsersCurrentPage,
|
|
61
|
+
} = useUsers({
|
|
62
|
+
pageSize: PAGE_SIZE,
|
|
63
|
+
enabled: isAuthUsers && open,
|
|
64
|
+
searchQuery: isAuthUsers ? searchQuery : '',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Sync current page with users hook
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (isAuthUsers) {
|
|
70
|
+
setUsersCurrentPage(currentPage);
|
|
71
|
+
}
|
|
72
|
+
}, [currentPage, isAuthUsers, setUsersCurrentPage]);
|
|
73
|
+
|
|
74
|
+
// Fetch table schema (skip for auth.users)
|
|
75
|
+
const { data: fetchedSchema } = useTableSchema(referenceTable, !isAuthUsers && open);
|
|
76
|
+
const schema = isAuthUsers ? authUsersSchema : fetchedSchema;
|
|
77
|
+
|
|
78
|
+
// Fetch records from the reference table (skip for auth.users)
|
|
54
79
|
const offset = (currentPage - 1) * PAGE_SIZE;
|
|
55
|
-
const { data: recordsResponse, isLoading } = recordsHook.useTableRecords(
|
|
80
|
+
const { data: recordsResponse, isLoading: isLoadingRecords } = recordsHook.useTableRecords(
|
|
56
81
|
PAGE_SIZE,
|
|
57
82
|
offset,
|
|
58
83
|
searchQuery || undefined,
|
|
59
84
|
sortColumns,
|
|
60
|
-
open
|
|
85
|
+
!isAuthUsers && open
|
|
61
86
|
);
|
|
62
87
|
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
// Combine data from either source
|
|
89
|
+
const recordsData = useMemo(() => {
|
|
90
|
+
if (isAuthUsers) {
|
|
91
|
+
return users.length > 0 || open
|
|
92
|
+
? {
|
|
93
|
+
schema: authUsersSchema,
|
|
94
|
+
records: users as DatabaseRecord[],
|
|
95
|
+
totalRecords: totalUsers,
|
|
96
|
+
}
|
|
97
|
+
: undefined;
|
|
98
|
+
}
|
|
99
|
+
return schema && recordsResponse
|
|
65
100
|
? {
|
|
66
101
|
schema,
|
|
67
102
|
records: recordsResponse.records,
|
|
68
|
-
totalRecords:
|
|
103
|
+
totalRecords:
|
|
104
|
+
recordsResponse.pagination.total ??
|
|
105
|
+
('recordCount' in schema ? (schema.recordCount as number) : 0),
|
|
69
106
|
}
|
|
70
107
|
: undefined;
|
|
108
|
+
}, [isAuthUsers, users, totalUsers, open, schema, recordsResponse]);
|
|
109
|
+
|
|
110
|
+
const isLoading = isAuthUsers ? isLoadingUsers : isLoadingRecords;
|
|
71
111
|
|
|
72
112
|
// Reset page when search query changes
|
|
73
113
|
useEffect(() => {
|
|
@@ -122,15 +162,23 @@ export function LinkRecordModal({
|
|
|
122
162
|
};
|
|
123
163
|
|
|
124
164
|
// Helper function to render cell value properly based on type
|
|
125
|
-
|
|
126
|
-
|
|
165
|
+
// Accepts DatabaseRecord value type and converts to display string
|
|
166
|
+
const renderCellValue = (
|
|
167
|
+
value: ConvertedValue | { [key: string]: string }[],
|
|
168
|
+
type: ColumnType | undefined
|
|
169
|
+
): string => {
|
|
170
|
+
// For JSON type, if value is already an object/array, stringify it for formatValueForDisplay
|
|
171
|
+
if (type === ColumnType.JSON && value !== null && typeof value === 'object') {
|
|
172
|
+
return formatValueForDisplay(JSON.stringify(value), type);
|
|
173
|
+
}
|
|
174
|
+
return formatValueForDisplay(value as ConvertedValue, type);
|
|
127
175
|
};
|
|
128
176
|
|
|
129
177
|
if (col.key === referenceColumn) {
|
|
130
178
|
return {
|
|
131
179
|
...baseCol,
|
|
132
180
|
renderCell: (props: RenderCellProps<DataGridRowType>) => {
|
|
133
|
-
const displayValue = renderCellValue(
|
|
181
|
+
const displayValue = renderCellValue(props.row[col.key], col.type);
|
|
134
182
|
return (
|
|
135
183
|
<div className="w-full h-full flex items-center cursor-pointer">
|
|
136
184
|
<span className="truncate font-medium" title={displayValue}>
|
|
@@ -155,7 +203,7 @@ export function LinkRecordModal({
|
|
|
155
203
|
...baseCol,
|
|
156
204
|
cellClass: 'link-modal-disabled-cell',
|
|
157
205
|
renderCell: (props: RenderCellProps<DataGridRowType>) => {
|
|
158
|
-
const displayValue = renderCellValue(
|
|
206
|
+
const displayValue = renderCellValue(props.row[col.key], col.type);
|
|
159
207
|
return (
|
|
160
208
|
<div className="w-full h-full flex items-center cursor-not-allowed relative">
|
|
161
209
|
<div className="absolute inset-0 pointer-events-none opacity-0 hover:opacity-10 bg-gray-200 dark:bg-gray-600 transition-opacity z-5" />
|
|
@@ -495,7 +495,7 @@ export function RecordFormField({ field, form, tableName }: RecordFormFieldProps
|
|
|
495
495
|
onChange={(newValue) => {
|
|
496
496
|
const result = convertValueForColumn(ColumnType.JSON, newValue as string);
|
|
497
497
|
if (result.success) {
|
|
498
|
-
formField.onChange(result.value
|
|
498
|
+
formField.onChange(result.value);
|
|
499
499
|
} else {
|
|
500
500
|
// If parsing fails, keep the string value
|
|
501
501
|
formField.onChange(newValue);
|
|
@@ -37,9 +37,6 @@ export function TableSidebar({
|
|
|
37
37
|
editLabel="Edit Table"
|
|
38
38
|
deleteLabel="Delete Table"
|
|
39
39
|
icon={Table}
|
|
40
|
-
filterItems={(tableNames) =>
|
|
41
|
-
tableNames.filter((name) => name !== 'auth' && name !== 'profiles' && name !== 'identifies')
|
|
42
|
-
}
|
|
43
40
|
renderSkeleton={() => <TableListSkeleton />}
|
|
44
41
|
renderEmptyState={(searchTerm) => <TableEmptyState searchTerm={searchTerm} />}
|
|
45
42
|
/>
|
|
@@ -15,7 +15,7 @@ export function TablesEmptyState({
|
|
|
15
15
|
onTemplateClick,
|
|
16
16
|
}: TablesEmptyStateProps) {
|
|
17
17
|
return (
|
|
18
|
-
<div className="flex justify-center w-full h-full bg-bg-gray dark:bg-neutral-800 px-6">
|
|
18
|
+
<div className="flex justify-center w-full h-full bg-bg-gray dark:bg-neutral-800 px-6 overflow-y-auto">
|
|
19
19
|
<div className="flex flex-col gap-6 max-w-[1024px] w-full pb-9 pt-6">
|
|
20
20
|
<h2 className="text-xl font-semibold text-zinc-950 dark:text-white leading-7 tracking-[-0.1px]">
|
|
21
21
|
Create Your First Table
|
|
@@ -70,7 +70,7 @@ export function TemplatePreview({ template, onCancel }: TemplatePreviewProps) {
|
|
|
70
70
|
externalSchemas={template.visualizerSchema}
|
|
71
71
|
metadata={{
|
|
72
72
|
auth: {
|
|
73
|
-
|
|
73
|
+
providers: [],
|
|
74
74
|
},
|
|
75
75
|
database: {
|
|
76
76
|
tables: [],
|
|
@@ -80,7 +80,6 @@ export function TemplatePreview({ template, onCancel }: TemplatePreviewProps) {
|
|
|
80
80
|
buckets: [],
|
|
81
81
|
totalSizeInGB: 0,
|
|
82
82
|
},
|
|
83
|
-
functions: [],
|
|
84
83
|
}}
|
|
85
84
|
showControls={false}
|
|
86
85
|
showMiniMap={false}
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { Type, Clock, Calendar, Hash, Percent, ToggleLeft, Fingerprint, Code } from 'lucide-react';
|
|
2
2
|
import { ColumnType } from '@insforge/shared-schemas';
|
|
3
3
|
|
|
4
|
+
// Special handling for auth.users foreign key references
|
|
5
|
+
export const AUTH_USERS_TABLE = 'auth.users';
|
|
6
|
+
|
|
7
|
+
// schema for auth.users - used for displaying user records
|
|
8
|
+
export const authUsersSchema = {
|
|
9
|
+
tableName: 'auth.users',
|
|
10
|
+
columns: [
|
|
11
|
+
{ columnName: 'id', type: 'uuid', isUnique: true, isNullable: false },
|
|
12
|
+
{ columnName: 'email', type: 'string', isUnique: true, isNullable: false },
|
|
13
|
+
{ columnName: 'emailVerified', type: 'boolean', isUnique: false, isNullable: false },
|
|
14
|
+
{ columnName: 'providers', type: 'json', isUnique: false, isNullable: true },
|
|
15
|
+
{ columnName: 'createdAt', type: 'timestamp', isUnique: false, isNullable: false },
|
|
16
|
+
{ columnName: 'updatedAt', type: 'timestamp', isUnique: false, isNullable: false },
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
|
|
4
20
|
export const columnTypeIcons: Record<ColumnType, React.ComponentType<{ className?: string }>> = {
|
|
5
21
|
[ColumnType.STRING]: Type,
|
|
6
22
|
[ColumnType.DATE]: Calendar,
|
|
@@ -22,31 +38,3 @@ export const columnTypeDescriptions: Record<ColumnType, string> = {
|
|
|
22
38
|
[ColumnType.UUID]: 'Unique identifiers (auto-generated)',
|
|
23
39
|
[ColumnType.JSON]: 'Complex structured data',
|
|
24
40
|
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* System tables that should be filtered out from user-facing database views
|
|
28
|
-
*/
|
|
29
|
-
export const SYSTEM_TABLES = ['users'];
|
|
30
|
-
export const SYSTEM_FUNCTIONS = [
|
|
31
|
-
'create_default_policies',
|
|
32
|
-
'create_policies_after_rls',
|
|
33
|
-
'email',
|
|
34
|
-
'reload_postgrest_schema',
|
|
35
|
-
'role',
|
|
36
|
-
'uid',
|
|
37
|
-
'update_updated_at_column',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Check if a table name is a system table
|
|
42
|
-
*/
|
|
43
|
-
export function isSystemTable(tableName: string): boolean {
|
|
44
|
-
return tableName.startsWith('_') || SYSTEM_TABLES.includes(tableName);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Check if a function name is a system function
|
|
49
|
-
*/
|
|
50
|
-
export function isSystemFunction(functionName: string): boolean {
|
|
51
|
-
return SYSTEM_FUNCTIONS.includes(functionName);
|
|
52
|
-
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useMutation } from '@tanstack/react-query';
|
|
2
|
-
import { recordService
|
|
2
|
+
import { recordService } from '../services/record.service.js';
|
|
3
|
+
import { BulkUpsertResponse } from '@insforge/shared-schemas';
|
|
3
4
|
|
|
4
5
|
interface UseCSVImportOptions {
|
|
5
|
-
onSuccess?: (data:
|
|
6
|
+
onSuccess?: (data: BulkUpsertResponse) => void;
|
|
6
7
|
onError?: (error: Error) => void;
|
|
7
8
|
}
|
|
8
9
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
2
|
-
import { advanceService
|
|
2
|
+
import { advanceService } from '../services/advance.service';
|
|
3
|
+
import { RawSQLResponse } from '@insforge/shared-schemas';
|
|
3
4
|
import { useToast } from '@/lib/hooks/useToast';
|
|
4
5
|
|
|
5
6
|
interface UseRawSQLOptions {
|
|
@@ -28,7 +29,7 @@ export function useRawSQL(options?: UseRawSQLOptions) {
|
|
|
28
29
|
void queryClient.invalidateQueries({ queryKey: ['tables', 'schemas'] });
|
|
29
30
|
|
|
30
31
|
if (options?.showSuccessToast !== false) {
|
|
31
|
-
const message =
|
|
32
|
+
const message = 'SQL query executed successfully';
|
|
32
33
|
showToast(message, 'success');
|
|
33
34
|
}
|
|
34
35
|
options?.onSuccess?.(data);
|
|
@@ -114,13 +114,11 @@ export function useAllTableSchemas(enabled = true) {
|
|
|
114
114
|
|
|
115
115
|
const { allSchemas, isLoadingSchemas } = useQueries({
|
|
116
116
|
queries: enabled
|
|
117
|
-
? tables
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
staleTime: 2 * 60 * 1000,
|
|
123
|
-
}))
|
|
117
|
+
? tables.map((tableName) => ({
|
|
118
|
+
queryKey: ['tables', tableName, 'schema'],
|
|
119
|
+
queryFn: () => tableService.getTableSchema(tableName),
|
|
120
|
+
staleTime: 2 * 60 * 1000,
|
|
121
|
+
}))
|
|
124
122
|
: [],
|
|
125
123
|
combine: (results) => ({
|
|
126
124
|
allSchemas: results.filter((r) => r.data).map((r) => r.data as GetTableSchemaResponse),
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
import { useFunctions } from '../hooks/useDatabase';
|
|
17
17
|
import { SQLModal, SQLCellButton } from '../components/SQLModal';
|
|
18
18
|
import type { DatabaseFunctionsResponse } from '@insforge/shared-schemas';
|
|
19
|
-
import { isSystemFunction } from '../constants';
|
|
20
19
|
|
|
21
20
|
interface FunctionRow extends DataGridRowType {
|
|
22
21
|
id: string;
|
|
@@ -36,10 +35,6 @@ function parseFunctionsFromResponse(
|
|
|
36
35
|
const functions: FunctionRow[] = [];
|
|
37
36
|
|
|
38
37
|
response.functions.forEach((func) => {
|
|
39
|
-
if (isSystemFunction(func.functionName)) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
functions.push({
|
|
44
39
|
id: func.functionName,
|
|
45
40
|
functionName: func.functionName,
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
import { useIndexes } from '../hooks/useDatabase';
|
|
17
17
|
import { SQLModal, SQLCellButton } from '../components/SQLModal';
|
|
18
18
|
import type { DatabaseIndexesResponse } from '@insforge/shared-schemas';
|
|
19
|
-
import { isSystemTable } from '../constants';
|
|
20
19
|
|
|
21
20
|
interface IndexRow extends DataGridRowType {
|
|
22
21
|
id: string;
|
|
@@ -36,10 +35,6 @@ function parseIndexesFromResponse(response: DatabaseIndexesResponse | undefined)
|
|
|
36
35
|
const indexes: IndexRow[] = [];
|
|
37
36
|
|
|
38
37
|
response.indexes.forEach((index) => {
|
|
39
|
-
if (isSystemTable(index.tableName)) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
indexes.push({
|
|
44
39
|
id: `${index.tableName}_${index.indexName}`,
|
|
45
40
|
tableName: index.tableName,
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
import { usePolicies } from '../hooks/useDatabase';
|
|
17
17
|
import { SQLModal, SQLCellButton } from '../components/SQLModal';
|
|
18
18
|
import type { DatabasePoliciesResponse } from '@insforge/shared-schemas';
|
|
19
|
-
import { isSystemTable } from '../constants';
|
|
20
19
|
|
|
21
20
|
interface PolicyRow extends DataGridRowType {
|
|
22
21
|
id: string;
|
|
@@ -37,10 +36,6 @@ function parsePoliciesFromResponse(response: DatabasePoliciesResponse | undefine
|
|
|
37
36
|
const policies: PolicyRow[] = [];
|
|
38
37
|
|
|
39
38
|
response.policies.forEach((policy) => {
|
|
40
|
-
if (isSystemTable(policy.tableName)) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
39
|
policies.push({
|
|
45
40
|
id: `${policy.tableName}_${policy.policyName}`,
|
|
46
41
|
tableName: policy.tableName,
|
|
@@ -304,7 +304,7 @@ export default function SQLEditorPage() {
|
|
|
304
304
|
language="sql"
|
|
305
305
|
value={activeTab?.query || ''}
|
|
306
306
|
onChange={handleQueryChange}
|
|
307
|
-
placeholder="SELECT *
|
|
307
|
+
placeholder="SELECT * from products LIMIT 10;"
|
|
308
308
|
/>
|
|
309
309
|
</div>
|
|
310
310
|
</div>
|
|
@@ -362,7 +362,7 @@ export default function SQLEditorPage() {
|
|
|
362
362
|
{isError && error ? (
|
|
363
363
|
<ErrorViewer error={error} />
|
|
364
364
|
) : isSuccess && data ? (
|
|
365
|
-
<ResultsViewer data={data.rows || data
|
|
365
|
+
<ResultsViewer data={data.rows || data} />
|
|
366
366
|
) : (
|
|
367
367
|
<div
|
|
368
368
|
className={cn(
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
import { useTriggers } from '../hooks/useDatabase';
|
|
17
17
|
import { SQLModal, SQLCellButton } from '../components/SQLModal';
|
|
18
18
|
import type { DatabaseTriggersResponse } from '@insforge/shared-schemas';
|
|
19
|
-
import { isSystemTable } from '../constants';
|
|
20
19
|
|
|
21
20
|
interface TriggerRow extends DataGridRowType {
|
|
22
21
|
id: string;
|
|
@@ -36,10 +35,6 @@ function parseTriggersFromResponse(response: DatabaseTriggersResponse | undefine
|
|
|
36
35
|
const triggers: TriggerRow[] = [];
|
|
37
36
|
|
|
38
37
|
response.triggers.forEach((trigger) => {
|
|
39
|
-
if (isSystemTable(trigger.tableName)) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
38
|
triggers.push({
|
|
44
39
|
id: `${trigger.tableName}_${trigger.triggerName}`,
|
|
45
40
|
tableName: trigger.tableName,
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import { apiClient } from '@/lib/api/client';
|
|
2
|
-
|
|
3
|
-
export interface RawSQLRequest {
|
|
4
|
-
query: string;
|
|
5
|
-
params?: unknown[];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface RawSQLResponse {
|
|
9
|
-
rows?: unknown[];
|
|
10
|
-
rowCount?: number;
|
|
11
|
-
fields?: Array<{ name: string; dataTypeID: number }>;
|
|
12
|
-
success?: boolean;
|
|
13
|
-
data?: unknown[];
|
|
14
|
-
error?: string;
|
|
15
|
-
message?: string;
|
|
16
|
-
}
|
|
2
|
+
import { RawSQLRequest, RawSQLResponse } from '@insforge/shared-schemas';
|
|
17
3
|
|
|
18
4
|
export class AdvanceService {
|
|
19
5
|
/**
|
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
import { ConvertedValue } from '@/components/datagrid/datagridTypes';
|
|
2
2
|
import { apiClient } from '@/lib/api/client';
|
|
3
|
-
import { ColumnSchema } from '@insforge/shared-schemas';
|
|
3
|
+
import { ColumnSchema, BulkUpsertResponse } from '@insforge/shared-schemas';
|
|
4
4
|
import { tableService } from './table.service';
|
|
5
5
|
|
|
6
|
-
export interface CSVImportResponse {
|
|
7
|
-
success: boolean;
|
|
8
|
-
message?: string;
|
|
9
|
-
data?: {
|
|
10
|
-
rowCount: number;
|
|
11
|
-
};
|
|
12
|
-
error?: string; // For backend error messages
|
|
13
|
-
}
|
|
14
|
-
|
|
15
6
|
export class RecordService {
|
|
16
7
|
/**
|
|
17
8
|
* Data fetching method with built-in search, sorting, and pagination for UI components.
|
|
@@ -190,7 +181,7 @@ export class RecordService {
|
|
|
190
181
|
return { valid: true };
|
|
191
182
|
}
|
|
192
183
|
|
|
193
|
-
async importCSV(tableName: string, file: File): Promise<
|
|
184
|
+
async importCSV(tableName: string, file: File): Promise<BulkUpsertResponse> {
|
|
194
185
|
const validation = this.validateCSVFile(file);
|
|
195
186
|
if (!validation.valid) {
|
|
196
187
|
throw new Error(validation.error || 'Invalid CSV file.');
|
|
@@ -200,19 +191,12 @@ export class RecordService {
|
|
|
200
191
|
formData.append('file', file);
|
|
201
192
|
formData.append('table', tableName);
|
|
202
193
|
|
|
203
|
-
const response = await apiClient.request(`/database/advance/bulk-upsert`, {
|
|
194
|
+
const response: BulkUpsertResponse = await apiClient.request(`/database/advance/bulk-upsert`, {
|
|
204
195
|
method: 'POST',
|
|
205
196
|
headers: apiClient.withAccessToken(),
|
|
206
197
|
body: formData,
|
|
207
198
|
});
|
|
208
|
-
return
|
|
209
|
-
success: response.success,
|
|
210
|
-
message: response.message,
|
|
211
|
-
data: {
|
|
212
|
-
rowCount: response.rowsAffected,
|
|
213
|
-
},
|
|
214
|
-
error: response.error,
|
|
215
|
-
};
|
|
199
|
+
return response;
|
|
216
200
|
}
|
|
217
201
|
}
|
|
218
202
|
|
|
@@ -9,12 +9,9 @@ import {
|
|
|
9
9
|
|
|
10
10
|
export class TableService {
|
|
11
11
|
async listTables(): Promise<string[]> {
|
|
12
|
-
|
|
12
|
+
return await apiClient.request('/database/tables', {
|
|
13
13
|
headers: apiClient.withAccessToken(),
|
|
14
14
|
});
|
|
15
|
-
// data is already unwrapped by request method and should be an array
|
|
16
|
-
// Filter out the 'users' table
|
|
17
|
-
return Array.isArray(data) ? data.filter((table) => table !== 'users') : [];
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
getTableSchema(tableName: string): Promise<GetTableSchemaResponse> {
|
|
@@ -18,7 +18,7 @@ export const aiChatbotTemplate: DatabaseTemplate = {
|
|
|
18
18
|
isNullable: true,
|
|
19
19
|
isUnique: false,
|
|
20
20
|
foreignKey: {
|
|
21
|
-
referenceTable: 'users',
|
|
21
|
+
referenceTable: 'auth.users',
|
|
22
22
|
referenceColumn: 'id',
|
|
23
23
|
onDelete: 'CASCADE',
|
|
24
24
|
onUpdate: 'CASCADE',
|
|
@@ -125,7 +125,7 @@ export const aiChatbotTemplate: DatabaseTemplate = {
|
|
|
125
125
|
isNullable: true,
|
|
126
126
|
isUnique: false,
|
|
127
127
|
foreignKey: {
|
|
128
|
-
referenceTable: 'users',
|
|
128
|
+
referenceTable: 'auth.users',
|
|
129
129
|
referenceColumn: 'id',
|
|
130
130
|
onDelete: 'CASCADE',
|
|
131
131
|
onUpdate: 'CASCADE',
|
|
@@ -165,7 +165,7 @@ export const aiChatbotTemplate: DatabaseTemplate = {
|
|
|
165
165
|
isNullable: true,
|
|
166
166
|
isUnique: false,
|
|
167
167
|
foreignKey: {
|
|
168
|
-
referenceTable: 'users',
|
|
168
|
+
referenceTable: 'auth.users',
|
|
169
169
|
referenceColumn: 'id',
|
|
170
170
|
onDelete: 'CASCADE',
|
|
171
171
|
onUpdate: 'CASCADE',
|
|
@@ -229,7 +229,7 @@ export const aiChatbotTemplate: DatabaseTemplate = {
|
|
|
229
229
|
-- Conversations table
|
|
230
230
|
CREATE TABLE conversations (
|
|
231
231
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
232
|
-
user_id UUID REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
232
|
+
user_id UUID REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
233
233
|
title VARCHAR(255),
|
|
234
234
|
model VARCHAR(100) DEFAULT 'gpt-4',
|
|
235
235
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
@@ -250,7 +250,7 @@ CREATE TABLE messages (
|
|
|
250
250
|
CREATE TABLE feedback (
|
|
251
251
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
252
252
|
message_id UUID REFERENCES messages(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
253
|
-
user_id UUID REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
253
|
+
user_id UUID REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
254
254
|
rating INTEGER CHECK (rating >= 1 AND rating <= 5),
|
|
255
255
|
comment TEXT,
|
|
256
256
|
created_at TIMESTAMP DEFAULT NOW()
|
|
@@ -259,7 +259,7 @@ CREATE TABLE feedback (
|
|
|
259
259
|
-- Prompts library table
|
|
260
260
|
CREATE TABLE prompts (
|
|
261
261
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
262
|
-
user_id UUID REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
262
|
+
user_id UUID REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
|
263
263
|
title VARCHAR(255) NOT NULL,
|
|
264
264
|
content TEXT NOT NULL,
|
|
265
265
|
category VARCHAR(100),
|