Files
ai-terminal-assistant/packages/desktop/src/App.tsx
T
kurihada 842cf1a3e8 fix(ui): 优化会话初始化逻辑
- 首次启动时自动创建会话
- 用户删除所有会话后不再自动创建,显示空状态
- 使用 localStorage 记录是否曾有会话
2025-12-15 10:05:17 +08:00

166 lines
5.3 KiB
TypeScript

/**
* App Component
*/
import { useState, useEffect, useCallback } from 'react';
import {
Sidebar,
FileBrowser,
ConfigPanel,
CommandPanel,
MCPPanel,
HooksPanel,
AgentsPanel,
CheckpointPanel,
ProvidersPanel,
Toaster,
listSessions,
createSession,
type Session,
} from '@ai-assistant/ui';
import { ChatPage } from './pages/Chat';
export function App() {
const [currentSessionId, setCurrentSessionId] = useState<string | null>(null);
const [isInitializing, setIsInitializing] = useState(true);
const [showFileBrowser, setShowFileBrowser] = useState(false);
const [showConfig, setShowConfig] = useState(false);
const [showCommands, setShowCommands] = useState(false);
const [showMCP, setShowMCP] = useState(false);
const [showHooks, setShowHooks] = useState(false);
const [showAgents, setShowAgents] = useState(false);
const [showCheckpoints, setShowCheckpoints] = useState(false);
const [showProviders, setShowProviders] = useState(false);
const [sessionTitleUpdate, setSessionTitleUpdate] = useState<{ sessionId: string; name: string } | null>(null);
// 初始化:加载会话(只在首次启动时自动创建)
useEffect(() => {
const HAS_SESSIONS_KEY = 'ai-assistant-has-sessions';
async function init() {
try {
const { data: sessions } = await listSessions();
if (sessions.length > 0) {
// 有会话,选择最近的
setCurrentSessionId(sessions[0].id);
localStorage.setItem(HAS_SESSIONS_KEY, 'true');
} else {
// 无会话:检查是否是首次启动
const hasHadSessions = localStorage.getItem(HAS_SESSIONS_KEY);
if (!hasHadSessions) {
// 首次启动,自动创建会话
const { data: newSession } = await createSession();
setCurrentSessionId(newSession.id);
localStorage.setItem(HAS_SESSIONS_KEY, 'true');
}
// 用户删除了所有会话:不自动创建,显示空状态
}
} catch (error) {
console.error('Failed to initialize:', error);
} finally {
setIsInitializing(false);
}
}
init();
}, []);
const handleSelectSession = (id: string) => {
setCurrentSessionId(id);
};
const handleCreateSession = (session: Session) => {
setCurrentSessionId(session.id);
};
// 会话标题更新回调
const handleSessionUpdated = useCallback((sessionId: string, name: string) => {
setSessionTitleUpdate({ sessionId, name });
}, []);
if (isInitializing) {
return (
<div className="h-screen flex items-center justify-center bg-gray-900">
<div className="text-center">
<div className="w-8 h-8 border-2 border-primary-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
<p className="text-gray-400">Initializing...</p>
</div>
</div>
);
}
return (
<div className="h-screen flex bg-gray-900">
<Sidebar
currentSessionId={currentSessionId}
onSelectSession={handleSelectSession}
onCreateSession={handleCreateSession}
sessionTitleUpdate={sessionTitleUpdate}
/>
<div className="flex-1 flex">
{/* 聊天区域 */}
<div className={`flex-1 ${showFileBrowser ? 'w-1/2' : 'w-full'}`}>
{currentSessionId ? (
<ChatPage
key={currentSessionId}
sessionId={currentSessionId}
onSessionUpdated={handleSessionUpdated}
showFileBrowser={showFileBrowser}
onToggleFileBrowser={() => setShowFileBrowser(!showFileBrowser)}
onOpenConfig={() => setShowConfig(true)}
onOpenCommands={() => setShowCommands(true)}
onOpenMCP={() => setShowMCP(true)}
onOpenHooks={() => setShowHooks(true)}
onOpenAgents={() => setShowAgents(true)}
onOpenCheckpoints={() => setShowCheckpoints(true)}
onOpenProviders={() => setShowProviders(true)}
/>
) : (
<div className="flex-1 flex items-center justify-center h-full">
<p className="text-gray-400">Select or create a session</p>
</div>
)}
</div>
{/* 文件浏览器 */}
{showFileBrowser && (
<div className="w-1/2 border-l border-gray-700">
<FileBrowser
onFileSelect={(path, _content) => {
console.log('Selected file:', path);
}}
/>
</div>
)}
</div>
{/* 配置面板 */}
{showConfig && <ConfigPanel onClose={() => setShowConfig(false)} />}
{/* 命令面板 */}
{showCommands && <CommandPanel onClose={() => setShowCommands(false)} />}
{/* MCP 面板 */}
{showMCP && <MCPPanel onClose={() => setShowMCP(false)} />}
{/* Hooks 面板 */}
{showHooks && <HooksPanel onClose={() => setShowHooks(false)} />}
{/* Agents 面板 */}
{showAgents && <AgentsPanel onClose={() => setShowAgents(false)} />}
{/* Checkpoints 面板 */}
{showCheckpoints && <CheckpointPanel onClose={() => setShowCheckpoints(false)} />}
{/* Providers 面板 */}
{showProviders && <ProvidersPanel onClose={() => setShowProviders(false)} />}
{/* Toast 通知 */}
<Toaster />
</div>
);
}