优化页面,国际化细节内容
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { api, type Agent } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
@@ -81,6 +82,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
onBack,
|
||||
className,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [projectPath, setProjectPath] = useState("");
|
||||
const [task, setTask] = useState(agent.default_task || "");
|
||||
const [model, setModel] = useState(agent.model || "sonnet");
|
||||
@@ -452,7 +454,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
if (isRunning) {
|
||||
// Show confirmation dialog before navigating away during execution
|
||||
const shouldLeave = window.confirm(
|
||||
"An agent is currently running. If you navigate away, the agent will continue running in the background. You can view running sessions in the 'Running Sessions' tab within CC Agents.\n\nDo you want to continue?"
|
||||
t('agents.agentRunningWarning')
|
||||
);
|
||||
if (!shouldLeave) {
|
||||
return;
|
||||
@@ -476,7 +478,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
const handleCopyAsMarkdown = async () => {
|
||||
let markdown = `# Agent Execution: ${agent.name}\n\n`;
|
||||
markdown += `**Task:** ${task}\n`;
|
||||
markdown += `**Model:** ${model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}\n`;
|
||||
markdown += `**Model:** ${model === 'opus' ? 'Claude 4.1 Opus' : 'Claude 4 Sonnet'}\n`;
|
||||
markdown += `**Date:** ${new Date().toISOString()}\n\n`;
|
||||
markdown += `---\n\n`;
|
||||
|
||||
@@ -572,9 +574,9 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
{renderIcon()}
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-xl font-bold">Execute: {agent.name}</h1>
|
||||
<h1 className="text-xl font-bold">{t('agents.execute')}: {agent.name}</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}
|
||||
{model === 'opus' ? 'Claude 4.1 Opus' : 'Claude 4 Sonnet'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -587,7 +589,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
disabled={messages.length === 0}
|
||||
>
|
||||
<Maximize2 className="h-4 w-4 mr-2" />
|
||||
Fullscreen
|
||||
{t('agents.fullscreen')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -612,12 +614,12 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
|
||||
{/* Project Path */}
|
||||
<div className="space-y-2">
|
||||
<Label>Project Path</Label>
|
||||
<Label>{t('agents.projectPath')}</Label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={projectPath}
|
||||
onChange={(e) => setProjectPath(e.target.value)}
|
||||
placeholder="Select or enter project path"
|
||||
placeholder={t('agents.selectProjectPath')}
|
||||
disabled={isRunning}
|
||||
className="flex-1"
|
||||
/>
|
||||
@@ -633,17 +635,17 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
variant="outline"
|
||||
onClick={handleOpenHooksDialog}
|
||||
disabled={isRunning || !projectPath}
|
||||
title="Configure hooks"
|
||||
title={t('agents.configureHooks')}
|
||||
>
|
||||
<Settings2 className="h-4 w-4 mr-2" />
|
||||
Hooks
|
||||
{t('agents.hooks')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Model Selection */}
|
||||
<div className="space-y-2">
|
||||
<Label>Model</Label>
|
||||
<Label>{t('agents.model')}</Label>
|
||||
<div className="flex gap-3">
|
||||
<button
|
||||
type="button"
|
||||
@@ -693,7 +695,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
<div className="w-1.5 h-1.5 rounded-full bg-primary-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<span>Claude 4 Opus</span>
|
||||
<span>Claude 4.1 Opus</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
@@ -701,12 +703,12 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
|
||||
{/* Task Input */}
|
||||
<div className="space-y-2">
|
||||
<Label>Task</Label>
|
||||
<Label>{t('app.task')}</Label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={task}
|
||||
onChange={(e) => setTask(e.target.value)}
|
||||
placeholder="Enter the task for the agent"
|
||||
placeholder={t('agents.enterTask')}
|
||||
disabled={isRunning}
|
||||
className="flex-1"
|
||||
onKeyPress={(e) => {
|
||||
@@ -723,12 +725,12 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
{isRunning ? (
|
||||
<>
|
||||
<StopCircle className="mr-2 h-4 w-4" />
|
||||
Stop
|
||||
{t('agents.stop')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Play className="mr-2 h-4 w-4" />
|
||||
Execute
|
||||
{t('agents.execute')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
@@ -759,9 +761,9 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
{messages.length === 0 && !isRunning && (
|
||||
<div className="flex flex-col items-center justify-center h-full text-center">
|
||||
<Terminal className="h-16 w-16 text-muted-foreground mb-4" />
|
||||
<h3 className="text-lg font-medium mb-2">Ready to Execute</h3>
|
||||
<h3 className="text-lg font-medium mb-2">{t('agents.readyToExecute')}</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Select a project path and enter a task to run the agent
|
||||
{t('agents.selectProjectPathAndTask')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -841,7 +843,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
Copy Output
|
||||
{t('app.copyOutput')}
|
||||
<ChevronDown className="h-3 w-3" />
|
||||
</Button>
|
||||
}
|
||||
@@ -853,7 +855,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -861,7 +863,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
@@ -901,9 +903,9 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
{messages.length === 0 && !isRunning && (
|
||||
<div className="flex flex-col items-center justify-center h-full text-center">
|
||||
<Terminal className="h-16 w-16 text-muted-foreground mb-4" />
|
||||
<h3 className="text-lg font-medium mb-2">Ready to Execute</h3>
|
||||
<h3 className="text-lg font-medium mb-2">{t('agents.readyToExecute')}</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Select a project path and enter a task to run the agent
|
||||
{t('agents.selectProjectPathAndTask')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -957,7 +959,7 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
||||
>
|
||||
<DialogContent className="max-w-4xl max-h-[80vh] overflow-hidden flex flex-col">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Configure Hooks</DialogTitle>
|
||||
<DialogTitle>{t('agents.configureHooks')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Configure hooks that run before, during, and after tool executions. Changes are saved immediately.
|
||||
</DialogDescription>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect, useRef, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
Maximize2,
|
||||
@@ -57,6 +58,7 @@ export function AgentRunOutputViewer({
|
||||
tabId,
|
||||
className
|
||||
}: AgentRunOutputViewerProps) {
|
||||
const { t } = useTranslation();
|
||||
const { updateTabTitle, updateTabStatus } = useTabState();
|
||||
const [run, setRun] = useState<AgentRunWithMetrics | null>(null);
|
||||
const [messages, setMessages] = useState<ClaudeStreamMessage[]>([]);
|
||||
@@ -330,7 +332,7 @@ export function AgentRunOutputViewer({
|
||||
if (!run) return;
|
||||
let markdown = `# Agent Execution: ${run.agent_name}\n\n`;
|
||||
markdown += `**Task:** ${run.task}\n`;
|
||||
markdown += `**Model:** ${run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}\n`;
|
||||
markdown += `**Model:** ${run.model === 'opus' ? 'Claude 4.1 Opus' : 'Claude 4 Sonnet'}\n`;
|
||||
markdown += `**Date:** ${formatISOTimestamp(run.created_at)}\n`;
|
||||
if (run.metrics?.duration_ms) markdown += `**Duration:** ${(run.metrics.duration_ms / 1000).toFixed(2)}s\n`;
|
||||
if (run.metrics?.total_tokens) markdown += `**Total Tokens:** ${run.metrics.total_tokens}\n`;
|
||||
@@ -566,7 +568,7 @@ export function AgentRunOutputViewer({
|
||||
</p>
|
||||
<div className="flex items-center gap-3 text-xs text-muted-foreground mt-2">
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}
|
||||
{run.model === 'opus' ? 'Claude 4.1 Opus' : 'Claude 4 Sonnet'}
|
||||
</Badge>
|
||||
<div className="flex items-center gap-1">
|
||||
<Clock className="h-3 w-3" />
|
||||
@@ -611,7 +613,7 @@ export function AgentRunOutputViewer({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -619,7 +621,7 @@ export function AgentRunOutputViewer({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
@@ -723,7 +725,7 @@ export function AgentRunOutputViewer({
|
||||
size="sm"
|
||||
>
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
Copy Output
|
||||
{t('app.copyOutput')}
|
||||
<ChevronDown className="h-3 w-3 ml-2" />
|
||||
</Button>
|
||||
}
|
||||
@@ -735,7 +737,7 @@ export function AgentRunOutputViewer({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -743,7 +745,7 @@ export function AgentRunOutputViewer({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Popover } from "@/components/ui/popover";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { api, type AgentRunWithMetrics } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatISOTimestamp } from "@/lib/date-utils";
|
||||
@@ -48,6 +49,7 @@ export const AgentRunView: React.FC<AgentRunViewProps> = ({
|
||||
onBack,
|
||||
className,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [run, setRun] = useState<AgentRunWithMetrics | null>(null);
|
||||
const [messages, setMessages] = useState<ClaudeStreamMessage[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -288,7 +290,7 @@ export const AgentRunView: React.FC<AgentRunViewProps> = ({
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
Copy Output
|
||||
{t('app.copyOutput')}
|
||||
<ChevronDown className="h-3 w-3" />
|
||||
</Button>
|
||||
}
|
||||
@@ -300,7 +302,7 @@ export const AgentRunView: React.FC<AgentRunViewProps> = ({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -308,7 +310,7 @@ export const AgentRunView: React.FC<AgentRunViewProps> = ({
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
@@ -327,7 +329,7 @@ export const AgentRunView: React.FC<AgentRunViewProps> = ({
|
||||
<h3 className="text-sm font-medium">Task:</h3>
|
||||
<p className="text-sm text-muted-foreground flex-1">{run.task}</p>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}
|
||||
{run.model === 'opus' ? 'Claude 4.1 Opus' : 'Claude 4 Sonnet'}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import { Play, Clock, Hash, Bot } from "lucide-react";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Pagination } from "@/components/ui/pagination";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { formatISOTimestamp } from "@/lib/date-utils";
|
||||
import type { AgentRunWithMetrics } from "@/lib/api";
|
||||
@@ -41,6 +42,7 @@ export const AgentRunsList: React.FC<AgentRunsListProps> = ({
|
||||
onRunClick,
|
||||
className,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const { createAgentTab } = useTabState();
|
||||
|
||||
@@ -91,7 +93,7 @@ export const AgentRunsList: React.FC<AgentRunsListProps> = ({
|
||||
return (
|
||||
<div className={cn("text-center py-8 text-muted-foreground", className)}>
|
||||
<Play className="h-8 w-8 mx-auto mb-2 opacity-50" />
|
||||
<p className="text-sm">No execution history yet</p>
|
||||
<p className="text-sm">{t('agents.noExecutionHistory')}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -361,7 +361,7 @@ export const AgentsModal: React.FC<AgentsModalProps> = ({ open, onOpenChange })
|
||||
<div className="flex items-center gap-4 mt-2 text-xs text-muted-foreground">
|
||||
<span>Started: {formatISOTimestamp(run.created_at)}</span>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}
|
||||
{run.model === 'opus' ? 'Claude 4.1 Opus' : 'Claude 4 Sonnet'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -17,6 +17,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Popover } from "@/components/ui/popover";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { api, type Session } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
@@ -76,6 +77,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
className,
|
||||
onStreamingChange,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [projectPath, setProjectPath] = useState(initialProjectPath || session?.project_path || "");
|
||||
const [messages, setMessages] = useState<ClaudeStreamMessage[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -1127,7 +1129,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
const messagesList = (
|
||||
<div
|
||||
ref={parentRef}
|
||||
className="flex-1 overflow-y-auto relative pb-40"
|
||||
className="flex-1 overflow-y-auto relative pb-24"
|
||||
style={{
|
||||
contain: 'strict',
|
||||
}}
|
||||
@@ -1247,7 +1249,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("flex flex-col h-full bg-background", className)}>
|
||||
<div className={cn("flex flex-col h-full bg-background relative", className)}>
|
||||
<div className="w-full h-full flex flex-col">
|
||||
{/* Header */}
|
||||
<motion.div
|
||||
@@ -1268,7 +1270,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
<div className="flex items-center gap-2">
|
||||
<Terminal className="h-5 w-5 text-muted-foreground" />
|
||||
<div className="flex-1">
|
||||
<h1 className="text-xl font-bold">Claude Code Session</h1>
|
||||
<h1 className="text-xl font-bold">{t('app.claudeCodeSession')}</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{projectPath ? `${projectPath}` : "No project selected"}
|
||||
</p>
|
||||
@@ -1300,13 +1302,6 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
</Button>
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
{showSettings && (
|
||||
<CheckpointSettings
|
||||
sessionId={effectiveSession?.id || ''}
|
||||
projectId={effectiveSession?.project_id || ''}
|
||||
projectPath={projectPath}
|
||||
/>
|
||||
)}
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
@@ -1320,7 +1315,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p>Checkpoint Settings</p>
|
||||
<p>{t('checkpoint.checkpointSettingsTitle')}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
@@ -1352,7 +1347,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
Copy Output
|
||||
{t('app.copyOutput')}
|
||||
<ChevronDown className="h-3 w-3" />
|
||||
</Button>
|
||||
}
|
||||
@@ -1364,7 +1359,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
onClick={handleCopyAsMarkdown}
|
||||
className="w-full justify-start"
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -1372,7 +1367,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
onClick={handleCopyAsJsonl}
|
||||
className="w-full justify-start"
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
@@ -1554,7 +1549,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
)}
|
||||
|
||||
<div className={cn(
|
||||
"fixed bottom-0 left-0 right-0 transition-all duration-300 z-50",
|
||||
"absolute bottom-0 left-0 right-0 transition-all duration-300 z-50",
|
||||
showTimeline && "sm:right-96"
|
||||
)}>
|
||||
<FloatingPromptInput
|
||||
@@ -1603,7 +1598,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
<div className="h-full flex flex-col">
|
||||
{/* Timeline Header */}
|
||||
<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">{t('app.sessionTimeline')}</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -1682,6 +1677,12 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
{showSettings && effectiveSession && (
|
||||
<Dialog open={showSettings} onOpenChange={setShowSettings}>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('checkpoint.checkpointSettingsTitle')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('app.checkpointingWarning')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<CheckpointSettings
|
||||
sessionId={effectiveSession.id}
|
||||
projectId={effectiveSession.project_id}
|
||||
@@ -1699,7 +1700,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
||||
<DialogHeader>
|
||||
<DialogTitle>Slash Commands</DialogTitle>
|
||||
<DialogDescription>
|
||||
Manage project-specific slash commands for {projectPath}
|
||||
{t('slashCommands.manageProjectCommands')} {projectPath}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
|
@@ -271,7 +271,7 @@ export const CreateAgent: React.FC<CreateAgentProps> = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="text-sm font-semibold">Claude 4 Opus</div>
|
||||
<div className="text-sm font-semibold">Claude 4.1 Opus</div>
|
||||
<div className="text-xs opacity-80">{t('agents.opusDescription')}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -20,7 +20,7 @@ import { SlashCommandPicker } from "./SlashCommandPicker";
|
||||
import { ImagePreview } from "./ImagePreview";
|
||||
import { type FileEntry, type SlashCommand } from "@/lib/api";
|
||||
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
|
||||
import { useTranslation } from "@/hooks/useTranslation";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface FloatingPromptInputProps {
|
||||
/**
|
||||
@@ -110,7 +110,7 @@ const MODELS: Model[] = [
|
||||
},
|
||||
{
|
||||
id: "opus",
|
||||
name: "Claude 4 Opus",
|
||||
name: "Claude 4.1 Opus",
|
||||
description: "More capable, better for complex tasks",
|
||||
icon: <Sparkles className="h-4 w-4" />
|
||||
}
|
||||
@@ -775,7 +775,7 @@ const FloatingPromptInputInner = (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-muted-foreground">Model:</span>
|
||||
<span className="text-xs text-muted-foreground">{t('app.model')}:</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -871,7 +871,7 @@ const FloatingPromptInputInner = (
|
||||
{/* Fixed Position Input Bar */}
|
||||
<div
|
||||
className={cn(
|
||||
"fixed bottom-0 left-0 right-0 z-40 bg-background border-t border-border",
|
||||
"absolute bottom-0 left-0 right-0 z-40 bg-background/98 backdrop-blur-sm border-t border-border/40",
|
||||
dragActive && "ring-2 ring-primary ring-offset-2",
|
||||
className
|
||||
)}
|
||||
@@ -890,8 +890,8 @@ const FloatingPromptInputInner = (
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="p-4">
|
||||
<div className="flex items-end gap-3">
|
||||
<div className="p-3">
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Model Picker */}
|
||||
<Popover
|
||||
trigger={
|
||||
@@ -899,7 +899,7 @@ const FloatingPromptInputInner = (
|
||||
variant="outline"
|
||||
size="default"
|
||||
disabled={disabled}
|
||||
className="gap-2 min-w-[180px] justify-start"
|
||||
className="gap-2 min-w-[160px] h-10 justify-start"
|
||||
>
|
||||
{selectedModelData.icon}
|
||||
<span className="flex-1 text-left">{selectedModelData.name}</span>
|
||||
@@ -948,7 +948,7 @@ const FloatingPromptInputInner = (
|
||||
variant="outline"
|
||||
size="default"
|
||||
disabled={disabled}
|
||||
className="gap-2"
|
||||
className="gap-2 h-10"
|
||||
>
|
||||
<Brain className="h-4 w-4" />
|
||||
<ThinkingModeIndicator
|
||||
@@ -1009,7 +1009,7 @@ const FloatingPromptInputInner = (
|
||||
placeholder={dragActive ? t('messages.dropImagesHere') : t('messages.askClaudeAnything')}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"min-h-[44px] max-h-[120px] resize-none pr-10",
|
||||
"min-h-[40px] max-h-[120px] resize-none pr-10 py-2",
|
||||
dragActive && "border-primary"
|
||||
)}
|
||||
rows={1}
|
||||
@@ -1056,7 +1056,7 @@ const FloatingPromptInputInner = (
|
||||
disabled={isLoading ? false : (!prompt.trim() || disabled)}
|
||||
variant={isLoading ? "destructive" : "default"}
|
||||
size="default"
|
||||
className="min-w-[60px]"
|
||||
className="min-w-[60px] h-10"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
|
@@ -5,6 +5,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { api, type ProcessInfo, type Session } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { formatISOTimestamp } from "@/lib/date-utils";
|
||||
|
||||
interface RunningClaudeSessionsProps {
|
||||
@@ -25,6 +26,7 @@ export const RunningClaudeSessions: React.FC<RunningClaudeSessionsProps> = ({
|
||||
onSessionClick,
|
||||
className,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [runningSessions, setRunningSessions] = useState<ProcessInfo[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -144,11 +146,11 @@ export const RunningClaudeSessions: React.FC<RunningClaudeSessionsProps> = ({
|
||||
</p>
|
||||
|
||||
<div className="flex items-center gap-3 text-xs text-muted-foreground">
|
||||
<span>Started: {formatISOTimestamp(session.started_at)}</span>
|
||||
<span>Model: {session.model}</span>
|
||||
<span>{t('app.started')}: {formatISOTimestamp(session.started_at)}</span>
|
||||
<span>{t('app.model')}: {session.model}</span>
|
||||
{session.task && (
|
||||
<span className="truncate max-w-[200px]" title={session.task}>
|
||||
Task: {session.task}
|
||||
{t('app.task')}: {session.task}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
@@ -10,6 +10,7 @@ import { api } from '@/lib/api';
|
||||
import { useOutputCache } from '@/lib/outputCache';
|
||||
import type { AgentRun } from '@/lib/api';
|
||||
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StreamMessage } from './StreamMessage';
|
||||
import { ErrorBoundary } from './ErrorBoundary';
|
||||
|
||||
@@ -38,6 +39,7 @@ export interface ClaudeStreamMessage {
|
||||
}
|
||||
|
||||
export function SessionOutputViewer({ session, onClose, className }: SessionOutputViewerProps) {
|
||||
const { t } = useTranslation();
|
||||
const [messages, setMessages] = useState<ClaudeStreamMessage[]>([]);
|
||||
const [rawJsonlOutput, setRawJsonlOutput] = useState<string[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -410,7 +412,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsFullscreen(!isFullscreen)}
|
||||
title="Fullscreen"
|
||||
title={t('agents.fullscreen')}
|
||||
>
|
||||
{isFullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
|
||||
</Button>
|
||||
@@ -422,7 +424,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
Copy Output
|
||||
{t('app.copyOutput')}
|
||||
<ChevronDown className="h-3 w-3" />
|
||||
</Button>
|
||||
}
|
||||
@@ -434,7 +436,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -442,7 +444,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
@@ -567,7 +569,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
Copy Output
|
||||
{t('app.copyOutput')}
|
||||
<ChevronDown className="h-3 w-3" />
|
||||
</Button>
|
||||
}
|
||||
@@ -579,7 +581,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -587,7 +589,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
||||
className="w-full justify-start"
|
||||
onClick={handleCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ import {
|
||||
import type { SlashCommand } from "@/lib/api";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTrackEvent, useFeatureAdoptionTracking } from "@/hooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface SlashCommandPickerProps {
|
||||
/**
|
||||
@@ -79,6 +80,7 @@ export const SlashCommandPicker: React.FC<SlashCommandPickerProps> = ({
|
||||
initialQuery = "",
|
||||
className,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [commands, setCommands] = useState<SlashCommand[]>([]);
|
||||
const [filteredCommands, setFilteredCommands] = useState<SlashCommand[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -241,7 +243,7 @@ export const SlashCommandPicker: React.FC<SlashCommandPickerProps> = ({
|
||||
const groupedCommands = filteredCommands.reduce((acc, cmd) => {
|
||||
let key: string;
|
||||
if (cmd.scope === "user") {
|
||||
key = cmd.namespace ? `User Commands: ${cmd.namespace}` : "User Commands";
|
||||
key = cmd.namespace ? `${t('slashCommands.userCommands')}: ${cmd.namespace}` : t('slashCommands.userCommands');
|
||||
} else if (cmd.scope === "project") {
|
||||
key = cmd.namespace ? `Project Commands: ${cmd.namespace}` : "Project Commands";
|
||||
} else {
|
||||
@@ -278,10 +280,10 @@ export const SlashCommandPicker: React.FC<SlashCommandPickerProps> = ({
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Command className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-sm font-medium">Slash Commands</span>
|
||||
<span className="text-sm font-medium">{t('slashCommands.slashCommands')}</span>
|
||||
{searchQuery && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Searching: "{searchQuery}"
|
||||
{t('slashCommands.searching')}: "{searchQuery}"
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -474,7 +476,7 @@ export const SlashCommandPicker: React.FC<SlashCommandPickerProps> = ({
|
||||
{Object.entries(groupedCommands).map(([groupKey, groupCommands]) => (
|
||||
<div key={groupKey}>
|
||||
<h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider px-3 mb-1 flex items-center gap-2">
|
||||
{groupKey.startsWith("User Commands") && <User className="h-3 w-3" />}
|
||||
{groupKey.startsWith(t('slashCommands.userCommands')) && <User className="h-3 w-3" />}
|
||||
{groupKey.startsWith("Project Commands") && <Building2 className="h-3 w-3" />}
|
||||
{groupKey}
|
||||
</h3>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import {
|
||||
Database,
|
||||
@@ -81,6 +82,7 @@ interface QueryResult {
|
||||
* StorageTab component - A beautiful SQLite database viewer/editor
|
||||
*/
|
||||
export const StorageTab: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const [tables, setTables] = useState<TableInfo[]>([]);
|
||||
const [selectedTable, setSelectedTable] = useState<string>("");
|
||||
const [tableData, setTableData] = useState<TableData | null>(null);
|
||||
@@ -934,7 +936,7 @@ export const StorageTab: React.FC = () => {
|
||||
{loading ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
"Execute"
|
||||
t('agents.execute')
|
||||
)}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { motion } from "framer-motion";
|
||||
import {
|
||||
GitBranch,
|
||||
@@ -57,6 +58,7 @@ export const TimelineNavigator: React.FC<TimelineNavigatorProps> = ({
|
||||
onCheckpointCreated,
|
||||
className
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [timeline, setTimeline] = useState<SessionTimeline | null>(null);
|
||||
const [selectedCheckpoint, setSelectedCheckpoint] = useState<Checkpoint | null>(null);
|
||||
const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set());
|
||||
@@ -413,9 +415,9 @@ export const TimelineNavigator: React.FC<TimelineNavigatorProps> = ({
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertCircle className="h-4 w-4 text-yellow-600 mt-0.5" />
|
||||
<div className="text-xs">
|
||||
<p className="font-medium text-yellow-600">Experimental Feature</p>
|
||||
<p className="font-medium text-yellow-600">{t('app.experimentalFeature')}</p>
|
||||
<p className="text-yellow-600/80">
|
||||
Checkpointing may affect directory structure or cause data loss. Use with caution.
|
||||
{t('app.checkpointingWarning')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -425,10 +427,10 @@ export const TimelineNavigator: React.FC<TimelineNavigatorProps> = ({
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<GitBranch className="h-5 w-5 text-muted-foreground" />
|
||||
<h3 className="text-sm font-medium">Timeline</h3>
|
||||
<h3 className="text-sm font-medium">{t('app.timeline')}</h3>
|
||||
{timeline && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{timeline.totalCheckpoints} checkpoints
|
||||
{timeline.totalCheckpoints} {t('app.checkpoints')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
@@ -459,7 +461,7 @@ export const TimelineNavigator: React.FC<TimelineNavigatorProps> = ({
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center py-8 text-sm text-muted-foreground">
|
||||
{isLoading ? "Loading timeline..." : "No checkpoints yet"}
|
||||
{isLoading ? t('app.loadingTimeline') : t('app.noCheckpointsYet')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@@ -49,6 +49,7 @@ import {
|
||||
Hash,
|
||||
} from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { getClaudeSyntaxTheme } from "@/lib/claudeSyntaxTheme";
|
||||
@@ -400,6 +401,7 @@ export const ReadWidget: React.FC<{ filePath: string; result?: any }> = ({ fileP
|
||||
* Widget for Read tool result - shows file content with line numbers
|
||||
*/
|
||||
export const ReadResultWidget: React.FC<{ content: string; filePath?: string }> = ({ content, filePath }) => {
|
||||
const { t } = useTranslation();
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const { theme } = useTheme();
|
||||
const syntaxTheme = getClaudeSyntaxTheme(theme);
|
||||
@@ -510,7 +512,7 @@ export const ReadResultWidget: React.FC<{ content: string; filePath?: string }>
|
||||
<div className="flex items-center gap-2">
|
||||
<FileText className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-xs font-mono text-muted-foreground">
|
||||
{filePath || "File content"}
|
||||
{filePath || t('app.fileContent')}
|
||||
</span>
|
||||
{isLargeFile && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
@@ -572,6 +574,7 @@ export const ReadResultWidget: React.FC<{ content: string; filePath?: string }>
|
||||
* Widget for Glob tool
|
||||
*/
|
||||
export const GlobWidget: React.FC<{ pattern: string; result?: any }> = ({ pattern, result }) => {
|
||||
const { t } = useTranslation();
|
||||
// Extract result content if available
|
||||
let resultContent = '';
|
||||
let isError = false;
|
||||
@@ -597,7 +600,7 @@ export const GlobWidget: React.FC<{ pattern: string; result?: any }> = ({ patter
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 p-3 rounded-lg bg-muted/50">
|
||||
<Search className="h-4 w-4 text-primary" />
|
||||
<span className="text-sm">Searching for pattern:</span>
|
||||
<span className="text-sm">{t('app.searchingForPattern')}:</span>
|
||||
<code className="text-sm font-mono bg-background px-2 py-0.5 rounded">
|
||||
{pattern}
|
||||
</code>
|
||||
@@ -874,6 +877,7 @@ export const GrepWidget: React.FC<{
|
||||
exclude?: string;
|
||||
result?: any;
|
||||
}> = ({ pattern, include, path, exclude, result }) => {
|
||||
const { t } = useTranslation();
|
||||
const [isExpanded, setIsExpanded] = useState(true);
|
||||
|
||||
// Extract result content if available
|
||||
@@ -927,7 +931,7 @@ export const GrepWidget: React.FC<{
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 p-3 rounded-lg bg-gradient-to-r from-emerald-500/10 to-teal-500/10 border border-emerald-500/20">
|
||||
<Search className="h-4 w-4 text-emerald-500" />
|
||||
<span className="text-sm font-medium">Searching with grep</span>
|
||||
<span className="text-sm font-medium">{t('app.searchingWithGrep')}</span>
|
||||
{!result && (
|
||||
<div className="ml-auto flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<div className="h-2 w-2 bg-emerald-500 rounded-full animate-pulse" />
|
||||
@@ -1804,6 +1808,7 @@ export const SystemInitializedWidget: React.FC<{
|
||||
cwd?: string;
|
||||
tools?: string[];
|
||||
}> = ({ sessionId, model, cwd, tools = [] }) => {
|
||||
const { t } = useTranslation();
|
||||
const [mcpExpanded, setMcpExpanded] = useState(false);
|
||||
|
||||
// Separate regular tools from MCP tools
|
||||
@@ -1880,14 +1885,14 @@ export const SystemInitializedWidget: React.FC<{
|
||||
<div className="flex items-start gap-3">
|
||||
<Settings className="h-5 w-5 text-blue-500 mt-0.5" />
|
||||
<div className="flex-1 space-y-4">
|
||||
<h4 className="font-semibold text-sm">System Initialized</h4>
|
||||
<h4 className="font-semibold text-sm">{t('app.systemInitialized')}</h4>
|
||||
|
||||
{/* Session Info */}
|
||||
<div className="space-y-2">
|
||||
{sessionId && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Fingerprint className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-muted-foreground">Session ID:</span>
|
||||
<span className="text-muted-foreground">{t('app.sessionId')}:</span>
|
||||
<code className="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">
|
||||
{sessionId}
|
||||
</code>
|
||||
@@ -1897,7 +1902,7 @@ export const SystemInitializedWidget: React.FC<{
|
||||
{model && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Cpu className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-muted-foreground">Model:</span>
|
||||
<span className="text-muted-foreground">{t('app.model')}:</span>
|
||||
<code className="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">
|
||||
{model}
|
||||
</code>
|
||||
@@ -1907,7 +1912,7 @@ export const SystemInitializedWidget: React.FC<{
|
||||
{cwd && (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<FolderOpen className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-muted-foreground">Working Directory:</span>
|
||||
<span className="text-muted-foreground">{t('app.workingDirectory')}:</span>
|
||||
<code className="font-mono text-xs bg-muted px-1.5 py-0.5 rounded break-all">
|
||||
{cwd}
|
||||
</code>
|
||||
@@ -1921,7 +1926,7 @@ export const SystemInitializedWidget: React.FC<{
|
||||
<div className="flex items-center gap-2">
|
||||
<Wrench className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-xs font-medium text-muted-foreground">
|
||||
Available Tools ({regularTools.length})
|
||||
{t('app.availableTools')} ({regularTools.length})
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
@@ -1950,7 +1955,7 @@ export const SystemInitializedWidget: React.FC<{
|
||||
className="flex items-center gap-2 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<Package className="h-3.5 w-3.5" />
|
||||
<span>MCP Services ({mcpTools.length})</span>
|
||||
<span>{t('app.mcpServices')} ({mcpTools.length})</span>
|
||||
<ChevronDown className={cn(
|
||||
"h-3 w-3 transition-transform",
|
||||
mcpExpanded && "rotate-180"
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { motion } from 'framer-motion';
|
||||
import {
|
||||
ArrowLeft,
|
||||
@@ -51,6 +52,7 @@ export const SessionHeader: React.FC<SessionHeaderProps> = React.memo(({
|
||||
onSlashCommandsSettings,
|
||||
setCopyPopoverOpen
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
@@ -70,7 +72,7 @@ export const SessionHeader: React.FC<SessionHeaderProps> = React.memo(({
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Terminal className="h-5 w-5 text-primary" />
|
||||
<span className="font-semibold">Claude Code Session</span>
|
||||
<span className="font-semibold">{t('app.claudeCodeSession')}</span>
|
||||
</div>
|
||||
|
||||
{projectPath && (
|
||||
@@ -125,7 +127,7 @@ export const SessionHeader: React.FC<SessionHeaderProps> = React.memo(({
|
||||
className="w-full justify-start"
|
||||
onClick={onCopyAsJsonl}
|
||||
>
|
||||
Copy as JSONL
|
||||
{t('app.copyAsJsonl')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -133,7 +135,7 @@ export const SessionHeader: React.FC<SessionHeaderProps> = React.memo(({
|
||||
className="w-full justify-start"
|
||||
onClick={onCopyAsMarkdown}
|
||||
>
|
||||
Copy as Markdown
|
||||
{t('app.copyAsMarkdown')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
|
@@ -34,7 +34,34 @@
|
||||
"of": "of",
|
||||
"loading": "Loading...",
|
||||
"from": "from",
|
||||
"retry": "Retry"
|
||||
"retry": "Retry",
|
||||
"model": "Model",
|
||||
"projectPath": "Project Path",
|
||||
"task": "Task",
|
||||
"started": "Started",
|
||||
"output": "Output",
|
||||
"copyOutput": "Copy Output",
|
||||
"copyAsMarkdown": "Copy as Markdown",
|
||||
"copyAsJsonl": "Copy as JSONL",
|
||||
"close": "Close",
|
||||
"systemInitialized": "System Initialized",
|
||||
"availableTools": "Available Tools",
|
||||
"workingDirectory": "Working Directory",
|
||||
"sessionId": "Session ID",
|
||||
"mcpServices": "MCP Services",
|
||||
"searchingWithGrep": "Searching with grep",
|
||||
"searchingForPattern": "Searching for pattern",
|
||||
"fileContent": "File content",
|
||||
"yesterday": "Yesterday",
|
||||
"commands": "Commands",
|
||||
"claudeCodeSession": "Claude Code Session",
|
||||
"experimentalFeature": "Experimental Feature",
|
||||
"checkpointingWarning": "Checkpointing may affect directory structure or cause data loss. Use with caution.",
|
||||
"timeline": "Timeline",
|
||||
"noCheckpointsYet": "No checkpoints yet",
|
||||
"sessionTimeline": "Session Timeline",
|
||||
"checkpoints": "checkpoints",
|
||||
"loadingTimeline": "Loading timeline..."
|
||||
},
|
||||
"navigation": {
|
||||
"projects": "CC Projects",
|
||||
@@ -80,6 +107,14 @@
|
||||
"editAgent": "Edit Agent",
|
||||
"deleteAgent": "Delete Agent",
|
||||
"executeAgent": "Execute Agent",
|
||||
"execute": "Execute",
|
||||
"readyToExecute": "Ready to Execute",
|
||||
"task": "Task",
|
||||
"enterTask": "Enter the task for the agent",
|
||||
"hooks": "Hooks",
|
||||
"configureHooks": "Configure Hooks",
|
||||
"fullscreen": "Fullscreen",
|
||||
"stop": "Stop",
|
||||
"agentName": "Agent Name",
|
||||
"agentNameRequired": "Agent name is required",
|
||||
"agentIcon": "Agent Icon",
|
||||
@@ -102,6 +137,8 @@
|
||||
"systemPromptRequired": "System prompt is required",
|
||||
"defaultTask": "Default Task",
|
||||
"model": "Model",
|
||||
"projectPath": "Project Path",
|
||||
"selectProjectPath": "Select or enter project path",
|
||||
"permissions": "Permissions",
|
||||
"fileAccess": "File Access",
|
||||
"networkAccess": "Network Access",
|
||||
@@ -119,7 +156,9 @@
|
||||
"updateFailed": "Failed to update agent",
|
||||
"basicInformation": "Basic Information",
|
||||
"optional": "Optional",
|
||||
"sonnetName": "Claude 4 Sonnet",
|
||||
"sonnetDescription": "Faster, efficient for most tasks",
|
||||
"opusName": "Claude 4.1 Opus",
|
||||
"opusDescription": "More capable, better for complex tasks",
|
||||
"defaultTaskDescription": "This will be used as the default task placeholder when executing the agent",
|
||||
"systemPromptDescription": "Define the behavior and capabilities of your CC Agent",
|
||||
@@ -128,6 +167,15 @@
|
||||
"createFirstAgent": "Create your first CC Agent to get started",
|
||||
"created": "Created",
|
||||
"execute": "Execute",
|
||||
"readyToExecute": "Ready to Execute",
|
||||
"enterTask": "Enter the task for the agent",
|
||||
"hooks": "Hooks",
|
||||
"configureHooks": "Configure Hooks",
|
||||
"fullscreen": "Fullscreen",
|
||||
"stop": "Stop",
|
||||
"selectProjectPathAndTask": "Select a project path and enter a task to run the agent",
|
||||
"noExecutionHistory": "No execution history yet",
|
||||
"agentRunningWarning": "An agent is currently running. If you navigate away, the agent will continue running in the background. You can view running sessions in the 'Running Sessions' tab within CC Agents.\n\nDo you want to continue?",
|
||||
"export": "Export",
|
||||
"import": "Import",
|
||||
"importFromFile": "From File",
|
||||
@@ -155,6 +203,8 @@
|
||||
},
|
||||
"slashCommands": {
|
||||
"slashCommands": "Slash Commands",
|
||||
"globalSearch": "Global Search",
|
||||
"searching": "Searching",
|
||||
"projectSlashCommands": "Project Slash Commands",
|
||||
"createCustomCommandsProject": "Create custom commands for this project",
|
||||
"createCustomCommandsWorkflow": "Create custom commands to streamline your workflow",
|
||||
@@ -162,6 +212,8 @@
|
||||
"allCommands": "All Commands",
|
||||
"project": "Project",
|
||||
"user": "User",
|
||||
"userCommands": "User Commands",
|
||||
"manageProjectCommands": "Manage project-specific slash commands for",
|
||||
"noCommandsFound": "No commands found",
|
||||
"noProjectCommandsYet": "No project commands created yet",
|
||||
"noCommandsYet": "No commands created yet",
|
||||
|
@@ -31,7 +31,34 @@
|
||||
"page": "页面",
|
||||
"of": "共",
|
||||
"loading": "加载中...",
|
||||
"from": "从"
|
||||
"from": "从",
|
||||
"model": "模型",
|
||||
"projectPath": "项目路径",
|
||||
"task": "任务",
|
||||
"started": "开始时间",
|
||||
"output": "输出",
|
||||
"copyOutput": "复制输出",
|
||||
"copyAsMarkdown": "复制为 Markdown",
|
||||
"copyAsJsonl": "复制为 JSONL",
|
||||
"close": "关闭",
|
||||
"systemInitialized": "系统已初始化",
|
||||
"availableTools": "可用工具",
|
||||
"workingDirectory": "工作目录",
|
||||
"sessionId": "会话 ID",
|
||||
"mcpServices": "MCP 服务",
|
||||
"searchingWithGrep": "使用 grep 搜索",
|
||||
"searchingForPattern": "搜索模式",
|
||||
"fileContent": "文件内容",
|
||||
"yesterday": "昨天",
|
||||
"commands": "命令",
|
||||
"claudeCodeSession": "Claude Code 会话",
|
||||
"experimentalFeature": "实验性功能",
|
||||
"checkpointingWarning": "检查点可能会影响目录结构或导致数据丢失。请谨慎使用。",
|
||||
"timeline": "时间线",
|
||||
"noCheckpointsYet": "尚无检查点",
|
||||
"sessionTimeline": "会话时间线",
|
||||
"checkpoints": "个检查点",
|
||||
"loadingTimeline": "加载时间线中..."
|
||||
},
|
||||
"navigation": {
|
||||
"projects": "Claude Code 项目",
|
||||
@@ -99,6 +126,8 @@
|
||||
"systemPromptRequired": "系统提示为必填项",
|
||||
"defaultTask": "默认任务",
|
||||
"model": "模型",
|
||||
"projectPath": "项目路径",
|
||||
"selectProjectPath": "选择或输入项目路径",
|
||||
"permissions": "权限",
|
||||
"fileAccess": "文件访问",
|
||||
"networkAccess": "网络访问",
|
||||
@@ -116,7 +145,9 @@
|
||||
"updateFailed": "更新智能体失败",
|
||||
"basicInformation": "基本信息",
|
||||
"optional": "可选",
|
||||
"sonnetName": "Claude 4 Sonnet",
|
||||
"sonnetDescription": "更快,适用于大多数任务",
|
||||
"opusName": "Claude 4.1 Opus",
|
||||
"opusDescription": "功能更强,适用于复杂任务",
|
||||
"defaultTaskDescription": "执行智能体时将用作默认任务占位符",
|
||||
"systemPromptDescription": "定义您的 CC 智能体的行为和功能",
|
||||
@@ -125,6 +156,15 @@
|
||||
"createFirstAgent": "创建您的第一个 CC 智能体来开始",
|
||||
"created": "创建于",
|
||||
"execute": "执行",
|
||||
"readyToExecute": "准备执行",
|
||||
"enterTask": "输入智能体的任务",
|
||||
"hooks": "钩子",
|
||||
"configureHooks": "配置钩子",
|
||||
"fullscreen": "全屏",
|
||||
"stop": "停止",
|
||||
"selectProjectPathAndTask": "选择项目路径并输入任务以运行智能体",
|
||||
"noExecutionHistory": "尚无执行历史",
|
||||
"agentRunningWarning": "智能体正在运行。如果您离开此页面,智能体将在后台继续运行。您可以在 CC Agents 中的“运行中的会话”选项卡中查看运行中的会话。\n\n是否继续?",
|
||||
"export": "导出",
|
||||
"import": "导入",
|
||||
"importFromFile": "从文件导入",
|
||||
@@ -152,6 +192,8 @@
|
||||
},
|
||||
"slashCommands": {
|
||||
"slashCommands": "斜杠命令",
|
||||
"globalSearch": "全局搜索",
|
||||
"searching": "搜索中",
|
||||
"projectSlashCommands": "项目斜杠命令",
|
||||
"createCustomCommandsProject": "为此项目创建自定义命令",
|
||||
"createCustomCommandsWorkflow": "创建自定义命令来简化您的工作流程",
|
||||
@@ -159,6 +201,8 @@
|
||||
"allCommands": "所有命令",
|
||||
"project": "项目",
|
||||
"user": "用户",
|
||||
"userCommands": "用户命令",
|
||||
"manageProjectCommands": "管理项目特定的斜杠命令",
|
||||
"noCommandsFound": "未找到命令",
|
||||
"noProjectCommandsYet": "尚未创建项目命令",
|
||||
"noCommandsYet": "尚未创建命令",
|
||||
@@ -519,6 +563,9 @@
|
||||
"noAgentDataSpecified": "未指定智能体数据",
|
||||
"importAgentComingSoon": "导入智能体功能即将推出...",
|
||||
"unknownTabType": "未知的标签页类型",
|
||||
"typeYourPromptHere": "在此输入您的提示...",
|
||||
"dropImagesHere": "在此放置图片...",
|
||||
"askClaudeAnything": "询问 Claude 任何问题...",
|
||||
"selectClaudeCodeInstallation": "选择 Claude Code 安装",
|
||||
"multipleInstallationsFound": "在您的系统上找到了多个 Claude Code 安装。请选择您要使用的安装。",
|
||||
"claudeCodeNotFoundDialog": "在常见安装位置中未找到 Claude Code。请安装 Claude Code 以继续。",
|
||||
|
Reference in New Issue
Block a user