feat(i18n): translate Claude session components to Chinese
Translate English interface text to Chinese in Claude Code session components: - ClaudeCodeSession.tsx: Session management UI, settings, timeline, and execution states - SessionOutputViewer.tsx: Output viewer, status messages, and copy operations Key translations: - Session management terms (会话, 恢复会话, 分叉会话) - Status indicators (运行中, 实时, 完成, 取消) - UI actions (复制输出, 刷新, 设置, 时间线) - Error and loading messages - Project directory selection interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -275,7 +275,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
setIsFirstPrompt(false);
|
setIsFirstPrompt(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to load session history:", err);
|
console.error("Failed to load session history:", err);
|
||||||
setError("Failed to load session history");
|
setError("加载会话历史失败");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -377,7 +377,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
const selected = await open({
|
const selected = await open({
|
||||||
directory: true,
|
directory: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
title: "Select Project Directory"
|
title: "选择项目目录"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
@@ -387,7 +387,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to select directory:", err);
|
console.error("Failed to select directory:", err);
|
||||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||||
setError(`Failed to select directory: ${errorMessage}`);
|
setError(`选择目录失败: ${errorMessage}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
console.log('[ClaudeCodeSession] handleSendPrompt called with:', { prompt, model, projectPath, claudeSessionId, effectiveSession });
|
console.log('[ClaudeCodeSession] handleSendPrompt called with:', { prompt, model, projectPath, claudeSessionId, effectiveSession });
|
||||||
|
|
||||||
if (!projectPath) {
|
if (!projectPath) {
|
||||||
setError("Please select a project directory first");
|
setError("请先选择项目目录");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,7 +597,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to send prompt:", err);
|
console.error("Failed to send prompt:", err);
|
||||||
setError("Failed to send prompt");
|
setError("发送提示失败");
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
hasActiveSessionRef.current = false;
|
hasActiveSessionRef.current = false;
|
||||||
}
|
}
|
||||||
@@ -711,7 +711,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
const cancelMessage: ClaudeStreamMessage = {
|
const cancelMessage: ClaudeStreamMessage = {
|
||||||
type: "system",
|
type: "system",
|
||||||
subtype: "info",
|
subtype: "info",
|
||||||
result: "Session cancelled by user",
|
result: "会话已被用户取消",
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
};
|
};
|
||||||
setMessages(prev => [...prev, cancelMessage]);
|
setMessages(prev => [...prev, cancelMessage]);
|
||||||
@@ -723,7 +723,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
const errorMessage: ClaudeStreamMessage = {
|
const errorMessage: ClaudeStreamMessage = {
|
||||||
type: "system",
|
type: "system",
|
||||||
subtype: "error",
|
subtype: "error",
|
||||||
result: `Failed to cancel execution: ${err instanceof Error ? err.message : 'Unknown error'}. The process may still be running in the background.`,
|
result: `取消执行失败: ${err instanceof Error ? err.message : '未知错误'}. 该进程可能仍在后台运行。`,
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
};
|
};
|
||||||
setMessages(prev => [...prev, errorMessage]);
|
setMessages(prev => [...prev, errorMessage]);
|
||||||
@@ -772,7 +772,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
setForkSessionName("");
|
setForkSessionName("");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Failed to fork checkpoint:", err);
|
console.error("Failed to fork checkpoint:", err);
|
||||||
setError("Failed to fork checkpoint");
|
setError("分叉检查点失败");
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -904,7 +904,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
className="p-4 border-b border-border flex-shrink-0"
|
className="p-4 border-b border-border flex-shrink-0"
|
||||||
>
|
>
|
||||||
<Label htmlFor="project-path" className="text-sm font-medium">
|
<Label htmlFor="project-path" className="text-sm font-medium">
|
||||||
Project Directory
|
项目目录
|
||||||
</Label>
|
</Label>
|
||||||
<div className="flex items-center gap-2 mt-1">
|
<div className="flex items-center gap-2 mt-1">
|
||||||
<Input
|
<Input
|
||||||
@@ -973,9 +973,9 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Terminal className="h-5 w-5" />
|
<Terminal className="h-5 w-5" />
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold">Claude Code Session</h2>
|
<h2 className="text-lg font-semibold">Claude Code 会话</h2>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{session ? `Resuming session ${session.id.slice(0, 8)}...` : 'Interactive session'}
|
{session ? `恢复会话 ${session.id.slice(0, 8)}...` : '交互式会话'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -991,7 +991,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Settings className="h-4 w-4" />
|
<Settings className="h-4 w-4" />
|
||||||
Settings
|
设置
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -1000,7 +1000,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<GitBranch className="h-4 w-4" />
|
<GitBranch className="h-4 w-4" />
|
||||||
Timeline
|
时间线
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -1023,13 +1023,13 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Globe className="h-4 w-4" />
|
<Globe className="h-4 w-4" />
|
||||||
{showPreview ? "Close Preview" : "Preview"}
|
{showPreview ? "关闭预览" : "预览"}
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
{showPreview
|
{showPreview
|
||||||
? "Close the preview pane"
|
? "关闭预览面板"
|
||||||
: "Open a browser preview to test your web applications"
|
: "打开浏览器预览以测试您的Web应用程序"
|
||||||
}
|
}
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -1044,7 +1044,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
Copy Output
|
复制输出
|
||||||
<ChevronDown className="h-3 w-3" />
|
<ChevronDown className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
@@ -1056,7 +1056,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
onClick={handleCopyAsMarkdown}
|
onClick={handleCopyAsMarkdown}
|
||||||
className="w-full justify-start"
|
className="w-full justify-start"
|
||||||
>
|
>
|
||||||
Copy as Markdown
|
复制为Markdown
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -1064,7 +1064,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
onClick={handleCopyAsJsonl}
|
onClick={handleCopyAsJsonl}
|
||||||
className="w-full justify-start"
|
className="w-full justify-start"
|
||||||
>
|
>
|
||||||
Copy as JSONL
|
复制为JSONL
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -1115,7 +1115,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="rotating-symbol text-primary text-2xl" />
|
<div className="rotating-symbol text-primary text-2xl" />
|
||||||
<span className="text-sm text-muted-foreground">
|
<span className="text-sm text-muted-foreground">
|
||||||
{session ? "Loading session history..." : "Initializing Claude Code..."}
|
{session ? "正在加载会话历史..." : "正在初始化Claude Code..."}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1138,7 +1138,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
<div className="bg-background/95 backdrop-blur-md border rounded-lg shadow-lg p-3 space-y-2">
|
<div className="bg-background/95 backdrop-blur-md border rounded-lg shadow-lg p-3 space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="text-xs font-medium text-muted-foreground mb-1">
|
<div className="text-xs font-medium text-muted-foreground mb-1">
|
||||||
Queued Prompts ({queuedPrompts.length})
|
队列提示 ({queuedPrompts.length})
|
||||||
</div>
|
</div>
|
||||||
<Button variant="ghost" size="icon" onClick={() => setQueuedPromptsCollapsed(prev => !prev)}>
|
<Button variant="ghost" size="icon" onClick={() => setQueuedPromptsCollapsed(prev => !prev)}>
|
||||||
{queuedPromptsCollapsed ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
|
{queuedPromptsCollapsed ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
|
||||||
@@ -1214,7 +1214,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-3 py-2 hover:bg-accent rounded-none"
|
className="px-3 py-2 hover:bg-accent rounded-none"
|
||||||
title="Scroll to top"
|
title="滚动到顶部"
|
||||||
>
|
>
|
||||||
<ChevronUp className="h-4 w-4" />
|
<ChevronUp className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1236,7 +1236,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-3 py-2 hover:bg-accent rounded-none"
|
className="px-3 py-2 hover:bg-accent rounded-none"
|
||||||
title="Scroll to bottom"
|
title="滚动到底部"
|
||||||
>
|
>
|
||||||
<ChevronDown className="h-4 w-4" />
|
<ChevronDown className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1272,7 +1272,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
<div className="flex items-center gap-1.5 text-xs">
|
<div className="flex items-center gap-1.5 text-xs">
|
||||||
<Hash className="h-3 w-3 text-muted-foreground" />
|
<Hash className="h-3 w-3 text-muted-foreground" />
|
||||||
<span className="font-mono">{totalTokens.toLocaleString()}</span>
|
<span className="font-mono">{totalTokens.toLocaleString()}</span>
|
||||||
<span className="text-muted-foreground">tokens</span>
|
<span className="text-muted-foreground">标记</span>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1294,7 +1294,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
{/* Timeline Header */}
|
{/* Timeline Header */}
|
||||||
<div className="flex items-center justify-between p-4 border-b border-border">
|
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||||
<h3 className="text-lg font-semibold">Session Timeline</h3>
|
<h3 className="text-lg font-semibold">会话时间线</h3>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
@@ -1327,18 +1327,18 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
<Dialog open={showForkDialog} onOpenChange={setShowForkDialog}>
|
<Dialog open={showForkDialog} onOpenChange={setShowForkDialog}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Fork Session</DialogTitle>
|
<DialogTitle>分叉会话</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Create a new session branch from the selected checkpoint.
|
从选定的检查点创建新的会话分支。
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="space-y-4 py-4">
|
<div className="space-y-4 py-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="fork-name">New Session Name</Label>
|
<Label htmlFor="fork-name">新会话名称</Label>
|
||||||
<Input
|
<Input
|
||||||
id="fork-name"
|
id="fork-name"
|
||||||
placeholder="e.g., Alternative approach"
|
placeholder="例如:备用方案"
|
||||||
value={forkSessionName}
|
value={forkSessionName}
|
||||||
onChange={(e) => setForkSessionName(e.target.value)}
|
onChange={(e) => setForkSessionName(e.target.value)}
|
||||||
onKeyPress={(e) => {
|
onKeyPress={(e) => {
|
||||||
@@ -1356,13 +1356,13 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||||||
onClick={() => setShowForkDialog(false)}
|
onClick={() => setShowForkDialog(false)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
Cancel
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleConfirmFork}
|
onClick={handleConfirmFork}
|
||||||
disabled={isLoading || !forkSessionName.trim()}
|
disabled={isLoading || !forkSessionName.trim()}
|
||||||
>
|
>
|
||||||
Create Fork
|
创建分叉
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
@@ -146,7 +146,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load session output:', error);
|
console.error('Failed to load session output:', error);
|
||||||
setToast({ message: 'Failed to load session output', type: 'error' });
|
setToast({ message: '加载会话输出失败', type: 'error' });
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -180,12 +180,12 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
});
|
});
|
||||||
|
|
||||||
const completeUnlisten = await listen<boolean>(`agent-complete:${session.id}`, () => {
|
const completeUnlisten = await listen<boolean>(`agent-complete:${session.id}`, () => {
|
||||||
setToast({ message: 'Agent execution completed', type: 'success' });
|
setToast({ message: '智能体执行完成', type: 'success' });
|
||||||
// Don't set status here as the parent component should handle it
|
// Don't set status here as the parent component should handle it
|
||||||
});
|
});
|
||||||
|
|
||||||
const cancelUnlisten = await listen<boolean>(`agent-cancelled:${session.id}`, () => {
|
const cancelUnlisten = await listen<boolean>(`agent-cancelled:${session.id}`, () => {
|
||||||
setToast({ message: 'Agent execution was cancelled', type: 'error' });
|
setToast({ message: '智能体执行已取消', type: 'error' });
|
||||||
});
|
});
|
||||||
|
|
||||||
unlistenRefs.current = [outputUnlisten, errorUnlisten, completeUnlisten, cancelUnlisten];
|
unlistenRefs.current = [outputUnlisten, errorUnlisten, completeUnlisten, cancelUnlisten];
|
||||||
@@ -199,7 +199,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
const jsonl = rawJsonlOutput.join('\n');
|
const jsonl = rawJsonlOutput.join('\n');
|
||||||
await navigator.clipboard.writeText(jsonl);
|
await navigator.clipboard.writeText(jsonl);
|
||||||
setCopyPopoverOpen(false);
|
setCopyPopoverOpen(false);
|
||||||
setToast({ message: 'Output copied as JSONL', type: 'success' });
|
setToast({ message: '输出已复制为JSONL', type: 'success' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCopyAsMarkdown = async () => {
|
const handleCopyAsMarkdown = async () => {
|
||||||
@@ -254,7 +254,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
|
|
||||||
await navigator.clipboard.writeText(markdown);
|
await navigator.clipboard.writeText(markdown);
|
||||||
setCopyPopoverOpen(false);
|
setCopyPopoverOpen(false);
|
||||||
setToast({ message: 'Output copied as Markdown', type: 'success' });
|
setToast({ message: '输出已复制为Markdown', type: 'success' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -262,10 +262,10 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
setRefreshing(true);
|
setRefreshing(true);
|
||||||
try {
|
try {
|
||||||
await loadOutput(true); // Skip cache when manually refreshing
|
await loadOutput(true); // Skip cache when manually refreshing
|
||||||
setToast({ message: 'Output refreshed', type: 'success' });
|
setToast({ message: '输出已刷新', type: 'success' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to refresh output:', error);
|
console.error('Failed to refresh output:', error);
|
||||||
setToast({ message: 'Failed to refresh output', type: 'error' });
|
setToast({ message: '刷新输出失败', type: 'error' });
|
||||||
} finally {
|
} finally {
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
}
|
}
|
||||||
@@ -345,7 +345,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<div className="text-2xl">{session.agent_icon}</div>
|
<div className="text-2xl">{session.agent_icon}</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-base">{session.agent_name} - Output</CardTitle>
|
<CardTitle className="text-base">{session.agent_name} - 输出</CardTitle>
|
||||||
<div className="flex items-center space-x-2 mt-1">
|
<div className="flex items-center space-x-2 mt-1">
|
||||||
<Badge variant={session.status === 'running' ? 'default' : 'secondary'}>
|
<Badge variant={session.status === 'running' ? 'default' : 'secondary'}>
|
||||||
{session.status}
|
{session.status}
|
||||||
@@ -353,11 +353,11 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
{session.status === 'running' && (
|
{session.status === 'running' && (
|
||||||
<Badge variant="outline" className="text-xs bg-green-50 text-green-700 border-green-200">
|
<Badge variant="outline" className="text-xs bg-green-50 text-green-700 border-green-200">
|
||||||
<div className="w-1.5 h-1.5 bg-green-500 rounded-full animate-pulse mr-1"></div>
|
<div className="w-1.5 h-1.5 bg-green-500 rounded-full animate-pulse mr-1"></div>
|
||||||
Live
|
实时
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
<span className="text-xs text-muted-foreground">
|
<span className="text-xs text-muted-foreground">
|
||||||
{messages.length} messages
|
{messages.length} 条消息
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -369,7 +369,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setIsFullscreen(!isFullscreen)}
|
onClick={() => setIsFullscreen(!isFullscreen)}
|
||||||
title="Fullscreen"
|
title="全屏"
|
||||||
>
|
>
|
||||||
{isFullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
|
{isFullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -381,7 +381,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
Copy Output
|
复制输出
|
||||||
<ChevronDown className="h-3 w-3" />
|
<ChevronDown className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
@@ -393,7 +393,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="w-full justify-start"
|
className="w-full justify-start"
|
||||||
onClick={handleCopyAsJsonl}
|
onClick={handleCopyAsJsonl}
|
||||||
>
|
>
|
||||||
Copy as JSONL
|
复制为JSONL
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -401,7 +401,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="w-full justify-start"
|
className="w-full justify-start"
|
||||||
onClick={handleCopyAsMarkdown}
|
onClick={handleCopyAsMarkdown}
|
||||||
>
|
>
|
||||||
Copy as Markdown
|
复制为Markdown
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -416,7 +416,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={refreshOutput}
|
onClick={refreshOutput}
|
||||||
disabled={refreshing}
|
disabled={refreshing}
|
||||||
title="Refresh output"
|
title="刷新输出"
|
||||||
>
|
>
|
||||||
<RotateCcw className={`h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />
|
<RotateCcw className={`h-4 w-4 ${refreshing ? 'animate-spin' : ''}`} />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -431,7 +431,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
<div className="flex items-center justify-center h-full">
|
<div className="flex items-center justify-center h-full">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||||
<span>Loading output...</span>
|
<span>正在加载输出...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -455,14 +455,14 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
{session.status === 'running' ? (
|
{session.status === 'running' ? (
|
||||||
<>
|
<>
|
||||||
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground mb-2" />
|
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground mb-2" />
|
||||||
<p className="text-muted-foreground">Waiting for output...</p>
|
<p className="text-muted-foreground">等待输出...</p>
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
Agent is running but no output received yet
|
智能体正在运行但尚未收到输出
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p className="text-muted-foreground">No output available</p>
|
<p className="text-muted-foreground">暂无输出</p>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -471,7 +471,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
disabled={refreshing}
|
disabled={refreshing}
|
||||||
>
|
>
|
||||||
{refreshing ? <RefreshCw className="h-4 w-4 animate-spin mr-2" /> : <RotateCcw className="h-4 w-4 mr-2" />}
|
{refreshing ? <RefreshCw className="h-4 w-4 animate-spin mr-2" /> : <RotateCcw className="h-4 w-4 mr-2" />}
|
||||||
Refresh
|
刷新
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -508,11 +508,11 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
<div className="flex items-center justify-between p-4 border-b border-border">
|
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="text-2xl">{session.agent_icon}</div>
|
<div className="text-2xl">{session.agent_icon}</div>
|
||||||
<h2 className="text-lg font-semibold">{session.agent_name} - Output</h2>
|
<h2 className="text-lg font-semibold">{session.agent_name} - 输出</h2>
|
||||||
{session.status === 'running' && (
|
{session.status === 'running' && (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
||||||
<span className="text-xs text-green-600 font-medium">Running</span>
|
<span className="text-xs text-green-600 font-medium">运行中</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -526,7 +526,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
Copy Output
|
复制输出
|
||||||
<ChevronDown className="h-3 w-3" />
|
<ChevronDown className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
@@ -538,7 +538,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="w-full justify-start"
|
className="w-full justify-start"
|
||||||
onClick={handleCopyAsJsonl}
|
onClick={handleCopyAsJsonl}
|
||||||
>
|
>
|
||||||
Copy as JSONL
|
复制为JSONL
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -546,7 +546,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="w-full justify-start"
|
className="w-full justify-start"
|
||||||
onClick={handleCopyAsMarkdown}
|
onClick={handleCopyAsMarkdown}
|
||||||
>
|
>
|
||||||
Copy as Markdown
|
复制为Markdown
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -562,7 +562,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
Close
|
关闭
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -589,14 +589,14 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||||||
{session.status === 'running' ? (
|
{session.status === 'running' ? (
|
||||||
<>
|
<>
|
||||||
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground mb-2" />
|
<RefreshCw className="h-8 w-8 animate-spin text-muted-foreground mb-2" />
|
||||||
<p className="text-muted-foreground">Waiting for output...</p>
|
<p className="text-muted-foreground">等待输出...</p>
|
||||||
<p className="text-xs text-muted-foreground mt-1">
|
<p className="text-xs text-muted-foreground mt-1">
|
||||||
Agent is running but no output received yet
|
智能体正在运行但尚未收到输出
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p className="text-muted-foreground">No output available</p>
|
<p className="text-muted-foreground">暂无输出</p>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user