Revert "fix: resolve chat conversation hanging and stream interruption issues (#1971)"

This reverts commit e68593f22d.
This commit is contained in:
Stijnus
2025-09-07 00:14:13 +02:00
committed by Stijnus
parent e68593f22d
commit 37217a5c7b
61 changed files with 1432 additions and 8811 deletions

View File

@@ -3,8 +3,7 @@ import { toast } from 'react-toastify';
import { classNames } from '~/utils/classNames';
import { useStore } from '@nanostores/react';
import { netlifyConnection, updateNetlifyConnection, initializeNetlifyConnection } from '~/lib/stores/netlify';
import type { NetlifySite, NetlifyDeploy, NetlifyBuild } from '~/types/netlify';
import { NetlifyQuickConnect } from './NetlifyQuickConnect';
import type { NetlifySite, NetlifyDeploy, NetlifyBuild, NetlifyUser } from '~/types/netlify';
import {
CloudIcon,
BuildingLibraryIcon,
@@ -43,16 +42,29 @@ interface SiteAction {
}
export default function NetlifyConnection() {
console.log('NetlifyConnection component mounted');
const connection = useStore(netlifyConnection);
const [tokenInput, setTokenInput] = useState('');
const [fetchingStats, setFetchingStats] = useState(false);
const [sites, setSites] = useState<NetlifySite[]>([]);
const [deploys, setDeploys] = useState<NetlifyDeploy[]>([]);
const [builds, setBuilds] = useState<NetlifyBuild[]>([]);
console.log('NetlifyConnection initial state:', {
connection: {
user: connection.user,
token: connection.token ? '[TOKEN_EXISTS]' : '[NO_TOKEN]',
},
envToken: import.meta.env?.VITE_NETLIFY_ACCESS_TOKEN ? '[ENV_TOKEN_EXISTS]' : '[NO_ENV_TOKEN]',
});
const [deploymentCount, setDeploymentCount] = useState(0);
const [lastUpdated, setLastUpdated] = useState('');
const [isStatsOpen, setIsStatsOpen] = useState(false);
const [activeSiteIndex, setActiveSiteIndex] = useState(0);
const [isActionLoading, setIsActionLoading] = useState(false);
const [isConnecting, setIsConnecting] = useState(false);
// Add site actions
const siteActions: SiteAction[] = [
@@ -139,6 +151,8 @@ export default function NetlifyConnection() {
};
useEffect(() => {
console.log('Netlify: Running initialization useEffect');
// Initialize connection with environment token if available
initializeNetlifyConnection();
}, []);
@@ -159,6 +173,46 @@ export default function NetlifyConnection() {
}
}, [connection]);
const handleConnect = async () => {
if (!tokenInput) {
toast.error('Please enter a Netlify API token');
return;
}
setIsConnecting(true);
try {
const response = await fetch('https://api.netlify.com/api/v1/user', {
headers: {
Authorization: `Bearer ${tokenInput}`,
},
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const userData = (await response.json()) as NetlifyUser;
// Update the connection store
updateNetlifyConnection({
user: userData,
token: tokenInput,
});
toast.success('Connected to Netlify successfully');
// Fetch stats after successful connection
fetchNetlifyStats(tokenInput);
} catch (error) {
console.error('Error connecting to Netlify:', error);
toast.error(`Failed to connect to Netlify: ${error instanceof Error ? error.message : 'Unknown error'}`);
} finally {
setIsConnecting(false);
setTokenInput('');
}
};
const handleDisconnect = () => {
// Clear from localStorage
localStorage.removeItem('netlify_connection');
@@ -608,15 +662,76 @@ export default function NetlifyConnection() {
{!connection.user ? (
<div className="mt-4">
<NetlifyQuickConnect
onSuccess={() => {
// Fetch stats after successful connection
if (connection.token) {
fetchNetlifyStats(connection.token);
}
}}
showInstructions={true}
<label className="block text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary mb-2">
API Token
</label>
<input
type="password"
value={tokenInput}
onChange={(e) => setTokenInput(e.target.value)}
placeholder="Enter your Netlify API token"
className={classNames(
'w-full px-3 py-2 rounded-lg text-sm',
'bg-[#F8F8F8] dark:bg-[#1A1A1A]',
'border border-[#E5E5E5] dark:border-[#333333]',
'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary',
'focus:outline-none focus:ring-1 focus:ring-bolt-elements-borderColorActive',
'disabled:opacity-50',
)}
/>
<div className="mt-2 text-sm text-bolt-elements-textSecondary">
<a
href="https://app.netlify.com/user/applications#personal-access-tokens"
target="_blank"
rel="noopener noreferrer"
className="text-bolt-elements-borderColorActive hover:underline inline-flex items-center gap-1"
>
Get your token
<div className="i-ph:arrow-square-out w-4 h-4" />
</a>
</div>
{/* Debug info - remove this later */}
<div className="mt-2 text-xs text-gray-500">
<p>Debug: Token present: {connection.token ? '✅' : '❌'}</p>
<p>Debug: User present: {connection.user ? '✅' : '❌'}</p>
<p>Debug: Env token: {import.meta.env?.VITE_NETLIFY_ACCESS_TOKEN ? '✅' : '❌'}</p>
</div>
<div className="flex gap-2 mt-4">
<button
onClick={handleConnect}
disabled={isConnecting || !tokenInput}
className={classNames(
'px-4 py-2 rounded-lg text-sm flex items-center gap-2',
'bg-[#303030] text-white',
'hover:bg-[#5E41D0] hover:text-white',
'disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200',
'transform active:scale-95',
)}
>
{isConnecting ? (
<>
<div className="i-ph:spinner-gap animate-spin" />
Connecting...
</>
) : (
<>
<div className="i-ph:plug-charging w-4 h-4" />
Connect
</>
)}
</button>
{/* Debug button - remove this later */}
<button
onClick={async () => {
console.log('Manual Netlify auto-connect test');
await initializeNetlifyConnection();
}}
className="px-3 py-2 rounded-lg text-xs bg-blue-500 text-white hover:bg-blue-600"
>
Test Auto-Connect
</button>
</div>
</div>
) : (
<div className="flex flex-col w-full gap-4 mt-4">

View File

@@ -1,226 +0,0 @@
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import { updateNetlifyConnection } from '~/lib/stores/netlify';
import { classNames } from '~/utils/classNames';
interface NetlifyQuickConnectProps {
onSuccess?: () => void;
showInstructions?: boolean;
}
export const NetlifyQuickConnect: React.FC<NetlifyQuickConnectProps> = ({ onSuccess, showInstructions = true }) => {
const [token, setToken] = useState('');
const [isConnecting, setIsConnecting] = useState(false);
const [showHelp, setShowHelp] = useState(false);
const handleConnect = async () => {
if (!token.trim()) {
toast.error('Please enter your Netlify API token');
return;
}
setIsConnecting(true);
try {
// Validate token with Netlify API
const response = await fetch('https://api.netlify.com/api/v1/user', {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error('Invalid token or authentication failed');
}
const userData = (await response.json()) as any;
// Fetch initial site statistics
const sitesResponse = await fetch('https://api.netlify.com/api/v1/sites', {
headers: {
Authorization: `Bearer ${token}`,
},
});
let sites: any[] = [];
if (sitesResponse.ok) {
sites = (await sitesResponse.json()) as any[];
}
// Update the connection store
updateNetlifyConnection({
user: userData,
token,
stats: {
sites,
totalSites: sites.length,
deploys: [],
builds: [],
lastDeployTime: '',
},
});
toast.success(`Connected to Netlify as ${userData.email || userData.name || 'User'}`);
setToken(''); // Clear the token field
if (onSuccess) {
onSuccess();
}
} catch (error) {
console.error('Netlify connection error:', error);
toast.error('Failed to connect to Netlify. Please check your token.');
} finally {
setIsConnecting(false);
}
};
return (
<div className="space-y-4">
<div className="space-y-3">
<div>
<div className="flex items-center justify-between mb-2">
<label className="block text-sm font-medium text-bolt-elements-textPrimary">Personal Access Token</label>
{showInstructions && (
<button
onClick={() => setShowHelp(!showHelp)}
className="text-xs text-accent-500 hover:text-accent-600 flex items-center gap-1"
>
<span className={classNames('i-ph:question-circle', showHelp ? 'text-accent-600' : '')} />
How to get token
</button>
)}
</div>
<div className="relative">
<input
type="password"
value={token}
onChange={(e) => setToken(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter' && token.trim() && !isConnecting) {
handleConnect();
}
}}
placeholder="Enter your Netlify API token"
className={classNames(
'w-full px-3 py-2 pr-10 rounded-lg text-sm',
'bg-bolt-elements-background-depth-1',
'border border-bolt-elements-borderColor',
'text-bolt-elements-textPrimary placeholder-bolt-elements-textTertiary',
'focus:outline-none focus:ring-2 focus:ring-accent-500 focus:border-transparent',
'disabled:opacity-50',
)}
disabled={isConnecting}
/>
{token && (
<button
onClick={() => setToken('')}
className="absolute right-3 top-1/2 -translate-y-1/2 text-bolt-elements-textTertiary hover:text-bolt-elements-textSecondary"
>
<span className="i-ph:x text-lg" />
</button>
)}
</div>
</div>
{showHelp && showInstructions && (
<div className="bg-bolt-elements-background-depth-2 rounded-lg p-4 space-y-3 animate-in fade-in-0 slide-in-from-top-2">
<div className="flex items-start gap-2">
<span className="i-ph:info text-accent-500 mt-0.5" />
<div className="space-y-2 text-sm">
<p className="font-medium text-bolt-elements-textPrimary">
Getting your Netlify Personal Access Token:
</p>
<ol className="space-y-2 text-bolt-elements-textSecondary">
<li className="flex items-start gap-2">
<span className="text-accent-500 font-medium">1.</span>
<span>
Go to{' '}
<a
href="https://app.netlify.com/user/applications#personal-access-tokens"
target="_blank"
rel="noopener noreferrer"
className="text-accent-500 hover:text-accent-600 underline inline-flex items-center gap-1"
>
Netlify Account Settings
<span className="i-ph:arrow-square-out text-xs" />
</a>
</span>
</li>
<li className="flex items-start gap-2">
<span className="text-accent-500 font-medium">2.</span>
<span>Navigate to "Applications" "Personal access tokens"</span>
</li>
<li className="flex items-start gap-2">
<span className="text-accent-500 font-medium">3.</span>
<span>Click "New access token"</span>
</li>
<li className="flex items-start gap-2">
<span className="text-accent-500 font-medium">4.</span>
<span>Give it a descriptive name (e.g., "bolt.diy deployment")</span>
</li>
<li className="flex items-start gap-2">
<span className="text-accent-500 font-medium">5.</span>
<span>Copy the token and paste it above</span>
</li>
</ol>
<div className="pt-2 border-t border-bolt-elements-borderColor">
<p className="text-xs text-bolt-elements-textTertiary">
<strong>Note:</strong> Keep your token safe! It provides full access to your Netlify account.
</p>
</div>
</div>
</div>
</div>
)}
<div className="flex gap-3">
<a
href="https://app.netlify.com/user/applications#personal-access-tokens"
target="_blank"
rel="noopener noreferrer"
className="px-4 py-2 rounded-lg border border-bolt-elements-borderColor text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-2 transition-all text-sm font-medium flex items-center gap-2"
>
<span className="i-ph:arrow-square-out" />
Get Token
</a>
<button
onClick={handleConnect}
disabled={isConnecting || !token.trim()}
className={classNames(
'flex-1 px-4 py-2 rounded-lg font-medium transition-all text-sm',
'bg-accent-500 text-white',
'hover:bg-accent-600',
'disabled:opacity-50 disabled:cursor-not-allowed',
'flex items-center justify-center gap-2',
)}
>
{isConnecting ? (
<>
<span className="i-svg-spinners:3-dots-scale" />
Connecting...
</>
) : (
<>
<span className="i-ph:plug-charging" />
Connect to Netlify
</>
)}
</button>
</div>
</div>
<div className="p-3 bg-accent-500/10 border border-accent-500/20 rounded-lg">
<div className="flex items-start gap-2">
<span className="i-ph:lightning text-accent-500 mt-0.5" />
<div className="space-y-1">
<p className="text-sm font-medium text-bolt-elements-textPrimary">Quick Tip</p>
<p className="text-xs text-bolt-elements-textSecondary">
Once connected, you can deploy any project with a single click directly from the editor!
</p>
</div>
</div>
</div>
</div>
);
};