insforge 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +58 -0
- package/.env.example +49 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +79 -0
- package/.github/copilot-instructions.md +147 -0
- package/.github/workflows/build-image.yml +65 -0
- package/.github/workflows/ci-premerge-check.yml +24 -0
- package/.github/workflows/deploy-aws.yml +130 -0
- package/.github/workflows/lint-and-format.yml +33 -0
- package/.prettierignore +65 -0
- package/.prettierrc +9 -0
- package/CHANGELOG.md +3 -0
- package/CONTRIBUTING.md +126 -0
- package/Dockerfile +27 -0
- package/GITHUB_OAUTH_SETUP.md +49 -0
- package/GOOGLE_OAUTH_SETUP.md +148 -0
- package/LICENSE +201 -0
- package/README.md +134 -0
- package/assets/Dark.svg +23 -0
- package/assets/archDiagram.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/mcpInstallv2.png +0 -0
- package/assets/sampleResponse.png +0 -0
- package/assets/signin.png +0 -0
- package/assets/userflow.png +0 -0
- package/backend/migrations/000_create-base-tables.sql +142 -0
- package/backend/migrations/001_create-helper-functions.sql +41 -0
- package/backend/migrations/002_rename-auth-tables.sql +30 -0
- package/backend/migrations/003_create-users-table.sql +56 -0
- package/backend/migrations/004_add-reload-postgrest-func.sql +24 -0
- package/backend/migrations/005_enable-project-admin-modify-users.sql +30 -0
- package/backend/migrations/006_modify-ai-usage-table.sql +25 -0
- package/backend/migrations/007_drop-metadata-table.sql +2 -0
- package/backend/migrations/008_add-system-tables.sql +77 -0
- package/backend/migrations/009_add-function-secrets.sql +24 -0
- package/backend/migrations/010_modify-ai-config-modalities.sql +93 -0
- package/backend/migrations/011_refactor-secrets-table.sql +15 -0
- package/backend/migrations/012_add-storage-uploaded-by.sql +8 -0
- package/backend/package.json +75 -0
- package/backend/src/api/middleware/auth.ts +240 -0
- package/backend/src/api/middleware/error.ts +231 -0
- package/backend/src/api/middleware/upload.ts +59 -0
- package/backend/src/api/routes/agent.ts +29 -0
- package/backend/src/api/routes/ai.ts +472 -0
- package/backend/src/api/routes/auth.oauth.ts +482 -0
- package/backend/src/api/routes/auth.ts +386 -0
- package/backend/src/api/routes/database.advance.ts +275 -0
- package/backend/src/api/routes/database.records.ts +246 -0
- package/backend/src/api/routes/database.tables.ts +161 -0
- package/backend/src/api/routes/docs.ts +66 -0
- package/backend/src/api/routes/functions.ts +183 -0
- package/backend/src/api/routes/logs.ts +150 -0
- package/backend/src/api/routes/metadata.ts +160 -0
- package/backend/src/api/routes/openapi.ts +82 -0
- package/backend/src/api/routes/secrets.ts +199 -0
- package/backend/src/api/routes/storage.ts +547 -0
- package/backend/src/api/routes/usage.ts +96 -0
- package/backend/src/core/ai/chat.ts +207 -0
- package/backend/src/core/ai/client.ts +242 -0
- package/backend/src/core/ai/config.ts +187 -0
- package/backend/src/core/ai/image.ts +156 -0
- package/backend/src/core/ai/model.ts +117 -0
- package/backend/src/core/ai/usage.ts +290 -0
- package/backend/src/core/auth/auth.ts +781 -0
- package/backend/src/core/auth/oauth.ts +398 -0
- package/backend/src/core/database/advance.ts +1074 -0
- package/backend/src/core/database/manager.ts +178 -0
- package/backend/src/core/database/table.ts +772 -0
- package/backend/src/core/documentation/agent.ts +689 -0
- package/backend/src/core/documentation/openapi.ts +856 -0
- package/backend/src/core/functions/functions.ts +310 -0
- package/backend/src/core/logs/analytics.ts +76 -0
- package/backend/src/core/logs/audit.ts +255 -0
- package/backend/src/core/logs/providers/base.provider.ts +83 -0
- package/backend/src/core/logs/providers/cloudwatch.provider.ts +510 -0
- package/backend/src/core/logs/providers/localdb.provider.ts +246 -0
- package/backend/src/core/secrets/encryption.ts +58 -0
- package/backend/src/core/secrets/secrets.ts +410 -0
- package/backend/src/core/socket/socket.ts +388 -0
- package/backend/src/core/socket/types.ts +79 -0
- package/backend/src/core/storage/storage.ts +923 -0
- package/backend/src/server.ts +288 -0
- package/backend/src/types/ai.ts +46 -0
- package/backend/src/types/auth.ts +90 -0
- package/backend/src/types/database.ts +136 -0
- package/backend/src/types/error-constants.ts +86 -0
- package/backend/src/types/logs.ts +47 -0
- package/backend/src/types/profile.ts +55 -0
- package/backend/src/types/storage.ts +23 -0
- package/backend/src/utils/cloud-token.ts +39 -0
- package/backend/src/utils/constants.ts +1 -0
- package/backend/src/utils/environment.ts +35 -0
- package/backend/src/utils/helpers.ts +49 -0
- package/backend/src/utils/logger.ts +13 -0
- package/backend/src/utils/response.ts +62 -0
- package/backend/src/utils/seed.ts +205 -0
- package/backend/src/utils/sql-parser.ts +63 -0
- package/backend/src/utils/uuid.ts +9 -0
- package/backend/src/utils/validations.ts +129 -0
- package/backend/tests/README.md +134 -0
- package/backend/tests/cleanup-all-test-data.sh +231 -0
- package/backend/tests/cloud/test-s3-multitenant.sh +132 -0
- package/backend/tests/local/comprehensive-curl-tests.sh +156 -0
- package/backend/tests/local/test-auth-router.sh +144 -0
- package/backend/tests/local/test-database-router.sh +222 -0
- package/backend/tests/local/test-e2e.sh +241 -0
- package/backend/tests/local/test-fk-errors.sh +97 -0
- package/backend/tests/local/test-id-field.sh +201 -0
- package/backend/tests/local/test-public-bucket.sh +265 -0
- package/backend/tests/local/test-secrets.sh +248 -0
- package/backend/tests/local/test-serverless-functions.sh.disabled +325 -0
- package/backend/tests/local/test-traditional-rest.sh +209 -0
- package/backend/tests/manual/README.md +51 -0
- package/backend/tests/manual/create-large-table-simple.sql +11 -0
- package/backend/tests/manual/seed-large-table.sql +101 -0
- package/backend/tests/manual/setup-large-table-extras.sql +34 -0
- package/backend/tests/manual/test-better-auth.sh +303 -0
- package/backend/tests/manual/test-bulk-upsert.sh +410 -0
- package/backend/tests/manual/test-database-advance.sh +297 -0
- package/backend/tests/manual/test-postgrest-stability.sh +192 -0
- package/backend/tests/manual/test-rawsql-export-import.sh +412 -0
- package/backend/tests/manual/test-universal-storage.sh +264 -0
- package/backend/tests/manual/test-users.sql +18 -0
- package/backend/tests/run-all-tests.sh +140 -0
- package/backend/tests/setup.ts +22 -0
- package/backend/tests/test-config.sh +303 -0
- package/backend/tsconfig.json +23 -0
- package/backend/tsup.config.ts +18 -0
- package/backend/vitest.config.ts +22 -0
- package/docker-compose.prod.yml +145 -0
- package/docker-compose.yml +167 -0
- package/docker-init/db/db-init.sql +125 -0
- package/docker-init/db/jwt.sql +5 -0
- package/docker-init/db/logs.sql +9 -0
- package/docker-init/db/postgresql.conf +17 -0
- package/docs/deprecated/insforge-auth-api.md +215 -0
- package/docs/deprecated/insforge-auth-sdk.md +100 -0
- package/docs/deprecated/insforge-db-api.md +359 -0
- package/docs/deprecated/insforge-db-sdk.md +140 -0
- package/docs/deprecated/insforge-debug-sdk.md +157 -0
- package/docs/deprecated/insforge-debug.md +65 -0
- package/docs/deprecated/insforge-instructions.md +124 -0
- package/docs/deprecated/insforge-project.md +118 -0
- package/docs/deprecated/insforge-storage-api.md +279 -0
- package/docs/deprecated/insforge-storage-sdk.md +159 -0
- package/docs/insforge-instructions-sdk.md +407 -0
- package/eslint.config.js +317 -0
- package/examples/oauth/frontend-oauth-example.html +251 -0
- package/examples/response-examples.md +444 -0
- package/frontend/README.md +112 -0
- package/frontend/components.json +17 -0
- package/frontend/index.html +13 -0
- package/frontend/package.json +63 -0
- package/frontend/public/favicon.ico +0 -0
- package/frontend/src/App.tsx +106 -0
- package/frontend/src/assets/icons/checkbox_checked.svg +6 -0
- package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -0
- package/frontend/src/assets/icons/checked.svg +3 -0
- package/frontend/src/assets/icons/error.svg +3 -0
- package/frontend/src/assets/icons/pencil.svg +4 -0
- package/frontend/src/assets/icons/refresh.svg +4 -0
- package/frontend/src/assets/icons/step_active.svg +3 -0
- package/frontend/src/assets/icons/step_inactive.svg +11 -0
- package/frontend/src/assets/icons/warning.svg +3 -0
- package/frontend/src/assets/logos/amazon.svg +1 -0
- package/frontend/src/assets/logos/claude_code.svg +3 -0
- package/frontend/src/assets/logos/cline.svg +6 -0
- package/frontend/src/assets/logos/cursor.svg +20 -0
- package/frontend/src/assets/logos/discord.svg +9 -0
- package/frontend/src/assets/logos/gemini.svg +19 -0
- package/frontend/src/assets/logos/github.svg +5 -0
- package/frontend/src/assets/logos/google.svg +13 -0
- package/frontend/src/assets/logos/grok.svg +10 -0
- package/frontend/src/assets/logos/insforge_dark.svg +15 -0
- package/frontend/src/assets/logos/insforge_light.svg +15 -0
- package/frontend/src/assets/logos/openai.svg +10 -0
- package/frontend/src/assets/logos/roo_code.svg +9 -0
- package/frontend/src/assets/logos/trae.svg +3 -0
- package/frontend/src/assets/logos/windsurf.svg +10 -0
- package/frontend/src/components/ButtonWithLoading.tsx +27 -0
- package/frontend/src/components/Checkbox.tsx +61 -0
- package/frontend/src/components/CodeBlock.tsx +32 -0
- package/frontend/src/components/ConfirmDialog.tsx +96 -0
- package/frontend/src/components/CopyButton.tsx +69 -0
- package/frontend/src/components/DeleteActionButton.tsx +42 -0
- package/frontend/src/components/EmptyState.tsx +41 -0
- package/frontend/src/components/ErrorState.tsx +35 -0
- package/frontend/src/components/FeatureSidebar.tsx +126 -0
- package/frontend/src/components/FeatureSidebarItem.tsx +101 -0
- package/frontend/src/components/JsonHighlight.tsx +61 -0
- package/frontend/src/components/LoadingState.tsx +16 -0
- package/frontend/src/components/PaginationControls.tsx +54 -0
- package/frontend/src/components/PromptDialog.tsx +68 -0
- package/frontend/src/components/SearchInput.tsx +90 -0
- package/frontend/src/components/SelectionClearButton.tsx +26 -0
- package/frontend/src/components/Stepper.tsx +139 -0
- package/frontend/src/components/ThemeToggle.tsx +58 -0
- package/frontend/src/components/TypeBadge.tsx +20 -0
- package/frontend/src/components/datagrid/DataGrid.tsx +264 -0
- package/frontend/src/components/datagrid/DefaultCellRenderer.tsx +114 -0
- package/frontend/src/components/datagrid/IdCell.tsx +44 -0
- package/frontend/src/components/datagrid/SortableHeader.tsx +74 -0
- package/frontend/src/components/datagrid/cell-editors/BooleanCellEditor.tsx +54 -0
- package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +483 -0
- package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +362 -0
- package/frontend/src/components/datagrid/cell-editors/TextCellEditor.tsx +38 -0
- package/frontend/src/components/datagrid/cell-editors/index.ts +14 -0
- package/frontend/src/components/datagrid/cell-editors/types.ts +43 -0
- package/frontend/src/components/datagrid/datagridTypes.tsx +72 -0
- package/frontend/src/components/datagrid/index.tsx +20 -0
- package/frontend/src/components/index.ts +39 -0
- package/frontend/src/components/layout/AppHeader.tsx +146 -0
- package/frontend/src/components/layout/AppSidebar.tsx +190 -0
- package/frontend/src/components/layout/CloudLayout.tsx +95 -0
- package/frontend/src/components/layout/Layout.tsx +43 -0
- package/frontend/src/components/radix/Alert.tsx +45 -0
- package/frontend/src/components/radix/AlertDialog.tsx +115 -0
- package/frontend/src/components/radix/Avatar.tsx +45 -0
- package/frontend/src/components/radix/Badge.tsx +33 -0
- package/frontend/src/components/radix/Button.tsx +50 -0
- package/frontend/src/components/radix/Card.tsx +58 -0
- package/frontend/src/components/radix/Dialog.tsx +98 -0
- package/frontend/src/components/radix/DropdownMenu.tsx +185 -0
- package/frontend/src/components/radix/Form.tsx +167 -0
- package/frontend/src/components/radix/Input.tsx +22 -0
- package/frontend/src/components/radix/Label.tsx +19 -0
- package/frontend/src/components/radix/Popover.tsx +29 -0
- package/frontend/src/components/radix/ScrollArea.tsx +44 -0
- package/frontend/src/components/radix/Select.tsx +151 -0
- package/frontend/src/components/radix/Separator.tsx +26 -0
- package/frontend/src/components/radix/Sheet.tsx +119 -0
- package/frontend/src/components/radix/Skeleton.tsx +7 -0
- package/frontend/src/components/radix/Switch.tsx +29 -0
- package/frontend/src/components/radix/Tabs.tsx +50 -0
- package/frontend/src/components/radix/Textarea.tsx +21 -0
- package/frontend/src/components/radix/Tooltip.tsx +28 -0
- package/frontend/src/features/ai/components/AIConfigCard.tsx +154 -0
- package/frontend/src/features/ai/components/AIConfigDialog.tsx +76 -0
- package/frontend/src/features/ai/components/AIConfigForm.tsx +222 -0
- package/frontend/src/features/ai/components/AIEmptyState.tsx +18 -0
- package/frontend/src/features/ai/components/fields/ModalityField.tsx +87 -0
- package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +134 -0
- package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +33 -0
- package/frontend/src/features/ai/helpers.ts +155 -0
- package/frontend/src/features/ai/hooks/useAIConfigs.ts +221 -0
- package/frontend/src/features/ai/hooks/useAIUsage.ts +77 -0
- package/frontend/src/features/ai/page/AIPage.tsx +178 -0
- package/frontend/src/features/ai/services/ai.service.ts +148 -0
- package/frontend/src/features/auth/components/AddOAuthDialog.tsx +106 -0
- package/frontend/src/features/auth/components/AuthMethodTab.tsx +238 -0
- package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +303 -0
- package/frontend/src/features/auth/components/OAuthEmptyState.tsx +15 -0
- package/frontend/src/features/auth/components/UserFormDialog.tsx +248 -0
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +183 -0
- package/frontend/src/features/auth/components/UsersTab.tsx +114 -0
- package/frontend/src/features/auth/hooks/useOAuthConfig.ts +129 -0
- package/frontend/src/features/auth/hooks/useUsers.ts +57 -0
- package/frontend/src/features/auth/index.ts +9 -0
- package/frontend/src/features/auth/page/AuthenticationPage.tsx +169 -0
- package/frontend/src/features/auth/services/auth.service.ts +112 -0
- package/frontend/src/features/auth/services/oauth.service.ts +49 -0
- package/frontend/src/features/dashboard/page/DashboardPage.tsx +194 -0
- package/frontend/src/features/database/components/ColumnTypeSelect.tsx +64 -0
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +282 -0
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +187 -0
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +378 -0
- package/frontend/src/features/database/components/LinkRecordModal.tsx +288 -0
- package/frontend/src/features/database/components/RecordFormDialog.tsx +164 -0
- package/frontend/src/features/database/components/RecordFormField.tsx +568 -0
- package/frontend/src/features/database/components/TableEmptyState.tsx +21 -0
- package/frontend/src/features/database/components/TableForm.tsx +656 -0
- package/frontend/src/features/database/components/TableFormColumn.tsx +137 -0
- package/frontend/src/features/database/components/TableListSkeleton.tsx +9 -0
- package/frontend/src/features/database/components/TableSidebar.tsx +47 -0
- package/frontend/src/features/database/constants.ts +26 -0
- package/frontend/src/features/database/helpers.ts +125 -0
- package/frontend/src/features/database/hooks/UseLinkModal.tsx +78 -0
- package/frontend/src/features/database/index.ts +12 -0
- package/frontend/src/features/database/page/DatabasePage.tsx +626 -0
- package/frontend/src/features/database/schema.ts +25 -0
- package/frontend/src/features/database/services/database.service.ts +216 -0
- package/frontend/src/features/functions/components/FunctionEmptyState.tsx +15 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +71 -0
- package/frontend/src/features/functions/components/FunctionViewer.tsx +46 -0
- package/frontend/src/features/functions/components/FunctionsContent.tsx +88 -0
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -0
- package/frontend/src/features/functions/components/SecretEmptyState.tsx +23 -0
- package/frontend/src/features/functions/components/SecretRow.tsx +68 -0
- package/frontend/src/features/functions/components/SecretsContent.tsx +120 -0
- package/frontend/src/features/functions/hooks/useFunctions.ts +106 -0
- package/frontend/src/features/functions/page/FunctionsPage.tsx +28 -0
- package/frontend/src/features/functions/services/functions.service.ts +48 -0
- package/frontend/src/features/login/components/AuthErrorBoundary.tsx +87 -0
- package/frontend/src/features/login/components/PrivateRoute.tsx +24 -0
- package/frontend/src/features/login/page/CloudLoginPage.tsx +93 -0
- package/frontend/src/features/login/page/LoginPage.tsx +174 -0
- package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +313 -0
- package/frontend/src/features/logs/components/LogsTable.tsx +199 -0
- package/frontend/src/features/logs/hooks/useAuditLogs.ts +39 -0
- package/frontend/src/features/logs/index.ts +5 -0
- package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +530 -0
- package/frontend/src/features/logs/page/AuditsPage.tsx +192 -0
- package/frontend/src/features/logs/services/log.service.ts +171 -0
- package/frontend/src/features/metadata/hooks/useMetadata.ts +53 -0
- package/frontend/src/features/metadata/index.ts +0 -0
- package/frontend/src/features/metadata/page/MetadataPage.tsx +136 -0
- package/frontend/src/features/metadata/services/metadata.service.ts +17 -0
- package/frontend/src/features/onboard/components/CompletionCard.tsx +41 -0
- package/frontend/src/features/onboard/components/OnboardButton.tsx +84 -0
- package/frontend/src/features/onboard/components/StepContent.tsx +91 -0
- package/frontend/src/features/onboard/components/TestConnectionStep.tsx +53 -0
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +35 -0
- package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +144 -0
- package/frontend/src/features/onboard/components/mcp/index.ts +4 -0
- package/frontend/src/features/onboard/components/mcp/mcp-helper.tsx +98 -0
- package/frontend/src/features/onboard/index.ts +3 -0
- package/frontend/src/features/onboard/page/OnBoardPage.tsx +104 -0
- package/frontend/src/features/onboard/types.ts +8 -0
- package/frontend/src/features/secrets/hooks/useSecrets.ts +139 -0
- package/frontend/src/features/secrets/services/secrets.service.ts +57 -0
- package/frontend/src/features/storage/components/BucketEmptyState.tsx +19 -0
- package/frontend/src/features/storage/components/BucketFormDialog.tsx +194 -0
- package/frontend/src/features/storage/components/BucketListSkeleton.tsx +17 -0
- package/frontend/src/features/storage/components/FilePreviewDialog.tsx +287 -0
- package/frontend/src/features/storage/components/StorageDataGrid.tsx +239 -0
- package/frontend/src/features/storage/components/StorageManager.tsx +236 -0
- package/frontend/src/features/storage/components/StorageSidebar.tsx +44 -0
- package/frontend/src/features/storage/components/UploadToast.tsx +46 -0
- package/frontend/src/features/storage/index.ts +3 -0
- package/frontend/src/features/storage/page/StoragePage.tsx +553 -0
- package/frontend/src/features/storage/services/storage.service.ts +144 -0
- package/frontend/src/features/visualizer/components/AuthNode.tsx +107 -0
- package/frontend/src/features/visualizer/components/BucketNode.tsx +34 -0
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +359 -0
- package/frontend/src/features/visualizer/components/TableNode.tsx +152 -0
- package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +24 -0
- package/frontend/src/features/visualizer/components/index.ts +5 -0
- package/frontend/src/features/visualizer/page/VisualizerPage.tsx +127 -0
- package/frontend/src/index.css +248 -0
- package/frontend/src/lib/api/client.ts +163 -0
- package/frontend/src/lib/contexts/AuthContext.tsx +157 -0
- package/frontend/src/lib/contexts/OnboardStepContext.tsx +68 -0
- package/frontend/src/lib/contexts/SocketContext.tsx +303 -0
- package/frontend/src/lib/contexts/ThemeContext.tsx +125 -0
- package/frontend/src/lib/hooks/useAuth.ts +4 -0
- package/frontend/src/lib/hooks/useConfirm.ts +55 -0
- package/frontend/src/lib/hooks/useInterval.ts +27 -0
- package/frontend/src/lib/hooks/useMediaQuery.ts +59 -0
- package/frontend/src/lib/hooks/useOnboardingCompletion.ts +29 -0
- package/frontend/src/lib/hooks/usePagination.ts +27 -0
- package/frontend/src/lib/hooks/useTimeout.ts +27 -0
- package/frontend/src/lib/hooks/useToast.tsx +229 -0
- package/frontend/src/lib/utils/constants.ts +38 -0
- package/frontend/src/lib/utils/utils.ts +165 -0
- package/frontend/src/lib/utils/validation-schemas.ts +126 -0
- package/frontend/src/main.tsx +16 -0
- package/frontend/src/rdg.css +194 -0
- package/frontend/src/vite-env.d.ts +12 -0
- package/frontend/tailwind.config.js +97 -0
- package/frontend/tsconfig.json +26 -0
- package/frontend/tsconfig.node.json +10 -0
- package/frontend/vite.config.ts +37 -0
- package/frontend/vitest.config.ts +36 -0
- package/functions/deno.json +25 -0
- package/functions/server.ts +290 -0
- package/functions/worker-template.js +126 -0
- package/openapi/ai.yaml +689 -0
- package/openapi/auth.yaml +563 -0
- package/openapi/functions.yaml +476 -0
- package/openapi/health.yaml +30 -0
- package/openapi/logs.yaml +224 -0
- package/openapi/metadata.yaml +178 -0
- package/openapi/records.yaml +382 -0
- package/openapi/secrets.yaml +371 -0
- package/openapi/storage.yaml +876 -0
- package/openapi/tables.yaml +464 -0
- package/package.json +88 -0
- package/shared-schemas/package.json +31 -0
- package/shared-schemas/src/ai-api.schema.ts +167 -0
- package/shared-schemas/src/ai.schema.ts +54 -0
- package/shared-schemas/src/auth-api.schema.ts +193 -0
- package/shared-schemas/src/auth.schema.ts +94 -0
- package/shared-schemas/src/database-api.schema.ts +259 -0
- package/shared-schemas/src/database.schema.ts +69 -0
- package/shared-schemas/src/functions-api.schema.ts +25 -0
- package/shared-schemas/src/functions.schema.ts +16 -0
- package/shared-schemas/src/index.ts +13 -0
- package/shared-schemas/src/logs-api.schema.ts +49 -0
- package/shared-schemas/src/logs.schema.ts +14 -0
- package/shared-schemas/src/metadata.schema.ts +56 -0
- package/shared-schemas/src/storage-api.schema.ts +65 -0
- package/shared-schemas/src/storage.schema.ts +19 -0
- package/shared-schemas/tsconfig.json +21 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/radix/Dialog';
|
|
2
|
+
import { CopyButton } from '@/components/CopyButton';
|
|
3
|
+
import { cn } from '@/lib/utils/utils';
|
|
4
|
+
|
|
5
|
+
interface PromptDialogProps {
|
|
6
|
+
open: boolean;
|
|
7
|
+
onOpenChange: (open: boolean) => void;
|
|
8
|
+
title?: string;
|
|
9
|
+
subtitle?: string;
|
|
10
|
+
prompt: string;
|
|
11
|
+
additionalAction?: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function PromptDialog({
|
|
15
|
+
open,
|
|
16
|
+
onOpenChange,
|
|
17
|
+
title = 'Integrate with your application',
|
|
18
|
+
subtitle = 'Paste the prompt below into your cloud agent',
|
|
19
|
+
prompt,
|
|
20
|
+
additionalAction,
|
|
21
|
+
}: PromptDialogProps) {
|
|
22
|
+
return (
|
|
23
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
24
|
+
<DialogContent className="max-w-4xl p-0 bg-white border border-zinc-200 shadow-[0px_1px_3px_0px_rgba(0,0,0,0.1)] dark:bg-neutral-800 dark:border-neutral-700">
|
|
25
|
+
<div className="flex flex-col">
|
|
26
|
+
<DialogHeader className="px-6 py-3 flex flex-col gap-1 justify-start border-b border-zinc-200 dark:border-neutral-700">
|
|
27
|
+
<DialogTitle className="text-lg font-semibold text-zinc-950 dark:text-white">
|
|
28
|
+
{title}
|
|
29
|
+
</DialogTitle>
|
|
30
|
+
</DialogHeader>
|
|
31
|
+
{/* Content */}
|
|
32
|
+
<div className="p-6 flex flex-col gap-4">
|
|
33
|
+
<p className="text-sm text-zinc-500 font-normal leading-5 dark:text-neutral-400">
|
|
34
|
+
{subtitle}
|
|
35
|
+
</p>
|
|
36
|
+
{/* Prompt display */}
|
|
37
|
+
<div className="relative">
|
|
38
|
+
<pre
|
|
39
|
+
className={cn(
|
|
40
|
+
'px-6 py-4 font-mono text-sm leading-5 overflow-auto whitespace-pre-wrap break-all rounded',
|
|
41
|
+
'max-h-96',
|
|
42
|
+
'bg-zinc-50 text-zinc-900 dark:bg-neutral-700 dark:text-white',
|
|
43
|
+
'border border-zinc-200 dark:border-neutral-700'
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
{prompt}
|
|
47
|
+
</pre>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
{/* Action buttons */}
|
|
51
|
+
<div className="flex items-center justify-end gap-2.5">
|
|
52
|
+
{additionalAction}
|
|
53
|
+
<CopyButton
|
|
54
|
+
text={prompt}
|
|
55
|
+
variant="default"
|
|
56
|
+
size="default"
|
|
57
|
+
showText={true}
|
|
58
|
+
className="h-9 pl-2 pr-3 py-2 text-sm font-medium"
|
|
59
|
+
copyText="Copy Prompt"
|
|
60
|
+
copiedText="Copied!"
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</DialogContent>
|
|
66
|
+
</Dialog>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import { Search, X } from 'lucide-react';
|
|
3
|
+
import { Input } from '@/components/radix/Input';
|
|
4
|
+
import { Button } from '@/components/radix/Button';
|
|
5
|
+
|
|
6
|
+
interface SearchInputProps {
|
|
7
|
+
value: string;
|
|
8
|
+
onChange: (value: string) => void;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
/** Debounce delay in milliseconds. Set to 0 to disable debouncing. Default: 500ms */
|
|
12
|
+
debounceTime?: number;
|
|
13
|
+
/** Callback fired immediately when input changes (before debounce) */
|
|
14
|
+
onImmediateChange?: (value: string) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function SearchInput({
|
|
18
|
+
value,
|
|
19
|
+
onChange,
|
|
20
|
+
placeholder = 'Search...',
|
|
21
|
+
className,
|
|
22
|
+
debounceTime = 500,
|
|
23
|
+
onImmediateChange,
|
|
24
|
+
}: SearchInputProps) {
|
|
25
|
+
const [internalValue, setInternalValue] = useState(value);
|
|
26
|
+
|
|
27
|
+
// Sync internal value with external value prop
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setInternalValue(value);
|
|
30
|
+
}, [value]);
|
|
31
|
+
|
|
32
|
+
// Handle debounced onChange
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (debounceTime === 0) {
|
|
35
|
+
// No debouncing, call onChange immediately
|
|
36
|
+
onChange(internalValue);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Set up debounce timer
|
|
41
|
+
const handler = setTimeout(() => {
|
|
42
|
+
onChange(internalValue);
|
|
43
|
+
}, debounceTime);
|
|
44
|
+
|
|
45
|
+
// Cleanup timer on value change
|
|
46
|
+
return () => {
|
|
47
|
+
clearTimeout(handler);
|
|
48
|
+
};
|
|
49
|
+
}, [internalValue, debounceTime, onChange]);
|
|
50
|
+
|
|
51
|
+
const handleInputChange = (newValue: string) => {
|
|
52
|
+
setInternalValue(newValue);
|
|
53
|
+
// Call immediate change callback if provided
|
|
54
|
+
onImmediateChange?.(newValue);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleClear = () => {
|
|
58
|
+
setInternalValue('');
|
|
59
|
+
onImmediateChange?.('');
|
|
60
|
+
// If no debouncing, clear immediately
|
|
61
|
+
if (debounceTime === 0) {
|
|
62
|
+
onChange('');
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div
|
|
68
|
+
className={`relative bg-white dark:bg-neutral-900 overflow-hidden rounded-md ${className || ''}`}
|
|
69
|
+
>
|
|
70
|
+
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground dark:text-zinc-300" />
|
|
71
|
+
<Input
|
|
72
|
+
type="text"
|
|
73
|
+
placeholder={placeholder}
|
|
74
|
+
value={internalValue}
|
|
75
|
+
onChange={(e) => handleInputChange(e.target.value)}
|
|
76
|
+
className="pl-9 pr-9 h-10 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
|
|
77
|
+
/>
|
|
78
|
+
{internalValue && (
|
|
79
|
+
<Button
|
|
80
|
+
variant="ghost"
|
|
81
|
+
size="icon"
|
|
82
|
+
onClick={handleClear}
|
|
83
|
+
className="absolute right-1 top-1/2 h-7 w-7 -translate-y-1/2"
|
|
84
|
+
>
|
|
85
|
+
<X className="h-3 w-3" />
|
|
86
|
+
</Button>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { X } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
interface SelectionClearButtonProps {
|
|
4
|
+
selectedCount: number;
|
|
5
|
+
itemType: string;
|
|
6
|
+
onClear: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function SelectionClearButton({
|
|
10
|
+
selectedCount,
|
|
11
|
+
itemType,
|
|
12
|
+
onClear,
|
|
13
|
+
}: SelectionClearButtonProps) {
|
|
14
|
+
const isPlural = selectedCount > 1;
|
|
15
|
+
const displayText = `${selectedCount} ${isPlural ? `${itemType}s` : itemType} selected`;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<button
|
|
19
|
+
className="flex items-center gap-1.5 h-10 px-3 rounded-[6px] bg-white border border-border-gray hover:bg-gray-50 dark:bg-neutral-600 dark:border-neutral-600 dark:hover:bg-neutral-700 transition-colors"
|
|
20
|
+
onClick={onClear}
|
|
21
|
+
>
|
|
22
|
+
<p className="text-zinc-950 dark:text-white text-sm">{displayText}</p>
|
|
23
|
+
<X className="h-4 w-4 text-gray-500 dark:text-neutral-400" />
|
|
24
|
+
</button>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils/utils';
|
|
2
|
+
|
|
3
|
+
interface CircularStepperProps {
|
|
4
|
+
isActive: boolean;
|
|
5
|
+
currentStep: number;
|
|
6
|
+
totalSteps: number;
|
|
7
|
+
size?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function CircularStepper({
|
|
11
|
+
isActive,
|
|
12
|
+
currentStep,
|
|
13
|
+
totalSteps,
|
|
14
|
+
size = 40,
|
|
15
|
+
}: CircularStepperProps) {
|
|
16
|
+
const radius = (size - 2) / 2;
|
|
17
|
+
const circumference = 2 * Math.PI * radius;
|
|
18
|
+
const progress = (currentStep / totalSteps) * circumference;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className="relative [&_svg]:w-full [&_svg]:h-full" style={{ width: size, height: size }}>
|
|
22
|
+
{/* Background circle */}
|
|
23
|
+
<svg className="absolute inset-0 transform">
|
|
24
|
+
<circle
|
|
25
|
+
cx={size / 2}
|
|
26
|
+
cy={size / 2}
|
|
27
|
+
r={radius}
|
|
28
|
+
stroke="currentColor"
|
|
29
|
+
strokeWidth="2"
|
|
30
|
+
fill="none"
|
|
31
|
+
className={cn(
|
|
32
|
+
'transition-all duration-300',
|
|
33
|
+
isActive ? 'text-zinc-50' : 'text-zinc-200 dark:text-zinc-500'
|
|
34
|
+
)}
|
|
35
|
+
/>
|
|
36
|
+
{/* Progress circle */}
|
|
37
|
+
<circle
|
|
38
|
+
cx={size / 2}
|
|
39
|
+
cy={size / 2}
|
|
40
|
+
r={radius}
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
strokeWidth="2"
|
|
43
|
+
fill="none"
|
|
44
|
+
strokeDasharray={circumference}
|
|
45
|
+
strokeDashoffset={circumference - progress}
|
|
46
|
+
className={cn(
|
|
47
|
+
'transition-all duration-300',
|
|
48
|
+
isActive ? 'text-zinc-400 dark:text-zinc-800' : 'text-zinc-950 dark:text-emerald-300'
|
|
49
|
+
)}
|
|
50
|
+
strokeLinecap="round"
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
{/* Step number */}
|
|
54
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
55
|
+
<span
|
|
56
|
+
className={cn(
|
|
57
|
+
'transition-all duration-300',
|
|
58
|
+
isActive ? 'text-zinc-200 dark:text-zinc-800' : 'text-zinc-950 dark:text-white'
|
|
59
|
+
)}
|
|
60
|
+
>
|
|
61
|
+
{currentStep}/{totalSteps}
|
|
62
|
+
</span>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
import ActiveStep from '@/assets/icons/step_active.svg?react';
|
|
69
|
+
import InactiveStep from '@/assets/icons/step_inactive.svg?react';
|
|
70
|
+
import CheckedIcon from '@/assets/icons/checked.svg?react';
|
|
71
|
+
|
|
72
|
+
interface LinearStepperProps {
|
|
73
|
+
currentStep: number;
|
|
74
|
+
totalSteps: number;
|
|
75
|
+
stepLabels: readonly string[];
|
|
76
|
+
className?: string;
|
|
77
|
+
isCompleted: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function LinearStepper({
|
|
81
|
+
currentStep,
|
|
82
|
+
totalSteps,
|
|
83
|
+
stepLabels,
|
|
84
|
+
className,
|
|
85
|
+
isCompleted,
|
|
86
|
+
}: LinearStepperProps) {
|
|
87
|
+
// Calculate progress percentage
|
|
88
|
+
const progressPercentage = isCompleted
|
|
89
|
+
? 100
|
|
90
|
+
: Math.min(((currentStep - 1) / totalSteps) * 100 + currentStep, 100);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div className={cn('w-full space-y-3', className)}>
|
|
94
|
+
{/* Progress Bar */}
|
|
95
|
+
<div className="relative w-full h-2 bg-zinc-200 dark:bg-zinc-600 rounded-full overflow-hidden">
|
|
96
|
+
<div
|
|
97
|
+
className="absolute top-0 left-0 h-full bg-zinc-950 dark:bg-white transition-all duration-500 ease-in-out"
|
|
98
|
+
style={{ width: `${progressPercentage}%` }}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
{/* Step Labels */}
|
|
103
|
+
<div className="flex justify-start items-center gap-6 w-full">
|
|
104
|
+
{stepLabels.map((label, index) => {
|
|
105
|
+
const stepNumber = index + 1;
|
|
106
|
+
const stepIsCompleted = stepNumber < currentStep || isCompleted;
|
|
107
|
+
const isCurrent = stepNumber === currentStep;
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div key={stepNumber} className="flex flex-row items-start justify-start gap-1 w-full">
|
|
111
|
+
{/* Step Number */}
|
|
112
|
+
<div className="w-5 h-5 flex items-center justify-center">
|
|
113
|
+
{stepIsCompleted ? (
|
|
114
|
+
<CheckedIcon className="w-5 h-5" />
|
|
115
|
+
) : isCurrent ? (
|
|
116
|
+
<ActiveStep className="w-5 h-5 dark:text-white" />
|
|
117
|
+
) : (
|
|
118
|
+
<InactiveStep className="w-5 h-5 dark:text-neutral-400" />
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{/* Step Label */}
|
|
123
|
+
<span
|
|
124
|
+
className={cn(
|
|
125
|
+
'text-sm text-center transition-colors duration-300',
|
|
126
|
+
stepIsCompleted || isCurrent
|
|
127
|
+
? 'text-zinc-950 dark:text-white'
|
|
128
|
+
: 'text-zinc-500 dark:text-neutral-400'
|
|
129
|
+
)}
|
|
130
|
+
>
|
|
131
|
+
{label}
|
|
132
|
+
</span>
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
})}
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Sun, Moon, Monitor } from 'lucide-react';
|
|
2
|
+
import { useTheme } from '@/lib/contexts/ThemeContext';
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from '@/components/radix/DropdownMenu';
|
|
9
|
+
import { Button } from '@/components/radix/Button';
|
|
10
|
+
|
|
11
|
+
export function ThemeToggle() {
|
|
12
|
+
const { theme, resolvedTheme, setTheme } = useTheme();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<DropdownMenu>
|
|
16
|
+
<DropdownMenuTrigger asChild>
|
|
17
|
+
<Button
|
|
18
|
+
variant="ghost"
|
|
19
|
+
size="icon"
|
|
20
|
+
className="h-9 w-9 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800"
|
|
21
|
+
aria-label="Toggle theme"
|
|
22
|
+
>
|
|
23
|
+
{resolvedTheme === 'light' ? (
|
|
24
|
+
<Sun className="h-5 w-5 text-gray-600 dark:text-gray-400" />
|
|
25
|
+
) : (
|
|
26
|
+
<Moon className="h-5 w-5 text-gray-600 dark:text-gray-400" />
|
|
27
|
+
)}
|
|
28
|
+
</Button>
|
|
29
|
+
</DropdownMenuTrigger>
|
|
30
|
+
<DropdownMenuContent align="end" className="w-36">
|
|
31
|
+
<DropdownMenuItem
|
|
32
|
+
onClick={() => setTheme('light')}
|
|
33
|
+
className="flex items-center gap-2 cursor-pointer"
|
|
34
|
+
>
|
|
35
|
+
<Sun className="h-4 w-4" />
|
|
36
|
+
<span>Light</span>
|
|
37
|
+
{theme === 'light' && <span className="ml-auto text-xs">✓</span>}
|
|
38
|
+
</DropdownMenuItem>
|
|
39
|
+
<DropdownMenuItem
|
|
40
|
+
onClick={() => setTheme('dark')}
|
|
41
|
+
className="flex items-center gap-2 cursor-pointer"
|
|
42
|
+
>
|
|
43
|
+
<Moon className="h-4 w-4" />
|
|
44
|
+
<span>Dark</span>
|
|
45
|
+
{theme === 'dark' && <span className="ml-auto text-xs">✓</span>}
|
|
46
|
+
</DropdownMenuItem>
|
|
47
|
+
<DropdownMenuItem
|
|
48
|
+
onClick={() => setTheme('system')}
|
|
49
|
+
className="flex items-center gap-2 cursor-pointer"
|
|
50
|
+
>
|
|
51
|
+
<Monitor className="h-4 w-4" />
|
|
52
|
+
<span>System</span>
|
|
53
|
+
{theme === 'system' && <span className="ml-auto text-xs">✓</span>}
|
|
54
|
+
</DropdownMenuItem>
|
|
55
|
+
</DropdownMenuContent>
|
|
56
|
+
</DropdownMenu>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cn } from '@/lib/utils/utils';
|
|
2
|
+
|
|
3
|
+
interface TypeBadgeProps {
|
|
4
|
+
type: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function TypeBadge({ type, className }: TypeBadgeProps) {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
className={cn(
|
|
12
|
+
'inline-flex items-center justify-center px-1.5 py-0.5 rounded',
|
|
13
|
+
'bg-white border border-zinc-200 dark:bg-neutral-900 dark:border-neutral-700',
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
>
|
|
17
|
+
<span className="text-xs font-normal text-zinc-500 dark:text-neutral-400">{type}</span>
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import '@/rdg.css';
|
|
2
|
+
import { useMemo, useCallback } from 'react';
|
|
3
|
+
import ReactDataGrid, {
|
|
4
|
+
type Column,
|
|
5
|
+
type SortColumn,
|
|
6
|
+
SelectColumn,
|
|
7
|
+
SELECT_COLUMN_KEY,
|
|
8
|
+
type CellClickArgs,
|
|
9
|
+
type CellMouseEvent,
|
|
10
|
+
type RenderCellProps,
|
|
11
|
+
} from 'react-data-grid';
|
|
12
|
+
import { cn } from '@/lib/utils/utils';
|
|
13
|
+
import { PaginationControls } from '../PaginationControls';
|
|
14
|
+
import { Checkbox } from '../Checkbox';
|
|
15
|
+
import { useTheme } from '@/lib/contexts/ThemeContext';
|
|
16
|
+
import type { DataGridColumn, DataGridRow, DataGridRowType } from './datagridTypes';
|
|
17
|
+
import SortableHeaderRenderer from './SortableHeader';
|
|
18
|
+
|
|
19
|
+
// Generic DataGrid props
|
|
20
|
+
export interface DataGridProps<TRow extends DataGridRowType = DataGridRow> {
|
|
21
|
+
data: TRow[];
|
|
22
|
+
columns: DataGridColumn<TRow>[];
|
|
23
|
+
loading?: boolean;
|
|
24
|
+
isSorting?: boolean;
|
|
25
|
+
isRefreshing?: boolean;
|
|
26
|
+
selectedRows?: Set<string>;
|
|
27
|
+
onSelectedRowsChange?: (selectedRows: Set<string>) => void;
|
|
28
|
+
sortColumns?: SortColumn[];
|
|
29
|
+
onSortColumnsChange?: (sortColumns: SortColumn[]) => void;
|
|
30
|
+
onCellClick?: (args: CellClickArgs<TRow>, event: CellMouseEvent) => void;
|
|
31
|
+
currentPage?: number;
|
|
32
|
+
totalPages?: number;
|
|
33
|
+
pageSize?: number;
|
|
34
|
+
totalRecords?: number;
|
|
35
|
+
onPageChange?: (page: number) => void;
|
|
36
|
+
emptyStateTitle?: string;
|
|
37
|
+
emptyStateActionText?: string;
|
|
38
|
+
onEmptyStateAction?: () => void;
|
|
39
|
+
rowKeyGetter?: (row: TRow) => string;
|
|
40
|
+
className?: string;
|
|
41
|
+
showSelection?: boolean;
|
|
42
|
+
showPagination?: boolean;
|
|
43
|
+
showTypeBadge?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Main DataGrid component
|
|
47
|
+
export default function DataGrid<TRow extends DataGridRowType = DataGridRow>({
|
|
48
|
+
data,
|
|
49
|
+
columns,
|
|
50
|
+
loading = false,
|
|
51
|
+
isSorting = false,
|
|
52
|
+
isRefreshing = false,
|
|
53
|
+
selectedRows,
|
|
54
|
+
onSelectedRowsChange,
|
|
55
|
+
sortColumns,
|
|
56
|
+
onSortColumnsChange,
|
|
57
|
+
onCellClick,
|
|
58
|
+
currentPage,
|
|
59
|
+
totalPages,
|
|
60
|
+
pageSize,
|
|
61
|
+
totalRecords,
|
|
62
|
+
onPageChange,
|
|
63
|
+
emptyStateTitle = 'No data available',
|
|
64
|
+
emptyStateActionText,
|
|
65
|
+
onEmptyStateAction,
|
|
66
|
+
rowKeyGetter,
|
|
67
|
+
className,
|
|
68
|
+
showSelection = false,
|
|
69
|
+
showPagination = true,
|
|
70
|
+
showTypeBadge = true,
|
|
71
|
+
}: DataGridProps<TRow>) {
|
|
72
|
+
const { resolvedTheme } = useTheme();
|
|
73
|
+
// Convert columns to react-data-grid format
|
|
74
|
+
const gridColumns = useMemo(() => {
|
|
75
|
+
const cols: Column<TRow>[] = [];
|
|
76
|
+
|
|
77
|
+
// Add selection column if enabled and not hidden
|
|
78
|
+
if (showSelection && selectedRows !== undefined && onSelectedRowsChange) {
|
|
79
|
+
cols.push({
|
|
80
|
+
...SelectColumn,
|
|
81
|
+
key: SELECT_COLUMN_KEY,
|
|
82
|
+
frozen: true,
|
|
83
|
+
width: 45,
|
|
84
|
+
minWidth: 45,
|
|
85
|
+
maxWidth: 45,
|
|
86
|
+
resizable: false,
|
|
87
|
+
renderCell: ({ row, tabIndex }) => (
|
|
88
|
+
<Checkbox
|
|
89
|
+
checked={selectedRows.has(String(row.id))}
|
|
90
|
+
onChange={(checked) => {
|
|
91
|
+
const newSelectedRows = new Set(selectedRows);
|
|
92
|
+
if (checked) {
|
|
93
|
+
newSelectedRows.add(String(row.id));
|
|
94
|
+
} else {
|
|
95
|
+
newSelectedRows.delete(String(row.id));
|
|
96
|
+
}
|
|
97
|
+
onSelectedRowsChange(newSelectedRows);
|
|
98
|
+
}}
|
|
99
|
+
tabIndex={tabIndex}
|
|
100
|
+
/>
|
|
101
|
+
),
|
|
102
|
+
renderHeaderCell: () => {
|
|
103
|
+
const selectedCount = data.filter((row) => selectedRows.has(String(row.id))).length;
|
|
104
|
+
const totalCount = data.length;
|
|
105
|
+
const isAllSelected = totalCount > 0 && selectedCount === totalCount;
|
|
106
|
+
const isPartiallySelected = selectedCount > 0 && selectedCount < totalCount;
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<Checkbox
|
|
110
|
+
checked={isAllSelected}
|
|
111
|
+
indeterminate={isPartiallySelected}
|
|
112
|
+
onChange={(checked) => {
|
|
113
|
+
const newSelectedRows = new Set(selectedRows);
|
|
114
|
+
if (checked) {
|
|
115
|
+
// Select all
|
|
116
|
+
data.forEach((row) => newSelectedRows.add(String(row.id)));
|
|
117
|
+
} else {
|
|
118
|
+
// Unselect all
|
|
119
|
+
data.forEach((row) => newSelectedRows.delete(String(row.id)));
|
|
120
|
+
}
|
|
121
|
+
onSelectedRowsChange(newSelectedRows);
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Add data columns
|
|
130
|
+
columns.forEach((col) => {
|
|
131
|
+
const currentSort = sortColumns?.find((sort) => sort.columnKey === col.key);
|
|
132
|
+
const sortDirection = currentSort?.direction;
|
|
133
|
+
|
|
134
|
+
const gridColumn: Column<TRow> = {
|
|
135
|
+
...col,
|
|
136
|
+
key: col.key,
|
|
137
|
+
name: col.name,
|
|
138
|
+
width: col.width,
|
|
139
|
+
minWidth: col.minWidth || 80,
|
|
140
|
+
maxWidth: col.maxWidth,
|
|
141
|
+
resizable: col.resizable !== false,
|
|
142
|
+
sortable: col.sortable !== false,
|
|
143
|
+
sortDescendingFirst: col.sortDescendingFirst ?? true,
|
|
144
|
+
editable: col.editable && !col.isPrimaryKey,
|
|
145
|
+
renderCell:
|
|
146
|
+
col.renderCell ||
|
|
147
|
+
(({ row, column }: RenderCellProps<TRow>) => {
|
|
148
|
+
const value = row[column.key];
|
|
149
|
+
const displayValue = String(value ?? '');
|
|
150
|
+
return (
|
|
151
|
+
<div className="w-full h-full flex items-center">
|
|
152
|
+
<span className="truncate dark:text-zinc-300" title={displayValue}>
|
|
153
|
+
{displayValue}
|
|
154
|
+
</span>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}),
|
|
158
|
+
renderEditCell: col.renderEditCell,
|
|
159
|
+
renderHeaderCell:
|
|
160
|
+
col.renderHeaderCell ||
|
|
161
|
+
(() => (
|
|
162
|
+
<SortableHeaderRenderer<TRow>
|
|
163
|
+
column={col}
|
|
164
|
+
sortDirection={sortDirection}
|
|
165
|
+
columnType={col.type}
|
|
166
|
+
showTypeBadge={showTypeBadge}
|
|
167
|
+
/>
|
|
168
|
+
)),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
cols.push(gridColumn);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return cols;
|
|
175
|
+
}, [
|
|
176
|
+
columns,
|
|
177
|
+
selectedRows,
|
|
178
|
+
onSelectedRowsChange,
|
|
179
|
+
data,
|
|
180
|
+
sortColumns,
|
|
181
|
+
showSelection,
|
|
182
|
+
showTypeBadge,
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
// Default row key getter
|
|
186
|
+
const defaultRowKeyGetter = useCallback((row: TRow) => row.id || Math.random().toString(), []);
|
|
187
|
+
const keyGetter = rowKeyGetter || defaultRowKeyGetter;
|
|
188
|
+
|
|
189
|
+
// Loading state - only show full loading screen if not sorting
|
|
190
|
+
if (loading && !isSorting) {
|
|
191
|
+
return (
|
|
192
|
+
<div className="h-full flex items-center justify-center bg-white dark:bg-neutral-800">
|
|
193
|
+
<div className="text-gray-500 dark:text-zinc-400">Loading...</div>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<div
|
|
200
|
+
className={cn(
|
|
201
|
+
'h-full flex flex-col bg-bg-gray dark:bg-neutral-800 overflow-hidden',
|
|
202
|
+
className
|
|
203
|
+
)}
|
|
204
|
+
>
|
|
205
|
+
<div className="flex-1 overflow-hidden relative mx-3 border border-border-gray dark:border-0">
|
|
206
|
+
<ReactDataGrid
|
|
207
|
+
columns={gridColumns}
|
|
208
|
+
rows={isRefreshing ? [] : data}
|
|
209
|
+
rowKeyGetter={keyGetter}
|
|
210
|
+
onRowsChange={() => {}}
|
|
211
|
+
selectedRows={selectedRows}
|
|
212
|
+
onSelectedRowsChange={onSelectedRowsChange}
|
|
213
|
+
sortColumns={sortColumns || []}
|
|
214
|
+
onSortColumnsChange={onSortColumnsChange}
|
|
215
|
+
onCellClick={onCellClick}
|
|
216
|
+
className={`h-full fill-grid ${resolvedTheme === 'dark' ? 'rdg-dark' : 'rdg-light'}`}
|
|
217
|
+
headerRowHeight={36}
|
|
218
|
+
rowHeight={36}
|
|
219
|
+
enableVirtualization={true}
|
|
220
|
+
renderers={{
|
|
221
|
+
noRowsFallback: (
|
|
222
|
+
<div className="absolute inset-x-0 top-0 mt-13 py-8 flex items-center justify-center bg-white dark:bg-neutral-800">
|
|
223
|
+
<div className="flex flex-col gap-1 items-center">
|
|
224
|
+
<div className="flex flex-row gap-2.5 items-center">
|
|
225
|
+
<div className="text-sm text-zinc-500 dark:text-zinc-400">
|
|
226
|
+
{emptyStateTitle}
|
|
227
|
+
</div>
|
|
228
|
+
{emptyStateActionText && onEmptyStateAction && (
|
|
229
|
+
<button
|
|
230
|
+
onClick={onEmptyStateAction}
|
|
231
|
+
className="inline-flex items-center text-sm font-medium text-chart-blue-dark focus:outline-none focus:ring-0 dark:text-zinc-400"
|
|
232
|
+
>
|
|
233
|
+
{emptyStateActionText}
|
|
234
|
+
</button>
|
|
235
|
+
)}
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
),
|
|
240
|
+
}}
|
|
241
|
+
/>
|
|
242
|
+
|
|
243
|
+
{/* Loading mask overlay */}
|
|
244
|
+
{isRefreshing && (
|
|
245
|
+
<div className="absolute inset-0 bg-white dark:bg-neutral-800 flex items-center justify-center z-50 mt-9">
|
|
246
|
+
<div className="flex items-center gap-1">
|
|
247
|
+
<div className="w-5 h-5 border-2 border-zinc-500 dark:border-neutral-700 border-t-transparent rounded-full animate-spin" />
|
|
248
|
+
<span className="text-sm text-zinc-500 dark:text-zinc-400">Loading</span>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
)}
|
|
252
|
+
</div>
|
|
253
|
+
{showPagination && onPageChange && (
|
|
254
|
+
<PaginationControls
|
|
255
|
+
currentPage={currentPage}
|
|
256
|
+
totalPages={totalPages}
|
|
257
|
+
onPageChange={onPageChange}
|
|
258
|
+
totalRecords={totalRecords}
|
|
259
|
+
pageSize={pageSize}
|
|
260
|
+
/>
|
|
261
|
+
)}
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
}
|