mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-05-05 12:44:38 +00:00
add: various improvements to connections
- improved organisation of connections (collapsibles) - improved deploy button - improved unique chat deployments
This commit is contained in:
parent
96a0b2a066
commit
19137c934b
@ -1,73 +1,8 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { logStore } from '~/lib/stores/logs';
|
||||
import { motion } from 'framer-motion';
|
||||
import { toast } from 'react-toastify';
|
||||
import { GithubConnection } from './GithubConnection';
|
||||
import { NetlifyConnection } from './NetlifyConnection';
|
||||
|
||||
interface GitHubUserResponse {
|
||||
login: string;
|
||||
avatar_url: string;
|
||||
html_url: string;
|
||||
name: string;
|
||||
bio: string;
|
||||
public_repos: number;
|
||||
followers: number;
|
||||
following: number;
|
||||
created_at: string;
|
||||
public_gists: number;
|
||||
}
|
||||
|
||||
interface GitHubRepoInfo {
|
||||
name: string;
|
||||
full_name: string;
|
||||
html_url: string;
|
||||
description: string;
|
||||
stargazers_count: number;
|
||||
forks_count: number;
|
||||
default_branch: string;
|
||||
updated_at: string;
|
||||
languages_url: string;
|
||||
}
|
||||
|
||||
interface GitHubOrganization {
|
||||
login: string;
|
||||
avatar_url: string;
|
||||
html_url: string;
|
||||
}
|
||||
|
||||
interface GitHubEvent {
|
||||
id: string;
|
||||
type: string;
|
||||
repo: {
|
||||
name: string;
|
||||
};
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
interface GitHubLanguageStats {
|
||||
[language: string]: number;
|
||||
}
|
||||
|
||||
interface GitHubStats {
|
||||
repos: GitHubRepoInfo[];
|
||||
totalStars: number;
|
||||
totalForks: number;
|
||||
organizations: GitHubOrganization[];
|
||||
recentActivity: GitHubEvent[];
|
||||
languages: GitHubLanguageStats;
|
||||
totalGists: number;
|
||||
}
|
||||
|
||||
interface GitHubConnection {
|
||||
user: GitHubUserResponse | null;
|
||||
token: string;
|
||||
tokenType: 'classic' | 'fine-grained';
|
||||
stats?: GitHubStats;
|
||||
}
|
||||
|
||||
export default function ConnectionsTab() {
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Header */}
|
||||
@ -85,9 +20,7 @@ export default function ConnectionsTab() {
|
||||
</p>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{/* GitHub Connection */}
|
||||
<GithubConnection />
|
||||
{/* Netlify Connection */}
|
||||
<NetlifyConnection />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -73,7 +73,6 @@ export function GithubConnection() {
|
||||
});
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const [isFetchingStats, setIsFetchingStats] = useState(false);
|
||||
const [expandedSections, setExpandedSections] = useState({
|
||||
organizations: false,
|
||||
languages: false,
|
||||
@ -82,16 +81,14 @@ export function GithubConnection() {
|
||||
});
|
||||
|
||||
const toggleSection = (section: keyof typeof expandedSections) => {
|
||||
setExpandedSections(prev => ({
|
||||
setExpandedSections((prev) => ({
|
||||
...prev,
|
||||
[section]: !prev[section]
|
||||
[section]: !prev[section],
|
||||
}));
|
||||
};
|
||||
|
||||
const fetchGitHubStats = async (token: string) => {
|
||||
try {
|
||||
setIsFetchingStats(true);
|
||||
|
||||
const reposResponse = await fetch(
|
||||
'https://api.github.com/user/repos?sort=updated&per_page=10&affiliation=owner,organization_member,collaborator',
|
||||
{
|
||||
@ -168,7 +165,6 @@ export function GithubConnection() {
|
||||
logStore.logError('Failed to fetch GitHub stats', { error });
|
||||
toast.error('Failed to fetch GitHub statistics');
|
||||
} finally {
|
||||
setIsFetchingStats(false);
|
||||
}
|
||||
};
|
||||
|
||||
@ -188,6 +184,7 @@ export function GithubConnection() {
|
||||
fetchGitHubStats(parsed.token);
|
||||
}
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
}, []);
|
||||
|
||||
@ -401,16 +398,18 @@ export function GithubConnection() {
|
||||
{/* Organizations Section */}
|
||||
{connection.stats.organizations.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
<button
|
||||
onClick={() => toggleSection('organizations')}
|
||||
className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
|
||||
>
|
||||
<div className="i-ph:buildings w-4 h-4" />
|
||||
Organizations ({connection.stats.organizations.length})
|
||||
<div className={classNames(
|
||||
"i-ph:caret-down w-4 h-4 ml-auto transition-transform",
|
||||
expandedSections.organizations ? "rotate-180" : ""
|
||||
)} />
|
||||
<div
|
||||
className={classNames(
|
||||
'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
|
||||
expandedSections.organizations ? 'rotate-180' : '',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
{expandedSections.organizations && (
|
||||
<div className="flex flex-wrap gap-3 pb-4">
|
||||
@ -433,16 +432,18 @@ export function GithubConnection() {
|
||||
|
||||
{/* Languages Section */}
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
<button
|
||||
onClick={() => toggleSection('languages')}
|
||||
className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
|
||||
>
|
||||
<div className="i-ph:code w-4 h-4" />
|
||||
Top Languages ({Object.keys(connection.stats.languages).length})
|
||||
<div className={classNames(
|
||||
"i-ph:caret-down w-4 h-4 ml-auto transition-transform",
|
||||
expandedSections.languages ? "rotate-180" : ""
|
||||
)} />
|
||||
<div
|
||||
className={classNames(
|
||||
'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
|
||||
expandedSections.languages ? 'rotate-180' : '',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
{expandedSections.languages && (
|
||||
<div className="flex flex-wrap gap-2 pb-4">
|
||||
@ -463,16 +464,18 @@ export function GithubConnection() {
|
||||
|
||||
{/* Recent Activity Section */}
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
<button
|
||||
onClick={() => toggleSection('recentActivity')}
|
||||
className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
|
||||
>
|
||||
<div className="i-ph:activity w-4 h-4" />
|
||||
Recent Activity ({connection.stats.recentActivity.length})
|
||||
<div className={classNames(
|
||||
"i-ph:caret-down w-4 h-4 ml-auto transition-transform",
|
||||
expandedSections.recentActivity ? "rotate-180" : ""
|
||||
)} />
|
||||
<div
|
||||
className={classNames(
|
||||
'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
|
||||
expandedSections.recentActivity ? 'rotate-180' : '',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
{expandedSections.recentActivity && (
|
||||
<div className="space-y-3 pb-4">
|
||||
@ -503,16 +506,18 @@ export function GithubConnection() {
|
||||
|
||||
{/* Repositories Section */}
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
<button
|
||||
onClick={() => toggleSection('repositories')}
|
||||
className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
|
||||
>
|
||||
<div className="i-ph:clock-counter-clockwise w-4 h-4" />
|
||||
Recent Repositories ({connection.stats.repos.length})
|
||||
<div className={classNames(
|
||||
"i-ph:caret-down w-4 h-4 ml-auto transition-transform",
|
||||
expandedSections.repositories ? "rotate-180" : ""
|
||||
)} />
|
||||
<div
|
||||
className={classNames(
|
||||
'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
|
||||
expandedSections.repositories ? 'rotate-180' : '',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
{expandedSections.repositories && (
|
||||
<div className="space-y-3">
|
||||
@ -574,4 +579,4 @@ function LoadingSpinner() {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -214,16 +214,18 @@ export function NetlifyConnection() {
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button
|
||||
<button
|
||||
onClick={() => setIsSitesExpanded(!isSitesExpanded)}
|
||||
className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary mb-3 flex items-center gap-2"
|
||||
>
|
||||
<div className="i-ph:buildings w-4 h-4" />
|
||||
Your Sites ({connection.stats?.totalSites || 0})
|
||||
<div className={classNames(
|
||||
"i-ph:caret-down w-4 h-4 ml-auto transition-transform",
|
||||
isSitesExpanded ? "rotate-180" : ""
|
||||
)} />
|
||||
<div
|
||||
className={classNames(
|
||||
'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
|
||||
isSitesExpanded ? 'rotate-180' : '',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
{isSitesExpanded && connection.stats?.sites?.length ? (
|
||||
<div className="grid gap-3">
|
||||
|
@ -33,6 +33,7 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
|
||||
}
|
||||
}
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
|
||||
@ -109,6 +110,7 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
|
||||
}
|
||||
|
||||
const fileContents = await getAllFiles(buildPath);
|
||||
|
||||
// Use chatId instead of artifact.id
|
||||
const existingSiteId = localStorage.getItem(`netlify-site-${currentChatId}`);
|
||||
|
||||
@ -209,65 +211,64 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
|
||||
className="px-4 hover:bg-bolt-elements-item-backgroundActive flex items-center gap-2"
|
||||
>
|
||||
{isDeploying ? 'Deploying...' : 'Deploy'}
|
||||
<div className={classNames(
|
||||
"i-ph:caret-down w-4 h-4 transition-transform",
|
||||
isDropdownOpen ? "rotate-180" : ""
|
||||
)} />
|
||||
<div
|
||||
className={classNames('i-ph:caret-down w-4 h-4 transition-transform', isDropdownOpen ? 'rotate-180' : '')}
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{isDropdownOpen && (
|
||||
<div className="absolute right-2 flex flex-col gap-1 z-50 p-1 mt-1 min-w-[13.5rem] bg-bolt-elements-background-depth-2 rounded-md shadow-lg bg-bolt-elements-backgroundDefault border border-bolt-elements-borderColor">
|
||||
<Button
|
||||
active
|
||||
onClick={() => {
|
||||
handleDeploy();
|
||||
setIsDropdownOpen(false);
|
||||
}}
|
||||
disabled={isDeploying || !activePreview}
|
||||
className="flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md"
|
||||
>
|
||||
<img
|
||||
className="w-5 h-5"
|
||||
height="24"
|
||||
width="24"
|
||||
crossOrigin="anonymous"
|
||||
src="https://cdn.simpleicons.org/netlify"
|
||||
/>
|
||||
<span className='mx-auto'>Deploy to Netlify</span>
|
||||
</Button>
|
||||
<Button
|
||||
active={false}
|
||||
disabled
|
||||
className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
|
||||
>
|
||||
<span className='sr-only'>Coming Soon</span>
|
||||
<img
|
||||
className="w-5 h-5 bg-black p-1 rounded"
|
||||
height="24"
|
||||
width="24"
|
||||
crossOrigin="anonymous"
|
||||
src="https://cdn.simpleicons.org/vercel/white"
|
||||
alt='vercel'
|
||||
/>
|
||||
<span className='mx-auto'>Deploy to Vercel (Coming Soon)</span>
|
||||
</Button>
|
||||
<Button
|
||||
active={false}
|
||||
disabled
|
||||
className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
|
||||
>
|
||||
<span className='sr-only'>Coming Soon</span>
|
||||
<img
|
||||
className="w-5 h-5"
|
||||
height="24"
|
||||
width="24"
|
||||
crossOrigin="anonymous"
|
||||
src="https://cdn.simpleicons.org/cloudflare"
|
||||
alt='vercel'
|
||||
/>
|
||||
<span className='mx-auto'>Deploy to Cloudflare (Coming Soon)</span>
|
||||
</Button>
|
||||
<Button
|
||||
active
|
||||
onClick={() => {
|
||||
handleDeploy();
|
||||
setIsDropdownOpen(false);
|
||||
}}
|
||||
disabled={isDeploying || !activePreview}
|
||||
className="flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md"
|
||||
>
|
||||
<img
|
||||
className="w-5 h-5"
|
||||
height="24"
|
||||
width="24"
|
||||
crossOrigin="anonymous"
|
||||
src="https://cdn.simpleicons.org/netlify"
|
||||
/>
|
||||
<span className="mx-auto">Deploy to Netlify</span>
|
||||
</Button>
|
||||
<Button
|
||||
active={false}
|
||||
disabled
|
||||
className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
|
||||
>
|
||||
<span className="sr-only">Coming Soon</span>
|
||||
<img
|
||||
className="w-5 h-5 bg-black p-1 rounded"
|
||||
height="24"
|
||||
width="24"
|
||||
crossOrigin="anonymous"
|
||||
src="https://cdn.simpleicons.org/vercel/white"
|
||||
alt="vercel"
|
||||
/>
|
||||
<span className="mx-auto">Deploy to Vercel (Coming Soon)</span>
|
||||
</Button>
|
||||
<Button
|
||||
active={false}
|
||||
disabled
|
||||
className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
|
||||
>
|
||||
<span className="sr-only">Coming Soon</span>
|
||||
<img
|
||||
className="w-5 h-5"
|
||||
height="24"
|
||||
width="24"
|
||||
crossOrigin="anonymous"
|
||||
src="https://cdn.simpleicons.org/cloudflare"
|
||||
alt="vercel"
|
||||
/>
|
||||
<span className="mx-auto">Deploy to Cloudflare (Coming Soon)</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@ import type { ChatHistoryItem } from './useChatHistory';
|
||||
export interface IChatMetadata {
|
||||
gitUrl: string;
|
||||
gitBranch?: string;
|
||||
netlifySiteId?: string; // Add this field
|
||||
netlifySiteId?: string;
|
||||
}
|
||||
|
||||
const logger = createScopedLogger('ChatHistory');
|
||||
|
Loading…
Reference in New Issue
Block a user