feat(flow): 实时全链路流程可视化 P1——trace→graph_update→前端全链路流程页(design/19)
后端: trace/graph.go(RunGraph 图构建器,kind/status 映射,父子优先连线,脱敏白名单+截断);
loop/flow.go(FlowPublisher 按会话增量发布 ws.graph_update,仅主人web会话); loop span
start/finish 折入图; run.go StartRound/EndRound; wire.go 组装+注入.
前端: Flow.tsx(全链路流程页:FlowGraphView+会话/节点/开始/耗时卡片+状态计数+节点点开日志);
FlowGraph 组件加 onNodeClick; types/wsParse 扩展; router/sections/AdminApp 注册 flow;
api-client.md §3.5 graph_update 契约.
验证: 后端 build/vet/test 全绿+flow_test.go 集成(span→graph→ws.graph_update主干); 前端 build 绿.
红线: 单二进制零新依赖; 工具参数/结果脱敏; 仅主人web会话; 身份靠actor元数据; 只读不虚构.
P2(并行子代理分支/泳道/节点实时日志)后置.
This commit is contained in:
1 parent
7a81071ec8
commit
44e7a5c2c5
18 files changed
+1126
-11
No files matched your search
@@ -144,7 +144,13 @@ function clampLabel(label: string): string {
|
||||
return label.length > 20 ? `${label.slice(0, 19)}…` : label;
|
||||
}
|
||||
|
||||
export function FlowGraphView({ graph }: { graph: FlowGraph }): ReactNode {
|
||||
export function FlowGraphView({
|
||||
graph,
|
||||
onNodeClick,
|
||||
}: {
|
||||
graph: FlowGraph;
|
||||
onNodeClick?: (node: FlowNode) => void;
|
||||
}): ReactNode {
|
||||
const markerId = useId().replace(/[^a-zA-Z0-9]/g, "");
|
||||
const { placed, edges, width, height } = layout(graph);
|
||||
|
||||
@@ -186,7 +192,11 @@ export function FlowGraphView({ graph }: { graph: FlowGraph }): ReactNode {
|
||||
);
|
||||
})}
|
||||
{placed.map((p) => (
|
||||
<g key={p.node.id}>
|
||||
<g
|
||||
key={p.node.id}
|
||||
onClick={onNodeClick ? () => onNodeClick(p.node) : undefined}
|
||||
className={onNodeClick ? "cursor-pointer" : undefined}
|
||||
>
|
||||
<rect
|
||||
x={p.x}
|
||||
y={p.y}
|
||||
|
||||
Reference in new issue
Block a user