V1 : Release of the new Settings Dashboard
# 🚀 Release v1.0.0 ## What's Changed 🌟 ### 🎨 UI/UX Improvements - **Dark Mode Support** - Implemented comprehensive dark theme across all components - Enhanced contrast and readability in dark mode - Added smooth theme transitions - Optimized dialog overlays and backdrops ### 🛠️ Settings Panel - **Data Management** - Added chat history export/import functionality - Implemented settings backup and restore - Added secure data deletion with confirmations - Added profile customization options - **Provider Management** - Added comprehensive provider configuration - Implemented URL-configurable providers - Added local model support (Ollama, LMStudio) - Added provider health checks - Added provider status indicators - **Ollama Integration** - Added Ollama Model Manager with real-time updates - Implemented model version tracking - Added bulk update capability - Added progress tracking for model updates - Displays model details (parameter size, quantization) - **GitHub Integration** - Added GitHub connection management - Implemented secure token storage - Added connection state persistence - Real-time connection status updates - Proper error handling and user feedback ### 📊 Event Logging - **System Monitoring** - Added real-time event logging system - Implemented log filtering by type (info, warning, error, debug) - Added log export functionality - Added auto-scroll and search capabilities - Enhanced log visualization with color coding ### 💫 Animations & Interactions - Added smooth page transitions - Implemented loading states with spinners - Added micro-interactions for better feedback - Enhanced button hover and active states - Added motion effects for UI elements ### 🔐 Security Features - Secure token storage - Added confirmation dialogs for destructive actions - Implemented data validation - Added file size and type validation - Secure connection management ### ♿️ Accessibility - Improved keyboard navigation - Enhanced screen reader support - Added ARIA labels and descriptions - Implemented focus management - Added proper dialog accessibility ### 🎯 Developer Experience - Added comprehensive debug information - Implemented system status monitoring - Added version control integration - Enhanced error handling and reporting - Added detailed logging system --- ## 🔧 Technical Details - **Frontend Stack** - React 18 with TypeScript - Framer Motion for animations - TailwindCSS for styling - Radix UI for accessible components - **State Management** - Local storage for persistence - React hooks for state - Custom stores for global state - **API Integration** - GitHub API integration - Ollama API integration - Provider API management - Error boundary implementation ## 📝 Notes - Initial release focusing on core functionality and user experience - Enhanced dark mode support across all components - Improved accessibility and keyboard navigation - Added comprehensive logging and debugging tools - Implemented robust error handling and user feedback
This commit is contained in:
@@ -2,6 +2,9 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useSettings } from '~/lib/hooks/useSettings';
|
||||
import { toast } from 'react-toastify';
|
||||
import { providerBaseUrlEnvKeys } from '~/utils/constants';
|
||||
import { motion } from 'framer-motion';
|
||||
import { classNames } from '~/utils/classNames';
|
||||
import { settingsStyles } from '~/components/settings/settings.styles';
|
||||
|
||||
interface ProviderStatus {
|
||||
name: string;
|
||||
@@ -438,107 +441,182 @@ export default function DebugTab() {
|
||||
}, [activeProviders, systemInfo, isLatestBranch]);
|
||||
|
||||
return (
|
||||
<div className="p-4 space-y-6">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-medium text-bolt-elements-textPrimary">Debug Information</h3>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="i-ph:bug-fill text-xl text-purple-500" />
|
||||
<h3 className="text-lg font-medium text-bolt-elements-textPrimary">Debug Information</h3>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
<motion.button
|
||||
onClick={handleCopyToClipboard}
|
||||
className="bg-bolt-elements-button-primary-background rounded-lg px-4 py-2 transition-colors duration-200 hover:bg-bolt-elements-button-primary-backgroundHover text-bolt-elements-button-primary-text"
|
||||
className={classNames(settingsStyles.button.base, settingsStyles.button.primary)}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
>
|
||||
<div className="i-ph:copy" />
|
||||
Copy Debug Info
|
||||
</button>
|
||||
<button
|
||||
</motion.button>
|
||||
<motion.button
|
||||
onClick={handleCheckForUpdate}
|
||||
disabled={isCheckingUpdate}
|
||||
className={`bg-bolt-elements-button-primary-background rounded-lg px-4 py-2 transition-colors duration-200
|
||||
${!isCheckingUpdate ? 'hover:bg-bolt-elements-button-primary-backgroundHover' : 'opacity-75 cursor-not-allowed'}
|
||||
text-bolt-elements-button-primary-text`}
|
||||
className={classNames(settingsStyles.button.base, settingsStyles.button.primary)}
|
||||
whileHover={!isCheckingUpdate ? { scale: 1.02 } : undefined}
|
||||
whileTap={!isCheckingUpdate ? { scale: 0.98 } : undefined}
|
||||
>
|
||||
{isCheckingUpdate ? 'Checking...' : 'Check for Updates'}
|
||||
</button>
|
||||
{isCheckingUpdate ? (
|
||||
<>
|
||||
<div className={settingsStyles['loading-spinner']} />
|
||||
Checking...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="i-ph:arrow-clockwise" />
|
||||
Check for Updates
|
||||
</>
|
||||
)}
|
||||
</motion.button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{updateMessage && (
|
||||
<div
|
||||
className={`bg-bolt-elements-surface rounded-lg p-3 ${
|
||||
updateMessage.includes('Update available') ? 'border-l-4 border-yellow-400' : ''
|
||||
}`}
|
||||
>
|
||||
<p className="text-bolt-elements-textSecondary whitespace-pre-line">{updateMessage}</p>
|
||||
{updateMessage.includes('Update available') && (
|
||||
<div className="mt-3 text-sm">
|
||||
<p className="font-medium text-bolt-elements-textPrimary">To update:</p>
|
||||
<ol className="list-decimal ml-4 mt-1 text-bolt-elements-textSecondary">
|
||||
<li>
|
||||
Pull the latest changes:{' '}
|
||||
<code className="bg-bolt-elements-surface-hover px-1 rounded">git pull upstream main</code>
|
||||
</li>
|
||||
<li>
|
||||
Install any new dependencies:{' '}
|
||||
<code className="bg-bolt-elements-surface-hover px-1 rounded">pnpm install</code>
|
||||
</li>
|
||||
<li>Restart the application</li>
|
||||
</ol>
|
||||
</div>
|
||||
<motion.div
|
||||
className={classNames(
|
||||
settingsStyles.card,
|
||||
'bg-bolt-elements-background-depth-2',
|
||||
updateMessage.includes('Update available') ? 'border-l-4 border-yellow-500' : '',
|
||||
)}
|
||||
</div>
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div
|
||||
className={classNames(
|
||||
updateMessage.includes('Update available')
|
||||
? 'i-ph:warning-fill text-yellow-500'
|
||||
: 'i-ph:info text-bolt-elements-textSecondary',
|
||||
'text-xl flex-shrink-0',
|
||||
)}
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="text-bolt-elements-textSecondary whitespace-pre-line">{updateMessage}</p>
|
||||
{updateMessage.includes('Update available') && (
|
||||
<div className="mt-3">
|
||||
<p className="font-medium text-bolt-elements-textPrimary">To update:</p>
|
||||
<ol className="list-decimal ml-4 mt-1 space-y-2">
|
||||
<li className="text-bolt-elements-textSecondary">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="i-ph:git-branch text-purple-500" />
|
||||
Pull the latest changes:{' '}
|
||||
<code className="px-1.5 py-0.5 rounded bg-bolt-elements-background-depth-3 text-bolt-elements-textPrimary">
|
||||
git pull upstream main
|
||||
</code>
|
||||
</div>
|
||||
</li>
|
||||
<li className="text-bolt-elements-textSecondary">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="i-ph:package text-purple-500" />
|
||||
Install any new dependencies:{' '}
|
||||
<code className="px-1.5 py-0.5 rounded bg-bolt-elements-background-depth-3 text-bolt-elements-textPrimary">
|
||||
pnpm install
|
||||
</code>
|
||||
</div>
|
||||
</li>
|
||||
<li className="text-bolt-elements-textSecondary">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="i-ph:arrows-clockwise text-purple-500" />
|
||||
Restart the application
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
<section className="space-y-4">
|
||||
<div>
|
||||
<h4 className="text-md font-medium text-bolt-elements-textPrimary mb-2">System Information</h4>
|
||||
<div className="bg-bolt-elements-surface rounded-lg p-4">
|
||||
<motion.div className="space-y-4">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<div className="i-ph:desktop text-xl text-purple-500" />
|
||||
<h4 className="text-md font-medium text-bolt-elements-textPrimary">System Information</h4>
|
||||
</div>
|
||||
<motion.div className={classNames(settingsStyles.card, 'bg-bolt-elements-background-depth-2')}>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Operating System</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:computer-tower text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Operating System</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.os}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Device Type</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:device-mobile text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Device Type</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.deviceType}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Browser</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:browser text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Browser</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.browser}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Display</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:monitor text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Display</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">
|
||||
{systemInfo.screen} ({systemInfo.colorDepth}) @{systemInfo.pixelRatio}x
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Connection</p>
|
||||
<p className="text-sm font-medium flex items-center gap-2">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:wifi-high text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Connection</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span
|
||||
className={`inline-block w-2 h-2 rounded-full ${systemInfo.online ? 'bg-green-500' : 'bg-red-500'}`}
|
||||
className={classNames('w-2 h-2 rounded-full', systemInfo.online ? 'bg-green-500' : 'bg-red-500')}
|
||||
/>
|
||||
<span className={`${systemInfo.online ? 'text-green-600' : 'text-red-600'}`}>
|
||||
<span
|
||||
className={classNames('text-sm font-medium', systemInfo.online ? 'text-green-500' : 'text-red-500')}
|
||||
>
|
||||
{systemInfo.online ? 'Online' : 'Offline'}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Screen Resolution</p>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.screen}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Language</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:translate text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Language</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.language}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Timezone</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:clock text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Timezone</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.timezone}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-bolt-elements-textSecondary">CPU Cores</p>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:cpu text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">CPU Cores</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.cores}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 pt-3 border-t border-bolt-elements-surface-hover">
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Version</p>
|
||||
<div className="mt-3 pt-3 border-t border-bolt-elements-borderColor">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<div className="i-ph:git-commit text-bolt-elements-textSecondary" />
|
||||
<p className="text-xs text-bolt-elements-textSecondary">Version</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium text-bolt-elements-textPrimary font-mono">
|
||||
{connitJson.commit.slice(0, 7)}
|
||||
<span className="ml-2 text-xs text-bolt-elements-textSecondary">
|
||||
@@ -546,22 +624,31 @@ export default function DebugTab() {
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-md font-medium text-bolt-elements-textPrimary mb-2">Local LLM Status</h4>
|
||||
<div className="bg-bolt-elements-surface rounded-lg">
|
||||
<div className="grid grid-cols-1 divide-y">
|
||||
<motion.div
|
||||
className="space-y-4"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<div className="i-ph:robot text-xl text-purple-500" />
|
||||
<h4 className="text-md font-medium text-bolt-elements-textPrimary">Local LLM Status</h4>
|
||||
</div>
|
||||
<motion.div className={classNames(settingsStyles.card, 'bg-bolt-elements-background-depth-2')}>
|
||||
<div className="divide-y divide-bolt-elements-borderColor">
|
||||
{activeProviders.map((provider) => (
|
||||
<div key={provider.name} className="p-3 flex flex-col space-y-2">
|
||||
<div key={provider.name} className="p-4 first:pt-0 last:pb-0">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex-shrink-0">
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
!provider.enabled ? 'bg-gray-300' : provider.isRunning ? 'bg-green-400' : 'bg-red-400'
|
||||
}`}
|
||||
className={classNames(
|
||||
'w-2 h-2 rounded-full',
|
||||
!provider.enabled ? 'bg-gray-400' : provider.isRunning ? 'bg-green-500' : 'bg-red-500',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -575,17 +662,21 @@ export default function DebugTab() {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={`px-2 py-0.5 text-xs rounded-full ${
|
||||
provider.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
|
||||
}`}
|
||||
className={classNames(
|
||||
'px-2 py-0.5 text-xs rounded-full',
|
||||
provider.enabled
|
||||
? 'bg-green-500/10 text-green-500'
|
||||
: 'bg-gray-500/10 text-bolt-elements-textSecondary',
|
||||
)}
|
||||
>
|
||||
{provider.enabled ? 'Enabled' : 'Disabled'}
|
||||
</span>
|
||||
{provider.enabled && (
|
||||
<span
|
||||
className={`px-2 py-0.5 text-xs rounded-full ${
|
||||
provider.isRunning ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
||||
}`}
|
||||
className={classNames(
|
||||
'px-2 py-0.5 text-xs rounded-full',
|
||||
provider.isRunning ? 'bg-green-500/10 text-green-500' : 'bg-red-500/10 text-red-500',
|
||||
)}
|
||||
>
|
||||
{provider.isRunning ? 'Running' : 'Not Running'}
|
||||
</span>
|
||||
@@ -593,31 +684,28 @@ export default function DebugTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pl-5 flex flex-col space-y-1 text-xs">
|
||||
{/* Status Details */}
|
||||
<div className="pl-5 mt-2 space-y-2">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<span className="text-bolt-elements-textSecondary">
|
||||
<span className="text-xs text-bolt-elements-textSecondary">
|
||||
Last checked: {new Date(provider.lastChecked).toLocaleTimeString()}
|
||||
</span>
|
||||
{provider.responseTime && (
|
||||
<span className="text-bolt-elements-textSecondary">
|
||||
<span className="text-xs text-bolt-elements-textSecondary">
|
||||
Response time: {Math.round(provider.responseTime)}ms
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Error Message */}
|
||||
{provider.error && (
|
||||
<div className="mt-1 text-red-600 bg-red-50 rounded-md p-2">
|
||||
<div className="mt-2 text-xs text-red-500 bg-red-500/10 rounded-md p-2">
|
||||
<span className="font-medium">Error:</span> {provider.error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Connection Info */}
|
||||
{provider.url && (
|
||||
<div className="text-bolt-elements-textSecondary">
|
||||
<div className="text-xs text-bolt-elements-textSecondary mt-2">
|
||||
<span className="font-medium">Endpoints checked:</span>
|
||||
<ul className="list-disc list-inside pl-2 mt-1">
|
||||
<ul className="list-disc list-inside pl-2 mt-1 space-y-1">
|
||||
<li>{provider.url} (root)</li>
|
||||
<li>{provider.url}/api/health</li>
|
||||
<li>{provider.url}/v1/models</li>
|
||||
@@ -631,8 +719,8 @@ export default function DebugTab() {
|
||||
<div className="p-4 text-center text-bolt-elements-textSecondary">No local LLMs configured</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user