mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-04-28 18:01:49 +00:00
* feat: Bulk Delete Chats from Sidebar feat(sidebar): Implement bulk chat deletion Adds the ability for users to select multiple chats from the history sidebar and delete them in bulk. **Key Changes:** * **Selection Mode:** Introduced a selection mode toggled by a dedicated button next to "Start new chat". * **Checkboxes:** Added checkboxes to each `HistoryItem` visible only when selection mode is active. * **Bulk Actions:** Added "Select All" / "Deselect All" and "Delete Selected" buttons (`Button` component with `ghost` variant) that appear above the chat list in selection mode. * **Confirmation Dialog:** Implemented a confirmation dialog (`Dialog` component) to prevent accidental deletion, listing the chats selected for removal. * **Deletion Logic:** Updated `Menu.client.tsx` to handle the selection state and perform bulk deletion using `deleteById` from persistence layer. * **Styling:** Ensured all new UI elements (`Checkbox`, `Button`) adhere to the existing project design system and support both light and dark themes using appropriate CSS classes and UnoCSS icons (`i-ph:` prefix). * **Refinement:** Replaced initial plain `<button>` elements with the project's `Button` component for consistency. Fixed incorrect icon prefixes. * Fix selection and Dark mode
227 lines
11 KiB
TypeScript
227 lines
11 KiB
TypeScript
import { motion } from 'framer-motion';
|
|
import React, { Suspense, useState } from 'react';
|
|
import { classNames } from '~/utils/classNames';
|
|
import ConnectionDiagnostics from './ConnectionDiagnostics';
|
|
import { Button } from '~/components/ui/Button';
|
|
import VercelConnection from './VercelConnection';
|
|
|
|
// 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-bolt-elements-background-depth-1 dark:bg-bolt-elements-background-depth-1 rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor">
|
|
<div className="flex items-center justify-center gap-2 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary">
|
|
<div className="i-ph:spinner-gap w-4 h-4 animate-spin" />
|
|
<span>Loading connection...</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
export default function ConnectionsTab() {
|
|
const [isEnvVarsExpanded, setIsEnvVarsExpanded] = useState(false);
|
|
const [showDiagnostics, setShowDiagnostics] = useState(false);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<motion.div
|
|
className="flex items-center justify-between gap-2"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: 0.1 }}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
<div className="i-ph:plugs-connected w-5 h-5 text-bolt-elements-item-contentAccent dark:text-bolt-elements-item-contentAccent" />
|
|
<h2 className="text-lg font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
|
|
Connection Settings
|
|
</h2>
|
|
</div>
|
|
<Button
|
|
onClick={() => setShowDiagnostics(!showDiagnostics)}
|
|
variant="outline"
|
|
className="flex items-center gap-2 hover:bg-bolt-elements-item-backgroundActive/10 hover:text-bolt-elements-textPrimary dark:hover:bg-bolt-elements-item-backgroundActive/10 dark:hover:text-bolt-elements-textPrimary transition-colors"
|
|
>
|
|
{showDiagnostics ? (
|
|
<>
|
|
<div className="i-ph:eye-slash w-4 h-4" />
|
|
Hide Diagnostics
|
|
</>
|
|
) : (
|
|
<>
|
|
<div className="i-ph:wrench w-4 h-4" />
|
|
Troubleshoot Connections
|
|
</>
|
|
)}
|
|
</Button>
|
|
</motion.div>
|
|
<p className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary">
|
|
Manage your external service connections and integrations
|
|
</p>
|
|
|
|
{/* Diagnostics Tool - Conditionally rendered */}
|
|
{showDiagnostics && <ConnectionDiagnostics />}
|
|
|
|
{/* Environment Variables Info - Collapsible */}
|
|
<motion.div
|
|
className="bg-bolt-elements-background dark:bg-bolt-elements-background rounded-lg border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: 0.2 }}
|
|
>
|
|
<div className="p-6">
|
|
<button
|
|
onClick={() => setIsEnvVarsExpanded(!isEnvVarsExpanded)}
|
|
className={classNames(
|
|
'w-full bg-transparent flex items-center justify-between',
|
|
'hover:bg-bolt-elements-item-backgroundActive/10 hover:text-bolt-elements-textPrimary',
|
|
'dark:hover:bg-bolt-elements-item-backgroundActive/10 dark:hover:text-bolt-elements-textPrimary',
|
|
'rounded-md p-2 -m-2 transition-colors',
|
|
)}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
<div className="i-ph:info w-5 h-5 text-bolt-elements-item-contentAccent dark:text-bolt-elements-item-contentAccent" />
|
|
<h3 className="text-base font-medium text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
|
|
Environment Variables
|
|
</h3>
|
|
</div>
|
|
<div
|
|
className={classNames(
|
|
'i-ph:caret-down w-4 h-4 text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary transition-transform',
|
|
isEnvVarsExpanded ? 'rotate-180' : '',
|
|
)}
|
|
/>
|
|
</button>
|
|
|
|
{isEnvVarsExpanded && (
|
|
<div className="mt-4">
|
|
<p className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary mb-2">
|
|
You can configure connections using environment variables in your{' '}
|
|
<code className="px-1 py-0.5 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 rounded">
|
|
.env.local
|
|
</code>{' '}
|
|
file:
|
|
</p>
|
|
<div className="bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 p-3 rounded-md text-xs font-mono overflow-x-auto">
|
|
<div className="text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary">
|
|
# GitHub Authentication
|
|
</div>
|
|
<div className="text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
|
|
VITE_GITHUB_ACCESS_TOKEN=your_token_here
|
|
</div>
|
|
<div className="text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary">
|
|
# Optional: Specify token type (defaults to 'classic' if not specified)
|
|
</div>
|
|
<div className="text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
|
|
VITE_GITHUB_TOKEN_TYPE=classic|fine-grained
|
|
</div>
|
|
<div className="text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary mt-2">
|
|
# Netlify Authentication
|
|
</div>
|
|
<div className="text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary">
|
|
VITE_NETLIFY_ACCESS_TOKEN=your_token_here
|
|
</div>
|
|
</div>
|
|
<div className="mt-3 text-xs text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary space-y-1">
|
|
<p>
|
|
<span className="font-medium">Token types:</span>
|
|
</p>
|
|
<ul className="list-disc list-inside pl-2 space-y-1">
|
|
<li>
|
|
<span className="font-medium">classic</span> - Personal Access Token with{' '}
|
|
<code className="px-1 py-0.5 bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 rounded">
|
|
repo, read:org, read:user
|
|
</code>{' '}
|
|
scopes
|
|
</li>
|
|
<li>
|
|
<span className="font-medium">fine-grained</span> - Fine-grained token with Repository and
|
|
Organization access
|
|
</li>
|
|
</ul>
|
|
<p className="mt-2">
|
|
When set, these variables will be used automatically without requiring manual connection.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Cloudflare Deployment Note - Highly visible */}
|
|
<motion.div
|
|
className="bg-gradient-to-r from-blue-50 to-blue-100 dark:from-blue-950/40 dark:to-blue-900/30 border border-blue-200 dark:border-blue-800/50 rounded-lg shadow-sm p-4 mb-6"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ delay: 0.3 }}
|
|
>
|
|
<div className="flex items-center gap-2 mb-2 text-blue-700 dark:text-blue-400">
|
|
<div className="i-ph:cloud-bold w-5 h-5" />
|
|
<h3 className="text-base font-medium">Using Cloudflare Pages?</h3>
|
|
</div>
|
|
<p className="text-sm text-blue-700 dark:text-blue-300 mb-2">
|
|
If you're experiencing GitHub connection issues (500 errors) on Cloudflare Pages deployments, you need to
|
|
configure environment variables in your Cloudflare dashboard:
|
|
</p>
|
|
<div className="bg-white/80 dark:bg-slate-900/60 rounded-md p-3 text-sm border border-blue-200 dark:border-blue-800/50">
|
|
<ol className="list-decimal list-inside pl-2 text-blue-700 dark:text-blue-300 space-y-2">
|
|
<li>
|
|
Go to <strong>Cloudflare Pages dashboard → Your project → Settings → Environment variables</strong>
|
|
</li>
|
|
<li>
|
|
Add <strong>both</strong> of these secrets (Production environment):
|
|
<ul className="list-disc list-inside pl-4 mt-1 mb-1">
|
|
<li>
|
|
<code className="px-1 py-0.5 bg-blue-100 dark:bg-blue-800/40 rounded">GITHUB_ACCESS_TOKEN</code>{' '}
|
|
(server-side API calls)
|
|
</li>
|
|
<li>
|
|
<code className="px-1 py-0.5 bg-blue-100 dark:bg-blue-800/40 rounded">VITE_GITHUB_ACCESS_TOKEN</code>{' '}
|
|
(client-side access)
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
Add <code className="px-1 py-0.5 bg-blue-100 dark:bg-blue-800/40 rounded">VITE_GITHUB_TOKEN_TYPE</code> if
|
|
using fine-grained tokens
|
|
</li>
|
|
<li>Deploy a fresh build after adding these variables</li>
|
|
</ol>
|
|
</div>
|
|
</motion.div>
|
|
|
|
<div className="grid grid-cols-1 gap-6">
|
|
<Suspense fallback={<LoadingFallback />}>
|
|
<GitHubConnection />
|
|
</Suspense>
|
|
<Suspense fallback={<LoadingFallback />}>
|
|
<NetlifyConnection />
|
|
</Suspense>
|
|
<Suspense fallback={<LoadingFallback />}>
|
|
<VercelConnection />
|
|
</Suspense>
|
|
</div>
|
|
|
|
{/* Additional help text */}
|
|
<div className="text-sm text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-2 p-4 rounded-lg">
|
|
<p className="flex items-center gap-1 mb-2">
|
|
<span className="i-ph:lightbulb w-4 h-4 text-bolt-elements-icon-success dark:text-bolt-elements-icon-success" />
|
|
<span className="font-medium">Troubleshooting Tip:</span>
|
|
</p>
|
|
<p className="mb-2">
|
|
If you're having trouble with connections, try using the troubleshooting tool at the top of this page. It can
|
|
help diagnose and fix common connection issues.
|
|
</p>
|
|
<p>For persistent issues:</p>
|
|
<ol className="list-decimal list-inside pl-4 mt-1">
|
|
<li>Check your browser console for errors</li>
|
|
<li>Verify that your tokens have the correct permissions</li>
|
|
<li>Try clearing your browser cache and cookies</li>
|
|
<li>Ensure your browser allows third-party cookies if using integrations</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|