insforge 0.3.3 → 1.3.0
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/.dockerignore +60 -57
- package/.env.example +84 -49
- package/.github/ISSUE_TEMPLATE/bug_report.yml +36 -83
- package/.github/ISSUE_TEMPLATE/config.yml +11 -11
- package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -79
- package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
- package/.github/copilot-instructions.md +146 -146
- package/.github/workflows/build-image.yml +66 -65
- package/.github/workflows/ci-premerge-check.yml +23 -23
- package/.github/workflows/e2e.yml +63 -0
- package/.github/workflows/lint-and-format.yml +32 -32
- package/.prettierignore +64 -64
- package/CHANGELOG.md +44 -3
- package/CLAUDE_PLUGIN.md +104 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +125 -125
- package/Dockerfile +30 -27
- package/GITHUB_OAUTH_SETUP.md +49 -49
- package/GOOGLE_OAUTH_SETUP.md +148 -148
- package/LICENSE +201 -201
- package/README.md +182 -134
- package/assets/Dark.svg +23 -23
- 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 +117 -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 +60 -0
- package/auth/src/pages/SignUpPage.tsx +60 -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 +78 -75
- 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} +22 -26
- package/backend/src/api/routes/auth/index.routes.ts +667 -0
- package/backend/src/api/routes/auth/oauth.routes.ts +473 -0
- package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +128 -65
- package/backend/src/api/routes/database/index.routes.ts +90 -0
- package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +26 -12
- package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +6 -23
- package/backend/src/api/routes/docs/index.routes.ts +75 -0
- package/backend/src/api/routes/email/index.routes.ts +35 -0
- package/backend/src/api/routes/functions/index.routes.ts +194 -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} +33 -31
- package/backend/src/api/routes/realtime/channels.routes.ts +81 -0
- package/backend/src/api/routes/realtime/index.routes.ts +12 -0
- package/backend/src/api/routes/realtime/messages.routes.ts +48 -0
- package/backend/src/api/routes/realtime/permissions.routes.ts +19 -0
- package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
- package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +48 -61
- package/backend/src/api/routes/usage/index.routes.ts +91 -0
- package/backend/src/infra/config/app.config.ts +51 -0
- package/backend/src/infra/database/database.manager.ts +182 -0
- package/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +141 -141
- package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +40 -40
- package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +29 -29
- package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +55 -55
- package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +23 -23
- package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +29 -29
- package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +24 -24
- package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +1 -1
- package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +76 -76
- package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +23 -23
- package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +93 -93
- package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +15 -15
- package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +7 -7
- 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/infra/database/migrations/017_create-realtime-schema.sql +233 -0
- package/backend/src/infra/realtime/realtime.manager.ts +246 -0
- package/backend/src/infra/realtime/webhook-sender.ts +82 -0
- package/backend/src/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
- package/backend/src/infra/security/token.manager.ts +219 -0
- package/backend/src/infra/socket/socket.manager.ts +522 -0
- package/backend/src/providers/ai/openrouter.provider.ts +380 -0
- package/backend/src/providers/email/base.provider.ts +38 -0
- package/backend/src/providers/email/cloud.provider.ts +271 -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/apple.provider.ts +266 -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 +8 -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 +317 -288
- 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 +1150 -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 +802 -0
- package/backend/src/services/database/database.service.ts +127 -0
- package/backend/src/services/email/email.service.ts +73 -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/services/realtime/index.ts +3 -0
- package/backend/src/services/realtime/realtime-auth.service.ts +104 -0
- package/backend/src/services/realtime/realtime-channel.service.ts +237 -0
- package/backend/src/services/realtime/realtime-message.service.ts +260 -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 +77 -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/types/realtime.ts +18 -0
- package/backend/src/{core/socket/types.ts → types/socket.ts} +11 -36
- package/backend/src/utils/cookies.ts +35 -0
- package/backend/src/utils/environment.ts +9 -3
- package/backend/src/utils/logger.ts +20 -2
- package/backend/src/utils/s3-config-loader.ts +64 -0
- package/backend/src/utils/seed.ts +301 -205
- package/backend/src/utils/sql-parser.ts +91 -1
- package/backend/src/utils/utils.ts +114 -0
- package/backend/src/utils/validations.ts +40 -4
- package/backend/tests/README.md +133 -133
- package/backend/tests/cleanup-all-test-data.sh +230 -230
- package/backend/tests/cloud/test-s3-multitenant.sh +131 -131
- package/backend/tests/local/comprehensive-curl-tests.sh +155 -155
- 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 +143 -143
- package/backend/tests/local/test-database-router.sh +222 -222
- package/backend/tests/local/test-e2e.sh +240 -240
- package/backend/tests/local/test-fk-errors.sh +96 -96
- package/backend/tests/local/test-functions.sh +123 -0
- package/backend/tests/local/test-id-field.sh +200 -200
- package/backend/tests/local/test-logs.sh +132 -0
- package/backend/tests/local/test-public-bucket.sh +264 -264
- package/backend/tests/local/test-secrets.sh +249 -247
- package/backend/tests/local/test-serverless-functions.sh.disabled +325 -325
- package/backend/tests/local/test-traditional-rest.sh +208 -208
- package/backend/tests/manual/README.md +50 -50
- package/backend/tests/manual/create-large-table-simple.sql +10 -10
- package/backend/tests/manual/seed-large-table.sql +100 -100
- package/backend/tests/manual/setup-large-table-extras.sql +33 -33
- package/backend/tests/manual/test-bulk-upsert.sh +409 -409
- package/backend/tests/manual/test-database-advance.sh +296 -296
- package/backend/tests/manual/test-postgrest-stability.sh +191 -191
- package/backend/tests/manual/test-rawsql-export-import.sh +411 -411
- package/backend/tests/manual/test-rawsql-modes.sh +244 -0
- package/backend/tests/manual/test-universal-storage.sh +263 -263
- package/backend/tests/manual/test-users.sql +17 -17
- package/backend/tests/run-all-tests.sh +139 -139
- package/backend/tests/setup.ts +0 -0
- package/backend/tests/test-config.sh +338 -302
- package/backend/tests/unit/analyze-query.test.ts +697 -0
- 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 +22 -22
- 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 +204 -144
- package/docker-compose.yml +232 -167
- package/docker-init/db/db-init.sql +97 -125
- package/docker-init/db/jwt.sql +5 -5
- package/docker-init/db/postgresql.conf +16 -16
- package/docker-init/logs/vector.yml +236 -0
- package/docs/README.md +44 -0
- package/docs/agent-docs/real-time.md +269 -0
- package/docs/changelog.mdx +119 -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/email/architecture.mdx +101 -0
- package/docs/core-concepts/email/sdk.mdx +53 -0
- package/docs/core-concepts/functions/architecture.mdx +105 -0
- package/docs/core-concepts/functions/sdk.mdx +184 -0
- package/docs/core-concepts/realtime/architecture.mdx +446 -0
- package/docs/core-concepts/realtime/sdk.mdx +409 -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/deprecated/insforge-auth-api.md +214 -214
- package/docs/deprecated/insforge-auth-sdk.md +99 -99
- package/docs/deprecated/insforge-db-api.md +358 -358
- package/docs/deprecated/insforge-db-sdk.md +139 -139
- package/docs/deprecated/insforge-debug-sdk.md +156 -156
- package/docs/deprecated/insforge-debug.md +64 -64
- package/docs/deprecated/insforge-instructions.md +123 -123
- package/docs/deprecated/insforge-project.md +117 -117
- package/docs/deprecated/insforge-storage-api.md +278 -278
- package/docs/deprecated/insforge-storage-sdk.md +158 -158
- package/docs/docs.json +232 -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/dec-2025/ai-integration.png +0 -0
- package/docs/images/changelog/dec-2025/ai-models.webp +0 -0
- package/docs/images/changelog/dec-2025/alipay-payment.webp +0 -0
- package/docs/images/changelog/dec-2025/apple-login.jpg +0 -0
- package/docs/images/changelog/dec-2025/mcp-installer.png +0 -0
- package/docs/images/changelog/dec-2025/realtime-module.jpg +0 -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 +89 -407
- package/docs/introduction.mdx +45 -0
- package/docs/logo/dark.svg +22 -0
- package/docs/logo/light.svg +20 -0
- package/docs/partnership.mdx +652 -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/examples/oauth/frontend-oauth-example.html +250 -250
- package/examples/response-examples.md +443 -443
- package/frontend/components.json +17 -17
- package/frontend/package.json +69 -63
- package/frontend/src/App.tsx +13 -82
- package/frontend/src/assets/icons/checkbox_checked.svg +6 -6
- package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -6
- package/frontend/src/assets/icons/checked.svg +3 -3
- package/frontend/src/assets/icons/connected.svg +3 -0
- package/frontend/src/assets/icons/error.svg +3 -3
- package/frontend/src/assets/icons/loader.svg +9 -0
- package/frontend/src/assets/icons/pencil.svg +4 -4
- package/frontend/src/assets/icons/refresh.svg +4 -4
- package/frontend/src/assets/icons/step_active.svg +3 -3
- package/frontend/src/assets/icons/step_inactive.svg +11 -11
- package/frontend/src/assets/icons/warning.svg +3 -3
- package/frontend/src/assets/logos/apple.svg +4 -0
- package/frontend/src/assets/logos/claude_code.svg +3 -3
- package/frontend/src/assets/logos/cline.svg +6 -6
- package/frontend/src/assets/logos/cursor.svg +20 -20
- package/frontend/src/assets/logos/discord.svg +8 -8
- package/frontend/src/assets/logos/facebook.svg +3 -0
- package/frontend/src/assets/logos/gemini.svg +19 -19
- package/frontend/src/assets/logos/github.svg +5 -5
- package/frontend/src/assets/logos/google.svg +13 -13
- package/frontend/src/assets/logos/grok.svg +10 -10
- package/frontend/src/assets/logos/insforge_dark.svg +15 -15
- package/frontend/src/assets/logos/insforge_light.svg +15 -15
- 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/openai.svg +10 -10
- package/frontend/src/assets/logos/roo_code.svg +9 -9
- package/frontend/src/assets/logos/spotify.svg +17 -0
- package/frontend/src/assets/logos/tiktok.svg +6 -0
- package/frontend/src/assets/logos/trae.svg +3 -3
- package/frontend/src/assets/logos/windsurf.svg +10 -10
- 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 +131 -91
- 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/pages/AIPage.tsx +166 -0
- 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 +54 -30
- package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +50 -14
- package/frontend/src/features/auth/components/index.ts +5 -0
- package/frontend/src/features/auth/helpers.tsx +208 -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/pages/AuthMethodsPage.tsx +275 -0
- package/frontend/src/features/auth/pages/ConfigurationPage.tsx +395 -0
- package/frontend/src/features/auth/pages/UsersPage.tsx +257 -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/pages/DashboardPage.tsx +212 -0
- 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/SQLModal.tsx +75 -0
- package/frontend/src/features/database/components/TableEmptyState.tsx +6 -5
- package/frontend/src/features/database/components/TableForm.tsx +28 -19
- 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/useDatabase.ts +66 -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 +135 -0
- package/frontend/src/features/database/index.ts +7 -1
- package/frontend/src/features/database/pages/FunctionsPage.tsx +203 -0
- package/frontend/src/features/database/pages/IndexesPage.tsx +228 -0
- package/frontend/src/features/database/pages/PoliciesPage.tsx +237 -0
- package/frontend/src/features/database/pages/SQLEditorPage.tsx +382 -0
- package/frontend/src/features/database/{page/DatabasePage.tsx → pages/TablesPage.tsx} +168 -209
- package/frontend/src/features/database/pages/TemplatesPage.tsx +39 -0
- package/frontend/src/features/database/pages/TriggersPage.tsx +230 -0
- package/frontend/src/features/database/services/advance.service.ts +40 -0
- package/frontend/src/features/database/services/database.service.ts +33 -194
- package/frontend/src/features/database/services/record.service.ts +219 -0
- package/frontend/src/features/database/services/table.service.ts +58 -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/pages/FunctionsPage.tsx +148 -0
- package/frontend/src/features/functions/{components/SecretsContent.tsx → pages/SecretsPage.tsx} +19 -21
- 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/pages/CloudLoginPage.tsx +118 -0
- package/frontend/src/features/login/{page → pages}/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 +128 -0
- package/frontend/src/features/logs/index.ts +8 -2
- package/frontend/src/features/logs/{page → pages}/AuditsPage.tsx +91 -38
- package/frontend/src/features/logs/pages/LogsPage.tsx +152 -0
- package/frontend/src/features/logs/pages/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/realtime/components/ChannelRow.tsx +83 -0
- package/frontend/src/features/realtime/components/EditChannelModal.tsx +246 -0
- package/frontend/src/features/realtime/components/MessageRow.tsx +85 -0
- package/frontend/src/features/realtime/components/RealtimeEmptyState.tsx +30 -0
- package/frontend/src/features/realtime/hooks/useRealtime.ts +218 -0
- package/frontend/src/features/realtime/index.ts +11 -0
- package/frontend/src/features/realtime/pages/RealtimeChannelsPage.tsx +172 -0
- package/frontend/src/features/realtime/pages/RealtimeMessagesPage.tsx +211 -0
- package/frontend/src/features/realtime/pages/RealtimePermissionsPage.tsx +191 -0
- package/frontend/src/features/realtime/services/realtime.service.ts +107 -0
- 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 → pages}/StoragePage.tsx +41 -143
- 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/pages/VisualizerPage.tsx +97 -0
- 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 +123 -80
- 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 +99 -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 +207 -0
- package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
- package/frontend/src/lib/utils/utils.ts +32 -1
- package/frontend/src/vite-env.d.ts +1 -0
- package/frontend/tsconfig.json +25 -25
- package/frontend/tsconfig.node.json +9 -9
- package/frontend/vite.config.ts +5 -3
- package/functions/deno.json +24 -24
- package/functions/server.ts +315 -290
- 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 +715 -688
- package/openapi/auth.yaml +1244 -563
- package/openapi/email.yaml +158 -0
- package/openapi/functions.yaml +475 -475
- package/openapi/health.yaml +29 -29
- package/openapi/logs.yaml +223 -223
- package/openapi/metadata.yaml +177 -177
- package/openapi/realtime.yaml +699 -0
- package/openapi/records.yaml +381 -381
- package/openapi/secrets.yaml +370 -370
- package/openapi/storage.yaml +875 -875
- package/openapi/tables.yaml +463 -463
- package/package.json +97 -88
- package/shared-schemas/package.json +31 -31
- package/shared-schemas/src/ai-api.schema.ts +34 -58
- package/shared-schemas/src/ai.schema.ts +63 -54
- package/shared-schemas/src/auth-api.schema.ts +352 -193
- package/shared-schemas/src/auth.schema.ts +43 -7
- package/shared-schemas/src/cloud-events.schema.ts +57 -0
- package/shared-schemas/src/database-api.schema.ts +35 -4
- package/shared-schemas/src/database.schema.ts +40 -1
- package/shared-schemas/src/docs.schema.ts +26 -0
- package/shared-schemas/src/email-api.schema.ts +30 -0
- package/shared-schemas/src/index.ts +5 -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 +18 -4
- package/shared-schemas/src/realtime-api.schema.ts +111 -0
- package/shared-schemas/src/realtime.schema.ts +143 -0
- package/shared-schemas/tsconfig.json +21 -21
- package/tsconfig.json +7 -7
- 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/manager.ts +0 -178
- 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/socket/socket.ts +0 -388
- 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/ai/page/AIPage.tsx +0 -178
- 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/dashboard/page/DashboardPage.tsx +0 -194
- 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/functions/page/FunctionsPage.tsx +0 -28
- package/frontend/src/features/login/components/AuthErrorBoundary.tsx +0 -87
- package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
- package/frontend/src/features/login/page/CloudLoginPage.tsx +0 -93
- 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/features/visualizer/page/VisualizerPage.tsx +0 -127
- 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/frontend/src/{features/metadata → lib}/services/metadata.service.ts +0 -0
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import { useState, useEffect, useMemo } from 'react';
|
|
2
2
|
import { useForm } from 'react-hook-form';
|
|
3
3
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
4
|
-
import {
|
|
4
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
5
5
|
import { AlertCircle } from 'lucide-react';
|
|
6
6
|
import {
|
|
7
|
+
Alert,
|
|
8
|
+
AlertDescription,
|
|
9
|
+
Button,
|
|
7
10
|
Dialog,
|
|
8
11
|
DialogContent,
|
|
9
12
|
DialogHeader,
|
|
10
13
|
DialogTitle,
|
|
11
14
|
DialogFooter,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import { ScrollArea } from '@/components/radix/ScrollArea';
|
|
16
|
-
import { databaseService } from '@/features/database/services/database.service';
|
|
15
|
+
ScrollArea,
|
|
16
|
+
} from '@/components';
|
|
17
|
+
import { useRecords } from '@/features/database/hooks/useRecords';
|
|
17
18
|
import { buildDynamicSchema, getInitialValues } from '@/features/database';
|
|
18
19
|
import { RecordFormField } from '@/features/database/components/RecordFormField';
|
|
19
20
|
import { cn } from '@/lib/utils/utils';
|
|
20
|
-
import { useToast } from '@/lib/hooks/useToast';
|
|
21
21
|
import { ColumnSchema } from '@insforge/shared-schemas';
|
|
22
22
|
import { SYSTEM_FIELDS } from '../helpers';
|
|
23
|
-
import { ConvertedValue } from '@/components/datagrid/datagridTypes';
|
|
24
23
|
|
|
25
24
|
interface RecordFormDialogProps {
|
|
26
25
|
open: boolean;
|
|
@@ -39,7 +38,7 @@ export function RecordFormDialog({
|
|
|
39
38
|
}: RecordFormDialogProps) {
|
|
40
39
|
const [error, setError] = useState<string | null>(null);
|
|
41
40
|
const queryClient = useQueryClient();
|
|
42
|
-
const {
|
|
41
|
+
const { createRecord, isCreating } = useRecords(tableName);
|
|
43
42
|
|
|
44
43
|
const displayFields = useMemo(() => {
|
|
45
44
|
const filteredFields = schema.filter((field) => !SYSTEM_FIELDS.includes(field.columnName));
|
|
@@ -72,31 +71,21 @@ export function RecordFormDialog({
|
|
|
72
71
|
}
|
|
73
72
|
}, [open]);
|
|
74
73
|
|
|
75
|
-
const createRecordMutation = useMutation({
|
|
76
|
-
mutationFn: (data: { [key: string]: ConvertedValue }) => {
|
|
77
|
-
return databaseService.createRecord(tableName, data);
|
|
78
|
-
},
|
|
79
|
-
onSuccess: () => {
|
|
80
|
-
void queryClient.invalidateQueries({ queryKey: ['records', tableName] });
|
|
81
|
-
void queryClient.invalidateQueries({ queryKey: ['table', tableName] });
|
|
82
|
-
onOpenChange(false);
|
|
83
|
-
form.reset();
|
|
84
|
-
setError(null);
|
|
85
|
-
if (onSuccess) {
|
|
86
|
-
onSuccess();
|
|
87
|
-
}
|
|
88
|
-
showToast('Record created successfully', 'success');
|
|
89
|
-
},
|
|
90
|
-
onError: (err: Error) => {
|
|
91
|
-
setError(err.message || 'Failed to create record');
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
74
|
const handleSubmit = form.handleSubmit(
|
|
96
75
|
async (data) => {
|
|
97
76
|
try {
|
|
98
|
-
await
|
|
77
|
+
await createRecord(data);
|
|
78
|
+
void queryClient.invalidateQueries({ queryKey: ['records', tableName] });
|
|
79
|
+
void queryClient.invalidateQueries({ queryKey: ['table', tableName] });
|
|
80
|
+
onOpenChange(false);
|
|
81
|
+
form.reset();
|
|
82
|
+
setError(null);
|
|
83
|
+
if (onSuccess) {
|
|
84
|
+
onSuccess();
|
|
85
|
+
}
|
|
99
86
|
} catch (err) {
|
|
87
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to create record';
|
|
88
|
+
setError(errorMessage);
|
|
100
89
|
console.error('Form submission error:', err);
|
|
101
90
|
}
|
|
102
91
|
},
|
|
@@ -148,13 +137,13 @@ export function RecordFormDialog({
|
|
|
148
137
|
</Button>
|
|
149
138
|
<Button
|
|
150
139
|
type="submit"
|
|
151
|
-
disabled={
|
|
140
|
+
disabled={isCreating}
|
|
152
141
|
className={cn(
|
|
153
142
|
'h-10 px-4 bg-zinc-950 text-white hover:bg-zinc-800 dark:bg-emerald-300 dark:text-zinc-950 dark:hover:bg-emerald-400',
|
|
154
|
-
|
|
143
|
+
isCreating && 'opacity-40'
|
|
155
144
|
)}
|
|
156
145
|
>
|
|
157
|
-
{
|
|
146
|
+
{isCreating ? 'Saving...' : 'Add Record'}
|
|
158
147
|
</Button>
|
|
159
148
|
</DialogFooter>
|
|
160
149
|
</form>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Control, Controller, FieldError, UseFormReturn } from 'react-hook-form';
|
|
3
|
-
import { Input } from '@/components/radix/Input';
|
|
4
|
-
import { Label } from '@/components/radix/Label';
|
|
5
|
-
import { Button } from '@/components/radix/Button';
|
|
6
3
|
import { Calendar, Clock, Link2, X } from 'lucide-react';
|
|
7
4
|
import {
|
|
5
|
+
Button,
|
|
6
|
+
Label,
|
|
7
|
+
Input,
|
|
8
8
|
BooleanCellEditor,
|
|
9
9
|
DateCellEditor,
|
|
10
10
|
JsonCellEditor,
|
|
11
11
|
type DatabaseRecord,
|
|
12
12
|
type ConvertedValue,
|
|
13
13
|
type UserInputValue,
|
|
14
|
-
|
|
14
|
+
TypeBadge,
|
|
15
|
+
} from '@/components';
|
|
15
16
|
import { ColumnSchema, ColumnType } from '@insforge/shared-schemas';
|
|
16
|
-
import { useLinkModal } from '@/features/database/hooks/UseLinkModal';
|
|
17
17
|
import { convertValueForColumn, cn, formatValueForDisplay } from '@/lib/utils/utils';
|
|
18
|
-
import {
|
|
18
|
+
import { LinkRecordModal } from '@/features/database/components/LinkRecordModal';
|
|
19
19
|
import { isValid, parseISO } from 'date-fns';
|
|
20
20
|
|
|
21
21
|
// Helper function to get appropriate placeholder text
|
|
@@ -184,7 +184,7 @@ function FormNumberEditor({ value, type, onChange, tableName, field }: FormNumbe
|
|
|
184
184
|
}
|
|
185
185
|
}}
|
|
186
186
|
placeholder={getPlaceholderText(field)}
|
|
187
|
-
className={`dark:text-white dark:placeholder:text-neutral-400 dark:bg-neutral-900 dark:border-neutral-700 ${field.foreignKey ? 'pr-
|
|
187
|
+
className={`dark:text-white dark:placeholder:text-neutral-400 dark:bg-neutral-900 dark:border-neutral-700 ${field.foreignKey ? 'pr-18' : ''}`}
|
|
188
188
|
/>
|
|
189
189
|
);
|
|
190
190
|
}
|
|
@@ -278,13 +278,14 @@ interface FieldWithLinkProps {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
function FieldWithLink({ field, control, children }: FieldWithLinkProps) {
|
|
281
|
-
const { openModal } = useLinkModal();
|
|
282
|
-
|
|
283
281
|
if (!field.foreignKey) {
|
|
284
282
|
// Regular field without foreign key
|
|
285
283
|
return <>{children}</>;
|
|
286
284
|
}
|
|
287
285
|
|
|
286
|
+
// Store foreignKey in a const to help TypeScript narrow the type
|
|
287
|
+
const foreignKey = field.foreignKey;
|
|
288
|
+
|
|
288
289
|
// Field with foreign key linking capability - integrated design
|
|
289
290
|
return (
|
|
290
291
|
<>
|
|
@@ -309,56 +310,53 @@ function FieldWithLink({ field, control, children }: FieldWithLinkProps) {
|
|
|
309
310
|
<div className="space-y-1">
|
|
310
311
|
<div className="relative">
|
|
311
312
|
{modifiedChildren}
|
|
312
|
-
<div className="absolute right-0 top-1/2 -translate-y-1/2 flex items-center">
|
|
313
|
-
{hasLinkedValue && (
|
|
313
|
+
<div className="absolute right-0 top-1/2 -translate-y-1/2 flex items-center gap-1">
|
|
314
|
+
{(hasLinkedValue || hasLinkedValue === 0) && (
|
|
314
315
|
<Button
|
|
315
316
|
type="button"
|
|
316
317
|
variant="ghost"
|
|
317
318
|
size="icon"
|
|
318
319
|
onClick={() => formField.onChange('')}
|
|
319
|
-
className="h-7 w-7 p-1 flex-shrink-0 text-zinc-500 hover:text-
|
|
320
|
+
className="h-7 w-7 p-1 flex-shrink-0 text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-700"
|
|
320
321
|
title="Clear linked record"
|
|
321
322
|
>
|
|
322
323
|
<X className="h-4 w-4" />
|
|
323
324
|
</Button>
|
|
324
325
|
)}
|
|
325
|
-
<
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
field.type,
|
|
340
|
-
String(referenceValue || '')
|
|
341
|
-
);
|
|
342
|
-
if (result.success) {
|
|
343
|
-
formField.onChange(result.value);
|
|
344
|
-
} else {
|
|
345
|
-
// Fallback to string if conversion fails
|
|
346
|
-
formField.onChange(String(referenceValue || ''));
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
},
|
|
350
|
-
});
|
|
326
|
+
<LinkRecordModal
|
|
327
|
+
referenceTable={foreignKey.referenceTable}
|
|
328
|
+
referenceColumn={foreignKey.referenceColumn}
|
|
329
|
+
onSelectRecord={(record: DatabaseRecord) => {
|
|
330
|
+
const referenceValue = record[foreignKey.referenceColumn];
|
|
331
|
+
const result = convertValueForColumn(
|
|
332
|
+
field.type,
|
|
333
|
+
String(referenceValue || '')
|
|
334
|
+
);
|
|
335
|
+
if (result.success) {
|
|
336
|
+
formField.onChange(result.value);
|
|
337
|
+
} else {
|
|
338
|
+
// Fallback to string if conversion fails
|
|
339
|
+
formField.onChange(String(referenceValue || ''));
|
|
351
340
|
}
|
|
352
341
|
}}
|
|
353
|
-
className="rounded-l-none h-9 w-9 p-2 flex-shrink-0 text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-700 border-l border-zinc-200 dark:border-neutral-700"
|
|
354
|
-
title={
|
|
355
|
-
hasLinkedValue
|
|
356
|
-
? `Change linked ${field.foreignKey?.referenceTable} record`
|
|
357
|
-
: `Link to ${field.foreignKey?.referenceTable} record`
|
|
358
|
-
}
|
|
359
342
|
>
|
|
360
|
-
|
|
361
|
-
|
|
343
|
+
{(openModal) => (
|
|
344
|
+
<Button
|
|
345
|
+
type="button"
|
|
346
|
+
variant="ghost"
|
|
347
|
+
size="icon"
|
|
348
|
+
onClick={openModal}
|
|
349
|
+
className="rounded-l-none h-9 w-9 p-2 flex-shrink-0 text-zinc-500 hover:text-zinc-700 hover:bg-zinc-100 dark:text-neutral-400 dark:hover:text-neutral-200 dark:hover:bg-neutral-700 border-l border-zinc-200 dark:border-neutral-700"
|
|
350
|
+
title={
|
|
351
|
+
hasLinkedValue
|
|
352
|
+
? `Change linked ${foreignKey.referenceTable} record`
|
|
353
|
+
: `Link to ${foreignKey.referenceTable} record`
|
|
354
|
+
}
|
|
355
|
+
>
|
|
356
|
+
<Link2 className="h-5 w-5" />
|
|
357
|
+
</Button>
|
|
358
|
+
)}
|
|
359
|
+
</LinkRecordModal>
|
|
362
360
|
</div>
|
|
363
361
|
</div>
|
|
364
362
|
|
|
@@ -366,7 +364,7 @@ function FieldWithLink({ field, control, children }: FieldWithLinkProps) {
|
|
|
366
364
|
<div className="text-xs text-medium text-black dark:text-neutral-400 flex items-center gap-1.5">
|
|
367
365
|
<span>Has a Foreign Key relation to</span>
|
|
368
366
|
<TypeBadge
|
|
369
|
-
type={`${
|
|
367
|
+
type={`${foreignKey.referenceTable}.${foreignKey.referenceColumn}`}
|
|
370
368
|
className="dark:bg-neutral-700"
|
|
371
369
|
/>
|
|
372
370
|
</div>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ExternalLink } from 'lucide-react';
|
|
2
|
+
import CodeMirror from '@uiw/react-codemirror';
|
|
3
|
+
import { sql } from '@codemirror/lang-sql';
|
|
4
|
+
import { EditorView } from '@codemirror/view';
|
|
5
|
+
import { vscodeDark, vscodeLight } from '@uiw/codemirror-theme-vscode';
|
|
6
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components';
|
|
7
|
+
import { useTheme } from '@/lib/contexts/ThemeContext';
|
|
8
|
+
|
|
9
|
+
const customTheme = EditorView.theme({
|
|
10
|
+
'&': { backgroundColor: 'transparent', maxHeight: '400px' },
|
|
11
|
+
'.cm-scroller': { overflow: 'auto' },
|
|
12
|
+
'.cm-gutters': { display: 'none' },
|
|
13
|
+
'.cm-content': { padding: '16px' },
|
|
14
|
+
'.cm-line': { padding: '0' },
|
|
15
|
+
'&.cm-focused': { outline: 'none' },
|
|
16
|
+
'.cm-selectionBackground': { backgroundColor: 'transparent !important' },
|
|
17
|
+
'&.cm-focused .cm-selectionBackground': { backgroundColor: 'transparent !important' },
|
|
18
|
+
'.cm-cursor': { display: 'none' },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
interface SQLModalProps {
|
|
22
|
+
open: boolean;
|
|
23
|
+
onOpenChange: (open: boolean) => void;
|
|
24
|
+
title: string;
|
|
25
|
+
value: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function SQLModal({ open, onOpenChange, title, value }: SQLModalProps) {
|
|
29
|
+
const { resolvedTheme } = useTheme();
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
33
|
+
<DialogContent className="max-w-2xl">
|
|
34
|
+
<DialogHeader>
|
|
35
|
+
<DialogTitle className="text-zinc-950 dark:text-white">{title}</DialogTitle>
|
|
36
|
+
</DialogHeader>
|
|
37
|
+
<div className="mt-2 rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-900">
|
|
38
|
+
<CodeMirror
|
|
39
|
+
value={value}
|
|
40
|
+
theme={[resolvedTheme === 'dark' ? vscodeDark : vscodeLight, customTheme]}
|
|
41
|
+
extensions={[sql(), EditorView.lineWrapping, EditorView.editable.of(false)]}
|
|
42
|
+
editable={false}
|
|
43
|
+
basicSetup={false}
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</DialogContent>
|
|
47
|
+
</Dialog>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface SQLCellButtonProps {
|
|
52
|
+
value: string | null;
|
|
53
|
+
onClick: () => void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function SQLCellButton({ value, onClick }: SQLCellButtonProps) {
|
|
57
|
+
if (!value) {
|
|
58
|
+
return <span className="text-sm">-</span>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="flex items-center justify-between gap-1 min-w-0">
|
|
63
|
+
<span className="text-sm truncate">{value}</span>
|
|
64
|
+
<button
|
|
65
|
+
onClick={(e) => {
|
|
66
|
+
e.stopPropagation();
|
|
67
|
+
onClick();
|
|
68
|
+
}}
|
|
69
|
+
className="shrink-0 p-1 hover:bg-neutral-200 dark:hover:bg-neutral-700 rounded transition-colors"
|
|
70
|
+
>
|
|
71
|
+
<ExternalLink className="size-4 text-zinc-400 dark:text-neutral-400" />
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Database } from 'lucide-react';
|
|
2
|
+
import { ConnectCTA } from '@/components/ConnectCTA';
|
|
2
3
|
|
|
3
4
|
interface TableEmptyStateProps {
|
|
4
5
|
searchTerm: string;
|
|
@@ -6,14 +7,14 @@ interface TableEmptyStateProps {
|
|
|
6
7
|
|
|
7
8
|
export function TableEmptyState({ searchTerm }: TableEmptyStateProps) {
|
|
8
9
|
return (
|
|
9
|
-
<div className="
|
|
10
|
-
<Database className="
|
|
11
|
-
<p className="text-sm text-
|
|
10
|
+
<div className="flex flex-col items-center justify-center py-4 text-center">
|
|
11
|
+
<Database className="h-10 w-10 text-gray-400 dark:text-neutral-600 mb-3" />
|
|
12
|
+
<p className="text-sm text-gray-600 dark:text-neutral-400 font-medium">
|
|
12
13
|
{searchTerm ? 'No tables found' : 'No tables yet'}
|
|
13
14
|
</p>
|
|
14
15
|
{!searchTerm && (
|
|
15
|
-
<p className="text-xs text-
|
|
16
|
-
Create your first table to get started
|
|
16
|
+
<p className="text-xs text-gray-500 dark:text-neutral-400 font-medium mt-1 mx-10">
|
|
17
|
+
<ConnectCTA fallback="Create your first table to get started" />
|
|
17
18
|
</p>
|
|
18
19
|
)}
|
|
19
20
|
</div>
|
|
@@ -3,10 +3,8 @@ import { useForm, useFieldArray } from 'react-hook-form';
|
|
|
3
3
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
4
4
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
5
5
|
import { AlertCircle, Plus, X, Link, MoveRight } from 'lucide-react';
|
|
6
|
-
import { Button } from '@/components
|
|
7
|
-
import {
|
|
8
|
-
import { Alert, AlertDescription } from '@/components/radix/Alert';
|
|
9
|
-
import { databaseService } from '@/features/database/services/database.service';
|
|
6
|
+
import { Alert, AlertDescription, Button, Input } from '@/components';
|
|
7
|
+
import { tableService } from '@/features/database/services/table.service';
|
|
10
8
|
import {
|
|
11
9
|
TableFormColumnSchema,
|
|
12
10
|
TableFormForeignKeySchema,
|
|
@@ -50,6 +48,7 @@ export function TableForm({
|
|
|
50
48
|
const [showForeignKeyDialog, setShowForeignKeyDialog] = useState(false);
|
|
51
49
|
const [editingForeignKey, setEditingForeignKey] = useState<string>();
|
|
52
50
|
const [foreignKeys, setForeignKeys] = useState<TableFormForeignKeySchema[]>([]);
|
|
51
|
+
const [foreignKeysDirty, setForeignKeysDirty] = useState(false);
|
|
53
52
|
const queryClient = useQueryClient();
|
|
54
53
|
const { showToast } = useToast();
|
|
55
54
|
|
|
@@ -220,7 +219,7 @@ export function TableForm({
|
|
|
220
219
|
};
|
|
221
220
|
});
|
|
222
221
|
|
|
223
|
-
return
|
|
222
|
+
return tableService.createTable(data.tableName, columns);
|
|
224
223
|
},
|
|
225
224
|
onSuccess: (data) => {
|
|
226
225
|
void queryClient.invalidateQueries({ queryKey: ['database-metadata'] });
|
|
@@ -232,12 +231,13 @@ export function TableForm({
|
|
|
232
231
|
form.reset();
|
|
233
232
|
setError(null);
|
|
234
233
|
setForeignKeys([]);
|
|
234
|
+
setForeignKeysDirty(false);
|
|
235
235
|
onSuccess?.(data.tableName);
|
|
236
236
|
},
|
|
237
237
|
onError: (err) => {
|
|
238
238
|
const errorMessage = err.message || 'Failed to create table';
|
|
239
239
|
setError(errorMessage);
|
|
240
|
-
showToast(
|
|
240
|
+
showToast(errorMessage, 'error');
|
|
241
241
|
},
|
|
242
242
|
});
|
|
243
243
|
|
|
@@ -350,7 +350,7 @@ export function TableForm({
|
|
|
350
350
|
operations.renameTable = { newTableName: data.tableName };
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
return
|
|
353
|
+
return tableService.updateTableSchema(editTable.tableName, operations);
|
|
354
354
|
},
|
|
355
355
|
onSuccess: (_, data) => {
|
|
356
356
|
void queryClient.invalidateQueries({ queryKey: ['database-metadata'] });
|
|
@@ -360,9 +360,6 @@ export function TableForm({
|
|
|
360
360
|
// Invalidate all table data queries for this table (with all parameter combinations)
|
|
361
361
|
void queryClient.invalidateQueries({ queryKey: ['table', editTable?.tableName] });
|
|
362
362
|
|
|
363
|
-
// Invalidate the separate table schema query used by AddRecordSheet
|
|
364
|
-
void queryClient.invalidateQueries({ queryKey: ['table-schema', editTable?.tableName] });
|
|
365
|
-
|
|
366
363
|
showToast(`Table "${data.tableName}" updated successfully!`, 'success');
|
|
367
364
|
|
|
368
365
|
form.reset();
|
|
@@ -373,15 +370,24 @@ export function TableForm({
|
|
|
373
370
|
onError: (err) => {
|
|
374
371
|
// Invalidate queries to ensure we have fresh data after failed request
|
|
375
372
|
void queryClient.invalidateQueries({ queryKey: ['table', editTable?.tableName] });
|
|
376
|
-
void queryClient.invalidateQueries({ queryKey: ['table-schema', editTable?.tableName] });
|
|
377
373
|
|
|
378
374
|
const errorMessage = err.message || 'Failed to update table';
|
|
379
375
|
setError(errorMessage);
|
|
380
|
-
showToast(
|
|
376
|
+
showToast(errorMessage, 'error');
|
|
381
377
|
},
|
|
382
378
|
});
|
|
383
379
|
|
|
384
380
|
const handleSubmit = form.handleSubmit((data) => {
|
|
381
|
+
const userColumns = data.columns.filter((col) => !col.isSystemColumn);
|
|
382
|
+
if (!userColumns.length) {
|
|
383
|
+
const msg =
|
|
384
|
+
mode === 'create'
|
|
385
|
+
? 'Please add at least one user-defined column to create a table.'
|
|
386
|
+
: 'Please ensure the table has at least one user-defined column.';
|
|
387
|
+
setError(msg);
|
|
388
|
+
showToast(msg, 'error');
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
385
391
|
if (mode === 'edit') {
|
|
386
392
|
updateTableMutation.mutate(data);
|
|
387
393
|
} else {
|
|
@@ -402,6 +408,7 @@ export function TableForm({
|
|
|
402
408
|
)
|
|
403
409
|
);
|
|
404
410
|
setEditingForeignKey(undefined);
|
|
411
|
+
setForeignKeysDirty(true);
|
|
405
412
|
} else {
|
|
406
413
|
// Add new foreign key
|
|
407
414
|
setForeignKeys([
|
|
@@ -411,10 +418,12 @@ export function TableForm({
|
|
|
411
418
|
},
|
|
412
419
|
]);
|
|
413
420
|
}
|
|
421
|
+
setForeignKeysDirty(true);
|
|
414
422
|
};
|
|
415
423
|
|
|
416
424
|
const handleRemoveForeignKey = (columnName?: string) => {
|
|
417
425
|
setForeignKeys(foreignKeys.filter((fk) => fk.columnName !== columnName));
|
|
426
|
+
setForeignKeysDirty(true);
|
|
418
427
|
};
|
|
419
428
|
|
|
420
429
|
if (!open) {
|
|
@@ -470,7 +479,7 @@ export function TableForm({
|
|
|
470
479
|
{/* Columns Table */}
|
|
471
480
|
<div className="px-3 overflow-x-auto">
|
|
472
481
|
{/* Table Headers */}
|
|
473
|
-
<div className="flex items-center gap-6 px-4 py-2 bg-slate-50 rounded-t text-sm font-medium text-zinc-950 dark:bg-neutral-700 dark:text-white">
|
|
482
|
+
<div className="flex items-center gap-6 px-4 py-2 w-min xl:w-full bg-slate-50 rounded-t text-sm font-medium text-zinc-950 dark:bg-neutral-700 dark:text-white">
|
|
474
483
|
<div className="flex-1 min-w-[175px]">Name</div>
|
|
475
484
|
<div className="flex-1 min-w-[175px]">Type</div>
|
|
476
485
|
<div className="flex-1 min-w-[175px]">Default Value</div>
|
|
@@ -511,7 +520,7 @@ export function TableForm({
|
|
|
511
520
|
</div>
|
|
512
521
|
|
|
513
522
|
{/* Foreign Keys Section */}
|
|
514
|
-
<div className="bg-white pb-3 rounded-xl border border-zinc-200 dark:bg-neutral-800 dark:border-transparent">
|
|
523
|
+
<div className="bg-white pb-3 rounded-xl border border-zinc-200 overflow-hidden dark:bg-neutral-800 dark:border-transparent">
|
|
515
524
|
<div className="p-6">
|
|
516
525
|
<h2 className="text-base font-semibold text-black dark:text-white">Foreign Keys</h2>
|
|
517
526
|
<p className="text-sm text-zinc-500 dark:text-neutral-400">
|
|
@@ -521,11 +530,11 @@ export function TableForm({
|
|
|
521
530
|
|
|
522
531
|
{/* Existing foreign keys */}
|
|
523
532
|
{foreignKeys.length > 0 && (
|
|
524
|
-
<div className="px-6 pb-6 space-y-3">
|
|
533
|
+
<div className="px-6 pb-6 space-y-3 overflow-x-auto">
|
|
525
534
|
{foreignKeys.map((fk) => (
|
|
526
535
|
<div
|
|
527
536
|
key={fk.columnName}
|
|
528
|
-
className="group flex items-center gap-6 2xl:gap-8 pl-4 pr-2 py-2 rounded-lg border border-zinc-200 bg-white hover:bg-zinc-100 transition-colors duration-150 dark:bg-neutral-700 dark:border-transparent dark:hover:bg-neutral-600"
|
|
537
|
+
className="group flex items-center gap-6 2xl:gap-8 pl-4 pr-2 py-2 w-min xl:w-full rounded-lg border border-zinc-200 bg-white hover:bg-zinc-100 transition-colors duration-150 dark:bg-neutral-700 dark:border-transparent dark:hover:bg-neutral-600"
|
|
529
538
|
>
|
|
530
539
|
<div className="flex items-center gap-2 flex-1 min-w-[188px] overflow-hidden">
|
|
531
540
|
<Link className="flex-shrink-0 w-5 h-5 text-zinc-500 dark:text-neutral-400" />
|
|
@@ -632,9 +641,8 @@ export function TableForm({
|
|
|
632
641
|
<div className="flex justify-end gap-3 max-w-[1080px] mx-auto px-6">
|
|
633
642
|
<Button
|
|
634
643
|
type="button"
|
|
635
|
-
variant="outline"
|
|
636
644
|
onClick={() => onOpenChange(false)}
|
|
637
|
-
className="h-10 px-4 text-sm font-medium border-zinc-200 shadow-
|
|
645
|
+
className="h-10 px-4 text-sm font-medium bg-white border border-zinc-200 shadow-[0px_1px_2px_0px_rgba(0,0,0,0.1)] text-zinc-950 hover:bg-zinc-50 dark:bg-neutral-600 dark:border-neutral-600 dark:text-white dark:hover:bg-neutral-700"
|
|
638
646
|
>
|
|
639
647
|
Cancel
|
|
640
648
|
</Button>
|
|
@@ -643,7 +651,8 @@ export function TableForm({
|
|
|
643
651
|
disabled={
|
|
644
652
|
!form.formState.isValid ||
|
|
645
653
|
createTableMutation.isPending ||
|
|
646
|
-
updateTableMutation.isPending
|
|
654
|
+
updateTableMutation.isPending ||
|
|
655
|
+
(!form.formState.isDirty && !foreignKeysDirty)
|
|
647
656
|
}
|
|
648
657
|
className="h-10 px-4 text-sm font-medium bg-zinc-950 text-neutral-50 shadow-sm disabled:opacity-40 dark:bg-emerald-300 dark:text-zinc-950 dark:hover:bg-emerald-400"
|
|
649
658
|
>
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { memo } from 'react';
|
|
2
2
|
import { Controller, Control } from 'react-hook-form';
|
|
3
3
|
import { X, Key } from 'lucide-react';
|
|
4
|
-
import { Input } from '@/components
|
|
5
|
-
import { Checkbox } from '@/components';
|
|
4
|
+
import { Input, Checkbox } from '@/components';
|
|
6
5
|
import { TableFormColumnSchema, TableFormSchema } from '../schema';
|
|
7
6
|
import { ColumnTypeSelect } from './ColumnTypeSelect';
|
|
8
7
|
|
|
@@ -25,7 +24,7 @@ export const TableFormColumn = memo(function TableFormColumn({
|
|
|
25
24
|
}: TableFormColumnProps) {
|
|
26
25
|
return (
|
|
27
26
|
<div
|
|
28
|
-
className={`flex items-center gap-6 px-4 py-2 ${
|
|
27
|
+
className={`flex items-center gap-6 px-4 py-2 w-min xl:w-full ${
|
|
29
28
|
isNewColumn ? 'bg-slate-50 dark:bg-neutral-800' : 'bg-white dark:bg-[#2D2D2D]'
|
|
30
29
|
}`}
|
|
31
30
|
>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Plus } from 'lucide-react';
|
|
2
|
+
import { Button } from '@/components/radix/Button';
|
|
3
|
+
import { DatabaseTemplate } from '@/features/database/templates';
|
|
4
|
+
import { TemplateCard } from './TemplateCard';
|
|
5
|
+
|
|
6
|
+
interface TablesEmptyStateProps {
|
|
7
|
+
templates: DatabaseTemplate[];
|
|
8
|
+
onCreateTable: () => void;
|
|
9
|
+
onTemplateClick: (template: DatabaseTemplate) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function TablesEmptyState({
|
|
13
|
+
templates,
|
|
14
|
+
onCreateTable,
|
|
15
|
+
onTemplateClick,
|
|
16
|
+
}: TablesEmptyStateProps) {
|
|
17
|
+
return (
|
|
18
|
+
<div className="flex justify-center w-full h-full bg-bg-gray dark:bg-neutral-800 px-6">
|
|
19
|
+
<div className="flex flex-col gap-6 max-w-[1024px] w-full pb-9 pt-6">
|
|
20
|
+
<h2 className="text-xl font-semibold text-zinc-950 dark:text-white leading-7 tracking-[-0.1px]">
|
|
21
|
+
Create Your First Table
|
|
22
|
+
</h2>
|
|
23
|
+
<Button
|
|
24
|
+
className="h-9 w-50 gap-2 font-medium dark:bg-emerald-300 dark:hover:bg-emerald-400 dark:text-black"
|
|
25
|
+
onClick={onCreateTable}
|
|
26
|
+
>
|
|
27
|
+
<Plus className="w-5 h-5" />
|
|
28
|
+
Create Table
|
|
29
|
+
</Button>
|
|
30
|
+
<div className="flex flex-col gap-3">
|
|
31
|
+
<p className="text-sm font-normal text-zinc-500 dark:text-neutral-400 leading-6">
|
|
32
|
+
or choose a template to start
|
|
33
|
+
</p>
|
|
34
|
+
<div className="grid grid-cols-2 xl:grid-cols-3 gap-6">
|
|
35
|
+
{templates.map((template) => (
|
|
36
|
+
<TemplateCard
|
|
37
|
+
key={template.id}
|
|
38
|
+
template={template}
|
|
39
|
+
onClick={() => onTemplateClick(template)}
|
|
40
|
+
showTableCount
|
|
41
|
+
/>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Table } from 'lucide-react';
|
|
2
|
+
import { DatabaseTemplate } from '@/features/database/templates';
|
|
3
|
+
|
|
4
|
+
interface TemplateCardProps {
|
|
5
|
+
template: DatabaseTemplate;
|
|
6
|
+
onClick: () => void;
|
|
7
|
+
showTableCount?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function TemplateCard({ template, onClick, showTableCount = false }: TemplateCardProps) {
|
|
11
|
+
return (
|
|
12
|
+
<button
|
|
13
|
+
onClick={onClick}
|
|
14
|
+
className="bg-white dark:bg-[#363636] border border-gray-200 dark:border-[#414141] rounded-[4px] pl-6 pr-4 pt-4 pb-6 text-left transition-colors hover:bg-gray-50 hover:border-gray-300 dark:hover:bg-neutral-700 dark:hover:border-[#525252] hover:shadow-sm flex flex-col gap-3"
|
|
15
|
+
>
|
|
16
|
+
<div className="flex flex-col gap-2">
|
|
17
|
+
<h3 className="text-base font-normal text-zinc-950 dark:text-white leading-6">
|
|
18
|
+
{template.title}
|
|
19
|
+
</h3>
|
|
20
|
+
{/* Fixed height container for description with line clamp */}
|
|
21
|
+
<div className="h-[72px]">
|
|
22
|
+
<p className="text-sm font-normal text-zinc-500 dark:text-neutral-400 leading-6 line-clamp-3">
|
|
23
|
+
{template.description}
|
|
24
|
+
</p>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
{showTableCount && (
|
|
28
|
+
<div className="flex items-center gap-2">
|
|
29
|
+
<Table className="w-5 h-5 text-zinc-500 dark:text-neutral-400" />
|
|
30
|
+
<p className="text-sm font-normal text-zinc-500 dark:text-neutral-400 leading-6">
|
|
31
|
+
{template.tableCount} {template.tableCount === 1 ? 'Table' : 'Tables'}
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
)}
|
|
35
|
+
</button>
|
|
36
|
+
);
|
|
37
|
+
}
|