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,1041 @@
|
|
|
1
|
+
import * as Dialog from '@radix-ui/react-dialog';
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { toast } from 'react-toastify';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import { Octokit } from '@octokit/rest';
|
|
6
|
+
import { classNames } from '~/utils/classNames';
|
|
7
|
+
import { getLocalStorage } from '~/lib/persistence/localStorage';
|
|
8
|
+
import type { GitHubUserResponse, GitHubRepoInfo } from '~/types/GitHub';
|
|
9
|
+
import { logStore } from '~/lib/stores/logs';
|
|
10
|
+
import { chatId } from '~/lib/persistence/useChatHistory';
|
|
11
|
+
import { useStore } from '@nanostores/react';
|
|
12
|
+
import { GitHubAuthDialog } from '~/components/@settings/tabs/github/components/GitHubAuthDialog';
|
|
13
|
+
import { SearchInput, EmptyState, StatusIndicator, Badge } from '~/components/ui';
|
|
14
|
+
|
|
15
|
+
interface GitHubDeploymentDialogProps {
|
|
16
|
+
isOpen: boolean;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
projectName: string;
|
|
19
|
+
files: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function GitHubDeploymentDialog({ isOpen, onClose, projectName, files }: GitHubDeploymentDialogProps) {
|
|
23
|
+
const [repoName, setRepoName] = useState('');
|
|
24
|
+
const [isPrivate, setIsPrivate] = useState(false);
|
|
25
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
26
|
+
const [user, setUser] = useState<GitHubUserResponse | null>(null);
|
|
27
|
+
const [recentRepos, setRecentRepos] = useState<GitHubRepoInfo[]>([]);
|
|
28
|
+
const [filteredRepos, setFilteredRepos] = useState<GitHubRepoInfo[]>([]);
|
|
29
|
+
const [repoSearchQuery, setRepoSearchQuery] = useState('');
|
|
30
|
+
const [isFetchingRepos, setIsFetchingRepos] = useState(false);
|
|
31
|
+
const [showSuccessDialog, setShowSuccessDialog] = useState(false);
|
|
32
|
+
const [createdRepoUrl, setCreatedRepoUrl] = useState('');
|
|
33
|
+
const [pushedFiles, setPushedFiles] = useState<{ path: string; size: number }[]>([]);
|
|
34
|
+
const [showAuthDialog, setShowAuthDialog] = useState(false);
|
|
35
|
+
const currentChatId = useStore(chatId);
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
* Load GitHub connection on mount
|
|
39
|
+
* Helper function to sanitize repository name
|
|
40
|
+
*/
|
|
41
|
+
const sanitizeRepoName = (name: string): string => {
|
|
42
|
+
return (
|
|
43
|
+
name
|
|
44
|
+
.toLowerCase()
|
|
45
|
+
// Replace spaces and underscores with hyphens
|
|
46
|
+
.replace(/[\s_]+/g, '-')
|
|
47
|
+
// Remove special characters except hyphens and alphanumeric
|
|
48
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
49
|
+
// Remove multiple consecutive hyphens
|
|
50
|
+
.replace(/-+/g, '-')
|
|
51
|
+
// Remove leading/trailing hyphens
|
|
52
|
+
.replace(/^-+|-+$/g, '')
|
|
53
|
+
// Ensure it's not empty and has reasonable length
|
|
54
|
+
.substring(0, 100) || 'my-project'
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (isOpen) {
|
|
60
|
+
const connection = getLocalStorage('github_connection');
|
|
61
|
+
|
|
62
|
+
// Set a default repository name based on the project name with proper sanitization
|
|
63
|
+
setRepoName(sanitizeRepoName(projectName));
|
|
64
|
+
|
|
65
|
+
if (connection?.user && connection?.token) {
|
|
66
|
+
setUser(connection.user);
|
|
67
|
+
|
|
68
|
+
// Only fetch if we have both user and token
|
|
69
|
+
if (connection.token.trim()) {
|
|
70
|
+
fetchRecentRepos(connection.token);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, [isOpen, projectName]);
|
|
75
|
+
|
|
76
|
+
// Filter repositories based on search query
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (recentRepos.length === 0) {
|
|
79
|
+
setFilteredRepos([]);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!repoSearchQuery.trim()) {
|
|
84
|
+
setFilteredRepos(recentRepos);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const query = repoSearchQuery.toLowerCase().trim();
|
|
89
|
+
const filtered = recentRepos.filter(
|
|
90
|
+
(repo) =>
|
|
91
|
+
repo.name.toLowerCase().includes(query) ||
|
|
92
|
+
(repo.description && repo.description.toLowerCase().includes(query)) ||
|
|
93
|
+
(repo.language && repo.language.toLowerCase().includes(query)),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
setFilteredRepos(filtered);
|
|
97
|
+
}, [recentRepos, repoSearchQuery]);
|
|
98
|
+
|
|
99
|
+
const fetchRecentRepos = async (token: string) => {
|
|
100
|
+
if (!token) {
|
|
101
|
+
logStore.logError('No GitHub token available');
|
|
102
|
+
toast.error('GitHub authentication required');
|
|
103
|
+
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
setIsFetchingRepos(true);
|
|
109
|
+
|
|
110
|
+
// Fetch ALL repos by paginating through all pages
|
|
111
|
+
let allRepos: GitHubRepoInfo[] = [];
|
|
112
|
+
let page = 1;
|
|
113
|
+
let hasMore = true;
|
|
114
|
+
|
|
115
|
+
while (hasMore) {
|
|
116
|
+
const requestUrl = `https://api.github.com/user/repos?sort=updated&per_page=100&page=${page}&affiliation=owner,organization_member`;
|
|
117
|
+
const response = await fetch(requestUrl, {
|
|
118
|
+
headers: {
|
|
119
|
+
Accept: 'application/vnd.github.v3+json',
|
|
120
|
+
Authorization: `Bearer ${token.trim()}`,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
if (!response.ok) {
|
|
125
|
+
let errorData: { message?: string } = {};
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
errorData = await response.json();
|
|
129
|
+
} catch {
|
|
130
|
+
errorData = { message: 'Could not parse error response' };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (response.status === 401) {
|
|
134
|
+
toast.error('GitHub token expired. Please reconnect your account.');
|
|
135
|
+
|
|
136
|
+
// Clear invalid token
|
|
137
|
+
const connection = getLocalStorage('github_connection');
|
|
138
|
+
|
|
139
|
+
if (connection) {
|
|
140
|
+
localStorage.removeItem('github_connection');
|
|
141
|
+
setUser(null);
|
|
142
|
+
}
|
|
143
|
+
} else if (response.status === 403 && response.headers.get('x-ratelimit-remaining') === '0') {
|
|
144
|
+
// Rate limit exceeded
|
|
145
|
+
const resetTime = response.headers.get('x-ratelimit-reset');
|
|
146
|
+
const resetDate = resetTime ? new Date(parseInt(resetTime) * 1000).toLocaleTimeString() : 'soon';
|
|
147
|
+
toast.error(`GitHub API rate limit exceeded. Limit resets at ${resetDate}`);
|
|
148
|
+
} else {
|
|
149
|
+
logStore.logError('Failed to fetch GitHub repositories', {
|
|
150
|
+
status: response.status,
|
|
151
|
+
statusText: response.statusText,
|
|
152
|
+
error: errorData,
|
|
153
|
+
});
|
|
154
|
+
toast.error(`Failed to fetch repositories: ${errorData.message || response.statusText}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const repos = (await response.json()) as GitHubRepoInfo[];
|
|
162
|
+
allRepos = allRepos.concat(repos);
|
|
163
|
+
|
|
164
|
+
if (repos.length < 100) {
|
|
165
|
+
hasMore = false;
|
|
166
|
+
} else {
|
|
167
|
+
page += 1;
|
|
168
|
+
}
|
|
169
|
+
} catch (parseError) {
|
|
170
|
+
logStore.logError('Failed to parse GitHub repositories response', { parseError });
|
|
171
|
+
toast.error('Failed to parse repository data');
|
|
172
|
+
setRecentRepos([]);
|
|
173
|
+
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
setRecentRepos(allRepos);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
logStore.logError('Failed to fetch GitHub repositories', { error });
|
|
181
|
+
toast.error('Failed to fetch recent repositories');
|
|
182
|
+
} finally {
|
|
183
|
+
setIsFetchingRepos(false);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Function to create a new repository or push to an existing one
|
|
188
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
189
|
+
e.preventDefault();
|
|
190
|
+
|
|
191
|
+
const connection = getLocalStorage('github_connection');
|
|
192
|
+
|
|
193
|
+
if (!connection?.token || !connection?.user) {
|
|
194
|
+
toast.error('Please connect your GitHub account in Settings > Connections first');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!repoName.trim()) {
|
|
199
|
+
toast.error('Repository name is required');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Validate repository name
|
|
204
|
+
const sanitizedName = sanitizeRepoName(repoName);
|
|
205
|
+
|
|
206
|
+
if (!sanitizedName || sanitizedName.length < 1) {
|
|
207
|
+
toast.error('Repository name must contain at least one alphanumeric character');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (sanitizedName.length > 100) {
|
|
212
|
+
toast.error('Repository name is too long (maximum 100 characters)');
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Update the repo name field with the sanitized version if it was changed
|
|
217
|
+
if (sanitizedName !== repoName) {
|
|
218
|
+
setRepoName(sanitizedName);
|
|
219
|
+
toast.info(`Repository name sanitized to: ${sanitizedName}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
setIsLoading(true);
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
// Initialize Octokit with the GitHub token
|
|
226
|
+
const octokit = new Octokit({ auth: connection.token });
|
|
227
|
+
let repoExists = false;
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
// Check if the repository already exists - ensure repo name is properly sanitized
|
|
231
|
+
const sanitizedRepoName = sanitizeRepoName(repoName);
|
|
232
|
+
const { data: existingRepo } = await octokit.repos.get({
|
|
233
|
+
owner: connection.user.login,
|
|
234
|
+
repo: sanitizedRepoName,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
repoExists = true;
|
|
238
|
+
|
|
239
|
+
// If we get here, the repo exists - confirm overwrite
|
|
240
|
+
let confirmMessage = `Repository "${repoName}" already exists. Do you want to update it? This will add or modify files in the repository.`;
|
|
241
|
+
|
|
242
|
+
// Add visibility change warning if needed
|
|
243
|
+
if (existingRepo.private !== isPrivate) {
|
|
244
|
+
const visibilityChange = isPrivate
|
|
245
|
+
? 'This will also change the repository from public to private.'
|
|
246
|
+
: 'This will also change the repository from private to public.';
|
|
247
|
+
|
|
248
|
+
confirmMessage += `\n\n${visibilityChange}`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const confirmOverwrite = window.confirm(confirmMessage);
|
|
252
|
+
|
|
253
|
+
if (!confirmOverwrite) {
|
|
254
|
+
setIsLoading(false);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// If visibility needs to be updated
|
|
259
|
+
if (existingRepo.private !== isPrivate) {
|
|
260
|
+
await octokit.repos.update({
|
|
261
|
+
owner: connection.user.login,
|
|
262
|
+
repo: sanitizedRepoName,
|
|
263
|
+
private: isPrivate,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
} catch (error: any) {
|
|
267
|
+
// 404 means repo doesn't exist, which is what we want for new repos
|
|
268
|
+
if (error.status !== 404) {
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Create repository if it doesn't exist
|
|
274
|
+
if (!repoExists) {
|
|
275
|
+
const sanitizedRepoName = sanitizeRepoName(repoName);
|
|
276
|
+
const { data: newRepo } = await octokit.repos.createForAuthenticatedUser({
|
|
277
|
+
name: sanitizedRepoName,
|
|
278
|
+
private: isPrivate,
|
|
279
|
+
|
|
280
|
+
// Initialize with a README to avoid empty repository issues
|
|
281
|
+
auto_init: true,
|
|
282
|
+
|
|
283
|
+
// Create a .gitignore file for the project
|
|
284
|
+
gitignore_template: 'Node',
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Set the URL for success dialog
|
|
288
|
+
setCreatedRepoUrl(newRepo.html_url);
|
|
289
|
+
|
|
290
|
+
// Since we created the repo with auto_init, we need to wait for GitHub to initialize it
|
|
291
|
+
console.log('Created new repository with auto_init, waiting for GitHub to initialize it...');
|
|
292
|
+
|
|
293
|
+
// Wait a moment for GitHub to set up the initial commit
|
|
294
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
295
|
+
} else {
|
|
296
|
+
// Set URL for existing repo
|
|
297
|
+
const sanitizedRepoName = sanitizeRepoName(repoName);
|
|
298
|
+
setCreatedRepoUrl(`https://github.com/${connection.user.login}/${sanitizedRepoName}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Process files to upload
|
|
302
|
+
const fileEntries = Object.entries(files);
|
|
303
|
+
|
|
304
|
+
// Filter out files and format them for display
|
|
305
|
+
const fileList = fileEntries.map(([filePath, content]) => {
|
|
306
|
+
// The paths are already properly formatted in the GitHubDeploy component
|
|
307
|
+
return {
|
|
308
|
+
path: filePath,
|
|
309
|
+
size: new TextEncoder().encode(content).length,
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
setPushedFiles(fileList);
|
|
314
|
+
|
|
315
|
+
/*
|
|
316
|
+
* Now we need to handle the repository, whether it's new or existing
|
|
317
|
+
* Get the default branch for the repository
|
|
318
|
+
*/
|
|
319
|
+
let defaultBranch: string;
|
|
320
|
+
let baseSha: string | null = null;
|
|
321
|
+
|
|
322
|
+
try {
|
|
323
|
+
// For both new and existing repos, get the repository info
|
|
324
|
+
const sanitizedRepoName = sanitizeRepoName(repoName);
|
|
325
|
+
const { data: repo } = await octokit.repos.get({
|
|
326
|
+
owner: connection.user.login,
|
|
327
|
+
repo: sanitizedRepoName,
|
|
328
|
+
});
|
|
329
|
+
defaultBranch = repo.default_branch || 'main';
|
|
330
|
+
console.log(`Repository default branch: ${defaultBranch}`);
|
|
331
|
+
|
|
332
|
+
// For a newly created repo (or existing one), get the reference to the default branch
|
|
333
|
+
try {
|
|
334
|
+
const { data: refData } = await octokit.git.getRef({
|
|
335
|
+
owner: connection.user.login,
|
|
336
|
+
repo: sanitizedRepoName,
|
|
337
|
+
ref: `heads/${defaultBranch}`,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
baseSha = refData.object.sha;
|
|
341
|
+
console.log(`Found existing reference with SHA: ${baseSha}`);
|
|
342
|
+
|
|
343
|
+
// Get the latest commit to use as a base for our tree
|
|
344
|
+
const { data: commitData } = await octokit.git.getCommit({
|
|
345
|
+
owner: connection.user.login,
|
|
346
|
+
repo: sanitizedRepoName,
|
|
347
|
+
commit_sha: baseSha,
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Store the base tree SHA for tree creation
|
|
351
|
+
baseSha = commitData.tree.sha;
|
|
352
|
+
console.log(`Using base tree SHA: ${baseSha}`);
|
|
353
|
+
} catch (refError) {
|
|
354
|
+
console.error('Error getting reference:', refError);
|
|
355
|
+
baseSha = null;
|
|
356
|
+
}
|
|
357
|
+
} catch (repoError) {
|
|
358
|
+
console.error('Error getting repository info:', repoError);
|
|
359
|
+
defaultBranch = 'main';
|
|
360
|
+
baseSha = null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
console.log('Creating tree for repository');
|
|
365
|
+
|
|
366
|
+
// Create a tree with all files
|
|
367
|
+
const tree = fileEntries.map(([filePath, content]) => ({
|
|
368
|
+
path: filePath, // We've already formatted the paths correctly
|
|
369
|
+
mode: '100644' as const, // Regular file
|
|
370
|
+
type: 'blob' as const,
|
|
371
|
+
content,
|
|
372
|
+
}));
|
|
373
|
+
|
|
374
|
+
console.log(`Creating tree with ${tree.length} files using base: ${baseSha || 'none'}`);
|
|
375
|
+
|
|
376
|
+
// Create a tree with all the files, using the base tree if available
|
|
377
|
+
const sanitizedRepoName = sanitizeRepoName(repoName);
|
|
378
|
+
const { data: treeData } = await octokit.git.createTree({
|
|
379
|
+
owner: connection.user.login,
|
|
380
|
+
repo: sanitizedRepoName,
|
|
381
|
+
tree,
|
|
382
|
+
base_tree: baseSha || undefined,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
console.log('Tree created successfully', treeData.sha);
|
|
386
|
+
|
|
387
|
+
// Get the current reference to use as parent for our commit
|
|
388
|
+
let parentCommitSha: string | null = null;
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
const { data: refData } = await octokit.git.getRef({
|
|
392
|
+
owner: connection.user.login,
|
|
393
|
+
repo: sanitizedRepoName,
|
|
394
|
+
ref: `heads/${defaultBranch}`,
|
|
395
|
+
});
|
|
396
|
+
parentCommitSha = refData.object.sha;
|
|
397
|
+
console.log(`Found parent commit: ${parentCommitSha}`);
|
|
398
|
+
} catch (refError) {
|
|
399
|
+
console.log('No reference found, this is a brand new repo', refError);
|
|
400
|
+
parentCommitSha = null;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Create a commit with the tree
|
|
404
|
+
console.log('Creating commit');
|
|
405
|
+
|
|
406
|
+
const { data: commitData } = await octokit.git.createCommit({
|
|
407
|
+
owner: connection.user.login,
|
|
408
|
+
repo: sanitizedRepoName,
|
|
409
|
+
message: !repoExists ? 'Initial commit from Bolt.diy' : 'Update from Bolt.diy',
|
|
410
|
+
tree: treeData.sha,
|
|
411
|
+
parents: parentCommitSha ? [parentCommitSha] : [], // Use parent if available
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
console.log('Commit created successfully', commitData.sha);
|
|
415
|
+
|
|
416
|
+
// Update the reference to point to the new commit
|
|
417
|
+
try {
|
|
418
|
+
console.log(`Updating reference: heads/${defaultBranch} to ${commitData.sha}`);
|
|
419
|
+
await octokit.git.updateRef({
|
|
420
|
+
owner: connection.user.login,
|
|
421
|
+
repo: sanitizedRepoName,
|
|
422
|
+
ref: `heads/${defaultBranch}`,
|
|
423
|
+
sha: commitData.sha,
|
|
424
|
+
force: true, // Use force to ensure the update works
|
|
425
|
+
});
|
|
426
|
+
console.log('Reference updated successfully');
|
|
427
|
+
} catch (refError) {
|
|
428
|
+
console.log('Failed to update reference, attempting to create it', refError);
|
|
429
|
+
|
|
430
|
+
// If the reference doesn't exist, create it (shouldn't happen with auto_init, but just in case)
|
|
431
|
+
try {
|
|
432
|
+
await octokit.git.createRef({
|
|
433
|
+
owner: connection.user.login,
|
|
434
|
+
repo: sanitizedRepoName,
|
|
435
|
+
ref: `refs/heads/${defaultBranch}`,
|
|
436
|
+
sha: commitData.sha,
|
|
437
|
+
});
|
|
438
|
+
console.log('Reference created successfully');
|
|
439
|
+
} catch (createRefError) {
|
|
440
|
+
console.error('Error creating reference:', createRefError);
|
|
441
|
+
|
|
442
|
+
const errorMsg =
|
|
443
|
+
typeof createRefError === 'object' && createRefError !== null && 'message' in createRefError
|
|
444
|
+
? String(createRefError.message)
|
|
445
|
+
: 'Unknown error';
|
|
446
|
+
throw new Error(`Failed to create Git reference: ${errorMsg}`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
} catch (gitError) {
|
|
450
|
+
console.error('Error with git operations:', gitError);
|
|
451
|
+
|
|
452
|
+
const gitErrorMsg =
|
|
453
|
+
typeof gitError === 'object' && gitError !== null && 'message' in gitError
|
|
454
|
+
? String(gitError.message)
|
|
455
|
+
: 'Unknown error';
|
|
456
|
+
throw new Error(`Failed during git operations: ${gitErrorMsg}`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Save the repository information for this chat
|
|
460
|
+
const sanitizedRepoName = sanitizeRepoName(repoName);
|
|
461
|
+
localStorage.setItem(
|
|
462
|
+
`github-repo-${currentChatId}`,
|
|
463
|
+
JSON.stringify({
|
|
464
|
+
owner: connection.user.login,
|
|
465
|
+
name: sanitizedRepoName,
|
|
466
|
+
url: `https://github.com/${connection.user.login}/${sanitizedRepoName}`,
|
|
467
|
+
}),
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
// Show success dialog
|
|
471
|
+
setShowSuccessDialog(true);
|
|
472
|
+
} catch (error) {
|
|
473
|
+
console.error('Error pushing to GitHub:', error);
|
|
474
|
+
|
|
475
|
+
// Attempt to extract more specific error information
|
|
476
|
+
let errorMessage = 'Failed to push to GitHub';
|
|
477
|
+
let isRetryable = false;
|
|
478
|
+
|
|
479
|
+
if (error instanceof Error) {
|
|
480
|
+
const errorMsg = error.message.toLowerCase();
|
|
481
|
+
|
|
482
|
+
if (errorMsg.includes('network') || errorMsg.includes('fetch failed') || errorMsg.includes('connection')) {
|
|
483
|
+
errorMessage = 'Network error. Please check your internet connection and try again.';
|
|
484
|
+
isRetryable = true;
|
|
485
|
+
} else if (errorMsg.includes('401') || errorMsg.includes('unauthorized')) {
|
|
486
|
+
errorMessage = 'GitHub authentication failed. Please check your access token in Settings > Connections.';
|
|
487
|
+
} else if (errorMsg.includes('403') || errorMsg.includes('forbidden')) {
|
|
488
|
+
errorMessage =
|
|
489
|
+
'Access denied. Your GitHub token may not have sufficient permissions to create/modify repositories.';
|
|
490
|
+
} else if (errorMsg.includes('404') || errorMsg.includes('not found')) {
|
|
491
|
+
errorMessage = 'Repository or resource not found. Please check the repository name and your permissions.';
|
|
492
|
+
} else if (errorMsg.includes('422') || errorMsg.includes('validation failed')) {
|
|
493
|
+
if (errorMsg.includes('name already exists')) {
|
|
494
|
+
errorMessage =
|
|
495
|
+
'A repository with this name already exists in your account. Please choose a different name.';
|
|
496
|
+
} else {
|
|
497
|
+
errorMessage = 'Repository validation failed. Please check the repository name and settings.';
|
|
498
|
+
}
|
|
499
|
+
} else if (errorMsg.includes('rate limit') || errorMsg.includes('429')) {
|
|
500
|
+
errorMessage = 'GitHub API rate limit exceeded. Please wait a moment and try again.';
|
|
501
|
+
isRetryable = true;
|
|
502
|
+
} else if (errorMsg.includes('timeout')) {
|
|
503
|
+
errorMessage = 'Request timed out. Please check your connection and try again.';
|
|
504
|
+
isRetryable = true;
|
|
505
|
+
} else {
|
|
506
|
+
errorMessage = `GitHub error: ${error.message}`;
|
|
507
|
+
}
|
|
508
|
+
} else if (typeof error === 'object' && error !== null) {
|
|
509
|
+
// Octokit errors
|
|
510
|
+
if ('message' in error) {
|
|
511
|
+
errorMessage = `GitHub API error: ${error.message as string}`;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// GitHub API errors
|
|
515
|
+
if ('documentation_url' in error) {
|
|
516
|
+
console.log('GitHub API documentation:', error.documentation_url);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Show error with retry suggestion if applicable
|
|
521
|
+
const finalMessage = isRetryable ? `${errorMessage} Click to retry.` : errorMessage;
|
|
522
|
+
toast.error(finalMessage);
|
|
523
|
+
|
|
524
|
+
// Log detailed error for debugging
|
|
525
|
+
console.error('Detailed GitHub deployment error:', {
|
|
526
|
+
error,
|
|
527
|
+
repoName: sanitizeRepoName(repoName),
|
|
528
|
+
user: connection?.user?.login,
|
|
529
|
+
isRetryable,
|
|
530
|
+
});
|
|
531
|
+
} finally {
|
|
532
|
+
setIsLoading(false);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
const handleClose = () => {
|
|
537
|
+
setRepoName('');
|
|
538
|
+
setIsPrivate(false);
|
|
539
|
+
setShowSuccessDialog(false);
|
|
540
|
+
setCreatedRepoUrl('');
|
|
541
|
+
onClose();
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const handleAuthDialogClose = () => {
|
|
545
|
+
setShowAuthDialog(false);
|
|
546
|
+
|
|
547
|
+
// Refresh user data after auth
|
|
548
|
+
const connection = getLocalStorage('github_connection');
|
|
549
|
+
|
|
550
|
+
if (connection?.user && connection?.token) {
|
|
551
|
+
setUser(connection.user);
|
|
552
|
+
fetchRecentRepos(connection.token);
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// Success Dialog
|
|
557
|
+
if (showSuccessDialog) {
|
|
558
|
+
return (
|
|
559
|
+
<Dialog.Root open={isOpen} onOpenChange={(open) => !open && handleClose()}>
|
|
560
|
+
<Dialog.Portal>
|
|
561
|
+
<Dialog.Overlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[9999]" />
|
|
562
|
+
<div className="fixed inset-0 flex items-center justify-center z-[9999]">
|
|
563
|
+
<motion.div
|
|
564
|
+
initial={{ opacity: 0, scale: 0.95 }}
|
|
565
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
566
|
+
exit={{ opacity: 0, scale: 0.95 }}
|
|
567
|
+
transition={{ duration: 0.2 }}
|
|
568
|
+
className="w-[90vw] md:w-[600px] max-h-[85vh] overflow-y-auto"
|
|
569
|
+
>
|
|
570
|
+
<Dialog.Content
|
|
571
|
+
className="bg-white dark:bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark shadow-xl"
|
|
572
|
+
aria-describedby="success-dialog-description"
|
|
573
|
+
>
|
|
574
|
+
<Dialog.Title className="sr-only">Successfully pushed to GitHub</Dialog.Title>
|
|
575
|
+
<div className="p-6 space-y-4">
|
|
576
|
+
<div className="flex items-center justify-between">
|
|
577
|
+
<div className="flex items-center gap-3">
|
|
578
|
+
<div className="w-10 h-10 rounded-xl bg-green-500/10 flex items-center justify-center text-green-500">
|
|
579
|
+
<div className="i-ph:check-circle w-5 h-5" />
|
|
580
|
+
</div>
|
|
581
|
+
<div>
|
|
582
|
+
<h3 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
|
|
583
|
+
Successfully pushed to GitHub
|
|
584
|
+
</h3>
|
|
585
|
+
<p
|
|
586
|
+
id="success-dialog-description"
|
|
587
|
+
className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark"
|
|
588
|
+
>
|
|
589
|
+
Your code is now available on GitHub
|
|
590
|
+
</p>
|
|
591
|
+
</div>
|
|
592
|
+
</div>
|
|
593
|
+
<Dialog.Close asChild>
|
|
594
|
+
<button
|
|
595
|
+
onClick={handleClose}
|
|
596
|
+
className="p-2 rounded-lg transition-all duration-200 ease-in-out bg-transparent text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textPrimary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 focus:outline-none focus:ring-2 focus:ring-bolt-elements-borderColor dark:focus:ring-bolt-elements-borderColor-dark"
|
|
597
|
+
>
|
|
598
|
+
<span className="i-ph:x block w-5 h-5" aria-hidden="true" />
|
|
599
|
+
<span className="sr-only">Close dialog</span>
|
|
600
|
+
</button>
|
|
601
|
+
</Dialog.Close>
|
|
602
|
+
</div>
|
|
603
|
+
|
|
604
|
+
<div className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg p-4 text-left border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
|
|
605
|
+
<p className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark mb-2 flex items-center gap-2">
|
|
606
|
+
<span className="i-ph:github-logo w-4 h-4 text-purple-500" />
|
|
607
|
+
Repository URL
|
|
608
|
+
</p>
|
|
609
|
+
<div className="flex items-center gap-2">
|
|
610
|
+
<code className="flex-1 text-sm bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-4 px-3 py-2 rounded border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark font-mono">
|
|
611
|
+
{createdRepoUrl}
|
|
612
|
+
</code>
|
|
613
|
+
<motion.button
|
|
614
|
+
onClick={() => {
|
|
615
|
+
navigator.clipboard.writeText(createdRepoUrl);
|
|
616
|
+
toast.success('URL copied to clipboard');
|
|
617
|
+
}}
|
|
618
|
+
className="p-2 text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textSecondary-dark dark:hover:text-bolt-elements-textPrimary-dark bg-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-4 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
|
|
619
|
+
whileHover={{ scale: 1.05 }}
|
|
620
|
+
whileTap={{ scale: 0.95 }}
|
|
621
|
+
>
|
|
622
|
+
<div className="i-ph:copy w-4 h-4" />
|
|
623
|
+
</motion.button>
|
|
624
|
+
</div>
|
|
625
|
+
</div>
|
|
626
|
+
|
|
627
|
+
<div className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg p-4 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
|
|
628
|
+
<p className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark mb-2 flex items-center gap-2">
|
|
629
|
+
<span className="i-ph:files w-4 h-4 text-purple-500" />
|
|
630
|
+
Pushed Files ({pushedFiles.length})
|
|
631
|
+
</p>
|
|
632
|
+
<div className="max-h-[200px] overflow-y-auto custom-scrollbar pr-2">
|
|
633
|
+
{pushedFiles.slice(0, 100).map((file) => (
|
|
634
|
+
<div
|
|
635
|
+
key={file.path}
|
|
636
|
+
className="flex items-center justify-between py-1.5 text-sm text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark border-b border-bolt-elements-borderColor/30 dark:border-bolt-elements-borderColor-dark/30 last:border-0"
|
|
637
|
+
>
|
|
638
|
+
<span className="font-mono truncate flex-1 text-xs">{file.path}</span>
|
|
639
|
+
<span className="text-xs px-2 py-0.5 rounded-full bg-bolt-elements-background-depth-3 dark:bg-bolt-elements-background-depth-4 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark ml-2">
|
|
640
|
+
{(file.size / 1024).toFixed(1)} KB
|
|
641
|
+
</span>
|
|
642
|
+
</div>
|
|
643
|
+
))}
|
|
644
|
+
{pushedFiles.length > 100 && (
|
|
645
|
+
<div className="py-2 text-center text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
|
|
646
|
+
+{pushedFiles.length - 100} more files
|
|
647
|
+
</div>
|
|
648
|
+
)}
|
|
649
|
+
</div>
|
|
650
|
+
</div>
|
|
651
|
+
|
|
652
|
+
<div className="flex justify-end gap-2 pt-2">
|
|
653
|
+
<motion.a
|
|
654
|
+
href={createdRepoUrl}
|
|
655
|
+
target="_blank"
|
|
656
|
+
rel="noopener noreferrer"
|
|
657
|
+
className="px-4 py-2 rounded-lg bg-purple-500 text-white hover:bg-purple-600 text-sm inline-flex items-center gap-2"
|
|
658
|
+
whileHover={{ scale: 1.02 }}
|
|
659
|
+
whileTap={{ scale: 0.98 }}
|
|
660
|
+
>
|
|
661
|
+
<div className="i-ph:github-logo w-4 h-4" />
|
|
662
|
+
View Repository
|
|
663
|
+
</motion.a>
|
|
664
|
+
<motion.button
|
|
665
|
+
onClick={() => {
|
|
666
|
+
navigator.clipboard.writeText(createdRepoUrl);
|
|
667
|
+
toast.success('URL copied to clipboard');
|
|
668
|
+
}}
|
|
669
|
+
className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 text-sm inline-flex items-center gap-2 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
|
|
670
|
+
whileHover={{ scale: 1.02 }}
|
|
671
|
+
whileTap={{ scale: 0.98 }}
|
|
672
|
+
>
|
|
673
|
+
<div className="i-ph:copy w-4 h-4" />
|
|
674
|
+
Copy URL
|
|
675
|
+
</motion.button>
|
|
676
|
+
<motion.button
|
|
677
|
+
onClick={handleClose}
|
|
678
|
+
className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 text-sm border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
|
|
679
|
+
whileHover={{ scale: 1.02 }}
|
|
680
|
+
whileTap={{ scale: 0.98 }}
|
|
681
|
+
>
|
|
682
|
+
Close
|
|
683
|
+
</motion.button>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
</Dialog.Content>
|
|
687
|
+
</motion.div>
|
|
688
|
+
</div>
|
|
689
|
+
</Dialog.Portal>
|
|
690
|
+
</Dialog.Root>
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if (!user) {
|
|
695
|
+
return (
|
|
696
|
+
<Dialog.Root open={isOpen} onOpenChange={(open) => !open && handleClose()}>
|
|
697
|
+
<Dialog.Portal>
|
|
698
|
+
<Dialog.Overlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[9999]" />
|
|
699
|
+
<div className="fixed inset-0 flex items-center justify-center z-[9999]">
|
|
700
|
+
<motion.div
|
|
701
|
+
initial={{ opacity: 0, scale: 0.95 }}
|
|
702
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
703
|
+
exit={{ opacity: 0, scale: 0.95 }}
|
|
704
|
+
transition={{ duration: 0.2 }}
|
|
705
|
+
className="w-[90vw] md:w-[500px]"
|
|
706
|
+
>
|
|
707
|
+
<Dialog.Content
|
|
708
|
+
className="bg-white dark:bg-bolt-elements-background-depth-1 rounded-lg p-6 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark shadow-xl"
|
|
709
|
+
aria-describedby="connection-required-description"
|
|
710
|
+
>
|
|
711
|
+
<Dialog.Title className="sr-only">GitHub Connection Required</Dialog.Title>
|
|
712
|
+
<div className="relative text-center space-y-4">
|
|
713
|
+
<Dialog.Close asChild>
|
|
714
|
+
<button
|
|
715
|
+
onClick={handleClose}
|
|
716
|
+
className="absolute right-0 top-0 p-2 rounded-lg transition-all duration-200 ease-in-out bg-transparent text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textPrimary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 focus:outline-none focus:ring-2 focus:ring-bolt-elements-borderColor dark:focus:ring-bolt-elements-borderColor-dark"
|
|
717
|
+
>
|
|
718
|
+
<span className="i-ph:x block w-5 h-5" aria-hidden="true" />
|
|
719
|
+
<span className="sr-only">Close dialog</span>
|
|
720
|
+
</button>
|
|
721
|
+
</Dialog.Close>
|
|
722
|
+
<motion.div
|
|
723
|
+
initial={{ scale: 0.8 }}
|
|
724
|
+
animate={{ scale: 1 }}
|
|
725
|
+
transition={{ delay: 0.1 }}
|
|
726
|
+
className="mx-auto w-16 h-16 rounded-xl bg-bolt-elements-background-depth-3 flex items-center justify-center text-purple-500"
|
|
727
|
+
>
|
|
728
|
+
<div className="i-ph:github-logo w-8 h-8" />
|
|
729
|
+
</motion.div>
|
|
730
|
+
<h3 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
|
|
731
|
+
GitHub Connection Required
|
|
732
|
+
</h3>
|
|
733
|
+
<p
|
|
734
|
+
id="connection-required-description"
|
|
735
|
+
className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark max-w-md mx-auto"
|
|
736
|
+
>
|
|
737
|
+
To deploy your code to GitHub, you need to connect your GitHub account first.
|
|
738
|
+
</p>
|
|
739
|
+
<div className="pt-2 flex justify-center gap-3">
|
|
740
|
+
<motion.button
|
|
741
|
+
className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark text-sm hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
|
|
742
|
+
whileHover={{ scale: 1.02 }}
|
|
743
|
+
whileTap={{ scale: 0.98 }}
|
|
744
|
+
onClick={handleClose}
|
|
745
|
+
>
|
|
746
|
+
Close
|
|
747
|
+
</motion.button>
|
|
748
|
+
<motion.button
|
|
749
|
+
onClick={() => setShowAuthDialog(true)}
|
|
750
|
+
className="px-4 py-2 rounded-lg bg-purple-500 text-white text-sm hover:bg-purple-600 inline-flex items-center gap-2"
|
|
751
|
+
whileHover={{ scale: 1.02 }}
|
|
752
|
+
whileTap={{ scale: 0.98 }}
|
|
753
|
+
>
|
|
754
|
+
<div className="i-ph:github-logo w-4 h-4" />
|
|
755
|
+
Connect GitHub Account
|
|
756
|
+
</motion.button>
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
759
|
+
</Dialog.Content>
|
|
760
|
+
</motion.div>
|
|
761
|
+
</div>
|
|
762
|
+
</Dialog.Portal>
|
|
763
|
+
|
|
764
|
+
{/* GitHub Auth Dialog */}
|
|
765
|
+
<GitHubAuthDialog isOpen={showAuthDialog} onClose={handleAuthDialogClose} />
|
|
766
|
+
</Dialog.Root>
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return (
|
|
771
|
+
<Dialog.Root open={isOpen} onOpenChange={(open) => !open && handleClose()}>
|
|
772
|
+
<Dialog.Portal>
|
|
773
|
+
<Dialog.Overlay className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[9999]" />
|
|
774
|
+
<div className="fixed inset-0 flex items-center justify-center z-[9999]">
|
|
775
|
+
<motion.div
|
|
776
|
+
initial={{ opacity: 0, scale: 0.95 }}
|
|
777
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
778
|
+
exit={{ opacity: 0, scale: 0.95 }}
|
|
779
|
+
transition={{ duration: 0.2 }}
|
|
780
|
+
className="w-[90vw] md:w-[500px]"
|
|
781
|
+
>
|
|
782
|
+
<Dialog.Content
|
|
783
|
+
className="bg-white dark:bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark shadow-xl"
|
|
784
|
+
aria-describedby="push-dialog-description"
|
|
785
|
+
>
|
|
786
|
+
<div className="p-6">
|
|
787
|
+
<div className="flex items-center gap-4 mb-6">
|
|
788
|
+
<motion.div
|
|
789
|
+
initial={{ scale: 0.8 }}
|
|
790
|
+
animate={{ scale: 1 }}
|
|
791
|
+
transition={{ delay: 0.1 }}
|
|
792
|
+
className="w-10 h-10 rounded-xl bg-bolt-elements-background-depth-3 flex items-center justify-center text-purple-500"
|
|
793
|
+
>
|
|
794
|
+
<div className="i-ph:github-logo w-5 h-5" />
|
|
795
|
+
</motion.div>
|
|
796
|
+
<div>
|
|
797
|
+
<Dialog.Title className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
|
|
798
|
+
Deploy to GitHub
|
|
799
|
+
</Dialog.Title>
|
|
800
|
+
<p
|
|
801
|
+
id="push-dialog-description"
|
|
802
|
+
className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark"
|
|
803
|
+
>
|
|
804
|
+
Deploy your code to a new or existing GitHub repository
|
|
805
|
+
</p>
|
|
806
|
+
</div>
|
|
807
|
+
<Dialog.Close asChild>
|
|
808
|
+
<button
|
|
809
|
+
onClick={handleClose}
|
|
810
|
+
className="ml-auto p-2 rounded-lg transition-all duration-200 ease-in-out bg-transparent text-bolt-elements-textTertiary hover:text-bolt-elements-textPrimary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textPrimary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 focus:outline-none focus:ring-2 focus:ring-bolt-elements-borderColor dark:focus:ring-bolt-elements-borderColor-dark"
|
|
811
|
+
>
|
|
812
|
+
<span className="i-ph:x block w-5 h-5" aria-hidden="true" />
|
|
813
|
+
<span className="sr-only">Close dialog</span>
|
|
814
|
+
</button>
|
|
815
|
+
</Dialog.Close>
|
|
816
|
+
</div>
|
|
817
|
+
|
|
818
|
+
<div className="flex items-center gap-3 mb-6 p-4 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
|
|
819
|
+
<div className="relative">
|
|
820
|
+
<img src={user.avatar_url} alt={user.login} className="w-10 h-10 rounded-full" />
|
|
821
|
+
<div className="absolute -bottom-1 -right-1 w-5 h-5 rounded-full bg-purple-500 flex items-center justify-center text-white">
|
|
822
|
+
<div className="i-ph:github-logo w-3 h-3" />
|
|
823
|
+
</div>
|
|
824
|
+
</div>
|
|
825
|
+
<div>
|
|
826
|
+
<p className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark">
|
|
827
|
+
{user.name || user.login}
|
|
828
|
+
</p>
|
|
829
|
+
<p className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
|
|
830
|
+
@{user.login}
|
|
831
|
+
</p>
|
|
832
|
+
</div>
|
|
833
|
+
</div>
|
|
834
|
+
|
|
835
|
+
<form onSubmit={handleSubmit} className="space-y-4">
|
|
836
|
+
<div className="space-y-2">
|
|
837
|
+
<label
|
|
838
|
+
htmlFor="repoName"
|
|
839
|
+
className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark"
|
|
840
|
+
>
|
|
841
|
+
Repository Name
|
|
842
|
+
</label>
|
|
843
|
+
<div className="relative">
|
|
844
|
+
<div className="absolute left-3 top-1/2 -translate-y-1/2 text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark">
|
|
845
|
+
<span className="i-ph:git-branch w-4 h-4" />
|
|
846
|
+
</div>
|
|
847
|
+
<input
|
|
848
|
+
id="repoName"
|
|
849
|
+
type="text"
|
|
850
|
+
value={repoName}
|
|
851
|
+
onChange={(e) => {
|
|
852
|
+
const value = e.target.value;
|
|
853
|
+
setRepoName(value);
|
|
854
|
+
|
|
855
|
+
// Show real-time feedback for invalid characters
|
|
856
|
+
const sanitized = sanitizeRepoName(value);
|
|
857
|
+
|
|
858
|
+
if (value && value !== sanitized) {
|
|
859
|
+
// Show preview of sanitized name without being too intrusive
|
|
860
|
+
e.target.setAttribute('data-sanitized', sanitized);
|
|
861
|
+
} else {
|
|
862
|
+
e.target.removeAttribute('data-sanitized');
|
|
863
|
+
}
|
|
864
|
+
}}
|
|
865
|
+
placeholder="my-awesome-project"
|
|
866
|
+
className="w-full pl-10 px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark placeholder-bolt-elements-textTertiary dark:placeholder-bolt-elements-textTertiary-dark focus:outline-none focus:ring-2 focus:ring-purple-500"
|
|
867
|
+
required
|
|
868
|
+
maxLength={100}
|
|
869
|
+
pattern="[a-zA-Z0-9\-_\s]+"
|
|
870
|
+
title="Repository name can contain letters, numbers, hyphens, underscores, and spaces"
|
|
871
|
+
/>
|
|
872
|
+
</div>
|
|
873
|
+
{repoName && sanitizeRepoName(repoName) !== repoName && (
|
|
874
|
+
<p className="text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark mt-1">
|
|
875
|
+
Will be created as:{' '}
|
|
876
|
+
<span className="font-mono text-purple-600 dark:text-purple-400">
|
|
877
|
+
{sanitizeRepoName(repoName)}
|
|
878
|
+
</span>
|
|
879
|
+
</p>
|
|
880
|
+
)}
|
|
881
|
+
</div>
|
|
882
|
+
|
|
883
|
+
<div className="space-y-2">
|
|
884
|
+
<div className="flex items-center justify-between mb-2">
|
|
885
|
+
<label className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
|
|
886
|
+
Recent Repositories
|
|
887
|
+
</label>
|
|
888
|
+
<span className="text-xs text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark">
|
|
889
|
+
{filteredRepos.length} of {recentRepos.length}
|
|
890
|
+
</span>
|
|
891
|
+
</div>
|
|
892
|
+
|
|
893
|
+
<div className="mb-2">
|
|
894
|
+
<SearchInput
|
|
895
|
+
placeholder="Search repositories..."
|
|
896
|
+
value={repoSearchQuery}
|
|
897
|
+
onChange={(e) => setRepoSearchQuery(e.target.value)}
|
|
898
|
+
onClear={() => setRepoSearchQuery('')}
|
|
899
|
+
className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-sm"
|
|
900
|
+
/>
|
|
901
|
+
</div>
|
|
902
|
+
|
|
903
|
+
{recentRepos.length === 0 && !isFetchingRepos ? (
|
|
904
|
+
<EmptyState
|
|
905
|
+
icon="i-ph:github-logo"
|
|
906
|
+
title="No repositories found"
|
|
907
|
+
description="We couldn't find any repositories in your GitHub account."
|
|
908
|
+
variant="compact"
|
|
909
|
+
/>
|
|
910
|
+
) : (
|
|
911
|
+
<div className="space-y-2 max-h-[200px] overflow-y-auto pr-2 custom-scrollbar">
|
|
912
|
+
{filteredRepos.length === 0 && repoSearchQuery.trim() !== '' ? (
|
|
913
|
+
<EmptyState
|
|
914
|
+
icon="i-ph:magnifying-glass"
|
|
915
|
+
title="No matching repositories"
|
|
916
|
+
description="Try a different search term"
|
|
917
|
+
variant="compact"
|
|
918
|
+
/>
|
|
919
|
+
) : (
|
|
920
|
+
filteredRepos.map((repo) => (
|
|
921
|
+
<motion.button
|
|
922
|
+
key={repo.full_name}
|
|
923
|
+
type="button"
|
|
924
|
+
onClick={() => setRepoName(repo.name)}
|
|
925
|
+
className="w-full p-3 text-left rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 transition-colors group border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark hover:border-purple-500/30"
|
|
926
|
+
whileHover={{ scale: 1.01 }}
|
|
927
|
+
whileTap={{ scale: 0.99 }}
|
|
928
|
+
>
|
|
929
|
+
<div className="flex items-center justify-between">
|
|
930
|
+
<div className="flex items-center gap-2">
|
|
931
|
+
<div className="i-ph:git-branch w-4 h-4 text-purple-500" />
|
|
932
|
+
<span className="text-sm font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark group-hover:text-purple-500">
|
|
933
|
+
{repo.name}
|
|
934
|
+
</span>
|
|
935
|
+
</div>
|
|
936
|
+
{repo.private && (
|
|
937
|
+
<Badge variant="primary" size="sm" icon="i-ph:lock w-3 h-3">
|
|
938
|
+
Private
|
|
939
|
+
</Badge>
|
|
940
|
+
)}
|
|
941
|
+
</div>
|
|
942
|
+
{repo.description && (
|
|
943
|
+
<p className="mt-1 text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark line-clamp-2">
|
|
944
|
+
{repo.description}
|
|
945
|
+
</p>
|
|
946
|
+
)}
|
|
947
|
+
<div className="mt-2 flex items-center gap-2 flex-wrap">
|
|
948
|
+
{repo.language && (
|
|
949
|
+
<Badge variant="subtle" size="sm" icon="i-ph:code w-3 h-3">
|
|
950
|
+
{repo.language}
|
|
951
|
+
</Badge>
|
|
952
|
+
)}
|
|
953
|
+
<Badge variant="subtle" size="sm" icon="i-ph:star w-3 h-3">
|
|
954
|
+
{repo.stargazers_count.toLocaleString()}
|
|
955
|
+
</Badge>
|
|
956
|
+
<Badge variant="subtle" size="sm" icon="i-ph:git-fork w-3 h-3">
|
|
957
|
+
{repo.forks_count.toLocaleString()}
|
|
958
|
+
</Badge>
|
|
959
|
+
<Badge variant="subtle" size="sm" icon="i-ph:clock w-3 h-3">
|
|
960
|
+
{new Date(repo.updated_at).toLocaleDateString()}
|
|
961
|
+
</Badge>
|
|
962
|
+
</div>
|
|
963
|
+
</motion.button>
|
|
964
|
+
))
|
|
965
|
+
)}
|
|
966
|
+
</div>
|
|
967
|
+
)}
|
|
968
|
+
</div>
|
|
969
|
+
|
|
970
|
+
{isFetchingRepos && (
|
|
971
|
+
<div className="flex items-center justify-center py-4">
|
|
972
|
+
<StatusIndicator status="loading" pulse={true} label="Loading repositories..." />
|
|
973
|
+
</div>
|
|
974
|
+
)}
|
|
975
|
+
|
|
976
|
+
<div className="p-3 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
|
|
977
|
+
<div className="flex items-center gap-2">
|
|
978
|
+
<input
|
|
979
|
+
type="checkbox"
|
|
980
|
+
id="private"
|
|
981
|
+
checked={isPrivate}
|
|
982
|
+
onChange={(e) => setIsPrivate(e.target.checked)}
|
|
983
|
+
className="rounded border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark text-purple-500 focus:ring-purple-500 dark:bg-bolt-elements-background-depth-3"
|
|
984
|
+
/>
|
|
985
|
+
<label
|
|
986
|
+
htmlFor="private"
|
|
987
|
+
className="text-sm text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark"
|
|
988
|
+
>
|
|
989
|
+
Make repository private
|
|
990
|
+
</label>
|
|
991
|
+
</div>
|
|
992
|
+
<p className="text-xs text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark mt-2 ml-6">
|
|
993
|
+
Private repositories are only visible to you and people you share them with
|
|
994
|
+
</p>
|
|
995
|
+
</div>
|
|
996
|
+
|
|
997
|
+
<div className="pt-4 flex gap-2">
|
|
998
|
+
<motion.button
|
|
999
|
+
type="button"
|
|
1000
|
+
onClick={handleClose}
|
|
1001
|
+
className="px-4 py-2 rounded-lg bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4 text-sm border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark"
|
|
1002
|
+
whileHover={{ scale: 1.02 }}
|
|
1003
|
+
whileTap={{ scale: 0.98 }}
|
|
1004
|
+
>
|
|
1005
|
+
Cancel
|
|
1006
|
+
</motion.button>
|
|
1007
|
+
<motion.button
|
|
1008
|
+
type="submit"
|
|
1009
|
+
disabled={isLoading}
|
|
1010
|
+
className={classNames(
|
|
1011
|
+
'flex-1 px-4 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600 text-sm inline-flex items-center justify-center gap-2',
|
|
1012
|
+
isLoading ? 'opacity-50 cursor-not-allowed' : '',
|
|
1013
|
+
)}
|
|
1014
|
+
whileHover={!isLoading ? { scale: 1.02 } : {}}
|
|
1015
|
+
whileTap={!isLoading ? { scale: 0.98 } : {}}
|
|
1016
|
+
>
|
|
1017
|
+
{isLoading ? (
|
|
1018
|
+
<>
|
|
1019
|
+
<div className="i-ph:spinner-gap animate-spin w-4 h-4" />
|
|
1020
|
+
Deploying...
|
|
1021
|
+
</>
|
|
1022
|
+
) : (
|
|
1023
|
+
<>
|
|
1024
|
+
<div className="i-ph:github-logo w-4 h-4" />
|
|
1025
|
+
Deploy to GitHub
|
|
1026
|
+
</>
|
|
1027
|
+
)}
|
|
1028
|
+
</motion.button>
|
|
1029
|
+
</div>
|
|
1030
|
+
</form>
|
|
1031
|
+
</div>
|
|
1032
|
+
</Dialog.Content>
|
|
1033
|
+
</motion.div>
|
|
1034
|
+
</div>
|
|
1035
|
+
</Dialog.Portal>
|
|
1036
|
+
|
|
1037
|
+
{/* GitHub Auth Dialog */}
|
|
1038
|
+
<GitHubAuthDialog isOpen={showAuthDialog} onClose={handleAuthDialogClose} />
|
|
1039
|
+
</Dialog.Root>
|
|
1040
|
+
);
|
|
1041
|
+
}
|