@railtownai/railtracks-visualizer 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -201
- package/README.md +52 -52
- package/dist/cjs/index.js +55 -40
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +55 -12
- package/dist/esm/index.js.map +1 -0
- package/dist/types/src/AgenticFlowVisualizer.d.ts.map +1 -0
- package/dist/types/src/App.d.ts.map +1 -0
- package/dist/types/src/Visualizer.d.ts.map +1 -0
- package/dist/types/src/components/Edge.d.ts.map +1 -0
- package/dist/types/src/components/FileSelector.d.ts.map +1 -0
- package/dist/types/src/components/Node.d.ts.map +1 -0
- package/dist/types/src/components/Timeline.d.ts.map +1 -0
- package/dist/types/src/components/VerticalTimeline.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useApi.d.ts.map +1 -0
- package/dist/types/src/hooks/useFlowData.d.ts.map +1 -0
- package/dist/types/{index.d.ts → src/index.d.ts} +1 -3
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/tests/setup.d.ts.map +1 -0
- package/package.json +93 -82
- package/dist/cjs/AgenticFlowVisualizer.js +0 -750
- package/dist/cjs/App.js +0 -94
- package/dist/cjs/Visualizer.js +0 -16
- package/dist/cjs/components/Edge.js +0 -75
- package/dist/cjs/components/FileSelector.js +0 -28
- package/dist/cjs/components/Node.js +0 -104
- package/dist/cjs/components/Timeline.js +0 -122
- package/dist/cjs/components/VerticalTimeline.js +0 -160
- package/dist/cjs/hooks/index.js +0 -7
- package/dist/cjs/hooks/useApi.js +0 -108
- package/dist/cjs/hooks/useFlowData.js +0 -53
- package/dist/cjs/test/Visualizer.test.js +0 -257
- package/dist/cjs/test/setup.js +0 -24
- package/dist/esm/AgenticFlowVisualizer.js +0 -710
- package/dist/esm/App.js +0 -89
- package/dist/esm/Visualizer.js +0 -11
- package/dist/esm/components/Edge.js +0 -74
- package/dist/esm/components/FileSelector.js +0 -24
- package/dist/esm/components/Node.js +0 -100
- package/dist/esm/components/Timeline.js +0 -118
- package/dist/esm/components/VerticalTimeline.js +0 -156
- package/dist/esm/hooks/index.js +0 -2
- package/dist/esm/hooks/useApi.js +0 -95
- package/dist/esm/hooks/useFlowData.js +0 -66
- package/dist/esm/test/Visualizer.test.js +0 -243
- package/dist/esm/test/setup.js +0 -22
- package/dist/types/AgenticFlowVisualizer.d.ts.map +0 -1
- package/dist/types/App.d.ts.map +0 -1
- package/dist/types/Visualizer.d.ts.map +0 -1
- package/dist/types/components/Edge.d.ts.map +0 -1
- package/dist/types/components/FileSelector.d.ts.map +0 -1
- package/dist/types/components/Node.d.ts.map +0 -1
- package/dist/types/components/Timeline.d.ts.map +0 -1
- package/dist/types/components/VerticalTimeline.d.ts.map +0 -1
- package/dist/types/hooks/index.d.ts.map +0 -1
- package/dist/types/hooks/useApi.d.ts.map +0 -1
- package/dist/types/hooks/useFlowData.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/test/Visualizer.test.d.ts +0 -2
- package/dist/types/test/Visualizer.test.d.ts.map +0 -1
- package/dist/types/test/setup.d.ts.map +0 -1
- /package/dist/types/{AgenticFlowVisualizer.d.ts → src/AgenticFlowVisualizer.d.ts} +0 -0
- /package/dist/types/{App.d.ts → src/App.d.ts} +0 -0
- /package/dist/types/{Visualizer.d.ts → src/Visualizer.d.ts} +0 -0
- /package/dist/types/{components → src/components}/Edge.d.ts +0 -0
- /package/dist/types/{components → src/components}/FileSelector.d.ts +0 -0
- /package/dist/types/{components → src/components}/Node.d.ts +0 -0
- /package/dist/types/{components → src/components}/Timeline.d.ts +0 -0
- /package/dist/types/{components → src/components}/VerticalTimeline.d.ts +0 -0
- /package/dist/types/{hooks → src/hooks}/index.d.ts +0 -0
- /package/dist/types/{hooks → src/hooks}/useApi.d.ts +0 -0
- /package/dist/types/{hooks → src/hooks}/useFlowData.d.ts +0 -0
- /package/dist/types/{test → tests}/setup.d.ts +0 -0
|
@@ -1,750 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
37
|
-
const react_1 = require("react");
|
|
38
|
-
const reactflow_1 = require("reactflow");
|
|
39
|
-
const reactflow_2 = __importStar(require("reactflow"));
|
|
40
|
-
require("reactflow/dist/style.css");
|
|
41
|
-
const lucide_react_1 = require("lucide-react");
|
|
42
|
-
const Edge_1 = require("./components/Edge");
|
|
43
|
-
const Node_1 = require("./components/Node");
|
|
44
|
-
const Timeline_1 = require("./components/Timeline");
|
|
45
|
-
const VerticalTimeline_1 = require("./components/VerticalTimeline");
|
|
46
|
-
// ============================================================================
|
|
47
|
-
// UTILITY FUNCTIONS
|
|
48
|
-
// ============================================================================
|
|
49
|
-
/**
|
|
50
|
-
* Calculates a clean tree layout: parents centered above children, siblings spaced evenly, no overlap.
|
|
51
|
-
*/
|
|
52
|
-
const calculateAutoLayout = (nodes, edges) => {
|
|
53
|
-
// Build maps for fast lookup
|
|
54
|
-
const nodeMap = new Map(nodes.map((n) => [n.identifier, n]));
|
|
55
|
-
const childrenMap = new Map();
|
|
56
|
-
const parentMap = new Map();
|
|
57
|
-
nodes.forEach((n) => childrenMap.set(n.identifier, []));
|
|
58
|
-
// Handle edges if they exist
|
|
59
|
-
if (edges.length > 0) {
|
|
60
|
-
edges.forEach((e) => {
|
|
61
|
-
var _a;
|
|
62
|
-
if (e.source && e.target) {
|
|
63
|
-
(_a = childrenMap.get(e.source)) === null || _a === void 0 ? void 0 : _a.push(e.target);
|
|
64
|
-
parentMap.set(e.target, e.source);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
// If no edges, try to infer relationships from parent field
|
|
70
|
-
nodes.forEach((node) => {
|
|
71
|
-
var _a;
|
|
72
|
-
if (node.parent && node.parent.identifier !== node.identifier) {
|
|
73
|
-
(_a = childrenMap.get(node.parent.identifier)) === null || _a === void 0 ? void 0 : _a.push(node.identifier);
|
|
74
|
-
parentMap.set(node.identifier, node.parent.identifier);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
// Find root nodes (no parent)
|
|
79
|
-
const roots = nodes.filter((n) => !parentMap.has(n.identifier));
|
|
80
|
-
// Assign levels (depths) - now vertical levels from top to bottom
|
|
81
|
-
const levelMap = new Map();
|
|
82
|
-
const assignLevels = (nodeId, level) => {
|
|
83
|
-
levelMap.set(nodeId, level);
|
|
84
|
-
for (const childId of childrenMap.get(nodeId) || []) {
|
|
85
|
-
assignLevels(childId, level + 1);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
roots.forEach((root) => assignLevels(root.identifier, 0));
|
|
89
|
-
// Group nodes by level
|
|
90
|
-
const levels = [];
|
|
91
|
-
nodes.forEach((n) => {
|
|
92
|
-
var _a;
|
|
93
|
-
const lvl = (_a = levelMap.get(n.identifier)) !== null && _a !== void 0 ? _a : 0;
|
|
94
|
-
if (!levels[lvl])
|
|
95
|
-
levels[lvl] = [];
|
|
96
|
-
levels[lvl].push(n.identifier);
|
|
97
|
-
});
|
|
98
|
-
// Calculate subtree widths for each node (for centering horizontally)
|
|
99
|
-
const subtreeWidth = new Map();
|
|
100
|
-
const nodeWidth = 200; // Approximate node width
|
|
101
|
-
const nodeSpacing = 100; // Horizontal spacing between nodes
|
|
102
|
-
const calcSubtreeWidth = (nodeId) => {
|
|
103
|
-
const children = childrenMap.get(nodeId) || [];
|
|
104
|
-
if (children.length === 0) {
|
|
105
|
-
subtreeWidth.set(nodeId, nodeWidth);
|
|
106
|
-
return nodeWidth;
|
|
107
|
-
}
|
|
108
|
-
let width = 0;
|
|
109
|
-
for (const childId of children) {
|
|
110
|
-
width += calcSubtreeWidth(childId);
|
|
111
|
-
}
|
|
112
|
-
width += (children.length - 1) * nodeSpacing;
|
|
113
|
-
subtreeWidth.set(nodeId, width);
|
|
114
|
-
return width;
|
|
115
|
-
};
|
|
116
|
-
roots.forEach((root) => calcSubtreeWidth(root.identifier));
|
|
117
|
-
// Assign positions recursively - now top to bottom
|
|
118
|
-
const positions = new Map();
|
|
119
|
-
const levelSpacing = 300; // Increased vertical spacing between levels
|
|
120
|
-
const verticalMargin = 100; // Add margin to the top
|
|
121
|
-
const assignPositions = (nodeId, xLeft, level) => {
|
|
122
|
-
const width = subtreeWidth.get(nodeId) || nodeWidth;
|
|
123
|
-
const y = level * levelSpacing + verticalMargin; // Add margin here
|
|
124
|
-
const children = childrenMap.get(nodeId) || [];
|
|
125
|
-
if (children.length === 0) {
|
|
126
|
-
// Leaf node: center in its width
|
|
127
|
-
positions.set(nodeId, { x: xLeft + width / 2 - nodeWidth / 2, y });
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
// Internal node: center above its children
|
|
131
|
-
let childX = xLeft;
|
|
132
|
-
for (const childId of children) {
|
|
133
|
-
const childWidth = subtreeWidth.get(childId) || nodeWidth;
|
|
134
|
-
assignPositions(childId, childX, level + 1);
|
|
135
|
-
childX += childWidth + nodeSpacing;
|
|
136
|
-
}
|
|
137
|
-
// Center parent above children
|
|
138
|
-
const firstChild = children[0];
|
|
139
|
-
const lastChild = children[children.length - 1];
|
|
140
|
-
const firstPos = positions.get(firstChild);
|
|
141
|
-
const lastPos = positions.get(lastChild);
|
|
142
|
-
const parentX = (firstPos.x + lastPos.x) / 2;
|
|
143
|
-
positions.set(nodeId, { x: parentX, y });
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
// Lay out each tree
|
|
147
|
-
let xCursor = 0;
|
|
148
|
-
for (const root of roots) {
|
|
149
|
-
assignPositions(root.identifier, xCursor, 0);
|
|
150
|
-
xCursor += (subtreeWidth.get(root.identifier) || nodeWidth) + nodeSpacing * 2;
|
|
151
|
-
}
|
|
152
|
-
return positions;
|
|
153
|
-
};
|
|
154
|
-
/**
|
|
155
|
-
* Extracts LLM details from node data for display
|
|
156
|
-
*/
|
|
157
|
-
const extractLLMDetails = (node) => {
|
|
158
|
-
var _a, _b;
|
|
159
|
-
let description = node.node_type;
|
|
160
|
-
let modelInfo = "";
|
|
161
|
-
if ((_b = (_a = node.details) === null || _a === void 0 ? void 0 : _a.internals) === null || _b === void 0 ? void 0 : _b.llm_details) {
|
|
162
|
-
const llmDetails = node.details.internals.llm_details;
|
|
163
|
-
if (llmDetails.length > 0) {
|
|
164
|
-
const lastLLM = llmDetails[llmDetails.length - 1];
|
|
165
|
-
modelInfo = `${lastLLM.model_name} (${lastLLM.model_provider})`;
|
|
166
|
-
description = `${node.node_type}\n${modelInfo}`;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return { description, modelInfo };
|
|
170
|
-
};
|
|
171
|
-
/**
|
|
172
|
-
* Truncates text to specified length with ellipsis
|
|
173
|
-
*/
|
|
174
|
-
const truncateText = (text, maxLength) => {
|
|
175
|
-
if (text.length <= maxLength)
|
|
176
|
-
return text;
|
|
177
|
-
return text.substring(0, maxLength) + "...";
|
|
178
|
-
};
|
|
179
|
-
const nodeTypes = {
|
|
180
|
-
agent: Node_1.Node
|
|
181
|
-
};
|
|
182
|
-
const edgeTypes = {
|
|
183
|
-
default: Edge_1.Edge
|
|
184
|
-
};
|
|
185
|
-
const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100%", height = "1000px", className = "" }) => {
|
|
186
|
-
var _a, _b, _c, _d;
|
|
187
|
-
// Use prop data directly, no hooks needed
|
|
188
|
-
const flowData = propFlowData;
|
|
189
|
-
// Show no data state if no flowData is available
|
|
190
|
-
if (!flowData) {
|
|
191
|
-
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
192
|
-
width: typeof width === "number" ? `${width}px` : width,
|
|
193
|
-
height: typeof height === "number" ? `${height}px` : height,
|
|
194
|
-
border: "1px solid #e5e7eb",
|
|
195
|
-
borderRadius: "8px",
|
|
196
|
-
background: "#f9fafb",
|
|
197
|
-
position: "relative",
|
|
198
|
-
minWidth: "800px",
|
|
199
|
-
minHeight: "600px",
|
|
200
|
-
display: "flex",
|
|
201
|
-
alignItems: "center",
|
|
202
|
-
justifyContent: "center"
|
|
203
|
-
}, className: className, children: (0, jsx_runtime_1.jsxs)("div", { style: { textAlign: "center" }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: "16px", color: "#6b7280", marginBottom: "8px" }, children: "No flow data available" }), (0, jsx_runtime_1.jsx)("div", { style: { fontSize: "14px", color: "#9ca3af" }, children: "Please provide flowData prop" })] }) }));
|
|
204
|
-
}
|
|
205
|
-
const containerRef = (0, react_1.useRef)(null);
|
|
206
|
-
const svgRef = (0, react_1.useRef)(null);
|
|
207
|
-
const [containerDimensions, setContainerDimensions] = (0, react_1.useState)({
|
|
208
|
-
width: typeof width === "number" ? width : 800,
|
|
209
|
-
height: typeof height === "number" ? height : 600
|
|
210
|
-
});
|
|
211
|
-
// Timeline state
|
|
212
|
-
const [currentStep, setCurrentStep] = (0, react_1.useState)(0);
|
|
213
|
-
const [isPlaying, setIsPlaying] = (0, react_1.useState)(false);
|
|
214
|
-
const playIntervalRef = (0, react_1.useRef)(null);
|
|
215
|
-
// Timeline visibility state
|
|
216
|
-
const [showTimelines, setShowTimelines] = (0, react_1.useState)(false);
|
|
217
|
-
// Drawer state
|
|
218
|
-
const [isDrawerOpen, setIsDrawerOpen] = (0, react_1.useState)(false);
|
|
219
|
-
const [selectedData, setSelectedData] = (0, react_1.useState)(null);
|
|
220
|
-
// Get max step from stamps or steps
|
|
221
|
-
const maxStep = (0, react_1.useMemo)(() => {
|
|
222
|
-
const stamps = flowData.stamps || flowData.steps || [];
|
|
223
|
-
return stamps.length > 0 ? Math.max(...stamps.map((s) => s.step)) : 0;
|
|
224
|
-
}, [flowData.stamps, flowData.steps]);
|
|
225
|
-
// Auto-play functionality
|
|
226
|
-
(0, react_1.useEffect)(() => {
|
|
227
|
-
if (isPlaying) {
|
|
228
|
-
playIntervalRef.current = setInterval(() => {
|
|
229
|
-
setCurrentStep((prev) => {
|
|
230
|
-
if (prev >= maxStep) {
|
|
231
|
-
setIsPlaying(false);
|
|
232
|
-
return prev;
|
|
233
|
-
}
|
|
234
|
-
return prev + 1;
|
|
235
|
-
});
|
|
236
|
-
}, 250); // 1 second per step
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
if (playIntervalRef.current) {
|
|
240
|
-
clearInterval(playIntervalRef.current);
|
|
241
|
-
playIntervalRef.current = null;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return () => {
|
|
245
|
-
if (playIntervalRef.current) {
|
|
246
|
-
clearInterval(playIntervalRef.current);
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
}, [isPlaying, maxStep]);
|
|
250
|
-
// Initialize current step to last step and pan to hub node
|
|
251
|
-
(0, react_1.useEffect)(() => {
|
|
252
|
-
const stamps = flowData.stamps || flowData.steps || [];
|
|
253
|
-
if (stamps.length > 0) {
|
|
254
|
-
setCurrentStep(Math.max(...stamps.map((s) => s.step)));
|
|
255
|
-
}
|
|
256
|
-
}, [flowData.stamps, flowData.steps]);
|
|
257
|
-
// Update dimensions when width/height props change
|
|
258
|
-
(0, react_1.useEffect)(() => {
|
|
259
|
-
const updateDimensions = () => {
|
|
260
|
-
if (containerRef.current) {
|
|
261
|
-
const rect = containerRef.current.getBoundingClientRect();
|
|
262
|
-
setContainerDimensions({
|
|
263
|
-
width: rect.width || (typeof width === "number" ? width : 800),
|
|
264
|
-
height: rect.height || (typeof height === "number" ? height : 600)
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
updateDimensions();
|
|
269
|
-
// Use ResizeObserver if available, otherwise fallback to window resize
|
|
270
|
-
if (window.ResizeObserver && containerRef.current) {
|
|
271
|
-
const resizeObserver = new ResizeObserver(updateDimensions);
|
|
272
|
-
resizeObserver.observe(containerRef.current);
|
|
273
|
-
return () => resizeObserver.disconnect();
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
window.addEventListener("resize", updateDimensions);
|
|
277
|
-
return () => window.removeEventListener("resize", updateDimensions);
|
|
278
|
-
}
|
|
279
|
-
}, [width, height]);
|
|
280
|
-
// Calculate auto-layout positions
|
|
281
|
-
const positions = (0, react_1.useMemo)(() => {
|
|
282
|
-
return calculateAutoLayout(flowData.nodes, flowData.edges || []);
|
|
283
|
-
}, [flowData.nodes, flowData.edges]);
|
|
284
|
-
// Get nodes and edges for current step
|
|
285
|
-
const getNodesForStep = (0, react_1.useCallback)((step) => {
|
|
286
|
-
return flowData.nodes.filter((node) => node.stamp.step <= step);
|
|
287
|
-
}, [flowData.nodes]);
|
|
288
|
-
const getEdgesForStep = (0, react_1.useCallback)((step) => {
|
|
289
|
-
return (flowData.edges || []).filter((edge) => edge.stamp.step <= step);
|
|
290
|
-
}, [flowData.edges]);
|
|
291
|
-
// Handle node inspection
|
|
292
|
-
const handleNodeInspect = (0, react_1.useCallback)((nodeData) => {
|
|
293
|
-
setSelectedData({ type: "node", data: nodeData });
|
|
294
|
-
setIsDrawerOpen(true);
|
|
295
|
-
}, []);
|
|
296
|
-
// Handle edge inspection
|
|
297
|
-
const handleEdgeInspect = (0, react_1.useCallback)((edgeData) => {
|
|
298
|
-
// Find the edge in the current edges to get the ID
|
|
299
|
-
const currentEdges = getEdgesForStep(currentStep);
|
|
300
|
-
const edge = currentEdges.find((e) => e.source === edgeData.source && e.target === edgeData.target);
|
|
301
|
-
const edgeWithId = Object.assign(Object.assign({}, edgeData), { id: (edge === null || edge === void 0 ? void 0 : edge.identifier) || "N/A" });
|
|
302
|
-
setSelectedData({ type: "edge", data: edgeWithId });
|
|
303
|
-
setIsDrawerOpen(true);
|
|
304
|
-
}, [getEdgesForStep, currentStep]);
|
|
305
|
-
// Convert flow data to ReactFlow format with step filtering
|
|
306
|
-
const nodes = (0, react_1.useMemo)(() => {
|
|
307
|
-
const stepNodes = getNodesForStep(currentStep);
|
|
308
|
-
const stepEdges = getEdgesForStep(currentStep);
|
|
309
|
-
return stepNodes.map((node) => {
|
|
310
|
-
var _a, _b;
|
|
311
|
-
const position = positions.get(node.identifier) || { x: 0, y: 0 };
|
|
312
|
-
const { description } = extractLLMDetails(node);
|
|
313
|
-
const isActive = node.stamp.step === currentStep;
|
|
314
|
-
return {
|
|
315
|
-
id: node.identifier,
|
|
316
|
-
type: "agent",
|
|
317
|
-
position,
|
|
318
|
-
data: {
|
|
319
|
-
label: node.node_type,
|
|
320
|
-
description,
|
|
321
|
-
nodeType: node.node_type,
|
|
322
|
-
step: (_a = node.stamp) === null || _a === void 0 ? void 0 : _a.step,
|
|
323
|
-
time: (_b = node.stamp) === null || _b === void 0 ? void 0 : _b.time,
|
|
324
|
-
isActive,
|
|
325
|
-
onInspect: handleNodeInspect,
|
|
326
|
-
id: node.identifier, // Add id for zoom functionality
|
|
327
|
-
edges: stepEdges // Pass edges to the node
|
|
328
|
-
},
|
|
329
|
-
style: {
|
|
330
|
-
filter: isActive ? "drop-shadow(0 4px 8px rgba(99, 102, 241, 0.3))" : "none"
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
});
|
|
334
|
-
}, [positions, currentStep, getNodesForStep, getEdgesForStep, handleNodeInspect]);
|
|
335
|
-
const edges = (0, react_1.useMemo)(() => {
|
|
336
|
-
const stepEdges = getEdgesForStep(currentStep);
|
|
337
|
-
return stepEdges
|
|
338
|
-
.filter((edge) => edge.source && edge.target)
|
|
339
|
-
.map((edge) => {
|
|
340
|
-
var _a, _b, _c, _d;
|
|
341
|
-
const isActive = edge.stamp.step === currentStep;
|
|
342
|
-
return {
|
|
343
|
-
id: edge.identifier,
|
|
344
|
-
type: "default",
|
|
345
|
-
source: edge.source,
|
|
346
|
-
target: edge.target,
|
|
347
|
-
animated: isActive,
|
|
348
|
-
bidirectional: true, // Enable bidirectional edges with arrow heads
|
|
349
|
-
style: {
|
|
350
|
-
stroke: isActive ? "#6366f1" : "#9ca3af",
|
|
351
|
-
strokeWidth: isActive ? 3 : 2
|
|
352
|
-
},
|
|
353
|
-
label: ((_a = edge.stamp) === null || _a === void 0 ? void 0 : _a.identifier) ? truncateText(String(edge.stamp.identifier), 50) : undefined,
|
|
354
|
-
data: {
|
|
355
|
-
label: ((_b = edge.stamp) === null || _b === void 0 ? void 0 : _b.identifier) ? truncateText(String(edge.stamp.identifier), 50) : undefined,
|
|
356
|
-
source: edge.source,
|
|
357
|
-
target: edge.target,
|
|
358
|
-
step: (_c = edge.stamp) === null || _c === void 0 ? void 0 : _c.step,
|
|
359
|
-
time: (_d = edge.stamp) === null || _d === void 0 ? void 0 : _d.time,
|
|
360
|
-
details: edge.details
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
});
|
|
364
|
-
}, [currentStep, getEdgesForStep]);
|
|
365
|
-
const [nodesState, setNodes, onNodesChange] = (0, reactflow_2.useNodesState)(nodes);
|
|
366
|
-
const [edgesState, setEdges, onEdgesChange] = (0, reactflow_2.useEdgesState)(edges);
|
|
367
|
-
// Update nodes and edges when currentStep changes
|
|
368
|
-
(0, react_1.useEffect)(() => {
|
|
369
|
-
setNodes(nodes);
|
|
370
|
-
}, [nodes, setNodes]);
|
|
371
|
-
(0, react_1.useEffect)(() => {
|
|
372
|
-
setEdges(edges);
|
|
373
|
-
}, [edges, setEdges]);
|
|
374
|
-
const onConnect = (0, react_1.useCallback)((params) => setEdges((eds) => (0, reactflow_2.addEdge)(params, eds)), [setEdges]);
|
|
375
|
-
const handleStepChange = (0, react_1.useCallback)((step) => {
|
|
376
|
-
setCurrentStep(step);
|
|
377
|
-
setIsPlaying(false);
|
|
378
|
-
}, []);
|
|
379
|
-
const handlePlayPause = (0, react_1.useCallback)(() => {
|
|
380
|
-
setIsPlaying((prev) => !prev);
|
|
381
|
-
}, []);
|
|
382
|
-
// Function to convert client (screen) coordinates to SVG coordinates
|
|
383
|
-
const clientToSvgCoords = (clientX, clientY) => {
|
|
384
|
-
var _a;
|
|
385
|
-
if (!svgRef.current)
|
|
386
|
-
return { x: 0, y: 0 };
|
|
387
|
-
const pt = svgRef.current.createSVGPoint();
|
|
388
|
-
pt.x = clientX;
|
|
389
|
-
pt.y = clientY;
|
|
390
|
-
const svgP = pt.matrixTransform((_a = svgRef.current.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse());
|
|
391
|
-
return { x: svgP.x, y: svgP.y };
|
|
392
|
-
};
|
|
393
|
-
const reactFlowInstance = (0, reactflow_1.useReactFlow)();
|
|
394
|
-
// Pan to hub node (most connected node) on initial load
|
|
395
|
-
(0, react_1.useEffect)(() => {
|
|
396
|
-
if (nodes.length > 0 && reactFlowInstance) {
|
|
397
|
-
// Find the node with the most connections
|
|
398
|
-
const nodeConnectionCounts = new Map();
|
|
399
|
-
// Count incoming and outgoing connections for each node
|
|
400
|
-
edges.forEach((edge) => {
|
|
401
|
-
// Count outgoing connections (source)
|
|
402
|
-
const sourceCount = nodeConnectionCounts.get(edge.source) || 0;
|
|
403
|
-
nodeConnectionCounts.set(edge.source, sourceCount + 1);
|
|
404
|
-
// Count incoming connections (target)
|
|
405
|
-
const targetCount = nodeConnectionCounts.get(edge.target) || 0;
|
|
406
|
-
nodeConnectionCounts.set(edge.target, targetCount + 1);
|
|
407
|
-
});
|
|
408
|
-
// Find the node with the highest connection count
|
|
409
|
-
let hubNodeId = "";
|
|
410
|
-
let maxConnections = 0;
|
|
411
|
-
nodeConnectionCounts.forEach((count, nodeId) => {
|
|
412
|
-
if (count > maxConnections) {
|
|
413
|
-
maxConnections = count;
|
|
414
|
-
hubNodeId = nodeId;
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
// If no hub node found (no edges), use the first node
|
|
418
|
-
if (!hubNodeId && nodes.length > 0) {
|
|
419
|
-
hubNodeId = nodes[0].id;
|
|
420
|
-
}
|
|
421
|
-
// Pan to the hub node
|
|
422
|
-
if (hubNodeId) {
|
|
423
|
-
setTimeout(() => {
|
|
424
|
-
reactFlowInstance.fitView({
|
|
425
|
-
nodes: [{ id: hubNodeId }],
|
|
426
|
-
duration: 1000,
|
|
427
|
-
padding: 0.2,
|
|
428
|
-
minZoom: 0.2,
|
|
429
|
-
maxZoom: 1.5
|
|
430
|
-
});
|
|
431
|
-
}, 500); // Small delay to ensure nodes are rendered
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}, [nodes, edges, reactFlowInstance]);
|
|
435
|
-
return ((0, jsx_runtime_1.jsxs)("div", { ref: containerRef, style: {
|
|
436
|
-
width: typeof width === "number" ? `${width}px` : width,
|
|
437
|
-
height: typeof height === "number" ? `${height}px` : height,
|
|
438
|
-
border: "1px solid #e5e7eb",
|
|
439
|
-
borderRadius: "8px",
|
|
440
|
-
overflow: "hidden",
|
|
441
|
-
position: "relative",
|
|
442
|
-
minWidth: "800px",
|
|
443
|
-
minHeight: "600px"
|
|
444
|
-
}, className: className, children: [(0, jsx_runtime_1.jsxs)("div", { className: `side-panel ${showTimelines ? "expanded" : "collapsed"}`, children: [!showTimelines && ((0, jsx_runtime_1.jsx)("button", { className: "panel-toggle", onClick: () => setShowTimelines(!showTimelines), title: "Expand Panel", children: (0, jsx_runtime_1.jsx)(lucide_react_1.PanelLeft, { size: 20 }) })), showTimelines && ((0, jsx_runtime_1.jsx)("div", { className: "panel-content", children: (0, jsx_runtime_1.jsx)(VerticalTimeline_1.VerticalTimeline, { stamps: flowData.stamps || flowData.steps || [], currentStep: currentStep, onStepChange: handleStepChange, onToggle: () => setShowTimelines(false) }) }))] }), (0, jsx_runtime_1.jsxs)(reactflow_2.default, { nodes: nodesState, edges: edgesState, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, onConnect: onConnect, nodeTypes: nodeTypes, edgeTypes: {
|
|
445
|
-
default: (edgeProps) => ((0, jsx_runtime_1.jsx)(Edge_1.Edge, Object.assign({}, edgeProps, { clientToSvgCoords: clientToSvgCoords, svgRef: svgRef, onInspect: handleEdgeInspect })))
|
|
446
|
-
}, attributionPosition: "bottom-left", style: {
|
|
447
|
-
width: showTimelines ? "calc(100% - 280px)" : "100%", // Account for side panel width when visible
|
|
448
|
-
height: "calc(100% - 60px)", // Account for timeline height
|
|
449
|
-
marginLeft: showTimelines ? "280px" : "0" // Push content to the right of side panel when visible
|
|
450
|
-
}, defaultViewport: { x: 0, y: 0, zoom: 1 }, onInit: (instance) => {
|
|
451
|
-
if (containerRef.current) {
|
|
452
|
-
const svg = containerRef.current.querySelector("svg");
|
|
453
|
-
if (svg)
|
|
454
|
-
svgRef.current = svg;
|
|
455
|
-
}
|
|
456
|
-
}, children: [(0, jsx_runtime_1.jsx)(reactflow_2.Controls, {}), (0, jsx_runtime_1.jsx)(reactflow_2.Background, { color: "#f3f4f6", gap: 16 })] }), (0, jsx_runtime_1.jsxs)("div", { className: `right-drawer ${isDrawerOpen ? "open" : ""}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "drawer-toggle", onClick: () => setIsDrawerOpen(!isDrawerOpen), children: (0, jsx_runtime_1.jsx)(lucide_react_1.PanelRight, { size: 20 }) }), isDrawerOpen && selectedData && ((0, jsx_runtime_1.jsxs)("div", { className: "drawer-content", children: [(0, jsx_runtime_1.jsx)("div", { className: "drawer-header", children: (0, jsx_runtime_1.jsx)("h3", { children: selectedData.type === "node" ? "Node Details" : "Edge Details" }) }), (0, jsx_runtime_1.jsx)("div", { className: "drawer-body", children: selectedData.type === "node" ? (
|
|
457
|
-
// Node Details
|
|
458
|
-
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Label:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.label || "N/A" })] }), selectedData.data.description && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Description:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.description })] })), selectedData.data.nodeType && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Type:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.nodeType })] })), selectedData.data.step && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Step:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.step })] })), selectedData.data.time && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Time:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: new Date(selectedData.data.time * 1000).toLocaleString() })] })), selectedData.data.icon && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Icon:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.icon })] }))] })) : (
|
|
459
|
-
// Edge Details
|
|
460
|
-
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "ID:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.id || "N/A" })] }), selectedData.data.source && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Source:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.source })] })), selectedData.data.target && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Target:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.target })] })), selectedData.data.label && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Label:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.label })] })), selectedData.data.step && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Step:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: selectedData.data.step })] })), selectedData.data.time && ((0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Time:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: new Date(selectedData.data.time * 1000).toLocaleString() })] })), ((_b = (_a = selectedData.data) === null || _a === void 0 ? void 0 : _a.details) === null || _b === void 0 ? void 0 : _b.input_args) &&
|
|
461
|
-
Array.isArray(selectedData.data.details.input_args) &&
|
|
462
|
-
selectedData.data.details.input_args.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Inputs" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", style: { overflowY: "auto", maxHeight: "300px" }, children: Array.isArray(selectedData.data.details.input_args[0]) ? (selectedData.data.details.input_args[0].map((arg, index) => ((0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: 8 }, children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Role:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: (arg === null || arg === void 0 ? void 0 : arg.role) || "Unknown" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Content:" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: (arg === null || arg === void 0 ? void 0 : arg.content) || "No content" })] }, (arg === null || arg === void 0 ? void 0 : arg.role) || index)))) : ((0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: JSON.stringify(selectedData.data.details.input_args[0], null, 2) })) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "detail-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "detail-label", children: "Outputs" }), (0, jsx_runtime_1.jsx)("span", { className: "detail-value", children: JSON.stringify((_d = (_c = selectedData.data) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.output, null, 2) })] })] }))] })) })] }))] }), showTimelines && ((0, jsx_runtime_1.jsx)("div", { style: { marginLeft: "280px", marginTop: "100px" }, children: (0, jsx_runtime_1.jsx)(Timeline_1.Timeline, { stamps: flowData.stamps || flowData.steps || [], currentStep: currentStep, isPlaying: isPlaying, onStepChange: handleStepChange, onPlayPause: handlePlayPause }) })), (0, jsx_runtime_1.jsx)("style", { children: `
|
|
463
|
-
.react-flow__edge-label {
|
|
464
|
-
font-size: 10px;
|
|
465
|
-
background: white;
|
|
466
|
-
padding: 2px 4px;
|
|
467
|
-
border-radius: 4px;
|
|
468
|
-
border: 1px solid #e5e7eb;
|
|
469
|
-
max-width: 150px;
|
|
470
|
-
overflow: hidden;
|
|
471
|
-
text-overflow: ellipsis;
|
|
472
|
-
white-space: nowrap;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/* Right Drawer Styles */
|
|
476
|
-
.right-drawer {
|
|
477
|
-
position: absolute;
|
|
478
|
-
top: 0;
|
|
479
|
-
right: 0;
|
|
480
|
-
height: 100%;
|
|
481
|
-
z-index: 1000;
|
|
482
|
-
display: flex;
|
|
483
|
-
align-items: flex-start;
|
|
484
|
-
transition: transform 0.3s ease;
|
|
485
|
-
margin-left: ${showTimelines ? "280px" : "0"}; /* Account for vertical timeline when visible */
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
.right-drawer:not(.open) {
|
|
489
|
-
transform: translateX(calc(100% - 50px));
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
.right-drawer.open {
|
|
493
|
-
transform: translateX(0);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
.drawer-toggle {
|
|
497
|
-
width: 50px;
|
|
498
|
-
height: 50px;
|
|
499
|
-
background: none;
|
|
500
|
-
color: #6b7280;
|
|
501
|
-
border: none;
|
|
502
|
-
cursor: pointer;
|
|
503
|
-
display: flex;
|
|
504
|
-
align-items: center;
|
|
505
|
-
justify-content: center;
|
|
506
|
-
transition: color 0.2s ease;
|
|
507
|
-
margin-top: 20px;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
.drawer-toggle:hover {
|
|
511
|
-
color: #374151;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
.drawer-content {
|
|
515
|
-
background: white;
|
|
516
|
-
border: 1px solid #e5e7eb;
|
|
517
|
-
border-radius: 8px 0 0 8px;
|
|
518
|
-
width: 400px;
|
|
519
|
-
height: calc(100% - 40px);
|
|
520
|
-
margin-top: 20px;
|
|
521
|
-
display: flex;
|
|
522
|
-
flex-direction: column;
|
|
523
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
524
|
-
animation: drawerSlideIn 0.3s ease-out;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
.drawer-header {
|
|
528
|
-
padding: 16px 20px;
|
|
529
|
-
border-bottom: 1px solid #e5e7eb;
|
|
530
|
-
background: #f9fafb;
|
|
531
|
-
display: flex;
|
|
532
|
-
justify-content: space-between;
|
|
533
|
-
align-items: center;
|
|
534
|
-
flex-shrink: 0;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
.drawer-header h3 {
|
|
538
|
-
margin: 0;
|
|
539
|
-
font-size: 16px;
|
|
540
|
-
font-weight: 600;
|
|
541
|
-
color: #1f2937;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
.close-button {
|
|
545
|
-
background: none;
|
|
546
|
-
border: none;
|
|
547
|
-
font-size: 20px;
|
|
548
|
-
color: #6b7280;
|
|
549
|
-
cursor: pointer;
|
|
550
|
-
padding: 4px;
|
|
551
|
-
width: 28px;
|
|
552
|
-
height: 28px;
|
|
553
|
-
display: flex;
|
|
554
|
-
align-items: center;
|
|
555
|
-
justify-content: center;
|
|
556
|
-
border-radius: 6px;
|
|
557
|
-
transition: all 0.2s ease;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
.close-button:hover {
|
|
561
|
-
background: #e5e7eb;
|
|
562
|
-
color: #1f2937;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
.drawer-body {
|
|
566
|
-
padding: 20px;
|
|
567
|
-
overflow-y: auto;
|
|
568
|
-
flex: 1;
|
|
569
|
-
width: 100%;
|
|
570
|
-
box-sizing: border-box;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
.detail-row {
|
|
574
|
-
display: grid;
|
|
575
|
-
grid-template-columns: 100px 1fr;
|
|
576
|
-
margin-bottom: 12px;
|
|
577
|
-
align-items: flex-start;
|
|
578
|
-
gap: 8px;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
.detail-row:last-child {
|
|
582
|
-
margin-bottom: 0;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
.detail-label {
|
|
586
|
-
font-weight: 600;
|
|
587
|
-
color: #6b7280;
|
|
588
|
-
font-size: 13px;
|
|
589
|
-
word-break: break-word;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
.detail-value {
|
|
593
|
-
color: #1f2937;
|
|
594
|
-
font-size: 13px;
|
|
595
|
-
word-break: break-word;
|
|
596
|
-
flex: 1;
|
|
597
|
-
width: 100%;
|
|
598
|
-
overflow: visible;
|
|
599
|
-
text-overflow: unset;
|
|
600
|
-
max-width: unset;
|
|
601
|
-
white-space: pre-line;
|
|
602
|
-
line-height: 1.4;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
@keyframes drawerSlideIn {
|
|
606
|
-
from {
|
|
607
|
-
opacity: 0;
|
|
608
|
-
transform: translateX(20px);
|
|
609
|
-
}
|
|
610
|
-
to {
|
|
611
|
-
opacity: 1;
|
|
612
|
-
transform: translateX(0);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
/* Scoreboard Styles */
|
|
617
|
-
.scoreboard {
|
|
618
|
-
position: absolute;
|
|
619
|
-
top: 20px;
|
|
620
|
-
left: 50%;
|
|
621
|
-
transform: translateX(-50%);
|
|
622
|
-
background: white;
|
|
623
|
-
border: 1px solid #e5e7eb;
|
|
624
|
-
border-radius: 8px;
|
|
625
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
626
|
-
z-index: 1000;
|
|
627
|
-
min-width: 400px;
|
|
628
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
.scoreboard-header {
|
|
632
|
-
padding: 12px 16px;
|
|
633
|
-
border-bottom: 1px solid #e5e7eb;
|
|
634
|
-
background: #f9fafb;
|
|
635
|
-
text-align: center;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
.scoreboard-header h3 {
|
|
639
|
-
margin: 0;
|
|
640
|
-
font-size: 14px;
|
|
641
|
-
font-weight: 600;
|
|
642
|
-
color: #1f2937;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
.scoreboard-content {
|
|
646
|
-
padding: 16px;
|
|
647
|
-
display: flex;
|
|
648
|
-
justify-content: space-around;
|
|
649
|
-
align-items: center;
|
|
650
|
-
gap: 20px;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
.scoreboard-item {
|
|
654
|
-
display: flex;
|
|
655
|
-
flex-direction: column;
|
|
656
|
-
align-items: center;
|
|
657
|
-
gap: 4px;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
.scoreboard-label {
|
|
661
|
-
font-size: 12px;
|
|
662
|
-
color: #6b7280;
|
|
663
|
-
font-weight: 500;
|
|
664
|
-
text-transform: uppercase;
|
|
665
|
-
letter-spacing: 0.5px;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
.scoreboard-count {
|
|
669
|
-
font-size: 18px;
|
|
670
|
-
font-weight: 700;
|
|
671
|
-
padding: 6px 12px;
|
|
672
|
-
border-radius: 6px;
|
|
673
|
-
min-width: 40px;
|
|
674
|
-
text-align: center;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
.scoreboard-count.open {
|
|
678
|
-
background: #fef3c7;
|
|
679
|
-
color: #92400e;
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
.scoreboard-count.completed {
|
|
683
|
-
background: #d1fae5;
|
|
684
|
-
color: #065f46;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
.scoreboard-count.error {
|
|
688
|
-
background: #fee2e2;
|
|
689
|
-
color: #991b1b;
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
.scoreboard-count.error.clickable {
|
|
693
|
-
transition: all 0.2s ease;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
.scoreboard-count.error.clickable:hover {
|
|
697
|
-
background: #fecaca;
|
|
698
|
-
transform: scale(1.05);
|
|
699
|
-
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.3);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
/* Side Panel Styles */
|
|
703
|
-
.side-panel {
|
|
704
|
-
position: absolute;
|
|
705
|
-
top: 0;
|
|
706
|
-
left: 0;
|
|
707
|
-
height: 100%;
|
|
708
|
-
z-index: 1000;
|
|
709
|
-
display: flex;
|
|
710
|
-
flex-direction: column;
|
|
711
|
-
transition: all 0.3s ease;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
.side-panel.collapsed {
|
|
715
|
-
width: 60px;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
.side-panel.expanded {
|
|
719
|
-
width: 280px;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
.panel-toggle {
|
|
723
|
-
display: flex;
|
|
724
|
-
align-items: center;
|
|
725
|
-
justify-content: center;
|
|
726
|
-
border: none;
|
|
727
|
-
background: none;
|
|
728
|
-
cursor: pointer;
|
|
729
|
-
color: #6b7280;
|
|
730
|
-
transition: color 0.2s ease;
|
|
731
|
-
padding: 8px;
|
|
732
|
-
margin: 20px 0 0 0;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
.panel-toggle:hover {
|
|
736
|
-
color: #374151;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
.panel-content {
|
|
740
|
-
flex: 1;
|
|
741
|
-
background: white;
|
|
742
|
-
border-right: 1px solid #e5e7eb;
|
|
743
|
-
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
|
|
744
|
-
overflow: hidden;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
` })] }));
|
|
749
|
-
};
|
|
750
|
-
exports.default = AgenticFlowVisualizer;
|