@@ -378,170 +395,247 @@ function TasksTreeView({
{/* Timeline */}
-
-
- {/* Follows the cursor */}
-
+
+
+
+
+ );
+}
-
- {/* The duration labels */}
-
-
-
- {(ms: number, index: number) => {
- if (index === tickCount - 1) return null;
- return (
-
- {(ms) => (
-
- {formatDurationMilliseconds(ms, {
- style: "short",
- maxDecimalPoints: ms < 1000 ? 0 : 1,
- })}
-
- )}
-
- );
- }}
-
- {rootSpanStatus !== "executing" && (
-
+type TimelineViewProps = Pick<
+ TasksTreeViewProps,
+ "totalDuration" | "rootSpanStatus" | "events" | "rootStartedAt"
+> & {
+ scale: number;
+ parentRef: React.RefObject;
+ timelineScrollRef: React.RefObject;
+ virtualizer: Virtualizer;
+ nodes: NodesState;
+ getNodeProps: UseTreeStateOutput["getNodeProps"];
+ getTreeProps: UseTreeStateOutput["getTreeProps"];
+ toggleNodeSelection: UseTreeStateOutput["toggleNodeSelection"];
+ showDurations: boolean;
+ treeScrollRef: React.RefObject;
+};
+
+const tickCount = 5;
+
+function TimelineView({
+ totalDuration,
+ scale,
+ rootSpanStatus,
+ rootStartedAt,
+ parentRef,
+ timelineScrollRef,
+ virtualizer,
+ events,
+ nodes,
+ getNodeProps,
+ getTreeProps,
+ toggleNodeSelection,
+ showDurations,
+ treeScrollRef,
+}: TimelineViewProps) {
+ const timelineContainerRef = useRef(null);
+ const initialTimelineDimensions = useInitialDimensions(timelineContainerRef);
+ const minTimelineWidth = initialTimelineDimensions?.width ?? 300;
+ const maxTimelineWidth = minTimelineWidth * 10;
+
+ //we want to live-update the duration if the root span is still executing
+ const [duration, setDuration] = useState(totalDuration);
+ useEffect(() => {
+ if (rootSpanStatus !== "executing" || !rootStartedAt) {
+ setDuration(totalDuration);
+ return;
+ }
+
+ const interval = setInterval(() => {
+ setDuration(millisecondsToNanoseconds(Date.now() - rootStartedAt.getTime()));
+ }, 500);
+
+ return () => clearInterval(interval);
+ }, [totalDuration, rootSpanStatus]);
+
+ return (
+
+
+ {/* Follows the cursor */}
+
+
+
+ {/* The duration labels */}
+
+
+
+ {(ms: number, index: number) => {
+ if (index === tickCount - 1) return null;
+ return (
+
+ {(ms) => (
+
+ {formatDurationMilliseconds(ms, {
+ style: "short",
+ maxDecimalPoints: ms < 1000 ? 0 : 1,
+ })}
+
+ )}
+
+ );
+ }}
+
+ {rootSpanStatus !== "executing" && (
+
+ {(ms) => (
+
+ {formatDurationMilliseconds(ms, {
+ style: "short",
+ maxDecimalPoints: ms < 1000 ? 0 : 1,
+ })}
+
+ )}
+
+ )}
+
+
+
+ {(ms: number, index: number) => {
+ if (index === 0 || index === tickCount - 1) return null;
+ return (
+
+ );
+ }}
+
+
+
+
+ {/* Main timeline body */}
+
+ {/* The vertical tick lines */}
+
+ {(ms: number, index: number) => {
+ if (index === 0) return null;
+ return ;
+ }}
+
+ {/* The completed line */}
+ {rootSpanStatus !== "executing" && (
+
+ )}
+ {
+ return (
+ console.log(`hover ${index}`)}
+ onClick={(e) => {
+ toggleNodeSelection(node.id);
+ }}
+ >
+ {node.data.level === "TRACE" ? (
+
+ ) : (
+
{(ms) => (
-
- {formatDurationMilliseconds(ms, {
- style: "short",
- maxDecimalPoints: ms < 1000 ? 0 : 1,
- })}
-
+
)}
)}
-
-
- {(ms: number, index: number) => {
- if (index === 0 || index === tickCount - 1) return null;
- return (
-
- );
- }}
-
-
-
-
- {/* Main timeline body */}
-
- {/* The vertical tick lines */}
-
- {(ms: number, index: number) => {
- if (index === 0) return null;
- return (
-
- );
- }}
-
- {/* The completed line */}
- {rootSpanStatus !== "executing" && (
-
- )}
- {
- return (
- console.log(`hover ${index}`)}
- onClick={(e) => {
- toggleNodeSelection(node.id);
- }}
- >
- {node.data.level === "TRACE" ? (
-
- ) : (
-
- )}
-
- );
- }}
- onScroll={(scrollTop) => {
- //sync the scroll to the tree
- if (treeScrollRef.current && treeScrollRef.current.scrollTop !== scrollTop) {
- treeScrollRef.current.scrollTop = scrollTop;
- }
- }}
- />
-
-
-
-
-
-
+ );
+ }}
+ onScroll={(scrollTop) => {
+ //sync the scroll to the tree
+ if (treeScrollRef.current && treeScrollRef.current.scrollTop !== scrollTop) {
+ treeScrollRef.current.scrollTop = scrollTop;
+ }
+ }}
+ />
+
+
+
);
}
@@ -659,11 +753,12 @@ function SpanWithDuration({
}: Timeline.SpanProps & { node: RunEvent; showDuration: boolean }) {
return (