Merge branch 'stackblitz-labs:main' into supabase

This commit is contained in:
KevIsDev
2025-03-19 22:20:00 +00:00
committed by GitHub
53 changed files with 6962 additions and 3774 deletions

View File

@@ -1,6 +1,19 @@
import { motion } from 'framer-motion';
import { GithubConnection } from './GithubConnection';
import { NetlifyConnection } from './NetlifyConnection';
import React, { Suspense } from 'react';
// Use React.lazy for dynamic imports
const GithubConnection = React.lazy(() => import('./GithubConnection'));
const NetlifyConnection = React.lazy(() => import('./NetlifyConnection'));
// Loading fallback component
const LoadingFallback = () => (
<div className="p-4 bg-white dark:bg-[#0A0A0A] rounded-lg border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="flex items-center gap-2 text-bolt-elements-textSecondary">
<div className="i-ph:spinner-gap w-5 h-5 animate-spin" />
<span>Loading connection...</span>
</div>
</div>
);
export default function ConnectionsTab() {
return (
@@ -20,8 +33,12 @@ export default function ConnectionsTab() {
</p>
<div className="grid grid-cols-1 gap-4">
<GithubConnection />
<NetlifyConnection />
<Suspense fallback={<LoadingFallback />}>
<GithubConnection />
</Suspense>
<Suspense fallback={<LoadingFallback />}>
<NetlifyConnection />
</Suspense>
</div>
</div>
);

View File

@@ -66,7 +66,7 @@ interface GitHubConnection {
stats?: GitHubStats;
}
export function GithubConnection() {
export default function GithubConnection() {
const [connection, setConnection] = useState<GitHubConnection>({
user: null,
token: '',
@@ -77,6 +77,46 @@ export function GithubConnection() {
const [isFetchingStats, setIsFetchingStats] = useState(false);
const [isStatsExpanded, setIsStatsExpanded] = useState(false);
const fetchGithubUser = async (token: string) => {
try {
setIsConnecting(true);
const response = await fetch('https://api.github.com/user', {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error('Invalid token or unauthorized');
}
const data = (await response.json()) as GitHubUserResponse;
const newConnection: GitHubConnection = {
user: data,
token,
tokenType: connection.tokenType,
};
localStorage.setItem('github_connection', JSON.stringify(newConnection));
Cookies.set('githubToken', token);
Cookies.set('githubUsername', data.login);
Cookies.set('git:github.com', JSON.stringify({ username: token, password: 'x-oauth-basic' }));
setConnection(newConnection);
await fetchGitHubStats(token);
toast.success('Successfully connected to GitHub');
} catch (error) {
logStore.logError('Failed to authenticate with GitHub', { error });
toast.error('Failed to connect to GitHub');
setConnection({ user: null, token: '', tokenType: 'classic' });
} finally {
setIsConnecting(false);
}
};
const fetchGitHubStats = async (token: string) => {
try {
setIsFetchingStats(true);
@@ -182,51 +222,25 @@ export function GithubConnection() {
setIsLoading(false);
}, []);
useEffect(() => {
if (!connection) {
return;
}
const token = connection.token;
const data = connection.user;
Cookies.set('githubToken', token);
Cookies.set('git:github.com', JSON.stringify({ username: token, password: 'x-oauth-basic' }));
if (data) {
Cookies.set('githubUsername', data.login);
}
}, [connection]);
if (isLoading || isConnecting || isFetchingStats) {
return <LoadingSpinner />;
}
const fetchGithubUser = async (token: string) => {
try {
setIsConnecting(true);
const response = await fetch('https://api.github.com/user', {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error('Invalid token or unauthorized');
}
const data = (await response.json()) as GitHubUserResponse;
const newConnection: GitHubConnection = {
user: data,
token,
tokenType: connection.tokenType,
};
localStorage.setItem('github_connection', JSON.stringify(newConnection));
Cookies.set('githubToken', token);
Cookies.set('githubUsername', data.login);
Cookies.set('git:github.com', JSON.stringify({ username: token, password: 'x-oauth-basic' }));
setConnection(newConnection);
await fetchGitHubStats(token);
toast.success('Successfully connected to GitHub');
} catch (error) {
logStore.logError('Failed to authenticate with GitHub', { error });
toast.error('Failed to connect to GitHub');
setConnection({ user: null, token: '', tokenType: 'classic' });
} finally {
setIsConnecting(false);
}
};
const handleConnect = async (event: React.FormEvent) => {
event.preventDefault();
await fetchGithubUser(connection.token);

View File

@@ -13,7 +13,7 @@ import {
} from '~/lib/stores/netlify';
import type { NetlifyUser } from '~/types/netlify';
export function NetlifyConnection() {
export default function NetlifyConnection() {
const connection = useStore(netlifyConnection);
const connecting = useStore(isConnecting);
const fetchingStats = useStore(isFetchingStats);

View File

@@ -292,11 +292,24 @@ export function RepositorySelectionDialog({ isOpen, onClose, onSelect }: Reposit
const connection = getLocalStorage('github_connection');
const headers: HeadersInit = connection?.token ? { Authorization: `Bearer ${connection.token}` } : {};
// Fetch repository tree
const treeResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/main?recursive=1`, {
const repoObjResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
headers,
});
const repoObjData = (await repoObjResponse.json()) as any;
if (!repoObjData.default_branch) {
throw new Error('Failed to fetch repository branch');
}
const defaultBranch = repoObjData.default_branch;
// Fetch repository tree
const treeResponse = await fetch(
`https://api.github.com/repos/${owner}/${repo}/git/trees/${defaultBranch}?recursive=1`,
{
headers,
},
);
if (!treeResponse.ok) {
throw new Error('Failed to fetch repository structure');

View File

@@ -1353,7 +1353,9 @@ export default function DebugTab() {
</div>
<div className="text-xs text-bolt-elements-textSecondary mt-2 flex items-center gap-1.5">
<div className="i-ph:code w-3.5 h-3.5 text-purple-500" />
DOM Ready: {systemInfo ? (systemInfo.performance.timing.domReadyTime / 1000).toFixed(2) : '-'}s
DOM Ready: {systemInfo
? (systemInfo.performance.timing.domReadyTime / 1000).toFixed(2)
: '-'}s
</div>
</div>

View File

@@ -323,7 +323,16 @@ export const ChatImpl = memo(
{
id: `1-${new Date().getTime()}`,
role: 'user',
content: messageContent,
content: [
{
type: 'text',
text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${messageContent}`,
},
...imageDataList.map((imageData) => ({
type: 'image',
image: imageData,
})),
] as any,
},
{
id: `2-${new Date().getTime()}`,
@@ -338,6 +347,15 @@ export const ChatImpl = memo(
},
]);
reload();
setInput('');
Cookies.remove(PROMPT_COOKIE_KEY);
setUploadedFiles([]);
setImageDataList([]);
resetEnhancer();
textareaRef.current?.blur();
setFakeLoading(false);
return;
@@ -364,6 +382,15 @@ export const ChatImpl = memo(
]);
reload();
setFakeLoading(false);
setInput('');
Cookies.remove(PROMPT_COOKIE_KEY);
setUploadedFiles([]);
setImageDataList([]);
resetEnhancer();
textareaRef.current?.blur();
return;
}