crca 1.4.0__py3-none-any.whl
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.
- .github/ISSUE_TEMPLATE/bug_report.md +65 -0
- .github/ISSUE_TEMPLATE/feature_request.md +41 -0
- .github/PULL_REQUEST_TEMPLATE.md +20 -0
- .github/workflows/publish-manual.yml +61 -0
- .github/workflows/publish.yml +64 -0
- .gitignore +214 -0
- CRCA.py +4156 -0
- LICENSE +201 -0
- MANIFEST.in +43 -0
- PKG-INFO +5035 -0
- README.md +4959 -0
- __init__.py +17 -0
- branches/CRCA-Q.py +2728 -0
- branches/crca_cg/corposwarm.py +9065 -0
- branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
- branches/crca_cg/package.json +5 -0
- branches/crca_cg/test_bolt_integration.py +446 -0
- branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
- branches/crca_cg/test_new_features.py +163 -0
- branches/crca_sd/__init__.py +149 -0
- branches/crca_sd/crca_sd_core.py +770 -0
- branches/crca_sd/crca_sd_governance.py +1325 -0
- branches/crca_sd/crca_sd_mpc.py +1130 -0
- branches/crca_sd/crca_sd_realtime.py +1844 -0
- branches/crca_sd/crca_sd_tui.py +1133 -0
- crca-1.4.0.dist-info/METADATA +5035 -0
- crca-1.4.0.dist-info/RECORD +501 -0
- crca-1.4.0.dist-info/WHEEL +4 -0
- crca-1.4.0.dist-info/licenses/LICENSE +201 -0
- docs/CRCA-Q.md +2333 -0
- examples/config.yaml.example +25 -0
- examples/crca_sd_example.py +513 -0
- examples/data_broker_example.py +294 -0
- examples/logistics_corporation.py +861 -0
- examples/palantir_example.py +299 -0
- examples/policy_bench.py +934 -0
- examples/pridnestrovia-sd.py +705 -0
- examples/pridnestrovia_realtime.py +1902 -0
- prompts/__init__.py +10 -0
- prompts/default_crca.py +101 -0
- pyproject.toml +151 -0
- requirements.txt +76 -0
- schemas/__init__.py +43 -0
- schemas/mcpSchemas.py +51 -0
- schemas/policy.py +458 -0
- templates/__init__.py +38 -0
- templates/base_specialized_agent.py +195 -0
- templates/drift_detection.py +325 -0
- templates/examples/causal_agent_template.py +309 -0
- templates/examples/drag_drop_example.py +213 -0
- templates/examples/logistics_agent_template.py +207 -0
- templates/examples/trading_agent_template.py +206 -0
- templates/feature_mixins.py +253 -0
- templates/graph_management.py +442 -0
- templates/llm_integration.py +194 -0
- templates/module_registry.py +276 -0
- templates/mpc_planner.py +280 -0
- templates/policy_loop.py +1168 -0
- templates/prediction_framework.py +448 -0
- templates/statistical_methods.py +778 -0
- tests/sanity.yml +31 -0
- tests/sanity_check +406 -0
- tests/test_core.py +47 -0
- tests/test_crca_excel.py +166 -0
- tests/test_crca_sd.py +780 -0
- tests/test_data_broker.py +424 -0
- tests/test_palantir.py +349 -0
- tools/__init__.py +38 -0
- tools/actuators.py +437 -0
- tools/bolt.diy/Dockerfile +103 -0
- tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
- tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
- tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
- tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
- tools/bolt.diy/app/components/@settings/index.ts +12 -0
- tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
- tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
- tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
- tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
- tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
- tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
- tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
- tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
- tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
- tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
- tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
- tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
- tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
- tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
- tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
- tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
- tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
- tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
- tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
- tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
- tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
- tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
- tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
- tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
- tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
- tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
- tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
- tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
- tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
- tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
- tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
- tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
- tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
- tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
- tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
- tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
- tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
- tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
- tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
- tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
- tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
- tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
- tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
- tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
- tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
- tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
- tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
- tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
- tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
- tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
- tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
- tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
- tools/bolt.diy/app/components/header/Header.tsx +42 -0
- tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
- tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
- tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
- tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
- tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
- tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
- tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
- tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
- tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
- tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
- tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
- tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
- tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
- tools/bolt.diy/app/components/txt +1 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
- tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
- tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
- tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
- tools/bolt.diy/app/components/ui/Button.tsx +46 -0
- tools/bolt.diy/app/components/ui/Card.tsx +55 -0
- tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
- tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
- tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
- tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
- tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
- tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
- tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
- tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
- tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
- tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
- tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
- tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
- tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
- tools/bolt.diy/app/components/ui/Input.tsx +22 -0
- tools/bolt.diy/app/components/ui/Label.tsx +20 -0
- tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
- tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
- tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
- tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
- tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
- tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
- tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
- tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
- tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
- tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
- tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
- tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
- tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
- tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
- tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
- tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
- tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
- tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
- tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
- tools/bolt.diy/app/components/ui/index.ts +38 -0
- tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
- tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
- tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
- tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
- tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
- tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
- tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
- tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
- tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
- tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
- tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
- tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
- tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
- tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
- tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
- tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
- tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
- tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
- tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
- tools/bolt.diy/app/entry.client.tsx +7 -0
- tools/bolt.diy/app/entry.server.tsx +80 -0
- tools/bolt.diy/app/root.tsx +156 -0
- tools/bolt.diy/app/routes/_index.tsx +175 -0
- tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
- tools/bolt.diy/app/routes/api.chat.ts +463 -0
- tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
- tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
- tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
- tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
- tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
- tools/bolt.diy/app/routes/api.git-info.ts +69 -0
- tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
- tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
- tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
- tools/bolt.diy/app/routes/api.github-template.ts +242 -0
- tools/bolt.diy/app/routes/api.github-user.ts +287 -0
- tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
- tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
- tools/bolt.diy/app/routes/api.health.ts +8 -0
- tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
- tools/bolt.diy/app/routes/api.mandate.ts +351 -0
- tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
- tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
- tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
- tools/bolt.diy/app/routes/api.models.ts +90 -0
- tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
- tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
- tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
- tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
- tools/bolt.diy/app/routes/api.supabase.ts +56 -0
- tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
- tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
- tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
- tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
- tools/bolt.diy/app/routes/api.update.ts +21 -0
- tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
- tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
- tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
- tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
- tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
- tools/bolt.diy/app/routes/git.tsx +25 -0
- tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
- tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
- tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
- tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
- tools/bolt.diy/app/styles/animations.scss +49 -0
- tools/bolt.diy/app/styles/components/code.scss +9 -0
- tools/bolt.diy/app/styles/components/editor.scss +135 -0
- tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
- tools/bolt.diy/app/styles/components/terminal.scss +3 -0
- tools/bolt.diy/app/styles/components/toast.scss +23 -0
- tools/bolt.diy/app/styles/diff-view.css +72 -0
- tools/bolt.diy/app/styles/index.scss +73 -0
- tools/bolt.diy/app/styles/variables.scss +255 -0
- tools/bolt.diy/app/styles/z-index.scss +37 -0
- tools/bolt.diy/app/types/GitHub.ts +182 -0
- tools/bolt.diy/app/types/GitLab.ts +103 -0
- tools/bolt.diy/app/types/actions.ts +85 -0
- tools/bolt.diy/app/types/artifact.ts +5 -0
- tools/bolt.diy/app/types/context.ts +26 -0
- tools/bolt.diy/app/types/design-scheme.ts +93 -0
- tools/bolt.diy/app/types/global.d.ts +13 -0
- tools/bolt.diy/app/types/mandate.ts +333 -0
- tools/bolt.diy/app/types/model.ts +25 -0
- tools/bolt.diy/app/types/netlify.ts +94 -0
- tools/bolt.diy/app/types/supabase.ts +54 -0
- tools/bolt.diy/app/types/template.ts +8 -0
- tools/bolt.diy/app/types/terminal.ts +9 -0
- tools/bolt.diy/app/types/theme.ts +1 -0
- tools/bolt.diy/app/types/vercel.ts +67 -0
- tools/bolt.diy/app/utils/buffer.ts +29 -0
- tools/bolt.diy/app/utils/classNames.ts +65 -0
- tools/bolt.diy/app/utils/constants.ts +147 -0
- tools/bolt.diy/app/utils/debounce.ts +13 -0
- tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
- tools/bolt.diy/app/utils/diff.spec.ts +11 -0
- tools/bolt.diy/app/utils/diff.ts +117 -0
- tools/bolt.diy/app/utils/easings.ts +3 -0
- tools/bolt.diy/app/utils/fileLocks.ts +96 -0
- tools/bolt.diy/app/utils/fileUtils.ts +121 -0
- tools/bolt.diy/app/utils/folderImport.ts +73 -0
- tools/bolt.diy/app/utils/formatSize.ts +12 -0
- tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
- tools/bolt.diy/app/utils/githubStats.ts +9 -0
- tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
- tools/bolt.diy/app/utils/logger.ts +162 -0
- tools/bolt.diy/app/utils/markdown.ts +155 -0
- tools/bolt.diy/app/utils/mobile.ts +4 -0
- tools/bolt.diy/app/utils/os.ts +4 -0
- tools/bolt.diy/app/utils/path.ts +19 -0
- tools/bolt.diy/app/utils/projectCommands.ts +197 -0
- tools/bolt.diy/app/utils/promises.ts +19 -0
- tools/bolt.diy/app/utils/react.ts +6 -0
- tools/bolt.diy/app/utils/sampler.ts +49 -0
- tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
- tools/bolt.diy/app/utils/shell.ts +384 -0
- tools/bolt.diy/app/utils/stacktrace.ts +27 -0
- tools/bolt.diy/app/utils/stripIndent.ts +23 -0
- tools/bolt.diy/app/utils/terminal.ts +11 -0
- tools/bolt.diy/app/utils/unreachable.ts +3 -0
- tools/bolt.diy/app/vite-env.d.ts +2 -0
- tools/bolt.diy/assets/entitlements.mac.plist +25 -0
- tools/bolt.diy/assets/icons/icon.icns +0 -0
- tools/bolt.diy/assets/icons/icon.ico +0 -0
- tools/bolt.diy/assets/icons/icon.png +0 -0
- tools/bolt.diy/bindings.js +78 -0
- tools/bolt.diy/bindings.sh +33 -0
- tools/bolt.diy/docker-compose.yaml +145 -0
- tools/bolt.diy/electron/main/index.ts +201 -0
- tools/bolt.diy/electron/main/tsconfig.json +30 -0
- tools/bolt.diy/electron/main/ui/menu.ts +29 -0
- tools/bolt.diy/electron/main/ui/window.ts +54 -0
- tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
- tools/bolt.diy/electron/main/utils/constants.ts +4 -0
- tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
- tools/bolt.diy/electron/main/utils/reload.ts +35 -0
- tools/bolt.diy/electron/main/utils/serve.ts +71 -0
- tools/bolt.diy/electron/main/utils/store.ts +3 -0
- tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
- tools/bolt.diy/electron/main/vite.config.ts +44 -0
- tools/bolt.diy/electron/preload/index.ts +22 -0
- tools/bolt.diy/electron/preload/tsconfig.json +7 -0
- tools/bolt.diy/electron/preload/vite.config.ts +31 -0
- tools/bolt.diy/electron-builder.yml +64 -0
- tools/bolt.diy/electron-update.yml +4 -0
- tools/bolt.diy/eslint.config.mjs +57 -0
- tools/bolt.diy/functions/[[path]].ts +12 -0
- tools/bolt.diy/icons/angular.svg +1 -0
- tools/bolt.diy/icons/astro.svg +8 -0
- tools/bolt.diy/icons/chat.svg +1 -0
- tools/bolt.diy/icons/expo-brand.svg +1 -0
- tools/bolt.diy/icons/expo.svg +4 -0
- tools/bolt.diy/icons/logo-text.svg +1 -0
- tools/bolt.diy/icons/logo.svg +4 -0
- tools/bolt.diy/icons/mcp.svg +1 -0
- tools/bolt.diy/icons/nativescript.svg +1 -0
- tools/bolt.diy/icons/netlify.svg +10 -0
- tools/bolt.diy/icons/nextjs.svg +1 -0
- tools/bolt.diy/icons/nuxt.svg +1 -0
- tools/bolt.diy/icons/qwik.svg +1 -0
- tools/bolt.diy/icons/react.svg +1 -0
- tools/bolt.diy/icons/remix.svg +24 -0
- tools/bolt.diy/icons/remotion.svg +1 -0
- tools/bolt.diy/icons/shadcn.svg +21 -0
- tools/bolt.diy/icons/slidev.svg +60 -0
- tools/bolt.diy/icons/solidjs.svg +1 -0
- tools/bolt.diy/icons/stars.svg +1 -0
- tools/bolt.diy/icons/svelte.svg +1 -0
- tools/bolt.diy/icons/typescript.svg +1 -0
- tools/bolt.diy/icons/vite.svg +1 -0
- tools/bolt.diy/icons/vue.svg +1 -0
- tools/bolt.diy/load-context.ts +9 -0
- tools/bolt.diy/notarize.cjs +31 -0
- tools/bolt.diy/package.json +218 -0
- tools/bolt.diy/playwright.config.preview.ts +35 -0
- tools/bolt.diy/pre-start.cjs +26 -0
- tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
- tools/bolt.diy/public/apple-touch-icon.png +0 -0
- tools/bolt.diy/public/favicon.ico +0 -0
- tools/bolt.diy/public/favicon.svg +4 -0
- tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
- tools/bolt.diy/public/icons/Anthropic.svg +4 -0
- tools/bolt.diy/public/icons/Cohere.svg +4 -0
- tools/bolt.diy/public/icons/Deepseek.svg +5 -0
- tools/bolt.diy/public/icons/Default.svg +4 -0
- tools/bolt.diy/public/icons/Google.svg +4 -0
- tools/bolt.diy/public/icons/Groq.svg +4 -0
- tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
- tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
- tools/bolt.diy/public/icons/LMStudio.svg +5 -0
- tools/bolt.diy/public/icons/Mistral.svg +4 -0
- tools/bolt.diy/public/icons/Ollama.svg +4 -0
- tools/bolt.diy/public/icons/OpenAI.svg +4 -0
- tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
- tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
- tools/bolt.diy/public/icons/Perplexity.svg +4 -0
- tools/bolt.diy/public/icons/Together.svg +4 -0
- tools/bolt.diy/public/icons/xAI.svg +5 -0
- tools/bolt.diy/public/inspector-script.js +292 -0
- tools/bolt.diy/public/logo-dark-styled.png +0 -0
- tools/bolt.diy/public/logo-dark.png +0 -0
- tools/bolt.diy/public/logo-light-styled.png +0 -0
- tools/bolt.diy/public/logo-light.png +0 -0
- tools/bolt.diy/public/logo.svg +15 -0
- tools/bolt.diy/public/social_preview_index.jpg +0 -0
- tools/bolt.diy/scripts/clean.js +45 -0
- tools/bolt.diy/scripts/electron-dev.mjs +181 -0
- tools/bolt.diy/scripts/setup-env.sh +41 -0
- tools/bolt.diy/scripts/update-imports.sh +7 -0
- tools/bolt.diy/scripts/update.sh +52 -0
- tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
- tools/bolt.diy/services/execution-governor/config.ts +42 -0
- tools/bolt.diy/services/execution-governor/index.ts +683 -0
- tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
- tools/bolt.diy/services/execution-governor/package.json +31 -0
- tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
- tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
- tools/bolt.diy/services/execution-governor/types.ts +145 -0
- tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
- tools/bolt.diy/services/headless-executor/executor.ts +210 -0
- tools/bolt.diy/services/headless-executor/index.ts +323 -0
- tools/bolt.diy/services/headless-executor/package.json +27 -0
- tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
- tools/bolt.diy/services/headless-executor/types.ts +38 -0
- tools/bolt.diy/test-workflows.sh +240 -0
- tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
- tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
- tools/bolt.diy/tests/mandates/complex.json +53 -0
- tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
- tools/bolt.diy/tests/mandates/simple.json +35 -0
- tools/bolt.diy/tsconfig.json +37 -0
- tools/bolt.diy/types/istextorbinary.d.ts +15 -0
- tools/bolt.diy/uno.config.ts +279 -0
- tools/bolt.diy/vite-electron.config.ts +76 -0
- tools/bolt.diy/vite.config.ts +112 -0
- tools/bolt.diy/worker-configuration.d.ts +22 -0
- tools/bolt.diy/wrangler.toml +6 -0
- tools/code_generator.py +461 -0
- tools/file_operations.py +465 -0
- tools/mandate_generator.py +337 -0
- tools/mcpClientUtils.py +1216 -0
- tools/sensors.py +285 -0
- utils/Agent_types.py +15 -0
- utils/AnyToStr.py +0 -0
- utils/HHCS.py +277 -0
- utils/__init__.py +30 -0
- utils/agent.py +3627 -0
- utils/aop.py +2948 -0
- utils/canonical.py +143 -0
- utils/conversation.py +1195 -0
- utils/doctrine_versioning +230 -0
- utils/formatter.py +474 -0
- utils/ledger.py +311 -0
- utils/out_types.py +16 -0
- utils/rollback.py +339 -0
- utils/router.py +929 -0
- utils/tui.py +1908 -0
|
@@ -0,0 +1,1089 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import { toast } from 'react-toastify';
|
|
4
|
+
import { useStore } from '@nanostores/react';
|
|
5
|
+
import { classNames } from '~/utils/classNames';
|
|
6
|
+
import { Button } from '~/components/ui/Button';
|
|
7
|
+
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '~/components/ui/Collapsible';
|
|
8
|
+
import {
|
|
9
|
+
supabaseConnection,
|
|
10
|
+
isConnecting,
|
|
11
|
+
isFetchingStats,
|
|
12
|
+
isFetchingApiKeys,
|
|
13
|
+
updateSupabaseConnection,
|
|
14
|
+
fetchSupabaseStats,
|
|
15
|
+
fetchProjectApiKeys,
|
|
16
|
+
initializeSupabaseConnection,
|
|
17
|
+
type SupabaseProject,
|
|
18
|
+
} from '~/lib/stores/supabase';
|
|
19
|
+
|
|
20
|
+
interface ConnectionTestResult {
|
|
21
|
+
status: 'success' | 'error' | 'testing';
|
|
22
|
+
message: string;
|
|
23
|
+
timestamp?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ProjectAction {
|
|
27
|
+
name: string;
|
|
28
|
+
icon: string;
|
|
29
|
+
action: (projectId: string) => Promise<void>;
|
|
30
|
+
requiresConfirmation?: boolean;
|
|
31
|
+
variant?: 'default' | 'destructive' | 'outline';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Supabase logo SVG component
|
|
35
|
+
const SupabaseLogo = () => (
|
|
36
|
+
<svg viewBox="0 0 109 113" className="w-5 h-5">
|
|
37
|
+
<path
|
|
38
|
+
fill="currentColor"
|
|
39
|
+
d="M63.7076 110.284C60.8481 113.885 55.0502 111.912 54.9813 107.314L53.9738 40.0627L99.1935 40.0627C107.384 40.0627 111.952 49.5228 106.859 55.9374L63.7076 110.284Z"
|
|
40
|
+
/>
|
|
41
|
+
<path
|
|
42
|
+
fillOpacity="0.2"
|
|
43
|
+
fill="currentColor"
|
|
44
|
+
d="M63.7076 110.284C60.8481 113.885 55.0502 111.912 54.9813 107.314L53.9738 40.0627L99.1935 40.0627C107.384 40.0627 111.952 49.5228 106.859 55.9374L63.7076 110.284Z"
|
|
45
|
+
/>
|
|
46
|
+
<path
|
|
47
|
+
fill="currentColor"
|
|
48
|
+
d="M45.317 2.07103C48.1765 -1.53037 53.9745 0.442937 54.0434 5.041L54.4849 72.2922H9.83113C1.64038 72.2922 -2.92775 62.8321 2.1655 56.4175L45.317 2.07103Z"
|
|
49
|
+
/>
|
|
50
|
+
</svg>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export default function SupabaseTab() {
|
|
54
|
+
const connection = useStore(supabaseConnection);
|
|
55
|
+
const connecting = useStore(isConnecting);
|
|
56
|
+
const fetchingStats = useStore(isFetchingStats);
|
|
57
|
+
const fetchingApiKeys = useStore(isFetchingApiKeys);
|
|
58
|
+
|
|
59
|
+
const [tokenInput, setTokenInput] = useState('');
|
|
60
|
+
const [isProjectsExpanded, setIsProjectsExpanded] = useState(false);
|
|
61
|
+
const [connectionTest, setConnectionTest] = useState<ConnectionTestResult | null>(null);
|
|
62
|
+
const [isProjectActionLoading, setIsProjectActionLoading] = useState(false);
|
|
63
|
+
const [selectedProjectId, setSelectedProjectId] = useState<string>('');
|
|
64
|
+
|
|
65
|
+
// Connection testing function - uses server-side API to test environment token
|
|
66
|
+
const testConnection = async () => {
|
|
67
|
+
setConnectionTest({
|
|
68
|
+
status: 'testing',
|
|
69
|
+
message: 'Testing connection...',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch('/api/supabase-user', {
|
|
74
|
+
method: 'GET',
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (response.ok) {
|
|
81
|
+
const data = (await response.json()) as any;
|
|
82
|
+
setConnectionTest({
|
|
83
|
+
status: 'success',
|
|
84
|
+
message: `Connected successfully using environment token. Found ${data.projects?.length || 0} projects`,
|
|
85
|
+
timestamp: Date.now(),
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
const errorData = (await response.json().catch(() => ({}))) as { error?: string };
|
|
89
|
+
setConnectionTest({
|
|
90
|
+
status: 'error',
|
|
91
|
+
message: `Connection failed: ${errorData.error || `${response.status} ${response.statusText}`}`,
|
|
92
|
+
timestamp: Date.now(),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
setConnectionTest({
|
|
97
|
+
status: 'error',
|
|
98
|
+
message: `Connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
99
|
+
timestamp: Date.now(),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Project actions
|
|
105
|
+
const projectActions: ProjectAction[] = [
|
|
106
|
+
{
|
|
107
|
+
name: 'Get API Keys',
|
|
108
|
+
icon: 'i-ph:key',
|
|
109
|
+
action: async (projectId: string) => {
|
|
110
|
+
try {
|
|
111
|
+
await fetchProjectApiKeys(projectId, connection.token);
|
|
112
|
+
toast.success('API keys fetched successfully');
|
|
113
|
+
} catch (err: unknown) {
|
|
114
|
+
const error = err instanceof Error ? err.message : 'Unknown error';
|
|
115
|
+
toast.error(`Failed to fetch API keys: ${error}`);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'View Dashboard',
|
|
121
|
+
icon: 'i-ph:layout',
|
|
122
|
+
action: async (projectId: string) => {
|
|
123
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}`, '_blank');
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'View Database',
|
|
128
|
+
icon: 'i-ph:database',
|
|
129
|
+
action: async (projectId: string) => {
|
|
130
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/editor`, '_blank');
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'View Auth',
|
|
135
|
+
icon: 'i-ph:user-circle',
|
|
136
|
+
action: async (projectId: string) => {
|
|
137
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/auth/users`, '_blank');
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: 'View Storage',
|
|
142
|
+
icon: 'i-ph:folder',
|
|
143
|
+
action: async (projectId: string) => {
|
|
144
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/storage/buckets`, '_blank');
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'View Functions',
|
|
149
|
+
icon: 'i-ph:code',
|
|
150
|
+
action: async (projectId: string) => {
|
|
151
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/functions`, '_blank');
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'View Logs',
|
|
156
|
+
icon: 'i-ph:scroll',
|
|
157
|
+
action: async (projectId: string) => {
|
|
158
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/logs`, '_blank');
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'View Settings',
|
|
163
|
+
icon: 'i-ph:gear',
|
|
164
|
+
action: async (projectId: string) => {
|
|
165
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/settings`, '_blank');
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: 'View API Docs',
|
|
170
|
+
icon: 'i-ph:book',
|
|
171
|
+
action: async (projectId: string) => {
|
|
172
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/api`, '_blank');
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'View Realtime',
|
|
177
|
+
icon: 'i-ph:radio',
|
|
178
|
+
action: async (projectId: string) => {
|
|
179
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/realtime`, '_blank');
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'View Edge Functions',
|
|
184
|
+
icon: 'i-ph:terminal',
|
|
185
|
+
action: async (projectId: string) => {
|
|
186
|
+
window.open(`https://supabase.com/dashboard/project/${projectId}/functions`, '_blank');
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
// Initialize connection on component mount - check server-side token first
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
const initializeConnection = async () => {
|
|
194
|
+
try {
|
|
195
|
+
// First try to initialize using server-side token
|
|
196
|
+
await initializeSupabaseConnection();
|
|
197
|
+
|
|
198
|
+
// If no connection was established, the user will need to manually enter a token
|
|
199
|
+
const currentState = supabaseConnection.get();
|
|
200
|
+
|
|
201
|
+
if (!currentState.user) {
|
|
202
|
+
console.log('No server-side Supabase token available, manual connection required');
|
|
203
|
+
}
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('Failed to initialize Supabase connection:', error);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
initializeConnection();
|
|
209
|
+
}, []);
|
|
210
|
+
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
const fetchProjects = async () => {
|
|
213
|
+
if (connection.user && connection.token && !connection.stats) {
|
|
214
|
+
await fetchSupabaseStats(connection.token);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
fetchProjects();
|
|
218
|
+
}, [connection.user, connection.token]);
|
|
219
|
+
|
|
220
|
+
const handleConnect = async () => {
|
|
221
|
+
if (!tokenInput) {
|
|
222
|
+
toast.error('Please enter a Supabase access token');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
isConnecting.set(true);
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
await fetchSupabaseStats(tokenInput);
|
|
230
|
+
updateSupabaseConnection({
|
|
231
|
+
token: tokenInput,
|
|
232
|
+
isConnected: true,
|
|
233
|
+
});
|
|
234
|
+
toast.success('Successfully connected to Supabase');
|
|
235
|
+
setTokenInput('');
|
|
236
|
+
} catch (error) {
|
|
237
|
+
console.error('Auth error:', error);
|
|
238
|
+
toast.error('Failed to connect to Supabase');
|
|
239
|
+
updateSupabaseConnection({ user: null, token: '' });
|
|
240
|
+
} finally {
|
|
241
|
+
isConnecting.set(false);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const handleDisconnect = () => {
|
|
246
|
+
updateSupabaseConnection({
|
|
247
|
+
user: null,
|
|
248
|
+
token: '',
|
|
249
|
+
stats: undefined,
|
|
250
|
+
selectedProjectId: undefined,
|
|
251
|
+
isConnected: false,
|
|
252
|
+
project: undefined,
|
|
253
|
+
credentials: undefined,
|
|
254
|
+
});
|
|
255
|
+
setConnectionTest(null);
|
|
256
|
+
setSelectedProjectId('');
|
|
257
|
+
toast.success('Disconnected from Supabase');
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const handleProjectAction = async (projectId: string, action: ProjectAction) => {
|
|
261
|
+
if (action.requiresConfirmation) {
|
|
262
|
+
if (!confirm(`Are you sure you want to ${action.name.toLowerCase()}?`)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
setIsProjectActionLoading(true);
|
|
268
|
+
await action.action(projectId);
|
|
269
|
+
setIsProjectActionLoading(false);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const handleProjectSelect = async (projectId: string) => {
|
|
273
|
+
setSelectedProjectId(projectId);
|
|
274
|
+
updateSupabaseConnection({ selectedProjectId: projectId });
|
|
275
|
+
|
|
276
|
+
if (projectId && connection.token) {
|
|
277
|
+
try {
|
|
278
|
+
await fetchProjectApiKeys(projectId, connection.token);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.error('Failed to fetch API keys:', error);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const renderProjects = () => {
|
|
286
|
+
if (fetchingStats) {
|
|
287
|
+
return (
|
|
288
|
+
<div className="flex items-center gap-2 text-sm text-bolt-elements-textSecondary">
|
|
289
|
+
<div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
|
|
290
|
+
Fetching Supabase projects...
|
|
291
|
+
</div>
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return (
|
|
296
|
+
<Collapsible open={isProjectsExpanded} onOpenChange={setIsProjectsExpanded}>
|
|
297
|
+
<CollapsibleTrigger asChild>
|
|
298
|
+
<div className="flex items-center justify-between p-4 rounded-lg bg-bolt-elements-background dark:bg-bolt-elements-background-depth-2 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor hover:border-bolt-elements-borderColorActive/70 dark:hover:border-bolt-elements-borderColorActive/70 transition-all duration-200 cursor-pointer">
|
|
299
|
+
<div className="flex items-center gap-2">
|
|
300
|
+
<div className="i-ph:database w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
301
|
+
<span className="text-sm font-medium text-bolt-elements-textPrimary">
|
|
302
|
+
Your Projects ({connection.stats?.totalProjects || 0})
|
|
303
|
+
</span>
|
|
304
|
+
</div>
|
|
305
|
+
<div
|
|
306
|
+
className={classNames(
|
|
307
|
+
'i-ph:caret-down w-4 h-4 transform transition-transform duration-200 text-bolt-elements-textSecondary',
|
|
308
|
+
isProjectsExpanded ? 'rotate-180' : '',
|
|
309
|
+
)}
|
|
310
|
+
/>
|
|
311
|
+
</div>
|
|
312
|
+
</CollapsibleTrigger>
|
|
313
|
+
<CollapsibleContent className="overflow-hidden">
|
|
314
|
+
<div className="space-y-4 mt-4">
|
|
315
|
+
{/* Supabase Overview Dashboard */}
|
|
316
|
+
{connection.stats?.projects?.length ? (
|
|
317
|
+
<div className="mb-6 p-4 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
|
|
318
|
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Supabase Overview</h4>
|
|
319
|
+
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
320
|
+
<div className="text-center">
|
|
321
|
+
<div className="text-2xl font-bold text-bolt-elements-textPrimary">
|
|
322
|
+
{connection.stats.totalProjects}
|
|
323
|
+
</div>
|
|
324
|
+
<div className="text-xs text-bolt-elements-textSecondary">Total Projects</div>
|
|
325
|
+
</div>
|
|
326
|
+
<div className="text-center">
|
|
327
|
+
<div className="text-2xl font-bold text-bolt-elements-textPrimary">
|
|
328
|
+
{connection.stats.projects.filter((p: SupabaseProject) => p.status === 'ACTIVE_HEALTHY').length}
|
|
329
|
+
</div>
|
|
330
|
+
<div className="text-xs text-bolt-elements-textSecondary">Active Projects</div>
|
|
331
|
+
</div>
|
|
332
|
+
<div className="text-center">
|
|
333
|
+
<div className="text-2xl font-bold text-bolt-elements-textPrimary">
|
|
334
|
+
{new Set(connection.stats.projects.map((p: SupabaseProject) => p.region)).size}
|
|
335
|
+
</div>
|
|
336
|
+
<div className="text-xs text-bolt-elements-textSecondary">Regions Used</div>
|
|
337
|
+
</div>
|
|
338
|
+
<div className="text-center">
|
|
339
|
+
<div className="text-2xl font-bold text-bolt-elements-textPrimary">
|
|
340
|
+
{connection.stats.projects.filter((p: SupabaseProject) => p.status !== 'ACTIVE_HEALTHY').length}
|
|
341
|
+
</div>
|
|
342
|
+
<div className="text-xs text-bolt-elements-textSecondary">Inactive Projects</div>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
) : null}
|
|
347
|
+
|
|
348
|
+
{connection.stats?.projects?.length ? (
|
|
349
|
+
<div className="grid gap-3">
|
|
350
|
+
{connection.stats.projects.map((project: SupabaseProject) => (
|
|
351
|
+
<div
|
|
352
|
+
key={project.id}
|
|
353
|
+
className={classNames(
|
|
354
|
+
'p-4 rounded-lg border transition-colors bg-bolt-elements-background-depth-1 cursor-pointer',
|
|
355
|
+
selectedProjectId === project.id
|
|
356
|
+
? 'border-bolt-elements-item-contentAccent bg-bolt-elements-item-backgroundActive/10'
|
|
357
|
+
: 'border-bolt-elements-borderColor hover:border-bolt-elements-borderColorActive/70',
|
|
358
|
+
)}
|
|
359
|
+
onClick={() => handleProjectSelect(project.id)}
|
|
360
|
+
>
|
|
361
|
+
<div className="flex items-center justify-between">
|
|
362
|
+
<div className="flex-1">
|
|
363
|
+
<h5 className="text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2">
|
|
364
|
+
<div className="i-ph:database w-4 h-4 text-bolt-elements-borderColorActive" />
|
|
365
|
+
{project.name}
|
|
366
|
+
</h5>
|
|
367
|
+
<div className="flex items-center gap-2 mt-2 text-xs text-bolt-elements-textSecondary">
|
|
368
|
+
<span className="flex items-center gap-1">
|
|
369
|
+
<div className="i-ph:globe w-3 h-3" />
|
|
370
|
+
{project.region}
|
|
371
|
+
</span>
|
|
372
|
+
<span>•</span>
|
|
373
|
+
<span className="flex items-center gap-1">
|
|
374
|
+
<div className="i-ph:clock w-3 h-3" />
|
|
375
|
+
{new Date(project.created_at).toLocaleDateString()}
|
|
376
|
+
</span>
|
|
377
|
+
<span>•</span>
|
|
378
|
+
<span
|
|
379
|
+
className={classNames(
|
|
380
|
+
'flex items-center gap-1 px-2 py-0.5 rounded-full text-xs',
|
|
381
|
+
project.status === 'ACTIVE_HEALTHY'
|
|
382
|
+
? 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400'
|
|
383
|
+
: project.status === 'SUSPENDED'
|
|
384
|
+
? 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400'
|
|
385
|
+
: project.status === 'INACTIVE'
|
|
386
|
+
? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400'
|
|
387
|
+
: 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400',
|
|
388
|
+
)}
|
|
389
|
+
>
|
|
390
|
+
<div
|
|
391
|
+
className={classNames(
|
|
392
|
+
'w-2 h-2 rounded-full',
|
|
393
|
+
project.status === 'ACTIVE_HEALTHY'
|
|
394
|
+
? 'bg-green-500'
|
|
395
|
+
: project.status === 'SUSPENDED'
|
|
396
|
+
? 'bg-red-500'
|
|
397
|
+
: project.status === 'INACTIVE'
|
|
398
|
+
? 'bg-yellow-500'
|
|
399
|
+
: 'bg-gray-500',
|
|
400
|
+
)}
|
|
401
|
+
/>
|
|
402
|
+
{project.status.replace('_', ' ')}
|
|
403
|
+
</span>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
406
|
+
{/* Project Details Grid */}
|
|
407
|
+
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mt-3 pt-3 border-t border-bolt-elements-borderColor">
|
|
408
|
+
<div className="text-center">
|
|
409
|
+
<div className="text-sm font-semibold text-bolt-elements-textPrimary">
|
|
410
|
+
{project.stats?.database?.tables ?? '--'}
|
|
411
|
+
</div>
|
|
412
|
+
<div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
|
|
413
|
+
<div className="i-ph:table w-3 h-3" />
|
|
414
|
+
Tables
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
<div className="text-center">
|
|
418
|
+
<div className="text-sm font-semibold text-bolt-elements-textPrimary">
|
|
419
|
+
{project.stats?.storage?.buckets ?? '--'}
|
|
420
|
+
</div>
|
|
421
|
+
<div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
|
|
422
|
+
<div className="i-ph:folder w-3 h-3" />
|
|
423
|
+
Buckets
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
<div className="text-center">
|
|
427
|
+
<div className="text-sm font-semibold text-bolt-elements-textPrimary">
|
|
428
|
+
{project.stats?.functions?.deployed ?? '--'}
|
|
429
|
+
</div>
|
|
430
|
+
<div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
|
|
431
|
+
<div className="i-ph:code w-3 h-3" />
|
|
432
|
+
Functions
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
435
|
+
<div className="text-center">
|
|
436
|
+
<div className="text-sm font-semibold text-bolt-elements-textPrimary">
|
|
437
|
+
{project.stats?.database?.size_mb ? `${project.stats.database.size_mb} MB` : '--'}
|
|
438
|
+
</div>
|
|
439
|
+
<div className="text-xs text-bolt-elements-textSecondary flex items-center justify-center gap-1">
|
|
440
|
+
<div className="i-ph:database w-3 h-3" />
|
|
441
|
+
DB Size
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
444
|
+
</div>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
{selectedProjectId === project.id && (
|
|
449
|
+
<div className="space-y-4 mt-4 pt-4 border-t border-bolt-elements-borderColor">
|
|
450
|
+
<div className="flex flex-wrap items-center gap-1">
|
|
451
|
+
{projectActions.map((action) => (
|
|
452
|
+
<Button
|
|
453
|
+
key={action.name}
|
|
454
|
+
variant={action.variant || 'outline'}
|
|
455
|
+
size="sm"
|
|
456
|
+
onClick={(e) => {
|
|
457
|
+
e.stopPropagation();
|
|
458
|
+
handleProjectAction(project.id, action);
|
|
459
|
+
}}
|
|
460
|
+
disabled={isProjectActionLoading || (action.name === 'Get API Keys' && fetchingApiKeys)}
|
|
461
|
+
className="flex items-center gap-1 text-xs px-2 py-1 text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary"
|
|
462
|
+
>
|
|
463
|
+
<div className={`${action.icon} w-2.5 h-2.5`} />
|
|
464
|
+
{action.name === 'Get API Keys' && fetchingApiKeys ? 'Fetching...' : action.name}
|
|
465
|
+
</Button>
|
|
466
|
+
))}
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
{/* Project Details */}
|
|
470
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
471
|
+
<div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg space-y-2">
|
|
472
|
+
<h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2">
|
|
473
|
+
<div className="i-ph:database w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
474
|
+
Database Schema
|
|
475
|
+
</h6>
|
|
476
|
+
<div className="space-y-1 text-xs text-bolt-elements-textSecondary">
|
|
477
|
+
<div className="flex justify-between">
|
|
478
|
+
<span>Tables:</span>
|
|
479
|
+
<span>{project.stats?.database?.tables ?? '--'}</span>
|
|
480
|
+
</div>
|
|
481
|
+
<div className="flex justify-between">
|
|
482
|
+
<span>Views:</span>
|
|
483
|
+
<span>{project.stats?.database?.views ?? '--'}</span>
|
|
484
|
+
</div>
|
|
485
|
+
<div className="flex justify-between">
|
|
486
|
+
<span>Functions:</span>
|
|
487
|
+
<span>{project.stats?.database?.functions ?? '--'}</span>
|
|
488
|
+
</div>
|
|
489
|
+
<div className="flex justify-between">
|
|
490
|
+
<span>Size:</span>
|
|
491
|
+
<span>
|
|
492
|
+
{project.stats?.database?.size_mb ? `${project.stats.database.size_mb} MB` : '--'}
|
|
493
|
+
</span>
|
|
494
|
+
</div>
|
|
495
|
+
</div>
|
|
496
|
+
</div>
|
|
497
|
+
|
|
498
|
+
<div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg space-y-2">
|
|
499
|
+
<h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2">
|
|
500
|
+
<div className="i-ph:folder w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
501
|
+
Storage
|
|
502
|
+
</h6>
|
|
503
|
+
<div className="space-y-1 text-xs text-bolt-elements-textSecondary">
|
|
504
|
+
<div className="flex justify-between">
|
|
505
|
+
<span>Buckets:</span>
|
|
506
|
+
<span>{project.stats?.storage?.buckets ?? '--'}</span>
|
|
507
|
+
</div>
|
|
508
|
+
<div className="flex justify-between">
|
|
509
|
+
<span>Files:</span>
|
|
510
|
+
<span>{project.stats?.storage?.files ?? '--'}</span>
|
|
511
|
+
</div>
|
|
512
|
+
<div className="flex justify-between">
|
|
513
|
+
<span>Used:</span>
|
|
514
|
+
<span>
|
|
515
|
+
{project.stats?.storage?.used_gb ? `${project.stats.storage.used_gb} GB` : '--'}
|
|
516
|
+
</span>
|
|
517
|
+
</div>
|
|
518
|
+
<div className="flex justify-between">
|
|
519
|
+
<span>Available:</span>
|
|
520
|
+
<span>
|
|
521
|
+
{project.stats?.storage?.available_gb
|
|
522
|
+
? `${project.stats.storage.available_gb} GB`
|
|
523
|
+
: '--'}
|
|
524
|
+
</span>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
529
|
+
|
|
530
|
+
{connection.credentials && (
|
|
531
|
+
<div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg space-y-2">
|
|
532
|
+
<h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2">
|
|
533
|
+
<div className="i-ph:key w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
534
|
+
Project Credentials
|
|
535
|
+
</h6>
|
|
536
|
+
<div className="space-y-2">
|
|
537
|
+
<div>
|
|
538
|
+
<label className="text-xs text-bolt-elements-textSecondary">Supabase URL:</label>
|
|
539
|
+
<div className="flex items-center gap-2 mt-1">
|
|
540
|
+
<input
|
|
541
|
+
type="text"
|
|
542
|
+
value={connection.credentials.supabaseUrl || ''}
|
|
543
|
+
readOnly
|
|
544
|
+
className="flex-1 px-2 py-1 text-xs bg-bolt-elements-background border border-bolt-elements-borderColor rounded"
|
|
545
|
+
/>
|
|
546
|
+
<Button
|
|
547
|
+
size="icon"
|
|
548
|
+
variant="outline"
|
|
549
|
+
onClick={(e) => {
|
|
550
|
+
e.stopPropagation();
|
|
551
|
+
|
|
552
|
+
if (connection.credentials?.supabaseUrl) {
|
|
553
|
+
navigator.clipboard.writeText(connection.credentials.supabaseUrl);
|
|
554
|
+
toast.success('URL copied to clipboard');
|
|
555
|
+
}
|
|
556
|
+
}}
|
|
557
|
+
className="w-8 h-8"
|
|
558
|
+
>
|
|
559
|
+
<div className="i-ph:copy w-3 h-3" />
|
|
560
|
+
</Button>
|
|
561
|
+
</div>
|
|
562
|
+
</div>
|
|
563
|
+
<div>
|
|
564
|
+
<label className="text-xs text-bolt-elements-textSecondary">Anon Key:</label>
|
|
565
|
+
<div className="flex items-center gap-2 mt-1">
|
|
566
|
+
<input
|
|
567
|
+
type="password"
|
|
568
|
+
value={connection.credentials.anonKey || ''}
|
|
569
|
+
readOnly
|
|
570
|
+
className="flex-1 px-2 py-1 text-xs bg-bolt-elements-background border border-bolt-elements-borderColor rounded"
|
|
571
|
+
/>
|
|
572
|
+
<Button
|
|
573
|
+
size="icon"
|
|
574
|
+
variant="outline"
|
|
575
|
+
onClick={(e) => {
|
|
576
|
+
e.stopPropagation();
|
|
577
|
+
|
|
578
|
+
if (connection.credentials?.anonKey) {
|
|
579
|
+
navigator.clipboard.writeText(connection.credentials.anonKey);
|
|
580
|
+
toast.success('Key copied to clipboard');
|
|
581
|
+
}
|
|
582
|
+
}}
|
|
583
|
+
className="w-8 h-8"
|
|
584
|
+
>
|
|
585
|
+
<div className="i-ph:copy w-3 h-3" />
|
|
586
|
+
</Button>
|
|
587
|
+
</div>
|
|
588
|
+
</div>
|
|
589
|
+
</div>
|
|
590
|
+
</div>
|
|
591
|
+
)}
|
|
592
|
+
</div>
|
|
593
|
+
)}
|
|
594
|
+
</div>
|
|
595
|
+
))}
|
|
596
|
+
</div>
|
|
597
|
+
) : (
|
|
598
|
+
<div className="text-sm text-bolt-elements-textSecondary flex items-center gap-2 p-4">
|
|
599
|
+
<div className="i-ph:info w-4 h-4" />
|
|
600
|
+
No projects found in your Supabase account
|
|
601
|
+
</div>
|
|
602
|
+
)}
|
|
603
|
+
</div>
|
|
604
|
+
</CollapsibleContent>
|
|
605
|
+
</Collapsible>
|
|
606
|
+
);
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
return (
|
|
610
|
+
<div className="space-y-6">
|
|
611
|
+
{/* Header */}
|
|
612
|
+
<motion.div
|
|
613
|
+
className="flex items-center justify-between gap-2"
|
|
614
|
+
initial={{ opacity: 0, y: 20 }}
|
|
615
|
+
animate={{ opacity: 1, y: 0 }}
|
|
616
|
+
transition={{ delay: 0.1 }}
|
|
617
|
+
>
|
|
618
|
+
<div className="flex items-center gap-2">
|
|
619
|
+
<div className="text-[#3ECF8E]">
|
|
620
|
+
<SupabaseLogo />
|
|
621
|
+
</div>
|
|
622
|
+
<h2 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
|
|
623
|
+
Supabase Integration
|
|
624
|
+
</h2>
|
|
625
|
+
</div>
|
|
626
|
+
<div className="flex items-center gap-2">
|
|
627
|
+
{connection.user && (
|
|
628
|
+
<Button
|
|
629
|
+
onClick={testConnection}
|
|
630
|
+
disabled={connectionTest?.status === 'testing'}
|
|
631
|
+
variant="outline"
|
|
632
|
+
size="sm"
|
|
633
|
+
className="flex items-center gap-2 hover:bg-bolt-elements-item-backgroundActive/10 hover:text-bolt-elements-textPrimary dark:hover:bg-bolt-elements-item-backgroundActive/10 dark:hover:text-bolt-elements-textPrimary transition-colors"
|
|
634
|
+
>
|
|
635
|
+
{connectionTest?.status === 'testing' ? (
|
|
636
|
+
<>
|
|
637
|
+
<div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
|
|
638
|
+
Testing...
|
|
639
|
+
</>
|
|
640
|
+
) : (
|
|
641
|
+
<>
|
|
642
|
+
<div className="i-ph:plug-charging w-4 h-4" />
|
|
643
|
+
Test Connection
|
|
644
|
+
</>
|
|
645
|
+
)}
|
|
646
|
+
</Button>
|
|
647
|
+
)}
|
|
648
|
+
</div>
|
|
649
|
+
</motion.div>
|
|
650
|
+
|
|
651
|
+
<p className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary">
|
|
652
|
+
Connect and manage your Supabase projects with database access, authentication, and storage controls
|
|
653
|
+
</p>
|
|
654
|
+
|
|
655
|
+
{/* Connection Test Results */}
|
|
656
|
+
{connectionTest && (
|
|
657
|
+
<motion.div
|
|
658
|
+
className={classNames('p-4 rounded-lg border', {
|
|
659
|
+
'bg-green-50 border-green-200 dark:bg-green-900/20 dark:border-green-700':
|
|
660
|
+
connectionTest.status === 'success',
|
|
661
|
+
'bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-700': connectionTest.status === 'error',
|
|
662
|
+
'bg-blue-50 border-blue-200 dark:bg-blue-900/20 dark:border-blue-700': connectionTest.status === 'testing',
|
|
663
|
+
})}
|
|
664
|
+
initial={{ opacity: 0, y: 10 }}
|
|
665
|
+
animate={{ opacity: 1, y: 0 }}
|
|
666
|
+
>
|
|
667
|
+
<div className="flex items-center gap-2">
|
|
668
|
+
{connectionTest.status === 'success' && (
|
|
669
|
+
<div className="i-ph:check-circle w-5 h-5 text-green-600 dark:text-green-400" />
|
|
670
|
+
)}
|
|
671
|
+
{connectionTest.status === 'error' && (
|
|
672
|
+
<div className="i-ph:warning-circle w-5 h-5 text-red-600 dark:text-red-400" />
|
|
673
|
+
)}
|
|
674
|
+
{connectionTest.status === 'testing' && (
|
|
675
|
+
<div className="i-ph:spinner-gap w-5 h-5 animate-spin text-blue-600 dark:text-blue-400" />
|
|
676
|
+
)}
|
|
677
|
+
<span
|
|
678
|
+
className={classNames('text-sm font-medium', {
|
|
679
|
+
'text-green-800 dark:text-green-200': connectionTest.status === 'success',
|
|
680
|
+
'text-red-800 dark:text-red-200': connectionTest.status === 'error',
|
|
681
|
+
'text-blue-800 dark:text-blue-200': connectionTest.status === 'testing',
|
|
682
|
+
})}
|
|
683
|
+
>
|
|
684
|
+
{connectionTest.message}
|
|
685
|
+
</span>
|
|
686
|
+
</div>
|
|
687
|
+
{connectionTest.timestamp && (
|
|
688
|
+
<p className="text-xs text-gray-500 mt-1">{new Date(connectionTest.timestamp).toLocaleString()}</p>
|
|
689
|
+
)}
|
|
690
|
+
</motion.div>
|
|
691
|
+
)}
|
|
692
|
+
|
|
693
|
+
{/* Main Connection Component */}
|
|
694
|
+
<motion.div
|
|
695
|
+
className="bg-bolt-elements-background dark:bg-bolt-elements-background border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor rounded-lg"
|
|
696
|
+
initial={{ opacity: 0, y: 20 }}
|
|
697
|
+
animate={{ opacity: 1, y: 0 }}
|
|
698
|
+
transition={{ delay: 0.2 }}
|
|
699
|
+
>
|
|
700
|
+
<div className="p-6 space-y-6">
|
|
701
|
+
{!connection.user ? (
|
|
702
|
+
<div className="space-y-4">
|
|
703
|
+
<div className="text-xs text-bolt-elements-textSecondary bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-1 p-3 rounded-lg mb-4">
|
|
704
|
+
<p className="flex items-center gap-1 mb-1">
|
|
705
|
+
<span className="i-ph:lightbulb w-3.5 h-3.5 text-bolt-elements-icon-success dark:text-bolt-elements-icon-success" />
|
|
706
|
+
<span className="font-medium">Tip:</span> You can also set the{' '}
|
|
707
|
+
<code className="px-1 py-0.5 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 rounded">
|
|
708
|
+
VITE_SUPABASE_ACCESS_TOKEN
|
|
709
|
+
</code>{' '}
|
|
710
|
+
environment variable to connect automatically.
|
|
711
|
+
</p>
|
|
712
|
+
</div>
|
|
713
|
+
|
|
714
|
+
<div>
|
|
715
|
+
<label className="block text-sm text-bolt-elements-textSecondary mb-2">Access Token</label>
|
|
716
|
+
<input
|
|
717
|
+
type="password"
|
|
718
|
+
value={tokenInput}
|
|
719
|
+
onChange={(e) => setTokenInput(e.target.value)}
|
|
720
|
+
disabled={connecting}
|
|
721
|
+
placeholder="Enter your Supabase access token"
|
|
722
|
+
className={classNames(
|
|
723
|
+
'w-full px-3 py-2 rounded-lg text-sm',
|
|
724
|
+
'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
|
|
725
|
+
'border border-[#E5E5E5] dark:border-[#333333]',
|
|
726
|
+
'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary',
|
|
727
|
+
'focus:outline-none focus:ring-1 focus:ring-bolt-elements-borderColorActive',
|
|
728
|
+
'disabled:opacity-50',
|
|
729
|
+
)}
|
|
730
|
+
/>
|
|
731
|
+
<div className="mt-2 text-sm text-bolt-elements-textSecondary">
|
|
732
|
+
<a
|
|
733
|
+
href="https://supabase.com/dashboard/account/tokens"
|
|
734
|
+
target="_blank"
|
|
735
|
+
rel="noopener noreferrer"
|
|
736
|
+
className="text-bolt-elements-borderColorActive hover:underline inline-flex items-center gap-1"
|
|
737
|
+
>
|
|
738
|
+
Get your token
|
|
739
|
+
<div className="i-ph:arrow-square-out w-4 h-4" />
|
|
740
|
+
</a>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
|
|
744
|
+
<button
|
|
745
|
+
onClick={handleConnect}
|
|
746
|
+
disabled={connecting || !tokenInput}
|
|
747
|
+
className={classNames(
|
|
748
|
+
'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
|
|
749
|
+
'bg-[#303030] text-white',
|
|
750
|
+
'hover:bg-[#5E41D0] hover:text-white',
|
|
751
|
+
'disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200',
|
|
752
|
+
'transform active:scale-95',
|
|
753
|
+
)}
|
|
754
|
+
>
|
|
755
|
+
{connecting ? (
|
|
756
|
+
<>
|
|
757
|
+
<div className="i-ph:spinner-gap animate-spin" />
|
|
758
|
+
Connecting...
|
|
759
|
+
</>
|
|
760
|
+
) : (
|
|
761
|
+
<>
|
|
762
|
+
<div className="i-ph:plug-charging w-4 h-4" />
|
|
763
|
+
Connect
|
|
764
|
+
</>
|
|
765
|
+
)}
|
|
766
|
+
</button>
|
|
767
|
+
</div>
|
|
768
|
+
) : (
|
|
769
|
+
<div className="space-y-6">
|
|
770
|
+
<div className="flex items-center justify-between">
|
|
771
|
+
<div className="flex items-center gap-3">
|
|
772
|
+
<button
|
|
773
|
+
onClick={handleDisconnect}
|
|
774
|
+
className={classNames(
|
|
775
|
+
'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
|
|
776
|
+
'bg-red-500 text-white',
|
|
777
|
+
'hover:bg-red-600',
|
|
778
|
+
)}
|
|
779
|
+
>
|
|
780
|
+
<div className="i-ph:plug w-4 h-4" />
|
|
781
|
+
Disconnect
|
|
782
|
+
</button>
|
|
783
|
+
<span className="text-sm text-bolt-elements-textSecondary flex items-center gap-1">
|
|
784
|
+
<div className="i-ph:check-circle w-4 h-4 text-green-500" />
|
|
785
|
+
Connected to Supabase
|
|
786
|
+
</span>
|
|
787
|
+
</div>
|
|
788
|
+
</div>
|
|
789
|
+
|
|
790
|
+
{connection.user && (
|
|
791
|
+
<div className="space-y-4">
|
|
792
|
+
<div className="flex items-center gap-4 p-4 bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-1 rounded-lg">
|
|
793
|
+
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-green-400 to-green-600 flex items-center justify-center">
|
|
794
|
+
<div className="i-ph:user w-6 h-6 text-white" />
|
|
795
|
+
</div>
|
|
796
|
+
<div className="flex-1">
|
|
797
|
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary">{connection.user.email}</h4>
|
|
798
|
+
<p className="text-sm text-bolt-elements-textSecondary">
|
|
799
|
+
{connection.user.role} • Member since{' '}
|
|
800
|
+
{new Date(connection.user.created_at).toLocaleDateString()}
|
|
801
|
+
</p>
|
|
802
|
+
<div className="flex items-center gap-4 mt-2 text-xs text-bolt-elements-textSecondary">
|
|
803
|
+
<span className="flex items-center gap-1">
|
|
804
|
+
<div className="i-ph:buildings w-3 h-3" />
|
|
805
|
+
{connection.stats?.totalProjects || 0} Projects
|
|
806
|
+
</span>
|
|
807
|
+
<span className="flex items-center gap-1">
|
|
808
|
+
<div className="i-ph:globe w-3 h-3" />
|
|
809
|
+
{new Set(connection.stats?.projects?.map((p: SupabaseProject) => p.region) || []).size}{' '}
|
|
810
|
+
Regions
|
|
811
|
+
</span>
|
|
812
|
+
<span className="flex items-center gap-1">
|
|
813
|
+
<div className="i-ph:activity w-3 h-3" />
|
|
814
|
+
{connection.stats?.projects?.filter((p: SupabaseProject) => p.status === 'ACTIVE_HEALTHY')
|
|
815
|
+
.length || 0}{' '}
|
|
816
|
+
Active
|
|
817
|
+
</span>
|
|
818
|
+
</div>
|
|
819
|
+
</div>
|
|
820
|
+
</div>
|
|
821
|
+
|
|
822
|
+
{/* Advanced Analytics */}
|
|
823
|
+
<div className="mb-6 space-y-4">
|
|
824
|
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary">Performance Analytics</h4>
|
|
825
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
826
|
+
<div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
|
|
827
|
+
<h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
|
|
828
|
+
<div className="i-ph:chart-line w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
829
|
+
Database Health
|
|
830
|
+
</h6>
|
|
831
|
+
<div className="space-y-1">
|
|
832
|
+
{(() => {
|
|
833
|
+
const totalProjects = connection.stats?.totalProjects || 0;
|
|
834
|
+
const activeProjects =
|
|
835
|
+
connection.stats?.projects?.filter((p: SupabaseProject) => p.status === 'ACTIVE_HEALTHY')
|
|
836
|
+
.length || 0;
|
|
837
|
+
const healthRate =
|
|
838
|
+
totalProjects > 0 ? Math.round((activeProjects / totalProjects) * 100) : 0;
|
|
839
|
+
const avgTablesPerProject =
|
|
840
|
+
totalProjects > 0
|
|
841
|
+
? Math.round(
|
|
842
|
+
(connection.stats?.projects?.reduce(
|
|
843
|
+
(sum, p) => sum + (p.stats?.database?.tables || 0),
|
|
844
|
+
0,
|
|
845
|
+
) || 0) / totalProjects,
|
|
846
|
+
)
|
|
847
|
+
: 0;
|
|
848
|
+
|
|
849
|
+
return [
|
|
850
|
+
{ label: 'Health Rate', value: `${healthRate}%` },
|
|
851
|
+
{ label: 'Active Projects', value: activeProjects },
|
|
852
|
+
{ label: 'Avg Tables/Project', value: avgTablesPerProject },
|
|
853
|
+
];
|
|
854
|
+
})().map((item, idx) => (
|
|
855
|
+
<div key={idx} className="flex justify-between text-xs">
|
|
856
|
+
<span className="text-bolt-elements-textSecondary">{item.label}:</span>
|
|
857
|
+
<span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
|
|
858
|
+
</div>
|
|
859
|
+
))}
|
|
860
|
+
</div>
|
|
861
|
+
</div>
|
|
862
|
+
|
|
863
|
+
<div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
|
|
864
|
+
<h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
|
|
865
|
+
<div className="i-ph:shield-check w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
866
|
+
Auth & Security
|
|
867
|
+
</h6>
|
|
868
|
+
<div className="space-y-1">
|
|
869
|
+
{(() => {
|
|
870
|
+
const totalProjects = connection.stats?.totalProjects || 0;
|
|
871
|
+
const projectsWithAuth =
|
|
872
|
+
connection.stats?.projects?.filter((p) => p.stats?.auth?.users !== undefined).length || 0;
|
|
873
|
+
const authEnabledRate =
|
|
874
|
+
totalProjects > 0 ? Math.round((projectsWithAuth / totalProjects) * 100) : 0;
|
|
875
|
+
const totalUsers =
|
|
876
|
+
connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.auth?.users || 0), 0) || 0;
|
|
877
|
+
|
|
878
|
+
return [
|
|
879
|
+
{ label: 'Auth Enabled', value: `${authEnabledRate}%` },
|
|
880
|
+
{ label: 'Total Users', value: totalUsers },
|
|
881
|
+
{
|
|
882
|
+
label: 'Avg Users/Project',
|
|
883
|
+
value: totalProjects > 0 ? Math.round(totalUsers / totalProjects) : 0,
|
|
884
|
+
},
|
|
885
|
+
];
|
|
886
|
+
})().map((item, idx) => (
|
|
887
|
+
<div key={idx} className="flex justify-between text-xs">
|
|
888
|
+
<span className="text-bolt-elements-textSecondary">{item.label}:</span>
|
|
889
|
+
<span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
|
|
890
|
+
</div>
|
|
891
|
+
))}
|
|
892
|
+
</div>
|
|
893
|
+
</div>
|
|
894
|
+
|
|
895
|
+
<div className="bg-bolt-elements-background-depth-2 p-3 rounded-lg border border-bolt-elements-borderColor">
|
|
896
|
+
<h6 className="text-xs font-medium text-bolt-elements-textPrimary flex items-center gap-2 mb-2">
|
|
897
|
+
<div className="i-ph:globe w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
898
|
+
Regional Distribution
|
|
899
|
+
</h6>
|
|
900
|
+
<div className="space-y-1">
|
|
901
|
+
{(() => {
|
|
902
|
+
const regions =
|
|
903
|
+
connection.stats?.projects?.reduce(
|
|
904
|
+
(acc, p: SupabaseProject) => {
|
|
905
|
+
acc[p.region] = (acc[p.region] || 0) + 1;
|
|
906
|
+
return acc;
|
|
907
|
+
},
|
|
908
|
+
{} as Record<string, number>,
|
|
909
|
+
) || {};
|
|
910
|
+
|
|
911
|
+
return Object.entries(regions)
|
|
912
|
+
.sort(([, a], [, b]) => b - a)
|
|
913
|
+
.slice(0, 3)
|
|
914
|
+
.map(([region, count]) => ({ label: region.toUpperCase(), value: count }));
|
|
915
|
+
})().map((item, idx) => (
|
|
916
|
+
<div key={idx} className="flex justify-between text-xs">
|
|
917
|
+
<span className="text-bolt-elements-textSecondary">{item.label}:</span>
|
|
918
|
+
<span className="text-bolt-elements-textPrimary font-medium">{item.value}</span>
|
|
919
|
+
</div>
|
|
920
|
+
))}
|
|
921
|
+
</div>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
</div>
|
|
925
|
+
|
|
926
|
+
{/* Resource Utilization */}
|
|
927
|
+
<div className="mb-6">
|
|
928
|
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-2">Resource Overview</h4>
|
|
929
|
+
<div className="grid grid-cols-2 md:grid-cols-5 gap-4">
|
|
930
|
+
{(() => {
|
|
931
|
+
const totalDatabase =
|
|
932
|
+
connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.database?.size_mb || 0), 0) ||
|
|
933
|
+
0;
|
|
934
|
+
const totalStorage =
|
|
935
|
+
connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.storage?.used_gb || 0), 0) ||
|
|
936
|
+
0;
|
|
937
|
+
const totalFunctions =
|
|
938
|
+
connection.stats?.projects?.reduce(
|
|
939
|
+
(sum, p) => sum + (p.stats?.functions?.deployed || 0),
|
|
940
|
+
0,
|
|
941
|
+
) || 0;
|
|
942
|
+
const totalTables =
|
|
943
|
+
connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.database?.tables || 0), 0) ||
|
|
944
|
+
0;
|
|
945
|
+
const totalBuckets =
|
|
946
|
+
connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.storage?.buckets || 0), 0) ||
|
|
947
|
+
0;
|
|
948
|
+
|
|
949
|
+
return [
|
|
950
|
+
{
|
|
951
|
+
label: 'Database',
|
|
952
|
+
value: totalDatabase > 0 ? `${totalDatabase} MB` : '--',
|
|
953
|
+
icon: 'i-ph:database',
|
|
954
|
+
color: 'text-blue-500',
|
|
955
|
+
bgColor: 'bg-blue-100 dark:bg-blue-900/20',
|
|
956
|
+
textColor: 'text-blue-800 dark:text-blue-400',
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
label: 'Storage',
|
|
960
|
+
value: totalStorage > 0 ? `${totalStorage} GB` : '--',
|
|
961
|
+
icon: 'i-ph:folder',
|
|
962
|
+
color: 'text-green-500',
|
|
963
|
+
bgColor: 'bg-green-100 dark:bg-green-900/20',
|
|
964
|
+
textColor: 'text-green-800 dark:text-green-400',
|
|
965
|
+
},
|
|
966
|
+
{
|
|
967
|
+
label: 'Functions',
|
|
968
|
+
value: totalFunctions,
|
|
969
|
+
icon: 'i-ph:code',
|
|
970
|
+
color: 'text-purple-500',
|
|
971
|
+
bgColor: 'bg-purple-100 dark:bg-purple-900/20',
|
|
972
|
+
textColor: 'text-purple-800 dark:text-purple-400',
|
|
973
|
+
},
|
|
974
|
+
{
|
|
975
|
+
label: 'Tables',
|
|
976
|
+
value: totalTables,
|
|
977
|
+
icon: 'i-ph:table',
|
|
978
|
+
color: 'text-orange-500',
|
|
979
|
+
bgColor: 'bg-orange-100 dark:bg-orange-900/20',
|
|
980
|
+
textColor: 'text-orange-800 dark:text-orange-400',
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
label: 'Buckets',
|
|
984
|
+
value: totalBuckets,
|
|
985
|
+
icon: 'i-ph:archive',
|
|
986
|
+
color: 'text-teal-500',
|
|
987
|
+
bgColor: 'bg-teal-100 dark:bg-teal-900/20',
|
|
988
|
+
textColor: 'text-teal-800 dark:text-teal-400',
|
|
989
|
+
},
|
|
990
|
+
];
|
|
991
|
+
})().map((metric, index) => (
|
|
992
|
+
<div
|
|
993
|
+
key={index}
|
|
994
|
+
className={`flex flex-col p-3 rounded-lg border border-bolt-elements-borderColor ${metric.bgColor}`}
|
|
995
|
+
>
|
|
996
|
+
<div className="flex items-center gap-2 mb-1">
|
|
997
|
+
<div className={`${metric.icon} w-4 h-4 ${metric.color}`} />
|
|
998
|
+
<span className="text-xs text-bolt-elements-textSecondary">{metric.label}</span>
|
|
999
|
+
</div>
|
|
1000
|
+
<span className={`text-lg font-medium ${metric.textColor}`}>{metric.value}</span>
|
|
1001
|
+
</div>
|
|
1002
|
+
))}
|
|
1003
|
+
</div>
|
|
1004
|
+
</div>
|
|
1005
|
+
|
|
1006
|
+
{/* Usage Metrics */}
|
|
1007
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
1008
|
+
<div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
|
|
1009
|
+
<div className="flex items-center gap-2 mb-2">
|
|
1010
|
+
<div className="i-ph:database w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
1011
|
+
<span className="text-xs font-medium text-bolt-elements-textPrimary">Database</span>
|
|
1012
|
+
</div>
|
|
1013
|
+
<div className="text-sm text-bolt-elements-textSecondary">
|
|
1014
|
+
<div>
|
|
1015
|
+
Tables:{' '}
|
|
1016
|
+
{connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.database?.tables || 0), 0) ||
|
|
1017
|
+
'--'}
|
|
1018
|
+
</div>
|
|
1019
|
+
<div>
|
|
1020
|
+
Size:{' '}
|
|
1021
|
+
{(() => {
|
|
1022
|
+
const totalSize =
|
|
1023
|
+
connection.stats?.projects?.reduce(
|
|
1024
|
+
(sum, p) => sum + (p.stats?.database?.size_mb || 0),
|
|
1025
|
+
0,
|
|
1026
|
+
) || 0;
|
|
1027
|
+
return totalSize > 0 ? `${totalSize} MB` : '--';
|
|
1028
|
+
})()}
|
|
1029
|
+
</div>
|
|
1030
|
+
</div>
|
|
1031
|
+
</div>
|
|
1032
|
+
<div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
|
|
1033
|
+
<div className="flex items-center gap-2 mb-2">
|
|
1034
|
+
<div className="i-ph:folder w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
1035
|
+
<span className="text-xs font-medium text-bolt-elements-textPrimary">Storage</span>
|
|
1036
|
+
</div>
|
|
1037
|
+
<div className="text-sm text-bolt-elements-textSecondary">
|
|
1038
|
+
<div>
|
|
1039
|
+
Buckets:{' '}
|
|
1040
|
+
{connection.stats?.projects?.reduce((sum, p) => sum + (p.stats?.storage?.buckets || 0), 0) ||
|
|
1041
|
+
'--'}
|
|
1042
|
+
</div>
|
|
1043
|
+
<div>
|
|
1044
|
+
Used:{' '}
|
|
1045
|
+
{(() => {
|
|
1046
|
+
const totalUsed =
|
|
1047
|
+
connection.stats?.projects?.reduce(
|
|
1048
|
+
(sum, p) => sum + (p.stats?.storage?.used_gb || 0),
|
|
1049
|
+
0,
|
|
1050
|
+
) || 0;
|
|
1051
|
+
return totalUsed > 0 ? `${totalUsed} GB` : '--';
|
|
1052
|
+
})()}
|
|
1053
|
+
</div>
|
|
1054
|
+
</div>
|
|
1055
|
+
</div>
|
|
1056
|
+
<div className="p-3 bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor">
|
|
1057
|
+
<div className="flex items-center gap-2 mb-2">
|
|
1058
|
+
<div className="i-ph:code w-4 h-4 text-bolt-elements-item-contentAccent" />
|
|
1059
|
+
<span className="text-xs font-medium text-bolt-elements-textPrimary">Functions</span>
|
|
1060
|
+
</div>
|
|
1061
|
+
<div className="text-sm text-bolt-elements-textSecondary">
|
|
1062
|
+
<div>
|
|
1063
|
+
Deployed:{' '}
|
|
1064
|
+
{connection.stats?.projects?.reduce(
|
|
1065
|
+
(sum, p) => sum + (p.stats?.functions?.deployed || 0),
|
|
1066
|
+
0,
|
|
1067
|
+
) || '--'}
|
|
1068
|
+
</div>
|
|
1069
|
+
<div>
|
|
1070
|
+
Invocations:{' '}
|
|
1071
|
+
{connection.stats?.projects?.reduce(
|
|
1072
|
+
(sum, p) => sum + (p.stats?.functions?.invocations || 0),
|
|
1073
|
+
0,
|
|
1074
|
+
) || '--'}
|
|
1075
|
+
</div>
|
|
1076
|
+
</div>
|
|
1077
|
+
</div>
|
|
1078
|
+
</div>
|
|
1079
|
+
</div>
|
|
1080
|
+
)}
|
|
1081
|
+
|
|
1082
|
+
{renderProjects()}
|
|
1083
|
+
</div>
|
|
1084
|
+
)}
|
|
1085
|
+
</div>
|
|
1086
|
+
</motion.div>
|
|
1087
|
+
</div>
|
|
1088
|
+
);
|
|
1089
|
+
}
|