style: improve code formatting and consistency in AgentAudit.tsx

This commit is contained in:
lintsinghua 2025-12-12 16:21:35 +08:00
parent b392e049e8
commit e13218a33e
1 changed files with 176 additions and 124 deletions

View File

@ -118,7 +118,7 @@ function SplashScreen({ onComplete }: { onComplete: () => void }) {
<div className="h-screen bg-[#0a0a0f] flex items-center justify-center">
<div className="text-center space-y-6">
<pre className="text-primary font-mono text-xs sm:text-sm leading-tight select-none">
{`
{`
@ -568,8 +568,7 @@ function StatsPanel({ task, findings }: { task: AgentTask | null; findings: Agen
<div className="pt-2 border-t border-gray-800">
<div className="flex justify-between items-center">
<span className="text-xs text-gray-500">Security Score</span>
<span className={`text-lg font-bold font-mono ${
task.security_score >= 80 ? 'text-green-400' :
<span className={`text-lg font-bold font-mono ${task.security_score >= 80 ? 'text-green-400' :
task.security_score >= 60 ? 'text-yellow-400' :
'text-red-400'
}`}>
@ -627,7 +626,8 @@ export default function AgentAuditPage() {
const currentThinkingId = useRef<string | null>(null);
const currentAgentName = useRef<string | null>(null);
const isRunning = task?.status === "running";
// 任务是否可取消(包括 pending 和 running 状态)
const isRunning = task?.status === "running" || task?.status === "pending";
const isComplete = task?.status === "completed" || task?.status === "failed" || task?.status === "cancelled";
// 构建 Agent 树结构(将扁平列表转换为树)
@ -727,6 +727,36 @@ export default function AgentAuditPage() {
}
}, [taskId]);
// 🔥 Agent 树刷新防抖 ref
const agentTreeRefreshTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
const lastAgentTreeRefreshTime = useRef<number>(0);
// 🔥 防抖刷新 Agent 树
const debouncedLoadAgentTree = useCallback(() => {
const now = Date.now();
const minInterval = 500; // 最小刷新间隔 500ms
// 清除之前的定时器
if (agentTreeRefreshTimer.current) {
clearTimeout(agentTreeRefreshTimer.current);
}
// 如果距离上次刷新不到 minInterval延迟刷新
const timeSinceLastRefresh = now - lastAgentTreeRefreshTime.current;
if (timeSinceLastRefresh < minInterval) {
agentTreeRefreshTimer.current = setTimeout(() => {
lastAgentTreeRefreshTime.current = Date.now();
loadAgentTree();
}, minInterval - timeSinceLastRefresh);
} else {
// 立即刷新,但添加一个小延迟确保后端数据已更新
agentTreeRefreshTimer.current = setTimeout(() => {
lastAgentTreeRefreshTime.current = Date.now();
loadAgentTree();
}, 100);
}
}, [loadAgentTree]);
// 流式事件处理
const streamOptions = useMemo(() => ({
includeThinking: true,
@ -737,15 +767,18 @@ export default function AgentAuditPage() {
currentAgentName.current = event.metadata.agent_name;
}
// 处理 dispatch 事件
// 🔥 处理 dispatch 相关事件 - 增加更多事件类型
const dispatchEvents = ['dispatch', 'dispatch_complete', 'node_start', 'phase_start'];
if (dispatchEvents.includes(event.type)) {
if (event.type === 'dispatch' || event.type === 'dispatch_complete') {
addLog({
type: 'dispatch',
title: event.message || `Agent dispatch: ${event.metadata?.agent || 'unknown'}`,
agentName: currentAgentName.current || undefined,
});
// 🔥 刷新 Agent 树,显示新创建的子 Agent
loadAgentTree();
}
// 🔥 使用防抖刷新 Agent 树,显示新创建的子 Agent
debouncedLoadAgentTree();
}
},
onThinkingStart: () => {
@ -859,7 +892,7 @@ export default function AgentAuditPage() {
onError: (err: string) => {
addLog({ type: 'error', title: `Error: ${err}` });
},
}), [addLog, loadTask, loadFindings, loadAgentTree]);
}), [addLog, loadTask, loadFindings, loadAgentTree, debouncedLoadAgentTree]);
const { connect: connectStream, disconnect: disconnectStream, isConnected } = useAgentStream(taskId || null, streamOptions);
@ -885,10 +918,10 @@ export default function AgentAuditPage() {
return () => disconnectStream();
}, [taskId, task?.status, connectStream, disconnectStream, addLog]);
// 定期刷新 Agent 树
// 定期刷新 Agent 树 - 每 2 秒刷新一次
useEffect(() => {
if (!taskId || !isRunning) return;
const interval = setInterval(loadAgentTree, 3000);
const interval = setInterval(loadAgentTree, 2000);
return () => clearInterval(interval);
}, [taskId, isRunning, loadAgentTree]);
@ -906,15 +939,30 @@ export default function AgentAuditPage() {
}
}, [logs, isAutoScroll]);
// 取消状态
const [isCancelling, setIsCancelling] = useState(false);
// 取消任务
const handleCancel = async () => {
if (!taskId) return;
if (!taskId || isCancelling) return;
setIsCancelling(true);
addLog({ type: 'info', title: '🛑 Requesting task cancellation...' });
try {
await cancelAgentTask(taskId);
toast.success("Task cancelled");
loadTask();
} catch {
toast.error("Failed to cancel task");
toast.success("Task cancellation requested");
addLog({ type: 'info', title: '🛑 Task cancellation confirmed' });
// 立即刷新任务状态
await loadTask();
// 断开流连接
disconnectStream();
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
toast.error(`Failed to cancel task: ${errorMessage}`);
addLog({ type: 'error', title: `Failed to cancel: ${errorMessage}` });
} finally {
setIsCancelling(false);
}
};
@ -978,10 +1026,15 @@ export default function AgentAuditPage() {
variant="ghost"
size="sm"
onClick={handleCancel}
className="text-red-400 hover:text-red-300 hover:bg-red-950/30"
disabled={isCancelling}
className="text-red-400 hover:text-red-300 hover:bg-red-950/30 disabled:opacity-50"
>
{isCancelling ? (
<Loader2 className="w-4 h-4 mr-1 animate-spin" />
) : (
<Square className="w-4 h-4 mr-1" />
Stop
)}
{isCancelling ? 'Stopping...' : 'Stop'}
</Button>
)}
<Button
@ -1018,8 +1071,7 @@ export default function AgentAuditPage() {
</div>
<button
onClick={() => setIsAutoScroll(!isAutoScroll)}
className={`text-xs px-2 py-1 rounded transition-colors ${
isAutoScroll ? 'bg-primary/20 text-primary' : 'text-gray-500 hover:text-gray-300'
className={`text-xs px-2 py-1 rounded transition-colors ${isAutoScroll ? 'bg-primary/20 text-primary' : 'text-gray-500 hover:text-gray-300'
}`}
>
Auto-scroll {isAutoScroll ? 'ON' : 'OFF'}