@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
package/dist/esm/App.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { ReactFlowProvider } from "reactflow";
|
|
3
|
-
import { useFlowData } from "./hooks";
|
|
4
|
-
import { FileSelector } from "./components/FileSelector";
|
|
5
|
-
import AgenticFlowVisualizer from "./AgenticFlowVisualizer";
|
|
6
|
-
const App = () => {
|
|
7
|
-
const { availableFiles, currentFile, flowData, loading, error, loadFile, refreshFiles } = useFlowData();
|
|
8
|
-
const handleFileSelect = (filename) => {
|
|
9
|
-
loadFile(filename);
|
|
10
|
-
};
|
|
11
|
-
return (_jsxs("div", { className: "app", children: [_jsxs("div", { className: "app-header", children: [_jsx("h1", { children: "RailTracks Visualizer" }), _jsx("div", { className: "file-selector-container", children: _jsx(FileSelector, { files: availableFiles, currentFile: currentFile, onFileSelect: handleFileSelect, onRefresh: refreshFiles, loading: loading, disabled: loading }) })] }), error && (_jsx("div", { className: "error-message", children: _jsxs("p", { children: ["Error: ", error] }) })), _jsx("div", { className: "visualizer-container", children: loading ? (_jsxs("div", { className: "loading-state", children: [_jsx("div", { className: "loading-spinner" }), _jsx("p", { children: "Loading flow data..." })] })) : flowData ? (_jsx(ReactFlowProvider, { children: _jsx(AgenticFlowVisualizer, { flowData: flowData }) })) : (_jsx("div", { className: "no-data-state", children: _jsx("p", { children: "Please select a file to visualize the flow data" }) })) }), _jsx("style", { children: `
|
|
12
|
-
.app {
|
|
13
|
-
min-height: 100vh;
|
|
14
|
-
background: #f9fafb;
|
|
15
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.app-header {
|
|
19
|
-
background: white;
|
|
20
|
-
border-bottom: 1px solid #e5e7eb;
|
|
21
|
-
padding: 5px;
|
|
22
|
-
display: flex;
|
|
23
|
-
align-items: center;
|
|
24
|
-
justify-content: space-between;
|
|
25
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.app-header h1 {
|
|
29
|
-
margin: 0;
|
|
30
|
-
font-size: 18px;
|
|
31
|
-
font-weight: 600;
|
|
32
|
-
color: #1f2937;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.file-selector-container {
|
|
36
|
-
display: flex;
|
|
37
|
-
align-items: center;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.error-message {
|
|
41
|
-
background: #fee2e2;
|
|
42
|
-
border: 1px solid #fecaca;
|
|
43
|
-
color: #991b1b;
|
|
44
|
-
padding: 12px 20px;
|
|
45
|
-
margin: 20px;
|
|
46
|
-
border-radius: 6px;
|
|
47
|
-
font-size: 14px;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.visualizer-container {
|
|
51
|
-
padding: 20px;
|
|
52
|
-
min-height: calc(100vh - 100px);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
.loading-state {
|
|
56
|
-
display: flex;
|
|
57
|
-
flex-direction: column;
|
|
58
|
-
align-items: center;
|
|
59
|
-
justify-content: center;
|
|
60
|
-
height: 400px;
|
|
61
|
-
color: #6b7280;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.loading-spinner {
|
|
65
|
-
width: 40px;
|
|
66
|
-
height: 40px;
|
|
67
|
-
border: 4px solid #e5e7eb;
|
|
68
|
-
border-top: 4px solid #6366f1;
|
|
69
|
-
border-radius: 50%;
|
|
70
|
-
animation: spin 1s linear infinite;
|
|
71
|
-
margin-bottom: 16px;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@keyframes spin {
|
|
75
|
-
0% { transform: rotate(0deg); }
|
|
76
|
-
100% { transform: rotate(360deg); }
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.no-data-state {
|
|
80
|
-
display: flex;
|
|
81
|
-
align-items: center;
|
|
82
|
-
justify-content: center;
|
|
83
|
-
height: 400px;
|
|
84
|
-
color: #6b7280;
|
|
85
|
-
font-size: 16px;
|
|
86
|
-
}
|
|
87
|
-
` })] }));
|
|
88
|
-
};
|
|
89
|
-
export default App;
|
package/dist/esm/Visualizer.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ReactFlowProvider } from "reactflow";
|
|
3
|
-
import AgenticFlowVisualizer from "./AgenticFlowVisualizer";
|
|
4
|
-
/**
|
|
5
|
-
* Visualizer component that wraps AgenticFlowVisualizer with ReactFlowProvider.
|
|
6
|
-
* This is the main component that should be imported from the npm package.
|
|
7
|
-
*/
|
|
8
|
-
const Visualizer = (props) => {
|
|
9
|
-
return (_jsx(ReactFlowProvider, { children: _jsx(AgenticFlowVisualizer, { ...props }) }));
|
|
10
|
-
};
|
|
11
|
-
export default Visualizer;
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
3
|
-
export const Edge = ({ id, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, style = {}, markerEnd, bidirectional = false, data, clientToSvgCoords, svgRef, onInspect }) => {
|
|
4
|
-
const [isHovered, setIsHovered] = useState(false);
|
|
5
|
-
// Function to determine stroke color based on edge state
|
|
6
|
-
const getStrokeColor = () => {
|
|
7
|
-
const state = data?.details?.state;
|
|
8
|
-
switch (state) {
|
|
9
|
-
case "Open":
|
|
10
|
-
return "#000000"; // Black
|
|
11
|
-
case "Completed":
|
|
12
|
-
return "#15803d"; // Darker Green
|
|
13
|
-
case "Error":
|
|
14
|
-
return "#ef4444"; // Red
|
|
15
|
-
default:
|
|
16
|
-
return style.stroke || "#6366f1"; // Default color
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
const [edgePath, arrowMarkers] = useMemo(() => {
|
|
20
|
-
// Always use curved paths for better visual appeal
|
|
21
|
-
const centerX = (sourceX + targetX) / 2;
|
|
22
|
-
const centerY = (sourceY + targetY) / 2;
|
|
23
|
-
const path = `M ${sourceX} ${sourceY} Q ${centerX} ${centerY} ${targetX} ${targetY}`;
|
|
24
|
-
// Create arrow markers for bidirectional edges
|
|
25
|
-
const markers = [];
|
|
26
|
-
if (bidirectional) {
|
|
27
|
-
const strokeColor = getStrokeColor();
|
|
28
|
-
// Forward arrow (source to target)
|
|
29
|
-
markers.push(_jsxs("defs", { children: [_jsx("marker", { id: `${id}-arrowhead-forward`, markerWidth: "10", markerHeight: "7", refX: "9", refY: "3.5", orient: "auto", markerUnits: "strokeWidth", children: _jsx("polygon", { points: "0 0, 10 3.5, 0 7", fill: strokeColor }) }), _jsx("marker", { id: `${id}-arrowhead-backward`, markerWidth: "10", markerHeight: "7", refX: "1", refY: "3.5", orient: "auto", markerUnits: "strokeWidth", children: _jsx("polygon", { points: "10 0, 0 3.5, 10 7", fill: strokeColor }) })] }, `${id}-markers`));
|
|
30
|
-
}
|
|
31
|
-
return [path, markers];
|
|
32
|
-
}, [sourceX, sourceY, targetX, targetY, id, bidirectional, data?.details?.state]);
|
|
33
|
-
const hoverStyle = {
|
|
34
|
-
...style,
|
|
35
|
-
stroke: getStrokeColor(),
|
|
36
|
-
strokeWidth: style.strokeWidth || 4,
|
|
37
|
-
cursor: "pointer"
|
|
38
|
-
};
|
|
39
|
-
const handleInspectClick = (event) => {
|
|
40
|
-
event.stopPropagation();
|
|
41
|
-
if (onInspect && data) {
|
|
42
|
-
onInspect(data);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
return (_jsxs("g", { "data-edge-id": id, children: [arrowMarkers, _jsx("path", { id: id, className: "react-flow__edge-path", d: edgePath, markerEnd: bidirectional ? `url(#${id}-arrowhead-forward)` : markerEnd, markerStart: bidirectional ? `url(#${id}-arrowhead-backward)` : undefined, style: hoverStyle }), data?.label && (_jsx("foreignObject", { x: (sourceX + targetX) / 2 - 50, y: (sourceY + targetY) / 2 - 20, width: "100", height: "40", style: { overflow: "visible", pointerEvents: "none" }, children: _jsx("div", { className: "edge-label-renderer", style: {
|
|
46
|
-
display: "flex",
|
|
47
|
-
alignItems: "center",
|
|
48
|
-
justifyContent: "center",
|
|
49
|
-
width: "100%",
|
|
50
|
-
height: "100%",
|
|
51
|
-
pointerEvents: "auto"
|
|
52
|
-
}, children: _jsx("button", { className: "edge-label-button", onClick: handleInspectClick, style: {
|
|
53
|
-
background: "#6366f1",
|
|
54
|
-
color: "white",
|
|
55
|
-
border: "none",
|
|
56
|
-
borderRadius: 6,
|
|
57
|
-
padding: "4px 12px",
|
|
58
|
-
fontSize: 12,
|
|
59
|
-
fontWeight: 600,
|
|
60
|
-
cursor: "pointer",
|
|
61
|
-
boxShadow: "0 2px 8px rgba(99,102,241,0.10)",
|
|
62
|
-
transition: "background 0.2s"
|
|
63
|
-
}, children: "Inspect" }) }) })), _jsx("style", { children: `
|
|
64
|
-
.edge-label-renderer {
|
|
65
|
-
z-index: 8001;
|
|
66
|
-
user-select: none;
|
|
67
|
-
pointer-events: auto;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.edge-label-button {
|
|
71
|
-
pointer-events: auto;
|
|
72
|
-
}
|
|
73
|
-
` })] }));
|
|
74
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { RefreshCw } from "lucide-react";
|
|
3
|
-
export const FileSelector = ({ files, currentFile, onFileSelect, onRefresh, loading = false, disabled = false }) => {
|
|
4
|
-
const handleRefresh = (e) => {
|
|
5
|
-
e.stopPropagation();
|
|
6
|
-
onRefresh();
|
|
7
|
-
};
|
|
8
|
-
return (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsxs("select", { value: currentFile || "", onChange: (e) => onFileSelect(e.target.value), disabled: disabled, style: {
|
|
9
|
-
cursor: "pointer",
|
|
10
|
-
padding: "8px 16px 8px 16px",
|
|
11
|
-
borderRadius: "4px",
|
|
12
|
-
fontSize: "14px",
|
|
13
|
-
border: "1px solid #ccc",
|
|
14
|
-
appearance: "none",
|
|
15
|
-
WebkitAppearance: "none",
|
|
16
|
-
MozAppearance: "none"
|
|
17
|
-
}, children: [_jsx("option", { value: "", children: "Select a RailTracks Run..." }), files.map((file) => (_jsx("option", { value: file.name, children: file.name }, file.name)))] }), _jsx("button", { onClick: handleRefresh, disabled: loading || disabled, title: "Refresh files", style: {
|
|
18
|
-
background: "none",
|
|
19
|
-
border: "none",
|
|
20
|
-
cursor: "pointer",
|
|
21
|
-
padding: "4px",
|
|
22
|
-
borderRadius: "4px"
|
|
23
|
-
}, children: _jsx(RefreshCw, { size: 16, style: { animation: loading ? "spin 1s linear infinite" : "none" } }) })] }));
|
|
24
|
-
};
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Handle, Position, useReactFlow } from "reactflow";
|
|
3
|
-
const Node = ({ data, id }) => {
|
|
4
|
-
const { fitView } = useReactFlow();
|
|
5
|
-
// Check if this node has any outgoing edges (source edges)
|
|
6
|
-
const hasOutgoingEdges = data.edges?.some((edge) => edge.source === id) || false;
|
|
7
|
-
const handleNodeClick = () => {
|
|
8
|
-
// Zoom to the node
|
|
9
|
-
fitView({
|
|
10
|
-
nodes: [{ id }],
|
|
11
|
-
duration: 800,
|
|
12
|
-
padding: 0.1,
|
|
13
|
-
minZoom: 0.5,
|
|
14
|
-
maxZoom: 1.5
|
|
15
|
-
});
|
|
16
|
-
// Open inspection drawer
|
|
17
|
-
if (data.onInspect) {
|
|
18
|
-
data.onInspect({
|
|
19
|
-
label: data.label,
|
|
20
|
-
description: data.description,
|
|
21
|
-
nodeType: data.nodeType,
|
|
22
|
-
step: data.step,
|
|
23
|
-
time: data.time,
|
|
24
|
-
icon: data.icon
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "agent-node", onClick: handleNodeClick, style: { cursor: "pointer" }, children: [_jsx(Handle, { type: "target", position: Position.Top, style: { background: "#6366f1" } }), _jsxs("div", { className: "agent-header", children: [_jsx("div", { className: "agent-icon", children: data.icon || "📋" }), _jsx("div", { className: "agent-label", children: data.label })] }), data.description && _jsx("div", { className: "agent-description", children: data.description }), data.step && (_jsxs("div", { className: "agent-meta", children: [_jsxs("span", { className: "step", children: ["Step: ", data.step] }), data.time && _jsx("span", { className: "time", children: new Date(data.time * 1000).toLocaleTimeString() })] })), hasOutgoingEdges && _jsx(Handle, { type: "source", position: Position.Bottom, style: { background: "#6366f1" } })] }), _jsx("style", { children: `
|
|
29
|
-
.agent-node {
|
|
30
|
-
padding: 12px;
|
|
31
|
-
border-radius: 8px;
|
|
32
|
-
background: white;
|
|
33
|
-
border: 2px solid #e5e7eb;
|
|
34
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
35
|
-
min-width: 200px;
|
|
36
|
-
max-width: 250px;
|
|
37
|
-
transition: all 0.2s ease;
|
|
38
|
-
position: relative;
|
|
39
|
-
z-index: -5;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.agent-node:hover {
|
|
43
|
-
border-color: #6366f1;
|
|
44
|
-
box-shadow: 0 4px 8px rgba(99, 102, 241, 0.2);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.agent-header {
|
|
48
|
-
display: flex;
|
|
49
|
-
align-items: center;
|
|
50
|
-
gap: 8px;
|
|
51
|
-
margin-bottom: 8px;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.agent-icon {
|
|
55
|
-
font-size: 20px;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.agent-label {
|
|
59
|
-
font-weight: 600;
|
|
60
|
-
color: #1f2937;
|
|
61
|
-
font-size: 14px;
|
|
62
|
-
word-break: break-word;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.agent-description {
|
|
66
|
-
color: #6b7280;
|
|
67
|
-
font-size: 12px;
|
|
68
|
-
line-height: 1.4;
|
|
69
|
-
word-break: break-word;
|
|
70
|
-
white-space: pre-line;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.agent-meta {
|
|
74
|
-
margin-top: 8px;
|
|
75
|
-
padding-top: 8px;
|
|
76
|
-
border-top: 1px solid #e5e7eb;
|
|
77
|
-
display: flex;
|
|
78
|
-
justify-content: space-between;
|
|
79
|
-
font-size: 10px;
|
|
80
|
-
color: #9ca3af;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.step {
|
|
84
|
-
background: #f3f4f6;
|
|
85
|
-
padding: 2px 6px;
|
|
86
|
-
border-radius: 4px;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
.time {
|
|
90
|
-
font-family: monospace;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.react-flow__handle {
|
|
94
|
-
width: 8px;
|
|
95
|
-
height: 8px;
|
|
96
|
-
border: 2px solid #6366f1;
|
|
97
|
-
}
|
|
98
|
-
` })] }));
|
|
99
|
-
};
|
|
100
|
-
export { Node };
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
const Timeline = ({ stamps, currentStep, isPlaying, onStepChange, onPlayPause }) => {
|
|
4
|
-
const maxStep = stamps.length > 0 ? Math.max(...stamps.map((s) => s.step)) : 0;
|
|
5
|
-
const minStep = stamps.length > 0 ? Math.min(...stamps.map((s) => s.step)) : 0;
|
|
6
|
-
const totalSteps = maxStep - minStep + 1;
|
|
7
|
-
// Initialize Bootstrap tooltips
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
// Initialize all tooltips
|
|
10
|
-
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
|
11
|
-
const tooltipList = Array.from(tooltipTriggerList).map((tooltipTriggerEl) => new window.bootstrap.Tooltip(tooltipTriggerEl));
|
|
12
|
-
// Cleanup function to dispose tooltips
|
|
13
|
-
return () => {
|
|
14
|
-
tooltipList.forEach((tooltip) => tooltip.dispose());
|
|
15
|
-
};
|
|
16
|
-
}, [stamps, currentStep]); // Re-initialize when stamps or currentStep changes
|
|
17
|
-
return (_jsxs("div", { style: {
|
|
18
|
-
position: "absolute",
|
|
19
|
-
bottom: 0,
|
|
20
|
-
left: 0,
|
|
21
|
-
right: 0,
|
|
22
|
-
height: "60px",
|
|
23
|
-
backgroundColor: "white",
|
|
24
|
-
borderTop: "1px solid #e5e7eb",
|
|
25
|
-
display: "flex",
|
|
26
|
-
alignItems: "center",
|
|
27
|
-
padding: "0 16px",
|
|
28
|
-
gap: "12px",
|
|
29
|
-
zIndex: 10
|
|
30
|
-
}, children: [_jsx("button", { onClick: onPlayPause, style: {
|
|
31
|
-
width: "32px",
|
|
32
|
-
height: "32px",
|
|
33
|
-
borderRadius: "50%",
|
|
34
|
-
border: "1px solid #d1d5db",
|
|
35
|
-
backgroundColor: "white",
|
|
36
|
-
display: "flex",
|
|
37
|
-
alignItems: "center",
|
|
38
|
-
justifyContent: "center",
|
|
39
|
-
cursor: "pointer",
|
|
40
|
-
transition: "all 0.2s ease"
|
|
41
|
-
}, onMouseEnter: (e) => {
|
|
42
|
-
e.currentTarget.style.backgroundColor = "#f3f4f6";
|
|
43
|
-
}, onMouseLeave: (e) => {
|
|
44
|
-
e.currentTarget.style.backgroundColor = "white";
|
|
45
|
-
}, children: isPlaying ? (_jsxs("div", { style: { display: "flex", gap: "2px" }, children: [_jsx("div", { style: {
|
|
46
|
-
width: "3px",
|
|
47
|
-
height: "12px",
|
|
48
|
-
backgroundColor: "#374151"
|
|
49
|
-
} }), _jsx("div", { style: {
|
|
50
|
-
width: "3px",
|
|
51
|
-
height: "12px",
|
|
52
|
-
backgroundColor: "#374151"
|
|
53
|
-
} })] })) : (_jsx("div", { style: {
|
|
54
|
-
width: 0,
|
|
55
|
-
height: 0,
|
|
56
|
-
borderLeft: "8px solid #374151",
|
|
57
|
-
borderTop: "6px solid transparent",
|
|
58
|
-
borderBottom: "6px solid transparent",
|
|
59
|
-
marginLeft: "2px"
|
|
60
|
-
} })) }), _jsx("div", { style: {
|
|
61
|
-
flex: 1,
|
|
62
|
-
display: "flex",
|
|
63
|
-
alignItems: "center",
|
|
64
|
-
gap: "8px",
|
|
65
|
-
padding: "0 8px"
|
|
66
|
-
}, children: Array.from({ length: totalSteps }, (_, index) => {
|
|
67
|
-
const step = minStep + index;
|
|
68
|
-
const isActive = step === currentStep;
|
|
69
|
-
const isPast = step < currentStep;
|
|
70
|
-
const hasStep = stamps.some((s) => s.step === step);
|
|
71
|
-
// Determine background color based on step state
|
|
72
|
-
let backgroundColor = "white";
|
|
73
|
-
if (isActive) {
|
|
74
|
-
backgroundColor = "#6366f1";
|
|
75
|
-
}
|
|
76
|
-
else if (isPast) {
|
|
77
|
-
backgroundColor = hasStep ? "#fef3c7" : "#fef3c7"; // Light yellow for past steps
|
|
78
|
-
}
|
|
79
|
-
else if (hasStep) {
|
|
80
|
-
backgroundColor = "#e5e7eb";
|
|
81
|
-
}
|
|
82
|
-
const tooltipText = `Step ${step}${hasStep ? ` - ${stamps.find((s) => s.step === step)?.identifier || ""}` : " - No activity"}`;
|
|
83
|
-
return (_jsx("button", { onClick: () => onStepChange(step), "data-bs-toggle": "tooltip", "data-bs-placement": "top", "data-bs-title": tooltipText, style: {
|
|
84
|
-
width: "16px",
|
|
85
|
-
height: "16px",
|
|
86
|
-
borderRadius: "50%",
|
|
87
|
-
border: isActive ? "2px solid #6366f1" : "1px solid #d1d5db",
|
|
88
|
-
backgroundColor: backgroundColor,
|
|
89
|
-
cursor: "pointer",
|
|
90
|
-
transition: "all 0.2s ease",
|
|
91
|
-
position: "relative"
|
|
92
|
-
}, onMouseEnter: (e) => {
|
|
93
|
-
if (!isActive) {
|
|
94
|
-
if (isPast) {
|
|
95
|
-
e.currentTarget.style.backgroundColor = hasStep ? "#fde68a" : "#fde68a"; // Darker yellow on hover for past steps
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
e.currentTarget.style.backgroundColor = hasStep ? "#d1d5db" : "#f3f4f6";
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}, onMouseLeave: (e) => {
|
|
102
|
-
if (!isActive) {
|
|
103
|
-
if (isPast) {
|
|
104
|
-
e.currentTarget.style.backgroundColor = hasStep ? "#fef3c7" : "#fef3c7"; // Back to light yellow for past steps
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
e.currentTarget.style.backgroundColor = hasStep ? "#e5e7eb" : "white";
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
} }, step));
|
|
111
|
-
}) }), _jsxs("div", { style: {
|
|
112
|
-
fontSize: "12px",
|
|
113
|
-
color: "#6b7280",
|
|
114
|
-
minWidth: "60px",
|
|
115
|
-
textAlign: "right"
|
|
116
|
-
}, children: [currentStep, " / ", maxStep] })] }));
|
|
117
|
-
};
|
|
118
|
-
export { Timeline };
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { PanelLeft } from "lucide-react";
|
|
3
|
-
const VerticalTimeline = ({ stamps, currentStep, onStepChange, onToggle }) => {
|
|
4
|
-
const maxStep = stamps.length > 0 ? Math.max(...stamps.map((s) => s.step)) : 0;
|
|
5
|
-
const minStep = stamps.length > 0 ? Math.min(...stamps.map((s) => s.step)) : 0;
|
|
6
|
-
const totalSteps = maxStep - minStep + 1;
|
|
7
|
-
// Calculate latency for each step
|
|
8
|
-
const getStepLatency = (step) => {
|
|
9
|
-
const stepStamps = stamps.filter((s) => s.step === step);
|
|
10
|
-
if (stepStamps.length === 0)
|
|
11
|
-
return null;
|
|
12
|
-
// Calculate time difference from previous step
|
|
13
|
-
const prevStep = step - 1;
|
|
14
|
-
const prevStepStamps = stamps.filter((s) => s.step === prevStep);
|
|
15
|
-
if (prevStepStamps.length === 0)
|
|
16
|
-
return null;
|
|
17
|
-
const currentTime = Math.min(...stepStamps.map((s) => s.time));
|
|
18
|
-
const prevTime = Math.max(...prevStepStamps.map((s) => s.time));
|
|
19
|
-
return currentTime - prevTime;
|
|
20
|
-
};
|
|
21
|
-
// Get step label
|
|
22
|
-
const getStepLabel = (step) => {
|
|
23
|
-
const stepStamps = stamps.filter((s) => s.step === step);
|
|
24
|
-
if (stepStamps.length === 0)
|
|
25
|
-
return `Step ${step}`;
|
|
26
|
-
// Get the first identifier for this step
|
|
27
|
-
const identifier = stepStamps[0]?.identifier || "";
|
|
28
|
-
return identifier || `Step ${step}`;
|
|
29
|
-
};
|
|
30
|
-
// Format latency
|
|
31
|
-
const formatLatency = (latency) => {
|
|
32
|
-
if (latency < 1000) {
|
|
33
|
-
return `${latency.toFixed(0)}ms`;
|
|
34
|
-
}
|
|
35
|
-
else if (latency < 60000) {
|
|
36
|
-
return `${(latency / 1000).toFixed(1)}s`;
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
return `${(latency / 60000).toFixed(1)}m`;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
return (_jsxs("div", { style: {
|
|
43
|
-
width: "100%",
|
|
44
|
-
height: "100%",
|
|
45
|
-
backgroundColor: "white",
|
|
46
|
-
display: "flex",
|
|
47
|
-
flexDirection: "column",
|
|
48
|
-
overflow: "hidden"
|
|
49
|
-
}, children: [_jsxs("div", { style: {
|
|
50
|
-
padding: "16px",
|
|
51
|
-
borderBottom: "1px solid #e5e7eb",
|
|
52
|
-
backgroundColor: "#f9fafb",
|
|
53
|
-
display: "flex",
|
|
54
|
-
justifyContent: "space-between",
|
|
55
|
-
alignItems: "flex-start"
|
|
56
|
-
}, children: [_jsxs("div", { children: [_jsx("h3", { style: {
|
|
57
|
-
margin: 0,
|
|
58
|
-
fontSize: "16px",
|
|
59
|
-
fontWeight: 600,
|
|
60
|
-
color: "#1f2937"
|
|
61
|
-
}, children: "Timeline" }), _jsx("p", { style: {
|
|
62
|
-
margin: "4px 0 0 0",
|
|
63
|
-
fontSize: "12px",
|
|
64
|
-
color: "#6b7280"
|
|
65
|
-
}, children: "Click to jump to step" })] }), onToggle && (_jsx("button", { onClick: onToggle, style: {
|
|
66
|
-
border: "none",
|
|
67
|
-
background: "none",
|
|
68
|
-
cursor: "pointer",
|
|
69
|
-
color: "#6b7280",
|
|
70
|
-
padding: "4px",
|
|
71
|
-
display: "flex",
|
|
72
|
-
alignItems: "center",
|
|
73
|
-
justifyContent: "center",
|
|
74
|
-
transition: "color 0.2s ease"
|
|
75
|
-
}, title: "Collapse Panel", children: _jsx(PanelLeft, { size: 16 }) }))] }), _jsx("div", { style: {
|
|
76
|
-
flex: 1,
|
|
77
|
-
overflowY: "auto",
|
|
78
|
-
padding: "8px 0 16px 0" // Add bottom padding
|
|
79
|
-
}, children: Array.from({ length: totalSteps }, (_, index) => {
|
|
80
|
-
const step = minStep + index;
|
|
81
|
-
const isActive = step === currentStep;
|
|
82
|
-
const isPast = step < currentStep;
|
|
83
|
-
const hasStep = stamps.some((s) => s.step === step);
|
|
84
|
-
const latency = getStepLatency(step);
|
|
85
|
-
const label = getStepLabel(step);
|
|
86
|
-
return (_jsxs("div", { onClick: () => hasStep && onStepChange(step), style: {
|
|
87
|
-
padding: "12px 16px",
|
|
88
|
-
borderBottom: "1px solid #f3f4f6",
|
|
89
|
-
cursor: hasStep ? "pointer" : "default",
|
|
90
|
-
backgroundColor: isActive ? "#f0f9ff" : "transparent",
|
|
91
|
-
borderLeft: isActive ? "4px solid #6366f1" : "4px solid transparent",
|
|
92
|
-
transition: "all 0.2s ease",
|
|
93
|
-
position: "relative"
|
|
94
|
-
}, onMouseEnter: (e) => {
|
|
95
|
-
if (hasStep && !isActive) {
|
|
96
|
-
e.currentTarget.style.backgroundColor = "#f8fafc";
|
|
97
|
-
}
|
|
98
|
-
}, onMouseLeave: (e) => {
|
|
99
|
-
if (hasStep && !isActive) {
|
|
100
|
-
e.currentTarget.style.backgroundColor = "transparent";
|
|
101
|
-
}
|
|
102
|
-
}, children: [_jsxs("div", { style: {
|
|
103
|
-
display: "flex",
|
|
104
|
-
alignItems: "center",
|
|
105
|
-
gap: "8px",
|
|
106
|
-
marginBottom: "4px"
|
|
107
|
-
}, children: [_jsx("div", { style: {
|
|
108
|
-
width: "12px",
|
|
109
|
-
height: "12px",
|
|
110
|
-
borderRadius: "50%",
|
|
111
|
-
backgroundColor: isActive ? "#6366f1" : isPast ? "#fbbf24" : hasStep ? "#9ca3af" : "#e5e7eb",
|
|
112
|
-
border: isActive ? "2px solid #6366f1" : "1px solid #d1d5db",
|
|
113
|
-
flexShrink: 0
|
|
114
|
-
} }), _jsxs("span", { style: {
|
|
115
|
-
fontSize: "14px",
|
|
116
|
-
fontWeight: isActive ? 600 : 500,
|
|
117
|
-
color: isActive ? "#1f2937" : "#6b7280"
|
|
118
|
-
}, children: ["Step ", step] }), latency && (_jsx("span", { style: {
|
|
119
|
-
fontSize: "11px",
|
|
120
|
-
color: "#9ca3af",
|
|
121
|
-
backgroundColor: "#f3f4f6",
|
|
122
|
-
padding: "2px 6px",
|
|
123
|
-
borderRadius: "4px",
|
|
124
|
-
marginLeft: "auto"
|
|
125
|
-
}, children: formatLatency(latency) }))] }), _jsx("div", { style: {
|
|
126
|
-
fontSize: "13px",
|
|
127
|
-
color: hasStep ? "#1f2937" : "#9ca3af",
|
|
128
|
-
lineHeight: "1.4",
|
|
129
|
-
wordBreak: "break-word",
|
|
130
|
-
fontStyle: hasStep ? "normal" : "italic"
|
|
131
|
-
}, children: hasStep ? label : "No activity" }), isActive && (_jsx("div", { style: {
|
|
132
|
-
position: "absolute",
|
|
133
|
-
right: "8px",
|
|
134
|
-
top: "50%",
|
|
135
|
-
transform: "translateY(-50%)",
|
|
136
|
-
width: "6px",
|
|
137
|
-
height: "6px",
|
|
138
|
-
borderRadius: "50%",
|
|
139
|
-
backgroundColor: "#6366f1",
|
|
140
|
-
animation: "pulse 2s infinite"
|
|
141
|
-
} }))] }, step));
|
|
142
|
-
}) }), _jsx("style", { children: `
|
|
143
|
-
@keyframes pulse {
|
|
144
|
-
0% {
|
|
145
|
-
opacity: 1;
|
|
146
|
-
}
|
|
147
|
-
50% {
|
|
148
|
-
opacity: 0.5;
|
|
149
|
-
}
|
|
150
|
-
100% {
|
|
151
|
-
opacity: 1;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
` })] }));
|
|
155
|
-
};
|
|
156
|
-
export { VerticalTimeline };
|
package/dist/esm/hooks/index.js
DELETED