style: improve code formatting and consistency in AgentAudit.tsx
This commit is contained in:
parent
b392e049e8
commit
e13218a33e
|
|
@ -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,11 +568,10 @@ 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'
|
||||
}`}>
|
||||
'text-red-400'
|
||||
}`}>
|
||||
{task.security_score.toFixed(0)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -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 事件
|
||||
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();
|
||||
// 🔥 处理 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
|
||||
debouncedLoadAgentTree();
|
||||
}
|
||||
},
|
||||
onThinkingStart: () => {
|
||||
|
|
@ -790,11 +823,11 @@ export default function AgentAuditPage() {
|
|||
setLogs(prev => prev.map(log =>
|
||||
log.id === currentThinkingId.current
|
||||
? {
|
||||
...log,
|
||||
title: cleanResponse.slice(0, 100) + (cleanResponse.length > 100 ? '...' : ''),
|
||||
content: cleanResponse,
|
||||
isStreaming: false
|
||||
}
|
||||
...log,
|
||||
title: cleanResponse.slice(0, 100) + (cleanResponse.length > 100 ? '...' : ''),
|
||||
content: cleanResponse,
|
||||
isStreaming: false
|
||||
}
|
||||
: log
|
||||
));
|
||||
currentThinkingId.current = null;
|
||||
|
|
@ -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"
|
||||
>
|
||||
<Square className="w-4 h-4 mr-1" />
|
||||
Stop
|
||||
{isCancelling ? (
|
||||
<Loader2 className="w-4 h-4 mr-1 animate-spin" />
|
||||
) : (
|
||||
<Square className="w-4 h-4 mr-1" />
|
||||
)}
|
||||
{isCancelling ? 'Stopping...' : 'Stop'}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
|
|
@ -1018,9 +1071,8 @@ 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'}
|
||||
</button>
|
||||
|
|
|
|||
Loading…
Reference in New Issue