insforge 0.3.3 → 1.2.10
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/.claude-plugin/marketplace.json +20 -0
- package/.cursor/rules/cursor-rules.mdc +94 -0
- package/.dockerignore +3 -0
- package/.env.example +33 -4
- package/.github/ISSUE_TEMPLATE/bug_report.yml +13 -60
- package/.github/ISSUE_TEMPLATE/config.yml +2 -2
- package/.github/ISSUE_TEMPLATE/feature_request.yml +10 -63
- package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
- package/.github/workflows/build-image.yml +2 -1
- package/.github/workflows/e2e.yml +63 -0
- package/CHANGELOG.md +41 -0
- package/CLAUDE_PLUGIN.md +104 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +1 -1
- package/Dockerfile +4 -1
- package/README.md +66 -18
- package/assets/mcpInstallv2.png +0 -0
- package/assets/sampleResponse.png +0 -0
- package/auth/index.html +13 -0
- package/auth/package.json +28 -0
- package/auth/public/favicon.ico +0 -0
- package/auth/src/App.tsx +33 -0
- package/auth/src/components/ErrorCard.tsx +37 -0
- package/auth/src/components/Layout.tsx +13 -0
- package/auth/src/index.css +19 -0
- package/auth/src/lib/broadcastService.ts +115 -0
- package/auth/src/lib/utils.ts +11 -0
- package/auth/src/main.tsx +22 -0
- package/auth/src/pages/ForgotPasswordPage.tsx +11 -0
- package/auth/src/pages/ResetPasswordPage.tsx +11 -0
- package/auth/src/pages/SignInPage.tsx +57 -0
- package/auth/src/pages/SignUpPage.tsx +57 -0
- package/auth/src/pages/VerifyEmailPage.tsx +20 -0
- package/auth/src/vite-env.d.ts +10 -0
- package/auth/tsconfig.json +32 -0
- package/auth/tsconfig.node.json +11 -0
- package/auth/vite.config.ts +25 -0
- package/backend/package.json +9 -9
- package/backend/src/api/{middleware → middlewares}/auth.ts +8 -9
- package/backend/src/api/middlewares/rate-limiters.ts +127 -0
- package/backend/src/api/routes/{ai.ts → ai/index.routes.ts} +20 -24
- package/backend/src/api/routes/auth/index.routes.ts +570 -0
- package/backend/src/api/routes/auth/oauth.routes.ts +448 -0
- package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +107 -65
- package/backend/src/api/routes/database/index.routes.ts +13 -0
- package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +22 -8
- package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +20 -23
- package/backend/src/api/routes/docs/index.routes.ts +76 -0
- package/backend/src/api/routes/functions/index.routes.ts +188 -0
- package/backend/src/api/routes/{logs.ts → logs/index.routes.ts} +25 -30
- package/backend/src/api/routes/{metadata.ts → metadata/index.routes.ts} +21 -31
- package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
- package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +34 -53
- package/backend/src/api/routes/usage/index.routes.ts +89 -0
- package/backend/src/infra/config/app.config.ts +51 -0
- package/backend/src/{core/database/manager.ts → infra/database/database.manager.ts} +76 -85
- package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -0
- package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +8 -0
- package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +60 -0
- package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -0
- package/backend/src/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
- package/backend/src/infra/security/token.manager.ts +125 -0
- package/backend/src/{core/socket/socket.ts → infra/socket/socket.manager.ts} +15 -15
- package/backend/src/providers/ai/openrouter.provider.ts +377 -0
- package/backend/src/providers/email/base.provider.ts +41 -0
- package/backend/src/providers/email/cloud.provider.ts +187 -0
- package/backend/src/{core/logs/providers → providers/logs}/base.provider.ts +11 -11
- package/backend/src/{core/logs/providers → providers/logs}/cloudwatch.provider.ts +61 -38
- package/backend/src/providers/logs/local.provider.ts +185 -0
- package/backend/src/providers/oauth/base.provider.ts +29 -0
- package/backend/src/providers/oauth/discord.provider.ts +195 -0
- package/backend/src/providers/oauth/facebook.provider.ts +194 -0
- package/backend/src/providers/oauth/github.provider.ts +208 -0
- package/backend/src/providers/oauth/google.provider.ts +249 -0
- package/backend/src/providers/oauth/index.ts +7 -0
- package/backend/src/providers/oauth/linkedin.provider.ts +240 -0
- package/backend/src/providers/oauth/microsoft.provider.ts +169 -0
- package/backend/src/providers/oauth/x.provider.ts +202 -0
- package/backend/src/providers/storage/base.provider.ts +29 -0
- package/backend/src/providers/storage/local.provider.ts +103 -0
- package/backend/src/providers/storage/s3.provider.ts +313 -0
- package/backend/src/server.ts +70 -74
- package/backend/src/{core/ai/config.ts → services/ai/ai-config.service.ts} +19 -24
- package/backend/src/services/ai/ai-model.service.ts +60 -0
- package/backend/src/{core/ai/usage.ts → services/ai/ai-usage.service.ts} +28 -35
- package/backend/src/{core/ai/chat.ts → services/ai/chat-completion.service.ts} +37 -24
- package/backend/src/services/ai/helpers.ts +64 -0
- package/backend/src/{core/ai/image.ts → services/ai/image-generation.service.ts} +17 -19
- package/backend/src/services/ai/index.ts +13 -0
- package/backend/src/services/auth/auth-config.service.ts +250 -0
- package/backend/src/services/auth/auth-otp.service.ts +424 -0
- package/backend/src/services/auth/auth.service.ts +1136 -0
- package/backend/src/services/auth/index.ts +4 -0
- package/backend/src/{core/auth/oauth.ts → services/auth/oauth-config.service.ts} +106 -52
- package/backend/src/{core/database/advance.ts → services/database/database-advance.service.ts} +97 -131
- package/backend/src/services/database/database-table.service.ts +811 -0
- package/backend/src/services/email/email.service.ts +75 -0
- package/backend/src/{core/functions/functions.ts → services/functions/function.service.ts} +95 -88
- package/backend/src/{core/logs/audit.ts → services/logs/audit.service.ts} +92 -75
- package/backend/src/services/logs/log.service.ts +73 -0
- package/backend/src/{core/secrets/secrets.ts → services/secrets/secret.service.ts} +48 -66
- package/backend/src/services/storage/storage.service.ts +617 -0
- package/backend/src/services/usage/usage.service.ts +149 -0
- package/backend/src/types/auth.ts +66 -2
- package/backend/src/types/email.ts +8 -0
- package/backend/src/types/error-constants.ts +4 -0
- package/backend/src/types/logs.ts +0 -29
- package/backend/src/{core/socket/types.ts → types/socket.ts} +5 -6
- package/backend/src/utils/environment.ts +9 -3
- package/backend/src/utils/logger.ts +20 -2
- package/backend/src/utils/seed.ts +150 -57
- package/backend/src/utils/sql-parser.ts +1 -1
- package/backend/src/utils/utils.ts +114 -0
- package/backend/src/utils/validations.ts +40 -4
- package/backend/tests/local/test-ai-config.sh +129 -0
- package/backend/tests/local/test-ai-usage.sh +80 -0
- package/backend/tests/local/test-auth-router.sh +1 -1
- package/backend/tests/local/test-e2e.sh +1 -1
- package/backend/tests/local/test-functions.sh +123 -0
- package/backend/tests/local/test-logs.sh +132 -0
- package/backend/tests/local/test-public-bucket.sh +3 -3
- package/backend/tests/local/test-secrets.sh +14 -12
- package/backend/tests/local/test-traditional-rest.sh +2 -2
- package/backend/tests/manual/test-rawsql-modes.sh +244 -0
- package/backend/tests/test-config.sh +37 -1
- package/backend/tests/unit/cloud-token.test.ts +48 -0
- package/backend/tests/unit/constant.test.ts +8 -0
- package/backend/tests/unit/email.test.ts +372 -0
- package/backend/tests/unit/environment.test.ts +59 -0
- package/backend/tests/unit/helpers.test.ts +63 -0
- package/backend/tests/unit/logger.test.ts +22 -0
- package/backend/tests/unit/rate-limit.test.ts +154 -0
- package/backend/tests/unit/response.test.ts +58 -0
- package/backend/tests/unit/sql-parser.test.ts +74 -0
- package/backend/tests/unit/uuid.test.ts +21 -0
- package/backend/tests/unit/validations.test.ts +80 -0
- package/backend/tsconfig.json +1 -1
- package/backend/vitest.config.ts +11 -0
- package/claude-plugin/.claude-plugin/plugin.json +24 -0
- package/claude-plugin/README.md +133 -0
- package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -0
- package/docker-compose.prod.yml +60 -4
- package/docker-compose.yml +65 -4
- package/docker-init/db/db-init.sql +6 -34
- package/docker-init/logs/vector.yml +236 -0
- package/docs/README.md +44 -0
- package/docs/changelog.mdx +67 -0
- package/docs/core-concepts/ai/architecture.mdx +373 -0
- package/docs/core-concepts/ai/sdk.mdx +213 -0
- package/docs/core-concepts/authentication/architecture.mdx +278 -0
- package/docs/core-concepts/authentication/sdk.mdx +414 -0
- package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -0
- package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -0
- package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -0
- package/docs/core-concepts/authentication/ui-components/react.mdx +129 -0
- package/docs/core-concepts/database/architecture.mdx +256 -0
- package/docs/core-concepts/database/sdk.mdx +382 -0
- package/docs/core-concepts/functions/architecture.mdx +105 -0
- package/docs/core-concepts/functions/sdk.mdx +184 -0
- package/docs/core-concepts/storage/architecture.mdx +243 -0
- package/docs/core-concepts/storage/sdk.mdx +253 -0
- package/docs/deployment/README.md +94 -0
- package/docs/deployment/deploy-to-aws-ec2.md +565 -0
- package/docs/deployment/deploy-to-azure-virtual-machines.md +313 -0
- package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -0
- package/docs/deployment/deploy-to-render.md +441 -0
- package/docs/docs.json +210 -0
- package/docs/examples/framework-guides/nextjs.mdx +131 -0
- package/docs/examples/framework-guides/nuxt.mdx +165 -0
- package/docs/examples/framework-guides/react.mdx +165 -0
- package/docs/examples/framework-guides/svelte.mdx +153 -0
- package/docs/examples/framework-guides/vue.mdx +159 -0
- package/docs/examples/overview.mdx +67 -0
- package/docs/favicon.svg +19 -0
- package/docs/images/changelog/nov-2025/auth-components.webp +0 -0
- package/docs/images/changelog/nov-2025/database-metadata.webp +0 -0
- package/docs/images/changelog/nov-2025/quickstart-prompts.webp +0 -0
- package/docs/images/changelog/nov-2025/sql-editor.webp +0 -0
- package/docs/images/changelog/nov-2025/usage-page.webp +0 -0
- package/docs/images/changelog/october-2025/csv-upload.webp +0 -0
- package/docs/images/changelog/october-2025/logs-feature.webp +0 -0
- package/docs/images/changelog/october-2025/oauth-providers.webp +0 -0
- package/docs/images/checks-passed.png +0 -0
- package/docs/images/dashboard-connect-expanded.png +0 -0
- package/docs/images/dashboard-connect.png +0 -0
- package/docs/images/hero-dark.png +0 -0
- package/docs/images/hero-light.png +0 -0
- package/docs/images/icons/ai.svg +4 -0
- package/docs/images/icons/auth.svg +1 -0
- package/docs/images/icons/database.svg +1 -0
- package/docs/images/icons/function.svg +1 -0
- package/docs/images/icons/storage.svg +1 -0
- package/docs/images/logos/nextjs.svg +4 -0
- package/docs/images/logos/nuxt.svg +4 -0
- package/docs/images/logos/react.svg +5 -0
- package/docs/images/logos/svelte.svg +4 -0
- package/docs/images/logos/vue.svg +5 -0
- package/docs/images/mcp-install.png +0 -0
- package/docs/images/onboarding-mcp.png +0 -0
- package/docs/insforge-instructions-sdk.md +55 -374
- package/docs/introduction.mdx +45 -0
- package/docs/logo/dark.svg +22 -0
- package/docs/logo/light.svg +20 -0
- package/docs/partnership.mdx +647 -0
- package/docs/quickstart.mdx +83 -0
- package/docs/showcase/2048-arena.png +0 -0
- package/docs/showcase/framegen-cloud.png +0 -0
- package/docs/showcase/line-connect-race.png +0 -0
- package/docs/showcase/moment-vibe.png +0 -0
- package/docs/showcase/national-flags.png +0 -0
- package/docs/showcase/pokemon-vibe.png +0 -0
- package/docs/showcase/pure-browse-buy.png +0 -0
- package/docs/showcase.mdx +52 -0
- package/docs/snippets/sdk-installation.mdx +22 -0
- package/docs/snippets/service-icons.mdx +27 -0
- package/eslint.config.js +10 -3
- package/frontend/package.json +10 -4
- package/frontend/src/App.tsx +13 -82
- package/frontend/src/assets/icons/connected.svg +3 -0
- package/frontend/src/assets/icons/loader.svg +9 -0
- package/frontend/src/assets/logos/apple.svg +4 -0
- package/frontend/src/assets/logos/discord.svg +1 -1
- package/frontend/src/assets/logos/facebook.svg +3 -0
- package/frontend/src/assets/logos/instagram.svg +2 -0
- package/frontend/src/assets/logos/linkedin.svg +3 -0
- package/frontend/src/assets/logos/microsoft.svg +1 -0
- package/frontend/src/assets/logos/spotify.svg +17 -0
- package/frontend/src/assets/logos/tiktok.svg +6 -0
- package/frontend/src/assets/logos/x.svg +3 -0
- package/frontend/src/components/Checkbox.tsx +27 -29
- package/frontend/src/components/CodeBlock.tsx +55 -2
- package/frontend/src/components/CodeEditor.tsx +92 -0
- package/frontend/src/components/ConfirmDialog.tsx +1 -1
- package/frontend/src/components/ConnectCTA.tsx +38 -0
- package/frontend/src/components/CopyButton.tsx +52 -15
- package/frontend/src/components/ErrorState.tsx +1 -2
- package/frontend/src/components/FeatureSidebar.tsx +6 -6
- package/frontend/src/components/FeatureSidebarItem.tsx +2 -2
- package/frontend/src/components/JsonHighlight.tsx +21 -9
- package/frontend/src/components/ProjectInfoModal.tsx +128 -0
- package/frontend/src/components/PromptDialog.tsx +1 -4
- package/frontend/src/components/SearchInput.tsx +1 -2
- package/frontend/src/components/Stepper.tsx +53 -0
- package/frontend/src/components/ThemeToggle.tsx +3 -3
- package/frontend/src/components/datagrid/DataGrid.tsx +25 -32
- package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +1 -2
- package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +2 -4
- package/frontend/src/components/datagrid/index.ts +23 -0
- package/frontend/src/components/index.ts +23 -30
- package/frontend/src/components/layout/AppHeader.tsx +133 -92
- package/frontend/src/components/layout/AppSidebar.tsx +80 -170
- package/frontend/src/components/layout/Layout.tsx +12 -23
- package/frontend/src/components/layout/PrimaryMenu.tsx +187 -0
- package/frontend/src/components/layout/SecondaryMenu.tsx +70 -0
- package/frontend/src/components/layout/index.ts +5 -0
- package/frontend/src/components/radix/Tooltip.tsx +24 -13
- package/frontend/src/components/radix/index.ts +22 -0
- package/frontend/src/features/ai/components/AIConfigCard.tsx +129 -83
- package/frontend/src/features/ai/components/AIEmptyState.tsx +12 -7
- package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +101 -0
- package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -0
- package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -0
- package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -0
- package/frontend/src/features/ai/components/index.ts +6 -0
- package/frontend/src/features/ai/helpers.ts +57 -71
- package/frontend/src/features/ai/hooks/useAIConfigs.ts +39 -113
- package/frontend/src/features/ai/hooks/useAIUsage.ts +0 -2
- package/frontend/src/features/ai/page/AIPage.tsx +67 -79
- package/frontend/src/features/ai/services/ai.service.ts +5 -5
- package/frontend/src/features/auth/components/AuthPreview.tsx +96 -0
- package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +53 -30
- package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +44 -14
- package/frontend/src/features/auth/components/index.ts +5 -0
- package/frontend/src/features/auth/helpers.tsx +200 -0
- package/frontend/src/features/auth/hooks/useAnonToken.ts +30 -0
- package/frontend/src/features/auth/hooks/useAuthConfig.ts +48 -0
- package/frontend/src/features/auth/hooks/useOAuthConfig.ts +14 -10
- package/frontend/src/features/auth/hooks/useUsers.ts +43 -5
- package/frontend/src/features/auth/index.ts +3 -2
- package/frontend/src/features/auth/page/AuthMethodsPage.tsx +275 -0
- package/frontend/src/features/auth/page/ConfigurationPage.tsx +395 -0
- package/frontend/src/features/auth/page/UsersPage.tsx +285 -0
- package/frontend/src/features/auth/services/anonToken.service.ts +11 -0
- package/frontend/src/features/auth/services/config.service.ts +19 -0
- package/frontend/src/features/auth/services/{oauth.service.ts → oauth-config.service.ts} +4 -4
- package/frontend/src/features/auth/services/{auth.service.ts → user.service.ts} +7 -53
- package/frontend/src/features/dashboard/components/ConnectionSuccessBanner.tsx +35 -0
- package/frontend/src/features/dashboard/components/PromptCard.tsx +21 -0
- package/frontend/src/features/dashboard/components/PromptDialog.tsx +103 -0
- package/frontend/src/features/dashboard/components/StatsCard.tsx +50 -0
- package/frontend/src/features/dashboard/components/index.ts +4 -0
- package/frontend/src/features/dashboard/page/DashboardPage.tsx +187 -169
- package/frontend/src/features/dashboard/prompts/ai-chatbot.ts +13 -0
- package/frontend/src/features/dashboard/prompts/crm-system.ts +13 -0
- package/frontend/src/features/dashboard/prompts/ecommerce-platform.ts +12 -0
- package/frontend/src/features/dashboard/prompts/index.ts +31 -0
- package/frontend/src/features/dashboard/prompts/instagram-clone.ts +11 -0
- package/frontend/src/features/dashboard/prompts/notion-clone.ts +14 -0
- package/frontend/src/features/dashboard/prompts/reddit-clone.ts +12 -0
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +48 -17
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +15 -34
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +19 -20
- package/frontend/src/features/database/components/LinkRecordModal.tsx +120 -125
- package/frontend/src/features/database/components/RecordFormDialog.tsx +22 -33
- package/frontend/src/features/database/components/RecordFormField.tsx +45 -47
- package/frontend/src/features/database/components/TableEmptyState.tsx +6 -5
- package/frontend/src/features/database/components/TableForm.tsx +28 -15
- package/frontend/src/features/database/components/TableFormColumn.tsx +2 -3
- package/frontend/src/features/database/components/TableSidebar.tsx +1 -1
- package/frontend/src/features/database/components/TablesEmptyState.tsx +48 -0
- package/frontend/src/features/database/components/TemplateCard.tsx +37 -0
- package/frontend/src/features/database/components/TemplatePreview.tsx +92 -0
- package/frontend/src/features/database/components/index.ts +19 -0
- package/frontend/src/features/database/constants.ts +28 -2
- package/frontend/src/features/database/contexts/SQLEditorContext.tsx +188 -0
- package/frontend/src/features/database/helpers.ts +2 -2
- package/frontend/src/features/database/hooks/useCSVImport.ts +29 -0
- package/frontend/src/features/database/hooks/useFullMetadata.ts +18 -0
- package/frontend/src/features/database/hooks/useRawSQL.ts +55 -0
- package/frontend/src/features/database/hooks/useRecords.ts +139 -0
- package/frontend/src/features/database/hooks/useTables.ts +131 -0
- package/frontend/src/features/database/index.ts +6 -1
- package/frontend/src/features/database/page/FunctionsPage.tsx +211 -0
- package/frontend/src/features/database/page/IndexesPage.tsx +240 -0
- package/frontend/src/features/database/page/PoliciesPage.tsx +248 -0
- package/frontend/src/features/database/page/SQLEditorPage.tsx +382 -0
- package/frontend/src/features/database/page/{DatabasePage.tsx → TablesPage.tsx} +186 -185
- package/frontend/src/features/database/page/TemplatesPage.tsx +39 -0
- package/frontend/src/features/database/page/TriggersPage.tsx +242 -0
- package/frontend/src/features/database/services/advance.service.ts +66 -0
- package/frontend/src/features/database/services/{database.service.ts → record.service.ts} +67 -64
- package/frontend/src/features/database/services/table.service.ts +64 -0
- package/frontend/src/features/database/templates/ai-chatbot.ts +402 -0
- package/frontend/src/features/database/templates/crm-system.ts +528 -0
- package/frontend/src/features/database/templates/ecommerce-platform.ts +553 -0
- package/frontend/src/features/database/templates/index.ts +34 -0
- package/frontend/src/features/database/templates/instagram-clone.ts +222 -0
- package/frontend/src/features/database/templates/notion-clone.ts +483 -0
- package/frontend/src/features/database/templates/reddit-clone.ts +526 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +2 -1
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +1 -1
- package/frontend/src/features/functions/components/SecretRow.tsx +1 -1
- package/frontend/src/features/functions/components/index.ts +5 -0
- package/frontend/src/features/functions/hooks/useFunctions.ts +4 -4
- package/frontend/src/features/{secrets → functions}/hooks/useSecrets.ts +5 -5
- package/frontend/src/features/functions/page/FunctionsPage.tsx +160 -17
- package/frontend/src/features/functions/{components/SecretsContent.tsx → page/SecretsPage.tsx} +8 -12
- package/frontend/src/features/functions/services/{functions.service.ts → function.service.ts} +2 -2
- package/frontend/src/features/{secrets/services/secrets.service.ts → functions/services/secret.service.ts} +2 -2
- package/frontend/src/features/login/hooks/usePartnerOrigin.ts +27 -0
- package/frontend/src/features/login/page/CloudLoginPage.tsx +79 -54
- package/frontend/src/features/login/page/LoginPage.tsx +16 -23
- package/frontend/src/features/login/services/partnership.service.ts +65 -0
- package/frontend/src/features/logs/components/LogsDataGrid.tsx +89 -0
- package/frontend/src/features/logs/components/SeverityBadge.tsx +18 -0
- package/frontend/src/features/logs/components/index.ts +2 -0
- package/frontend/src/features/logs/helpers.ts +24 -0
- package/frontend/src/features/logs/hooks/useAuditLogs.ts +4 -4
- package/frontend/src/features/logs/hooks/useLogSources.ts +137 -0
- package/frontend/src/features/logs/hooks/useLogs.ts +163 -0
- package/frontend/src/features/logs/hooks/useMcpUsage.ts +181 -0
- package/frontend/src/features/logs/index.ts +8 -2
- package/frontend/src/features/logs/page/AuditsPage.tsx +91 -38
- package/frontend/src/features/logs/page/LogsPage.tsx +152 -0
- package/frontend/src/features/logs/page/MCPLogsPage.tsx +84 -0
- package/frontend/src/features/logs/services/audit.service.ts +63 -0
- package/frontend/src/features/logs/services/log.service.ts +15 -110
- package/frontend/src/features/logs/services/usage.service.ts +31 -0
- package/frontend/src/features/onboard/components/McpConnectionStatus.tsx +68 -0
- package/frontend/src/features/onboard/components/OnboardingModal.tsx +267 -0
- package/frontend/src/features/onboard/components/VideoDemoModal.tsx +38 -0
- package/frontend/src/features/onboard/components/index.ts +4 -0
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +2 -2
- package/frontend/src/features/onboard/components/mcp/{mcp-helper.tsx → helpers.tsx} +8 -8
- package/frontend/src/features/onboard/components/mcp/index.ts +2 -3
- package/frontend/src/features/onboard/index.ts +13 -3
- package/frontend/src/features/storage/components/BucketEmptyState.tsx +9 -6
- package/frontend/src/features/storage/components/BucketFormDialog.tsx +25 -41
- package/frontend/src/features/storage/components/FilePreviewDialog.tsx +20 -8
- package/frontend/src/features/storage/components/StorageDataGrid.tsx +4 -3
- package/frontend/src/features/storage/components/StorageManager.tsx +23 -34
- package/frontend/src/features/storage/components/index.ts +12 -0
- package/frontend/src/features/storage/hooks/useStorage.ts +208 -0
- package/frontend/src/features/storage/page/StoragePage.tsx +41 -115
- package/frontend/src/features/storage/services/storage.service.ts +22 -1
- package/frontend/src/features/visualizer/components/AuthNode.tsx +72 -56
- package/frontend/src/features/visualizer/components/BucketNode.tsx +4 -4
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +108 -80
- package/frontend/src/features/visualizer/components/TableNode.tsx +34 -41
- package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +12 -4
- package/frontend/src/features/visualizer/page/VisualizerPage.tsx +33 -29
- package/frontend/src/index.css +1 -0
- package/frontend/src/lib/analytics/posthog.tsx +27 -0
- package/frontend/src/lib/contexts/AuthContext.tsx +38 -31
- package/frontend/src/lib/contexts/SocketContext.tsx +5 -6
- package/frontend/src/{features/metadata → lib}/hooks/useMetadata.ts +1 -1
- package/frontend/src/lib/hooks/useToast.tsx +6 -2
- package/frontend/src/lib/routing/AppRoutes.tsx +84 -0
- package/frontend/src/lib/routing/RequireAuth.tsx +27 -0
- package/frontend/src/lib/utils/cloudMessaging.ts +20 -0
- package/frontend/src/lib/utils/menuItems.ts +183 -0
- package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
- package/frontend/src/lib/utils/utils.ts +19 -1
- package/frontend/src/vite-env.d.ts +1 -0
- package/frontend/vite.config.ts +5 -3
- package/functions/server.ts +28 -3
- package/functions/worker-template.js +15 -4
- package/i18n/README.ar.md +130 -0
- package/i18n/README.de.md +130 -0
- package/i18n/README.es.md +154 -0
- package/i18n/README.fr.md +134 -0
- package/i18n/README.hi.md +129 -0
- package/i18n/README.ja.md +174 -0
- package/i18n/README.ko.md +137 -0
- package/i18n/README.pt-BR.md +131 -0
- package/i18n/README.ru.md +129 -0
- package/i18n/README.zh-CN.md +133 -0
- package/openapi/ai.yaml +31 -4
- package/openapi/auth.yaml +827 -146
- package/package.json +16 -7
- package/shared-schemas/package.json +1 -1
- package/shared-schemas/src/ai-api.schema.ts +34 -58
- package/shared-schemas/src/ai.schema.ts +5 -0
- package/shared-schemas/src/auth-api.schema.ts +154 -8
- package/shared-schemas/src/auth.schema.ts +42 -6
- package/shared-schemas/src/cloud-events.schema.ts +57 -0
- package/shared-schemas/src/database-api.schema.ts +3 -3
- package/shared-schemas/src/database.schema.ts +1 -1
- package/shared-schemas/src/index.ts +1 -0
- package/shared-schemas/src/logs-api.schema.ts +7 -1
- package/shared-schemas/src/logs.schema.ts +26 -0
- package/shared-schemas/src/metadata.schema.ts +9 -4
- package/test-gemini.sh +35 -0
- package/test-usage-admin.sh +57 -0
- package/test-usage.sh +50 -0
- package/zeabur/README.md +13 -0
- package/zeabur/template.yml +1032 -0
- package/.github/workflows/deploy-aws.yml +0 -130
- package/backend/src/api/routes/agent.ts +0 -29
- package/backend/src/api/routes/auth.oauth.ts +0 -482
- package/backend/src/api/routes/auth.ts +0 -386
- package/backend/src/api/routes/docs.ts +0 -66
- package/backend/src/api/routes/functions.ts +0 -183
- package/backend/src/api/routes/openapi.ts +0 -82
- package/backend/src/api/routes/usage.ts +0 -96
- package/backend/src/core/ai/client.ts +0 -242
- package/backend/src/core/ai/model.ts +0 -117
- package/backend/src/core/auth/auth.ts +0 -780
- package/backend/src/core/database/table.ts +0 -772
- package/backend/src/core/documentation/agent.ts +0 -689
- package/backend/src/core/documentation/openapi.ts +0 -856
- package/backend/src/core/logs/analytics.ts +0 -76
- package/backend/src/core/logs/providers/localdb.provider.ts +0 -246
- package/backend/src/core/storage/storage.ts +0 -923
- package/backend/src/utils/cloud-token.ts +0 -39
- package/backend/src/utils/helpers.ts +0 -49
- package/backend/src/utils/uuid.ts +0 -9
- package/backend/tests/manual/test-better-auth.sh +0 -303
- package/docker-init/db/logs.sql +0 -9
- package/frontend/README.md +0 -112
- package/frontend/src/components/datagrid/index.tsx +0 -20
- package/frontend/src/components/layout/CloudLayout.tsx +0 -95
- package/frontend/src/features/ai/components/AIConfigDialog.tsx +0 -76
- package/frontend/src/features/ai/components/AIConfigForm.tsx +0 -222
- package/frontend/src/features/ai/components/fields/ModalityField.tsx +0 -87
- package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +0 -134
- package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +0 -33
- package/frontend/src/features/auth/components/AddOAuthDialog.tsx +0 -106
- package/frontend/src/features/auth/components/AuthMethodTab.tsx +0 -238
- package/frontend/src/features/auth/components/UsersTab.tsx +0 -114
- package/frontend/src/features/auth/page/AuthenticationPage.tsx +0 -169
- package/frontend/src/features/database/hooks/UseLinkModal.tsx +0 -78
- package/frontend/src/features/functions/components/FunctionViewer.tsx +0 -46
- package/frontend/src/features/functions/components/FunctionsContent.tsx +0 -88
- package/frontend/src/features/login/components/AuthErrorBoundary.tsx +0 -87
- package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
- package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +0 -313
- package/frontend/src/features/logs/components/LogsTable.tsx +0 -199
- package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +0 -530
- package/frontend/src/features/metadata/index.ts +0 -0
- package/frontend/src/features/metadata/page/MetadataPage.tsx +0 -136
- package/frontend/src/features/onboard/components/CompletionCard.tsx +0 -41
- package/frontend/src/features/onboard/components/OnboardButton.tsx +0 -84
- package/frontend/src/features/onboard/components/StepContent.tsx +0 -91
- package/frontend/src/features/onboard/components/TestConnectionStep.tsx +0 -53
- package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +0 -144
- package/frontend/src/features/onboard/page/OnBoardPage.tsx +0 -104
- package/frontend/src/features/onboard/types.ts +0 -8
- package/frontend/src/lib/contexts/OnboardStepContext.tsx +0 -68
- package/frontend/src/lib/hooks/useOnboardingCompletion.ts +0 -29
- /package/backend/src/api/{middleware → middlewares}/error.ts +0 -0
- /package/backend/src/api/{middleware → middlewares}/upload.ts +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +0 -0
- /package/frontend/src/{features/metadata → lib}/services/metadata.service.ts +0 -0
|
@@ -1,31 +1,36 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Plus } from 'lucide-react';
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { Plus, Upload } from 'lucide-react';
|
|
4
4
|
import PencilIcon from '@/assets/icons/pencil.svg?react';
|
|
5
5
|
import RefreshIcon from '@/assets/icons/refresh.svg?react';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { Button } from '@/components/radix/Button';
|
|
9
|
-
import { Alert, AlertDescription } from '@/components/radix/Alert';
|
|
6
|
+
import { useTables } from '@/features/database/hooks/useTables';
|
|
7
|
+
import { useRecords } from '@/features/database/hooks/useRecords';
|
|
10
8
|
import { TableSidebar } from '@/features/database/components/TableSidebar';
|
|
11
9
|
import { RecordFormDialog } from '@/features/database/components/RecordFormDialog';
|
|
12
10
|
import { TableForm } from '@/features/database/components/TableForm';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import { TablesEmptyState } from '@/features/database/components/TablesEmptyState';
|
|
12
|
+
import { TemplatePreview } from '@/features/database/components/TemplatePreview';
|
|
13
|
+
import { DATABASE_TEMPLATES, DatabaseTemplate } from '@/features/database/templates';
|
|
15
14
|
import {
|
|
15
|
+
Alert,
|
|
16
|
+
AlertDescription,
|
|
17
|
+
Button,
|
|
18
|
+
ConfirmDialog,
|
|
19
|
+
ConnectCTA,
|
|
20
|
+
EmptyState,
|
|
21
|
+
SearchInput,
|
|
22
|
+
SelectionClearButton,
|
|
23
|
+
DeleteActionButton,
|
|
16
24
|
Tooltip,
|
|
17
25
|
TooltipContent,
|
|
18
26
|
TooltipProvider,
|
|
19
27
|
TooltipTrigger,
|
|
20
|
-
} from '@/components
|
|
28
|
+
} from '@/components';
|
|
21
29
|
import { useConfirm } from '@/lib/hooks/useConfirm';
|
|
22
30
|
import { useToast } from '@/lib/hooks/useToast';
|
|
23
31
|
import { DatabaseDataGrid } from '@/features/database/components/DatabaseDataGrid';
|
|
24
|
-
import { SearchInput, SelectionClearButton, DeleteActionButton } from '@/components';
|
|
25
32
|
import { SortColumn } from 'react-data-grid';
|
|
26
33
|
import { convertValueForColumn } from '@/lib/utils/utils';
|
|
27
|
-
import { LinkModalProvider, useLinkModal } from '@/features/database/hooks/UseLinkModal';
|
|
28
|
-
import { LinkRecordModal } from '@/features/database/components/LinkRecordModal';
|
|
29
34
|
import {
|
|
30
35
|
DataUpdatePayload,
|
|
31
36
|
DataUpdateResourceType,
|
|
@@ -33,10 +38,11 @@ import {
|
|
|
33
38
|
SocketMessage,
|
|
34
39
|
useSocket,
|
|
35
40
|
} from '@/lib/contexts/SocketContext';
|
|
41
|
+
import { useCSVImport } from '@/features/database/hooks/useCSVImport';
|
|
36
42
|
|
|
37
43
|
const PAGE_SIZE = 50;
|
|
38
44
|
|
|
39
|
-
function
|
|
45
|
+
export default function TablesPage() {
|
|
40
46
|
// Load selected table from localStorage on mount
|
|
41
47
|
const [selectedTable, setSelectedTable] = useState<string | null>(() => {
|
|
42
48
|
return localStorage.getItem('selectedTable');
|
|
@@ -52,14 +58,30 @@ function DatabasePageContent() {
|
|
|
52
58
|
const [currentPage, setCurrentPage] = useState(1);
|
|
53
59
|
const [isSorting, setIsSorting] = useState(false);
|
|
54
60
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
61
|
+
const [previewingTemplate, setPreviewingTemplate] = useState<DatabaseTemplate | null>(null);
|
|
55
62
|
|
|
56
63
|
const { confirm, confirmDialogProps } = useConfirm();
|
|
57
64
|
const { showToast } = useToast();
|
|
58
65
|
const queryClient = useQueryClient();
|
|
59
|
-
const
|
|
66
|
+
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
67
|
+
const { tables, isLoadingTables, tablesError, deleteTable, useTableSchema, refetchTables } =
|
|
68
|
+
useTables();
|
|
69
|
+
|
|
70
|
+
const recordsHook = useRecords(selectedTable || '');
|
|
60
71
|
|
|
61
72
|
const { socket, isConnected } = useSocket();
|
|
62
73
|
|
|
74
|
+
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
75
|
+
const file = event.target.files?.[0];
|
|
76
|
+
if (file && selectedTable) {
|
|
77
|
+
importCSV(file);
|
|
78
|
+
}
|
|
79
|
+
// Reset file input to allow re-uploading the same file
|
|
80
|
+
if (event.target) {
|
|
81
|
+
event.target.value = '';
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
63
85
|
// Persist selected table to localStorage when it changes
|
|
64
86
|
useEffect(() => {
|
|
65
87
|
if (selectedTable) {
|
|
@@ -96,74 +118,71 @@ function DatabasePageContent() {
|
|
|
96
118
|
[showToast]
|
|
97
119
|
);
|
|
98
120
|
|
|
99
|
-
// Fetch
|
|
100
|
-
const {
|
|
121
|
+
// Fetch schema for selected table
|
|
122
|
+
const { data: schemaData } = useTableSchema(selectedTable || '', !!selectedTable);
|
|
123
|
+
|
|
124
|
+
// Fetch schema for editing table
|
|
125
|
+
const { data: editingTableSchema } = useTableSchema(editingTable || '', !!editingTable);
|
|
126
|
+
|
|
127
|
+
const primaryKeyColumn = useMemo(() => {
|
|
128
|
+
return schemaData?.columns.find((col) => col.isPrimaryKey)?.columnName;
|
|
129
|
+
}, [schemaData]);
|
|
101
130
|
|
|
102
|
-
// Fetch table data when selected
|
|
103
131
|
const {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
queryFn: async () => {
|
|
118
|
-
if (!selectedTable) {
|
|
119
|
-
return null;
|
|
132
|
+
mutate: importCSV,
|
|
133
|
+
isPending: isImporting,
|
|
134
|
+
reset: resetImport,
|
|
135
|
+
} = useCSVImport(selectedTable || '', {
|
|
136
|
+
onSuccess: (data) => {
|
|
137
|
+
if (data.success) {
|
|
138
|
+
showToast(data.message || 'Import successful!', 'success');
|
|
139
|
+
void refetchTableData();
|
|
140
|
+
} else {
|
|
141
|
+
// This case handles validation errors returned with a 200 OK but success: false
|
|
142
|
+
const errorMessage =
|
|
143
|
+
data.message || 'CSV import failed due to validation errors. Please check the file.';
|
|
144
|
+
showToast(errorMessage, 'error');
|
|
120
145
|
}
|
|
146
|
+
resetImport();
|
|
147
|
+
},
|
|
148
|
+
onError: (error: Error) => {
|
|
149
|
+
// This handles 400/500 errors from the API client
|
|
150
|
+
const message =
|
|
151
|
+
error?.message || 'An unexpected error occurred during import. Please try again.';
|
|
152
|
+
showToast(message, 'error');
|
|
153
|
+
resetImport();
|
|
154
|
+
},
|
|
155
|
+
});
|
|
121
156
|
|
|
122
|
-
|
|
157
|
+
// Fetch table records using the hook
|
|
158
|
+
const offset = (currentPage - 1) * PAGE_SIZE;
|
|
159
|
+
const {
|
|
160
|
+
data: recordsData,
|
|
161
|
+
isLoading: isLoadingRecords,
|
|
162
|
+
error: recordsError,
|
|
163
|
+
refetch: refetchRecords,
|
|
164
|
+
} = recordsHook.useTableRecords(
|
|
165
|
+
PAGE_SIZE,
|
|
166
|
+
offset,
|
|
167
|
+
searchQuery,
|
|
168
|
+
sortColumns,
|
|
169
|
+
!!selectedTable && !!schemaData
|
|
170
|
+
);
|
|
123
171
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
selectedTable,
|
|
129
|
-
PAGE_SIZE,
|
|
130
|
-
offset,
|
|
131
|
-
searchQuery,
|
|
132
|
-
sortColumns
|
|
133
|
-
),
|
|
134
|
-
]);
|
|
135
|
-
|
|
136
|
-
return {
|
|
172
|
+
// Combine schema and records data
|
|
173
|
+
const tableData =
|
|
174
|
+
selectedTable && schemaData && recordsData
|
|
175
|
+
? {
|
|
137
176
|
name: selectedTable,
|
|
138
|
-
schema,
|
|
139
|
-
records:
|
|
140
|
-
totalRecords:
|
|
141
|
-
};
|
|
142
|
-
} catch (error) {
|
|
143
|
-
// If sorting caused the error, retry without sorting
|
|
144
|
-
if (sortColumns && sortColumns.length > 0) {
|
|
145
|
-
setSortColumns([]);
|
|
146
|
-
|
|
147
|
-
const [schema, records] = await Promise.all([
|
|
148
|
-
databaseService.getTableSchema(selectedTable),
|
|
149
|
-
databaseService.getTableRecords(selectedTable, PAGE_SIZE, offset, searchQuery, []),
|
|
150
|
-
]);
|
|
151
|
-
|
|
152
|
-
showToast('Sorting not supported for this table. Showing unsorted results.', 'info');
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
name: selectedTable,
|
|
156
|
-
schema,
|
|
157
|
-
records: records.records,
|
|
158
|
-
totalRecords: records.pagination.total || schema.recordCount,
|
|
159
|
-
};
|
|
177
|
+
schema: schemaData,
|
|
178
|
+
records: recordsData.records,
|
|
179
|
+
totalRecords: recordsData.pagination.total ?? schemaData.recordCount,
|
|
160
180
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
181
|
+
: null;
|
|
182
|
+
|
|
183
|
+
const isLoadingTable = isLoadingRecords;
|
|
184
|
+
const tableError = recordsError;
|
|
185
|
+
const refetchTableData = refetchRecords;
|
|
167
186
|
|
|
168
187
|
useEffect(() => {
|
|
169
188
|
if (!socket || !isConnected) {
|
|
@@ -171,12 +190,21 @@ function DatabasePageContent() {
|
|
|
171
190
|
}
|
|
172
191
|
|
|
173
192
|
const handleDataUpdate = (message: SocketMessage<DataUpdatePayload>) => {
|
|
174
|
-
if (
|
|
175
|
-
message.payload?.resource === DataUpdateResourceType.METADATA ||
|
|
176
|
-
message.payload?.resource === DataUpdateResourceType.DATABASE_SCHEMA
|
|
177
|
-
) {
|
|
193
|
+
if (message.payload?.resource === DataUpdateResourceType.DATABASE) {
|
|
178
194
|
// Invalidate all tables queries
|
|
179
195
|
void queryClient.invalidateQueries({ queryKey: ['tables'] });
|
|
196
|
+
void queryClient.invalidateQueries({ queryKey: ['records', selectedTable] });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (message.payload?.resource === DataUpdateResourceType.RECORDS) {
|
|
200
|
+
// Invalidate records queries for the updated table
|
|
201
|
+
const data = message.payload.data as { tableName?: string };
|
|
202
|
+
const updatedTableName = data?.tableName;
|
|
203
|
+
|
|
204
|
+
// Only invalidate if this is the currently selected table
|
|
205
|
+
if (updatedTableName && updatedTableName === selectedTable) {
|
|
206
|
+
void queryClient.invalidateQueries({ queryKey: ['records', selectedTable] });
|
|
207
|
+
}
|
|
180
208
|
}
|
|
181
209
|
};
|
|
182
210
|
|
|
@@ -185,7 +213,7 @@ function DatabasePageContent() {
|
|
|
185
213
|
return () => {
|
|
186
214
|
socket.off(ServerEvents.DATA_UPDATE, handleDataUpdate);
|
|
187
215
|
};
|
|
188
|
-
}, [socket, isConnected, queryClient]);
|
|
216
|
+
}, [socket, isConnected, queryClient, selectedTable]);
|
|
189
217
|
|
|
190
218
|
// Reset sorting flag when loading completes
|
|
191
219
|
useEffect(() => {
|
|
@@ -196,7 +224,7 @@ function DatabasePageContent() {
|
|
|
196
224
|
|
|
197
225
|
// Auto-select first table (excluding system tables)
|
|
198
226
|
useEffect(() => {
|
|
199
|
-
if (!
|
|
227
|
+
if (!isLoadingTables && tables) {
|
|
200
228
|
if (pendingTableSelection && tables.includes(pendingTableSelection)) {
|
|
201
229
|
setSelectedTable(pendingTableSelection);
|
|
202
230
|
setPendingTableSelection(undefined);
|
|
@@ -208,11 +236,11 @@ function DatabasePageContent() {
|
|
|
208
236
|
return;
|
|
209
237
|
}
|
|
210
238
|
|
|
211
|
-
if (!selectedTable && tables.length
|
|
239
|
+
if (!selectedTable && tables.length && !showTableForm && !pendingTableSelection) {
|
|
212
240
|
setSelectedTable(tables[0]);
|
|
213
241
|
}
|
|
214
242
|
}
|
|
215
|
-
}, [tables, pendingTableSelection, selectedTable, showTableForm,
|
|
243
|
+
}, [tables, pendingTableSelection, selectedTable, showTableForm, isLoadingTables]);
|
|
216
244
|
|
|
217
245
|
const handleRefresh = async () => {
|
|
218
246
|
setIsRefreshing(true);
|
|
@@ -227,7 +255,7 @@ function DatabasePageContent() {
|
|
|
227
255
|
if (selectedTable) {
|
|
228
256
|
await refetchTableData();
|
|
229
257
|
}
|
|
230
|
-
await
|
|
258
|
+
await refetchTables();
|
|
231
259
|
} finally {
|
|
232
260
|
setIsRefreshing(false);
|
|
233
261
|
}
|
|
@@ -291,28 +319,23 @@ function DatabasePageContent() {
|
|
|
291
319
|
const shouldDelete = await confirm(confirmOptions);
|
|
292
320
|
|
|
293
321
|
if (shouldDelete) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
setSelectedTable(null);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
await databaseService.deleteTable(tableName);
|
|
301
|
-
showToast('Table deleted successfully', 'success');
|
|
302
|
-
|
|
303
|
-
// Invalidate all related queries for the deleted table
|
|
304
|
-
void queryClient.invalidateQueries({ queryKey: ['metadata'] });
|
|
305
|
-
void queryClient.invalidateQueries({ queryKey: ['tables'] });
|
|
306
|
-
void queryClient.invalidateQueries({ queryKey: ['table', tableName] });
|
|
307
|
-
void queryClient.invalidateQueries({ queryKey: ['table-schema', tableName] });
|
|
308
|
-
void queryClient.invalidateQueries({ queryKey: ['metadata'] });
|
|
309
|
-
} catch (error) {
|
|
310
|
-
const errorMessage = error instanceof Error ? error.message : 'Failed to delete table';
|
|
311
|
-
showToast(errorMessage, 'error');
|
|
322
|
+
// Update selectedTable BEFORE deleting to prevent queries on deleted table
|
|
323
|
+
if (selectedTable === tableName) {
|
|
324
|
+
setSelectedTable(null);
|
|
312
325
|
}
|
|
326
|
+
|
|
327
|
+
deleteTable(tableName);
|
|
313
328
|
}
|
|
314
329
|
};
|
|
315
330
|
|
|
331
|
+
const handleTemplateClick = (template: DatabaseTemplate) => {
|
|
332
|
+
setPreviewingTemplate(template);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const handleCancelPreview = () => {
|
|
336
|
+
setPreviewingTemplate(null);
|
|
337
|
+
};
|
|
338
|
+
|
|
316
339
|
// Handle record update
|
|
317
340
|
const handleRecordUpdate = async (rowId: string, columnKey: string, newValue: string) => {
|
|
318
341
|
if (!selectedTable) {
|
|
@@ -331,9 +354,11 @@ function DatabasePageContent() {
|
|
|
331
354
|
return;
|
|
332
355
|
}
|
|
333
356
|
const updates = { [columnKey]: conversionResult.value };
|
|
334
|
-
await
|
|
335
|
-
|
|
336
|
-
|
|
357
|
+
await recordsHook.updateRecord({
|
|
358
|
+
pkColumn: primaryKeyColumn || 'id',
|
|
359
|
+
pkValue: rowId,
|
|
360
|
+
data: updates,
|
|
361
|
+
});
|
|
337
362
|
}
|
|
338
363
|
} catch (error) {
|
|
339
364
|
showToast('Failed to update record', 'error');
|
|
@@ -343,7 +368,7 @@ function DatabasePageContent() {
|
|
|
343
368
|
|
|
344
369
|
// Handle bulk delete
|
|
345
370
|
const handleBulkDelete = async (ids: string[]) => {
|
|
346
|
-
if (!selectedTable || ids.length
|
|
371
|
+
if (!selectedTable || !ids.length) {
|
|
347
372
|
return;
|
|
348
373
|
}
|
|
349
374
|
|
|
@@ -355,51 +380,25 @@ function DatabasePageContent() {
|
|
|
355
380
|
});
|
|
356
381
|
|
|
357
382
|
if (shouldDelete) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
refetchTableData(),
|
|
362
|
-
refetchMetadata(), // Also refresh metadata to update sidebar record counts
|
|
363
|
-
]);
|
|
364
|
-
setSelectedRows(new Set());
|
|
365
|
-
showToast(`${ids.length} records deleted successfully`, 'success');
|
|
366
|
-
} catch {
|
|
367
|
-
showToast('Failed to delete some records', 'error');
|
|
368
|
-
}
|
|
383
|
+
await recordsHook.deleteRecords({ pkColumn: primaryKeyColumn || 'id', pkValues: ids });
|
|
384
|
+
// Query invalidation is handled by the mutation, no manual refetch needed
|
|
385
|
+
setSelectedRows(new Set());
|
|
369
386
|
}
|
|
370
387
|
};
|
|
371
388
|
|
|
372
|
-
const error =
|
|
373
|
-
|
|
374
|
-
// Fetch schema for selected table
|
|
375
|
-
const { data: schemaData } = useQuery({
|
|
376
|
-
queryKey: ['table-schema', selectedTable],
|
|
377
|
-
queryFn: async () => {
|
|
378
|
-
if (!selectedTable) {
|
|
379
|
-
return undefined;
|
|
380
|
-
}
|
|
381
|
-
return await databaseService.getTableSchema(selectedTable);
|
|
382
|
-
},
|
|
383
|
-
enabled: !!selectedTable,
|
|
384
|
-
staleTime: 30 * 1000, // 30 seconds
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// Fetch schema for editing table
|
|
388
|
-
const { data: editingTableSchema } = useQuery({
|
|
389
|
-
queryKey: ['table-schema', editingTable],
|
|
390
|
-
queryFn: async () => {
|
|
391
|
-
if (!editingTable) {
|
|
392
|
-
return undefined;
|
|
393
|
-
}
|
|
394
|
-
const editingTableSchema = await databaseService.getTableSchema(editingTable);
|
|
395
|
-
return editingTableSchema;
|
|
396
|
-
},
|
|
397
|
-
enabled: !!editingTable,
|
|
398
|
-
});
|
|
389
|
+
const error = tablesError || tableError;
|
|
399
390
|
|
|
400
391
|
// Calculate pagination
|
|
401
392
|
const totalPages = Math.ceil((tableData?.totalRecords || 0) / PAGE_SIZE);
|
|
402
393
|
|
|
394
|
+
// Show empty state when there are no tables and not loading
|
|
395
|
+
const showEmptyState = !isLoadingTables && tables?.length === 0 && !showTableForm;
|
|
396
|
+
|
|
397
|
+
// Show template preview - takes full width without sidebar
|
|
398
|
+
if (previewingTemplate) {
|
|
399
|
+
return <TemplatePreview template={previewingTemplate} onCancel={handleCancelPreview} />;
|
|
400
|
+
}
|
|
401
|
+
|
|
403
402
|
return (
|
|
404
403
|
<div className="flex h-full bg-bg-gray dark:bg-neutral-800">
|
|
405
404
|
{/* Secondary Sidebar - Table List */}
|
|
@@ -407,7 +406,7 @@ function DatabasePageContent() {
|
|
|
407
406
|
tables={tables}
|
|
408
407
|
selectedTable={selectedTable || undefined}
|
|
409
408
|
onTableSelect={handleSelectTable}
|
|
410
|
-
loading={
|
|
409
|
+
loading={isLoadingTables}
|
|
411
410
|
onNewTable={handleCreateTable}
|
|
412
411
|
onEditTable={handleEditTable}
|
|
413
412
|
onDeleteTable={(tableName) => void handleDeleteTable(tableName)}
|
|
@@ -428,7 +427,7 @@ function DatabasePageContent() {
|
|
|
428
427
|
editTable={editingTable ? editingTableSchema : undefined}
|
|
429
428
|
setFormIsDirty={setIsTableFormDirty}
|
|
430
429
|
onSuccess={(newTableName?: string) => {
|
|
431
|
-
void
|
|
430
|
+
void refetchTables();
|
|
432
431
|
void refetchTableData();
|
|
433
432
|
setShowTableForm(false);
|
|
434
433
|
setPendingTableSelection(newTableName);
|
|
@@ -469,7 +468,6 @@ function DatabasePageContent() {
|
|
|
469
468
|
<p>Edit Table</p>
|
|
470
469
|
</TooltipContent>
|
|
471
470
|
</Tooltip>
|
|
472
|
-
|
|
473
471
|
<Tooltip>
|
|
474
472
|
<TooltipTrigger asChild>
|
|
475
473
|
<Button
|
|
@@ -503,11 +501,13 @@ function DatabasePageContent() {
|
|
|
503
501
|
itemType="record"
|
|
504
502
|
onClear={() => setSelectedRows(new Set())}
|
|
505
503
|
/>
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
504
|
+
{
|
|
505
|
+
<DeleteActionButton
|
|
506
|
+
selectedCount={selectedRows.size}
|
|
507
|
+
itemType="record"
|
|
508
|
+
onDelete={() => void handleBulkDelete(Array.from(selectedRows))}
|
|
509
|
+
/>
|
|
510
|
+
}
|
|
511
511
|
</div>
|
|
512
512
|
) : (
|
|
513
513
|
<SearchInput
|
|
@@ -519,8 +519,18 @@ function DatabasePageContent() {
|
|
|
519
519
|
/>
|
|
520
520
|
)}
|
|
521
521
|
<div className="flex items-center gap-2 ml-4">
|
|
522
|
-
{selectedRows.size === 0 &&
|
|
522
|
+
{selectedRows.size === 0 && (
|
|
523
523
|
<>
|
|
524
|
+
{/* Import CSV Button */}
|
|
525
|
+
<Button
|
|
526
|
+
variant="secondary"
|
|
527
|
+
className="h-10 px-4 font-medium gap-1.5 border border-zinc-200 dark:border-neutral-600"
|
|
528
|
+
onClick={() => fileInputRef.current?.click()}
|
|
529
|
+
disabled={isImporting}
|
|
530
|
+
>
|
|
531
|
+
<Upload className="w-5 h-5" />
|
|
532
|
+
{isImporting ? 'Importing...' : 'Import CSV'}
|
|
533
|
+
</Button>
|
|
524
534
|
{/* Add Record Button */}
|
|
525
535
|
<Button
|
|
526
536
|
className="h-10 px-4 font-medium gap-1.5 dark:bg-emerald-300 dark:hover:bg-emerald-400"
|
|
@@ -546,7 +556,13 @@ function DatabasePageContent() {
|
|
|
546
556
|
</Alert>
|
|
547
557
|
)}
|
|
548
558
|
|
|
549
|
-
{
|
|
559
|
+
{showEmptyState ? (
|
|
560
|
+
<TablesEmptyState
|
|
561
|
+
templates={DATABASE_TEMPLATES}
|
|
562
|
+
onCreateTable={handleCreateTable}
|
|
563
|
+
onTemplateClick={handleTemplateClick}
|
|
564
|
+
/>
|
|
565
|
+
) : !selectedTable ? (
|
|
550
566
|
<div className="flex-1 flex items-center justify-center">
|
|
551
567
|
<EmptyState
|
|
552
568
|
title="No Table Selected"
|
|
@@ -560,18 +576,24 @@ function DatabasePageContent() {
|
|
|
560
576
|
loading={isLoadingTable && !tableData}
|
|
561
577
|
isSorting={isSorting}
|
|
562
578
|
isRefreshing={isRefreshing}
|
|
579
|
+
rowKeyGetter={(row) => String(row[primaryKeyColumn || 'id'])}
|
|
563
580
|
selectedRows={selectedRows}
|
|
564
581
|
onSelectedRowsChange={setSelectedRows}
|
|
565
582
|
sortColumns={sortColumns}
|
|
566
583
|
onSortColumnsChange={handleSortColumnsChange}
|
|
567
584
|
onCellEdit={handleRecordUpdate}
|
|
568
585
|
onJumpToTable={setSelectedTable}
|
|
569
|
-
searchQuery={searchQuery}
|
|
570
586
|
currentPage={currentPage}
|
|
571
587
|
totalPages={totalPages}
|
|
572
588
|
pageSize={PAGE_SIZE}
|
|
573
589
|
totalRecords={tableData?.totalRecords || 0}
|
|
574
590
|
onPageChange={setCurrentPage}
|
|
591
|
+
emptyState={
|
|
592
|
+
<div className="text-sm text-black dark:text-white">
|
|
593
|
+
{searchQuery ? 'No records match your search criteria' : 'No records found'}.{' '}
|
|
594
|
+
<ConnectCTA />
|
|
595
|
+
</div>
|
|
596
|
+
}
|
|
575
597
|
/>
|
|
576
598
|
)}
|
|
577
599
|
</div>
|
|
@@ -579,6 +601,14 @@ function DatabasePageContent() {
|
|
|
579
601
|
)}
|
|
580
602
|
</div>
|
|
581
603
|
|
|
604
|
+
<input
|
|
605
|
+
type="file"
|
|
606
|
+
ref={fileInputRef}
|
|
607
|
+
onChange={handleFileSelect}
|
|
608
|
+
accept=".csv,text/csv"
|
|
609
|
+
style={{ display: 'none' }}
|
|
610
|
+
/>
|
|
611
|
+
|
|
582
612
|
{/* Add Record Form */}
|
|
583
613
|
{selectedTable && schemaData && (
|
|
584
614
|
// In the RecordForm onSuccess callback
|
|
@@ -587,40 +617,11 @@ function DatabasePageContent() {
|
|
|
587
617
|
onOpenChange={setShowRecordForm}
|
|
588
618
|
tableName={selectedTable}
|
|
589
619
|
schema={schemaData.columns}
|
|
590
|
-
onSuccess={() => {
|
|
591
|
-
void refetchTableData();
|
|
592
|
-
void refetchMetadata();
|
|
593
|
-
// Also invalidate the schema cache to ensure fresh data
|
|
594
|
-
void queryClient.invalidateQueries({ queryKey: ['table-schema', selectedTable] });
|
|
595
|
-
}}
|
|
596
620
|
/>
|
|
597
621
|
)}
|
|
598
622
|
|
|
599
623
|
{/* Confirm Dialog */}
|
|
600
624
|
<ConfirmDialog {...confirmDialogProps} />
|
|
601
|
-
|
|
602
|
-
{/* Global Link Record Modal */}
|
|
603
|
-
{modalState.isOpen && modalState.referenceTable && modalState.referenceColumn && (
|
|
604
|
-
<LinkRecordModal
|
|
605
|
-
open={modalState.isOpen}
|
|
606
|
-
onOpenChange={closeModal}
|
|
607
|
-
referenceTable={modalState.referenceTable}
|
|
608
|
-
referenceColumn={modalState.referenceColumn}
|
|
609
|
-
currentValue={modalState.currentValue}
|
|
610
|
-
onSelectRecord={(record) => {
|
|
611
|
-
modalState.onSelectRecord?.(record);
|
|
612
|
-
closeModal();
|
|
613
|
-
}}
|
|
614
|
-
/>
|
|
615
|
-
)}
|
|
616
625
|
</div>
|
|
617
626
|
);
|
|
618
627
|
}
|
|
619
|
-
|
|
620
|
-
export default function DatabasePage() {
|
|
621
|
-
return (
|
|
622
|
-
<LinkModalProvider>
|
|
623
|
-
<DatabasePageContent />
|
|
624
|
-
</LinkModalProvider>
|
|
625
|
-
);
|
|
626
|
-
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useNavigate } from 'react-router-dom';
|
|
2
|
+
import { DATABASE_TEMPLATES, type DatabaseTemplate } from '@/features/database/templates';
|
|
3
|
+
import { useSQLEditorContext } from '@/features/database/contexts/SQLEditorContext';
|
|
4
|
+
import { TemplateCard } from '@/features/database/components/TemplateCard';
|
|
5
|
+
|
|
6
|
+
export default function TemplatesPage() {
|
|
7
|
+
const navigate = useNavigate();
|
|
8
|
+
const { addTab } = useSQLEditorContext();
|
|
9
|
+
|
|
10
|
+
const handleTemplateClick = (template: DatabaseTemplate) => {
|
|
11
|
+
// Create a new tab with the template's SQL query prefilled
|
|
12
|
+
addTab(template.sql, template.title);
|
|
13
|
+
// Navigate to the SQL Editor page
|
|
14
|
+
void navigate('/dashboard/database/sql-editor');
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className="flex flex-col h-full items-center bg-bg-gray dark:bg-neutral-800 overflow-auto">
|
|
19
|
+
{/* Main Content - Centered */}
|
|
20
|
+
<div className="flex flex-col max-w-[1024px] justify-center px-6 pb-6">
|
|
21
|
+
{/* Header */}
|
|
22
|
+
<div className="flex items-center justify-start gap-3 h-[72px] bg-bg-gray dark:bg-neutral-800 flex-shrink-0">
|
|
23
|
+
<h1 className="text-xl font-semibold text-zinc-950 dark:text-white">Database Template</h1>
|
|
24
|
+
</div>
|
|
25
|
+
<div className="w-full max-w-[1024px]">
|
|
26
|
+
<div className="grid grid-cols-2 xl:grid-cols-3 gap-6">
|
|
27
|
+
{DATABASE_TEMPLATES.map((template) => (
|
|
28
|
+
<TemplateCard
|
|
29
|
+
key={template.id}
|
|
30
|
+
template={template}
|
|
31
|
+
onClick={() => handleTemplateClick(template)}
|
|
32
|
+
/>
|
|
33
|
+
))}
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|