gMAS / web_ui /frontend /src /components /execution /ExecutionPanel.tsx
Артём Боярских
chore: initial commit
3193174
import { useState, useEffect } from "react";
import { Play, Square, RotateCcw } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Separator } from "@/components/ui/separator";
import { ExecutionTimeline } from "./ExecutionTimeline";
import { TokenUsageChart } from "./TokenUsageChart";
import { ResultViewer } from "./ResultViewer";
import { AgentStatusBadge } from "./AgentStatusBadge";
import { useExecutionStore } from "@/stores/executionStore";
import { useGraphStore } from "@/stores/graphStore";
import { useConfigStore } from "@/stores/configStore";
import type { AgentExecutionStatus } from "@/types/execution";
export function ExecutionPanel() {
const { taskQuery, setTaskQuery, toGraphRequest, updateNodeExecutionStatus, resetExecutionStatus, nodes } =
useGraphStore();
const {
status,
events,
agentStatuses,
tokenUsage,
finalAnswer,
totalTokens,
totalTime,
error,
startExecution,
cancelExecution,
clearRun,
} = useExecutionStore();
const { runnerConfig, llmProviders } = useConfigStore();
const isRunning = status === "running";
// Sync execution statuses to graph nodes for live visualization
useEffect(() => {
Object.entries(agentStatuses).forEach(([agentId, agentStatus]) => {
updateNodeExecutionStatus(agentId, agentStatus as AgentExecutionStatus);
});
}, [agentStatuses, updateNodeExecutionStatus]);
// Update node token counts
useEffect(() => {
Object.entries(tokenUsage).forEach(([agentId, tokens]) => {
updateNodeExecutionStatus(agentId, agentStatuses[agentId] as AgentExecutionStatus || "completed", undefined, tokens);
});
}, [tokenUsage]);
const handleRun = async () => {
resetExecutionStatus();
const graphData = toGraphRequest();
const provider = llmProviders.length > 0 ? llmProviders[0] : null;
await startExecution(null, graphData, taskQuery, runnerConfig, provider);
};
const handleStop = () => {
cancelExecution();
};
const handleClear = () => {
clearRun();
resetExecutionStatus();
};
return (
<div className="flex h-full w-80 flex-col border-l bg-card">
<div className="p-3 border-b space-y-3">
<div className="space-y-2">
<Label className="text-xs">Task Query</Label>
<Input
placeholder="Describe the task for the agents..."
value={taskQuery}
onChange={(e) => setTaskQuery(e.target.value)}
disabled={isRunning}
/>
</div>
<div className="flex gap-2">
{!isRunning ? (
<Button
onClick={handleRun}
disabled={nodes.length === 0 || !taskQuery.trim()}
className="flex-1 gap-1"
size="sm"
>
<Play className="h-3.5 w-3.5" />
Execute
</Button>
) : (
<Button onClick={handleStop} variant="destructive" className="flex-1 gap-1" size="sm">
<Square className="h-3.5 w-3.5" />
Stop
</Button>
)}
<Button onClick={handleClear} variant="outline" size="sm" disabled={isRunning}>
<RotateCcw className="h-3.5 w-3.5" />
</Button>
</div>
{/* Agent statuses */}
{Object.keys(agentStatuses).length > 0 && (
<>
<Separator />
<div className="space-y-1">
{Object.entries(agentStatuses).map(([id, agentStatus]) => (
<AgentStatusBadge
key={id}
status={agentStatus as AgentExecutionStatus}
agentName={id}
/>
))}
</div>
</>
)}
</div>
<Tabs defaultValue="timeline" className="flex-1 flex flex-col">
<TabsList className="mx-3 mt-2">
<TabsTrigger value="timeline" className="text-xs">
Timeline
</TabsTrigger>
<TabsTrigger value="tokens" className="text-xs">
Tokens
</TabsTrigger>
<TabsTrigger value="result" className="text-xs">
Result
</TabsTrigger>
</TabsList>
<TabsContent value="timeline" className="flex-1 overflow-hidden mt-0">
<ExecutionTimeline events={events} />
</TabsContent>
<TabsContent value="tokens" className="flex-1 overflow-hidden mt-0 p-3">
<TokenUsageChart tokenUsage={tokenUsage} />
</TabsContent>
<TabsContent value="result" className="flex-1 overflow-hidden mt-0">
<ResultViewer
status={status}
finalAnswer={finalAnswer}
totalTokens={totalTokens}
totalTime={totalTime}
events={events}
error={error}
/>
</TabsContent>
</Tabs>
</div>
);
}