@workflow/web-shared 4.1.0-beta.47 → 4.1.0-beta.49
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/README.md +26 -52
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/{error-boundary.js → components/error-boundary.js} +1 -1
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/{event-list-view.d.ts → components/event-list-view.d.ts} +2 -3
- package/dist/components/event-list-view.d.ts.map +1 -0
- package/dist/{event-list-view.js → components/event-list-view.js} +9 -17
- package/dist/components/event-list-view.js.map +1 -0
- package/dist/{hook-actions.d.ts → components/hook-actions.d.ts} +2 -3
- package/dist/components/hook-actions.d.ts.map +1 -0
- package/dist/{hook-actions.js → components/hook-actions.js} +3 -4
- package/dist/components/hook-actions.js.map +1 -0
- package/dist/components/index.d.ts +10 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/run-trace-view.d.ts +22 -0
- package/dist/components/run-trace-view.d.ts.map +1 -0
- package/dist/components/run-trace-view.js +11 -0
- package/dist/components/run-trace-view.js.map +1 -0
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -0
- package/dist/{sidebar → components/sidebar}/attribute-panel.js +3 -3
- package/dist/components/sidebar/attribute-panel.js.map +1 -0
- package/dist/components/sidebar/conversation-view.d.ts.map +1 -0
- package/dist/components/sidebar/conversation-view.js.map +1 -0
- package/dist/components/sidebar/detail-card.d.ts.map +1 -0
- package/dist/components/sidebar/detail-card.js.map +1 -0
- package/dist/components/sidebar/entity-detail-panel.d.ts +32 -0
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -0
- package/dist/{sidebar → components/sidebar}/entity-detail-panel.js +61 -49
- package/dist/components/sidebar/entity-detail-panel.js.map +1 -0
- package/dist/components/sidebar/events-list.d.ts +8 -0
- package/dist/components/sidebar/events-list.d.ts.map +1 -0
- package/dist/components/sidebar/events-list.js +16 -0
- package/dist/components/sidebar/events-list.js.map +1 -0
- package/dist/components/sidebar/resolve-hook-modal.d.ts.map +1 -0
- package/dist/components/sidebar/resolve-hook-modal.js.map +1 -0
- package/dist/components/stream-viewer.d.ts +18 -0
- package/dist/components/stream-viewer.d.ts.map +1 -0
- package/dist/{stream-viewer.js → components/stream-viewer.js} +1 -59
- package/dist/components/stream-viewer.js.map +1 -0
- package/dist/components/trace-viewer/components/map.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/map.js.map +1 -0
- package/dist/components/trace-viewer/components/markers.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/markers.js.map +1 -0
- package/dist/components/trace-viewer/components/node.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/node.js.map +1 -0
- package/dist/components/trace-viewer/components/search-input.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/search-input.js.map +1 -0
- package/dist/components/trace-viewer/components/search.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/search.js.map +1 -0
- package/dist/components/trace-viewer/components/span-detail-panel.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/span-detail-panel.js.map +1 -0
- package/dist/components/trace-viewer/components/ui.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/ui.js.map +1 -0
- package/dist/components/trace-viewer/components/zoom-button.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/zoom-button.js.map +1 -0
- package/dist/components/trace-viewer/components/zoom-icons.d.ts.map +1 -0
- package/dist/components/trace-viewer/components/zoom-icons.js.map +1 -0
- package/dist/components/trace-viewer/context.d.ts.map +1 -0
- package/dist/components/trace-viewer/context.js.map +1 -0
- package/dist/components/trace-viewer/index.d.ts.map +1 -0
- package/dist/components/trace-viewer/index.js.map +1 -0
- package/dist/components/trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/trace-viewer/trace-viewer.js.map +1 -0
- package/dist/components/trace-viewer/types.d.ts.map +1 -0
- package/dist/components/trace-viewer/types.js.map +1 -0
- package/dist/components/trace-viewer/util/constants.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/constants.js.map +1 -0
- package/dist/components/trace-viewer/util/scrollbar-width.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/scrollbar-width.js.map +1 -0
- package/dist/{trace-viewer → components/trace-viewer}/util/timing.d.ts +1 -1
- package/dist/components/trace-viewer/util/timing.d.ts.map +1 -0
- package/dist/{trace-viewer → components/trace-viewer}/util/timing.js +1 -1
- package/dist/components/trace-viewer/util/timing.js.map +1 -0
- package/dist/components/trace-viewer/util/tree.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/tree.js.map +1 -0
- package/dist/components/trace-viewer/util/use-immediate-style.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/use-immediate-style.js.map +1 -0
- package/dist/components/trace-viewer/util/use-streaming-spans.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/use-streaming-spans.js.map +1 -0
- package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts.map +1 -0
- package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +1 -0
- package/dist/components/trace-viewer/worker.d.ts.map +1 -0
- package/dist/components/trace-viewer/worker.js.map +1 -0
- package/dist/components/workflow-trace-view.d.ts +24 -0
- package/dist/components/workflow-trace-view.d.ts.map +1 -0
- package/dist/components/workflow-trace-view.js +152 -0
- package/dist/components/workflow-trace-view.js.map +1 -0
- package/dist/components/workflow-traces/event-colors.d.ts.map +1 -0
- package/dist/components/workflow-traces/event-colors.js.map +1 -0
- package/dist/components/workflow-traces/trace-colors.d.ts.map +1 -0
- package/dist/components/workflow-traces/trace-colors.js.map +1 -0
- package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -0
- package/dist/components/workflow-traces/trace-span-construction.js.map +1 -0
- package/dist/components/workflow-traces/trace-time-utils.d.ts.map +1 -0
- package/dist/components/workflow-traces/trace-time-utils.js.map +1 -0
- package/dist/index.d.ts +3 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -9
- package/dist/index.js.map +1 -1
- package/package.json +15 -11
- package/src/components/error-boundary.tsx +79 -0
- package/src/components/event-list-view.tsx +429 -0
- package/src/components/hook-actions.tsx +167 -0
- package/src/components/index.d.ts +1 -0
- package/src/components/index.ts +23 -0
- package/src/components/run-trace-view.tsx +75 -0
- package/src/components/sidebar/attribute-panel.tsx +938 -0
- package/src/components/sidebar/conversation-view.tsx +235 -0
- package/src/components/sidebar/detail-card.tsx +43 -0
- package/src/components/sidebar/entity-detail-panel.tsx +338 -0
- package/src/components/sidebar/events-list.tsx +119 -0
- package/src/components/sidebar/resolve-hook-modal.tsx +219 -0
- package/src/components/stream-viewer.tsx +143 -0
- package/src/components/trace-viewer/components/map.tsx +226 -0
- package/src/components/trace-viewer/components/markers.tsx +564 -0
- package/src/components/trace-viewer/components/node.tsx +259 -0
- package/src/components/trace-viewer/components/search-input.tsx +52 -0
- package/src/components/trace-viewer/components/search.tsx +47 -0
- package/src/components/trace-viewer/components/span-detail-panel.tsx +650 -0
- package/src/components/trace-viewer/components/ui.tsx +156 -0
- package/src/components/trace-viewer/components/zoom-button.tsx +61 -0
- package/src/components/trace-viewer/components/zoom-icons.tsx +65 -0
- package/src/components/trace-viewer/context.tsx +633 -0
- package/src/components/trace-viewer/index.tsx +4 -0
- package/src/components/trace-viewer/modules.d.ts +16 -0
- package/src/components/trace-viewer/trace-viewer.module.css +1292 -0
- package/src/components/trace-viewer/trace-viewer.tsx +448 -0
- package/src/components/trace-viewer/types.ts +234 -0
- package/src/components/trace-viewer/util/constants.ts +8 -0
- package/src/components/trace-viewer/util/scrollbar-width.ts +13 -0
- package/src/components/trace-viewer/util/timing.ts +33 -0
- package/src/components/trace-viewer/util/tree.ts +277 -0
- package/src/components/trace-viewer/util/use-immediate-style.ts +38 -0
- package/src/components/trace-viewer/util/use-streaming-spans.ts +415 -0
- package/src/components/trace-viewer/util/use-trackpad-zoom.tsx +51 -0
- package/src/components/trace-viewer/worker.ts +128 -0
- package/src/components/ui/alert.tsx +59 -0
- package/src/components/ui/card.tsx +88 -0
- package/src/components/ui/error-card.tsx +65 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/workflow-trace-view.tsx +306 -0
- package/src/components/workflow-traces/event-colors.ts +94 -0
- package/src/components/workflow-traces/trace-colors.ts +112 -0
- package/src/components/workflow-traces/trace-span-construction.ts +299 -0
- package/src/components/workflow-traces/trace-time-utils.ts +50 -0
- package/src/hooks/use-dark-mode.ts +34 -0
- package/src/index.d.ts +1 -0
- package/src/index.ts +29 -0
- package/src/lib/event-analysis.ts +231 -0
- package/src/lib/utils.ts +166 -0
- package/dist/api/workflow-api-client.d.ts +0 -543
- package/dist/api/workflow-api-client.d.ts.map +0 -1
- package/dist/api/workflow-api-client.js +0 -953
- package/dist/api/workflow-api-client.js.map +0 -1
- package/dist/api/workflow-server-actions.d.ts +0 -230
- package/dist/api/workflow-server-actions.d.ts.map +0 -1
- package/dist/api/workflow-server-actions.js +0 -861
- package/dist/api/workflow-server-actions.js.map +0 -1
- package/dist/error-boundary.d.ts.map +0 -1
- package/dist/error-boundary.js.map +0 -1
- package/dist/event-list-view.d.ts.map +0 -1
- package/dist/event-list-view.js.map +0 -1
- package/dist/hook-actions.d.ts.map +0 -1
- package/dist/hook-actions.js.map +0 -1
- package/dist/run-trace-view.d.ts +0 -8
- package/dist/run-trace-view.d.ts.map +0 -1
- package/dist/run-trace-view.js +0 -15
- package/dist/run-trace-view.js.map +0 -1
- package/dist/sidebar/attribute-panel.d.ts.map +0 -1
- package/dist/sidebar/attribute-panel.js.map +0 -1
- package/dist/sidebar/conversation-view.d.ts.map +0 -1
- package/dist/sidebar/conversation-view.js.map +0 -1
- package/dist/sidebar/detail-card.d.ts.map +0 -1
- package/dist/sidebar/detail-card.js.map +0 -1
- package/dist/sidebar/entity-detail-panel.d.ts +0 -12
- package/dist/sidebar/entity-detail-panel.d.ts.map +0 -1
- package/dist/sidebar/entity-detail-panel.js.map +0 -1
- package/dist/sidebar/events-list.d.ts +0 -9
- package/dist/sidebar/events-list.d.ts.map +0 -1
- package/dist/sidebar/events-list.js +0 -36
- package/dist/sidebar/events-list.js.map +0 -1
- package/dist/sidebar/resolve-hook-modal.d.ts.map +0 -1
- package/dist/sidebar/resolve-hook-modal.js.map +0 -1
- package/dist/stream-viewer.d.ts +0 -13
- package/dist/stream-viewer.d.ts.map +0 -1
- package/dist/stream-viewer.js.map +0 -1
- package/dist/trace-viewer/components/map.d.ts.map +0 -1
- package/dist/trace-viewer/components/map.js.map +0 -1
- package/dist/trace-viewer/components/markers.d.ts.map +0 -1
- package/dist/trace-viewer/components/markers.js.map +0 -1
- package/dist/trace-viewer/components/node.d.ts.map +0 -1
- package/dist/trace-viewer/components/node.js.map +0 -1
- package/dist/trace-viewer/components/search-input.d.ts.map +0 -1
- package/dist/trace-viewer/components/search-input.js.map +0 -1
- package/dist/trace-viewer/components/search.d.ts.map +0 -1
- package/dist/trace-viewer/components/search.js.map +0 -1
- package/dist/trace-viewer/components/span-detail-panel.d.ts.map +0 -1
- package/dist/trace-viewer/components/span-detail-panel.js.map +0 -1
- package/dist/trace-viewer/components/ui.d.ts.map +0 -1
- package/dist/trace-viewer/components/ui.js.map +0 -1
- package/dist/trace-viewer/components/zoom-button.d.ts.map +0 -1
- package/dist/trace-viewer/components/zoom-button.js.map +0 -1
- package/dist/trace-viewer/components/zoom-icons.d.ts.map +0 -1
- package/dist/trace-viewer/components/zoom-icons.js.map +0 -1
- package/dist/trace-viewer/context.d.ts.map +0 -1
- package/dist/trace-viewer/context.js.map +0 -1
- package/dist/trace-viewer/index.d.ts.map +0 -1
- package/dist/trace-viewer/index.js.map +0 -1
- package/dist/trace-viewer/trace-viewer.d.ts.map +0 -1
- package/dist/trace-viewer/trace-viewer.js.map +0 -1
- package/dist/trace-viewer/types.d.ts.map +0 -1
- package/dist/trace-viewer/types.js.map +0 -1
- package/dist/trace-viewer/util/constants.d.ts.map +0 -1
- package/dist/trace-viewer/util/constants.js.map +0 -1
- package/dist/trace-viewer/util/scrollbar-width.d.ts.map +0 -1
- package/dist/trace-viewer/util/scrollbar-width.js.map +0 -1
- package/dist/trace-viewer/util/timing.d.ts.map +0 -1
- package/dist/trace-viewer/util/timing.js.map +0 -1
- package/dist/trace-viewer/util/tree.d.ts.map +0 -1
- package/dist/trace-viewer/util/tree.js.map +0 -1
- package/dist/trace-viewer/util/use-immediate-style.d.ts.map +0 -1
- package/dist/trace-viewer/util/use-immediate-style.js.map +0 -1
- package/dist/trace-viewer/util/use-streaming-spans.d.ts.map +0 -1
- package/dist/trace-viewer/util/use-streaming-spans.js.map +0 -1
- package/dist/trace-viewer/util/use-trackpad-zoom.d.ts.map +0 -1
- package/dist/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
- package/dist/trace-viewer/worker.d.ts.map +0 -1
- package/dist/trace-viewer/worker.js.map +0 -1
- package/dist/workflow-trace-view.d.ts +0 -14
- package/dist/workflow-trace-view.d.ts.map +0 -1
- package/dist/workflow-trace-view.js +0 -135
- package/dist/workflow-trace-view.js.map +0 -1
- package/dist/workflow-traces/event-colors.d.ts.map +0 -1
- package/dist/workflow-traces/event-colors.js.map +0 -1
- package/dist/workflow-traces/trace-colors.d.ts.map +0 -1
- package/dist/workflow-traces/trace-colors.js.map +0 -1
- package/dist/workflow-traces/trace-span-construction.d.ts.map +0 -1
- package/dist/workflow-traces/trace-span-construction.js.map +0 -1
- package/dist/workflow-traces/trace-time-utils.d.ts.map +0 -1
- package/dist/workflow-traces/trace-time-utils.js.map +0 -1
- package/server/README.md +0 -1
- package/server/package.json +0 -4
- /package/dist/{error-boundary.d.ts → components/error-boundary.d.ts} +0 -0
- /package/dist/{sidebar → components/sidebar}/attribute-panel.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/conversation-view.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/conversation-view.js +0 -0
- /package/dist/{sidebar → components/sidebar}/detail-card.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/detail-card.js +0 -0
- /package/dist/{sidebar → components/sidebar}/resolve-hook-modal.d.ts +0 -0
- /package/dist/{sidebar → components/sidebar}/resolve-hook-modal.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/map.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/map.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/markers.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/markers.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/node.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/node.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search-input.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search-input.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/search.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/span-detail-panel.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/span-detail-panel.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/ui.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/ui.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-button.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-button.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-icons.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-icons.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/context.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/context.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/index.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/index.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.module.css +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/types.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/types.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/constants.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/constants.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/scrollbar-width.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/scrollbar-width.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/tree.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/tree.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-immediate-style.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-immediate-style.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-streaming-spans.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-streaming-spans.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-trackpad-zoom.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/util/use-trackpad-zoom.js +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/worker.d.ts +0 -0
- /package/dist/{trace-viewer → components/trace-viewer}/worker.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/event-colors.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/event-colors.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-colors.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-colors.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-span-construction.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-span-construction.js +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-time-utils.d.ts +0 -0
- /package/dist/{workflow-traces → components/workflow-traces}/trace-time-utils.js +0 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import type { CSSProperties, MouseEventHandler, ReactNode } from 'react';
|
|
5
|
+
import { useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
|
6
|
+
import { MiniMap } from './components/map';
|
|
7
|
+
import { CursorMarker, EventMarkers, Markers } from './components/markers';
|
|
8
|
+
import { SpanNodes } from './components/node';
|
|
9
|
+
import { SearchBar } from './components/search';
|
|
10
|
+
import { SpanDetailPanel } from './components/span-detail-panel';
|
|
11
|
+
import { ZoomButton } from './components/zoom-button';
|
|
12
|
+
import { TraceViewerContextProvider, useTraceViewer } from './context';
|
|
13
|
+
import styles from './trace-viewer.module.css';
|
|
14
|
+
import type { GetQuickLinks, Trace } from './types';
|
|
15
|
+
import {
|
|
16
|
+
MAP_HEIGHT,
|
|
17
|
+
MARKER_HEIGHT,
|
|
18
|
+
MARKER_NOTCH_HEIGHT,
|
|
19
|
+
ROW_HEIGHT,
|
|
20
|
+
ROW_PADDING,
|
|
21
|
+
SEARCH_GAP,
|
|
22
|
+
SEARCH_HEIGHT,
|
|
23
|
+
TIMELINE_PADDING,
|
|
24
|
+
} from './util/constants';
|
|
25
|
+
import { parseTrace } from './util/tree';
|
|
26
|
+
import { useStreamingSpans } from './util/use-streaming-spans';
|
|
27
|
+
|
|
28
|
+
interface TraceViewerProps {
|
|
29
|
+
trace?: Trace;
|
|
30
|
+
className?: string;
|
|
31
|
+
scrollLock?: boolean;
|
|
32
|
+
height?: string | number;
|
|
33
|
+
withPanel?: boolean;
|
|
34
|
+
getQuickLinks?: GetQuickLinks;
|
|
35
|
+
highlightedSpans?: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function TraceViewerProvider({
|
|
39
|
+
getQuickLinks,
|
|
40
|
+
children,
|
|
41
|
+
}: Pick<TraceViewerProps, 'getQuickLinks'> & {
|
|
42
|
+
children: ReactNode;
|
|
43
|
+
}): ReactNode {
|
|
44
|
+
return (
|
|
45
|
+
<TraceViewerContextProvider getQuickLinks={getQuickLinks}>
|
|
46
|
+
{children}
|
|
47
|
+
</TraceViewerContextProvider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface LastClickRef {
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
t: number;
|
|
55
|
+
spanId: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const skeletonTrace: Trace = {
|
|
59
|
+
traceId: 'skeleton',
|
|
60
|
+
spans: [
|
|
61
|
+
{
|
|
62
|
+
parentSpanId: '',
|
|
63
|
+
spanId: 'root',
|
|
64
|
+
name: 'root span',
|
|
65
|
+
kind: 1,
|
|
66
|
+
resource: 'vercel.runtime',
|
|
67
|
+
startTime: [5000, 0],
|
|
68
|
+
endTime: [6000, 0],
|
|
69
|
+
duration: [1000, 0],
|
|
70
|
+
library: {
|
|
71
|
+
name: 'vercel-site',
|
|
72
|
+
},
|
|
73
|
+
status: {
|
|
74
|
+
code: 1,
|
|
75
|
+
},
|
|
76
|
+
attributes: {
|
|
77
|
+
'vercel.ownerId': 'team_abc',
|
|
78
|
+
},
|
|
79
|
+
traceFlags: 1,
|
|
80
|
+
events: [],
|
|
81
|
+
links: [],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
resources: [
|
|
85
|
+
{
|
|
86
|
+
name: 'vercel.runtime',
|
|
87
|
+
attributes: {},
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
rootSpanId: 'root',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export function TraceViewerTimeline({
|
|
94
|
+
trace = skeletonTrace,
|
|
95
|
+
className = '',
|
|
96
|
+
scrollLock = false,
|
|
97
|
+
height,
|
|
98
|
+
withPanel = false,
|
|
99
|
+
highlightedSpans,
|
|
100
|
+
}: Omit<TraceViewerProps, 'getQuickLinks'>): ReactNode {
|
|
101
|
+
const isSkeleton = trace === skeletonTrace;
|
|
102
|
+
const { state, dispatch } = useTraceViewer();
|
|
103
|
+
const { timelineRef, scrollSnapshotRef } = state;
|
|
104
|
+
const memoCache = state.memoCacheRef.current;
|
|
105
|
+
const hideSearchBar =
|
|
106
|
+
(highlightedSpans?.length ?? 0) > 0 || trace.spans.length <= 10;
|
|
107
|
+
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
const { root, map: spanMap } = parseTrace(trace);
|
|
110
|
+
dispatch({
|
|
111
|
+
type: 'setRoot',
|
|
112
|
+
root,
|
|
113
|
+
spanMap,
|
|
114
|
+
resources: trace.resources || [],
|
|
115
|
+
});
|
|
116
|
+
}, [dispatch, trace]);
|
|
117
|
+
|
|
118
|
+
const { rows, spans, events, scale } = useStreamingSpans(highlightedSpans);
|
|
119
|
+
|
|
120
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
121
|
+
useLayoutEffect(() => {
|
|
122
|
+
const $el = ref.current;
|
|
123
|
+
if (!$el) return;
|
|
124
|
+
|
|
125
|
+
const onResize = (): void => {
|
|
126
|
+
const padding = 2 * TIMELINE_PADDING;
|
|
127
|
+
const rect = $el.getBoundingClientRect();
|
|
128
|
+
|
|
129
|
+
dispatch({
|
|
130
|
+
type: 'setSize',
|
|
131
|
+
width: rect.width - padding,
|
|
132
|
+
height: rect.height,
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
onResize();
|
|
137
|
+
|
|
138
|
+
const observer = new ResizeObserver(onResize);
|
|
139
|
+
observer.observe($el);
|
|
140
|
+
window.addEventListener('resize', onResize);
|
|
141
|
+
|
|
142
|
+
return () => {
|
|
143
|
+
observer.disconnect();
|
|
144
|
+
window.removeEventListener('resize', onResize);
|
|
145
|
+
};
|
|
146
|
+
}, [dispatch]);
|
|
147
|
+
|
|
148
|
+
const lastClickRef = useRef<LastClickRef>({
|
|
149
|
+
t: 0,
|
|
150
|
+
x: -1,
|
|
151
|
+
y: -1,
|
|
152
|
+
spanId: '',
|
|
153
|
+
});
|
|
154
|
+
const onClick: MouseEventHandler = useCallback(
|
|
155
|
+
(event) => {
|
|
156
|
+
// NOTE(wits): We manually implement double-click logic here so that we can support double
|
|
157
|
+
// clicking a span even if the first click moves the span that the user is clicking on due
|
|
158
|
+
// to the panel opening. If we used a regular double click listener we would need to delay
|
|
159
|
+
// the opening of the panel artificially. This implementation allows us to always be
|
|
160
|
+
// FAST while also avoiding a FRUSTRATING situation.
|
|
161
|
+
const prev = lastClickRef.current;
|
|
162
|
+
const t = Date.now();
|
|
163
|
+
const { clientX: x, clientY: y } = event;
|
|
164
|
+
const d = Math.sqrt((x - prev.x) ** 2 + (y - prev.y) ** 2);
|
|
165
|
+
// double click
|
|
166
|
+
if (t - prev.t <= 500 && d <= 8) {
|
|
167
|
+
event.stopPropagation();
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
if (!prev.spanId) {
|
|
170
|
+
dispatch({
|
|
171
|
+
type: 'resetScale',
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
dispatch({
|
|
176
|
+
type: 'select',
|
|
177
|
+
id: prev.spanId,
|
|
178
|
+
});
|
|
179
|
+
dispatch({
|
|
180
|
+
type: 'scaleToNode',
|
|
181
|
+
id: prev.spanId,
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const target = event.target as HTMLElement;
|
|
186
|
+
if (!target.closest(`.${String(styles.timeline)}`)) return;
|
|
187
|
+
const $button = target.closest<HTMLButtonElement>('[data-span-id]');
|
|
188
|
+
const spanId = $button?.dataset.spanId || '';
|
|
189
|
+
lastClickRef.current = {
|
|
190
|
+
x,
|
|
191
|
+
y,
|
|
192
|
+
t,
|
|
193
|
+
spanId,
|
|
194
|
+
};
|
|
195
|
+
if (!spanId) return;
|
|
196
|
+
dispatch({
|
|
197
|
+
type: 'toggleSelection',
|
|
198
|
+
id: spanId,
|
|
199
|
+
});
|
|
200
|
+
event.stopPropagation();
|
|
201
|
+
},
|
|
202
|
+
[dispatch]
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// Zoom helper
|
|
206
|
+
useLayoutEffect(() => {
|
|
207
|
+
const $timeline = timelineRef.current;
|
|
208
|
+
if (!$timeline) return;
|
|
209
|
+
|
|
210
|
+
const snapshot = scrollSnapshotRef.current;
|
|
211
|
+
if (snapshot) {
|
|
212
|
+
$timeline.scrollLeft = snapshot.anchorT * scale - snapshot.anchorX;
|
|
213
|
+
}
|
|
214
|
+
}, [scrollSnapshotRef, timelineRef, scale]);
|
|
215
|
+
|
|
216
|
+
// Selection helper
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
const spanId = state.selected?.span.spanId;
|
|
219
|
+
if (!spanId) return;
|
|
220
|
+
|
|
221
|
+
const timeout = setTimeout(() => {
|
|
222
|
+
const $timeline = state.timelineRef.current;
|
|
223
|
+
const $span = $timeline?.querySelector(`[data-span-id="${spanId}"]`);
|
|
224
|
+
if (!$timeline || !$span) return;
|
|
225
|
+
|
|
226
|
+
const viewRect = $timeline.getBoundingClientRect();
|
|
227
|
+
const spanRect = $span.getBoundingClientRect();
|
|
228
|
+
|
|
229
|
+
// If the selected span is narrower than the timeline, scroll it into view
|
|
230
|
+
if (
|
|
231
|
+
spanRect.width < viewRect.width &&
|
|
232
|
+
(spanRect.left < viewRect.left ||
|
|
233
|
+
spanRect.right > viewRect.right ||
|
|
234
|
+
spanRect.top < viewRect.top ||
|
|
235
|
+
spanRect.bottom > viewRect.bottom)
|
|
236
|
+
) {
|
|
237
|
+
$span.scrollIntoView({
|
|
238
|
+
block: 'nearest',
|
|
239
|
+
inline: 'center',
|
|
240
|
+
behavior: 'smooth',
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}, 500);
|
|
244
|
+
|
|
245
|
+
return () => {
|
|
246
|
+
clearTimeout(timeout);
|
|
247
|
+
};
|
|
248
|
+
}, [state.selected, state.timelineRef]);
|
|
249
|
+
|
|
250
|
+
// Global keyboard shortcuts
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
const onKeyDown = (e: KeyboardEvent): void => {
|
|
253
|
+
if (e.key === 'Escape') {
|
|
254
|
+
dispatch({
|
|
255
|
+
type: 'escape',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
window.addEventListener('keydown', onKeyDown);
|
|
260
|
+
|
|
261
|
+
return () => {
|
|
262
|
+
window.removeEventListener('keydown', onKeyDown);
|
|
263
|
+
};
|
|
264
|
+
}, [dispatch]);
|
|
265
|
+
|
|
266
|
+
// Scroll locking
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
if (!scrollLock) return;
|
|
269
|
+
|
|
270
|
+
const $html = document.documentElement;
|
|
271
|
+
const $body = document.body;
|
|
272
|
+
|
|
273
|
+
$html.style.overflow = 'clip';
|
|
274
|
+
$body.style.overflow = 'clip';
|
|
275
|
+
|
|
276
|
+
const onScroll = (event?: Event): void => {
|
|
277
|
+
if (event?.cancelable) {
|
|
278
|
+
event.preventDefault();
|
|
279
|
+
} else {
|
|
280
|
+
window.scrollTo({
|
|
281
|
+
left: 0,
|
|
282
|
+
top: 0,
|
|
283
|
+
behavior: 'instant',
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
onScroll();
|
|
288
|
+
window.addEventListener('scroll', onScroll, {
|
|
289
|
+
passive: false,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return () => {
|
|
293
|
+
$html.style.overflow = '';
|
|
294
|
+
$body.style.overflow = '';
|
|
295
|
+
window.removeEventListener('scroll', onScroll);
|
|
296
|
+
};
|
|
297
|
+
}, [scrollLock]);
|
|
298
|
+
|
|
299
|
+
const timelineHeight = Math.max(
|
|
300
|
+
state.timelineHeight - state.scrollbarWidth,
|
|
301
|
+
MARKER_HEIGHT +
|
|
302
|
+
ROW_PADDING +
|
|
303
|
+
rows.length * (ROW_HEIGHT + ROW_PADDING) -
|
|
304
|
+
ROW_PADDING +
|
|
305
|
+
// When there are enough spans to be near the bottom edge, add some extra padding
|
|
306
|
+
// to avoid overlapping with the zoom buttons, etc.
|
|
307
|
+
84
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
const inert = Boolean(state.isMobile && state.selected);
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<div
|
|
314
|
+
className={clsx(
|
|
315
|
+
styles.traceViewer,
|
|
316
|
+
isSkeleton && styles.skeleton,
|
|
317
|
+
className
|
|
318
|
+
)}
|
|
319
|
+
onClickCapture={onClick}
|
|
320
|
+
ref={ref}
|
|
321
|
+
style={
|
|
322
|
+
{
|
|
323
|
+
height,
|
|
324
|
+
'--timeline-padding': `${TIMELINE_PADDING}px`,
|
|
325
|
+
'--row-height': `${ROW_HEIGHT}px`,
|
|
326
|
+
'--row-padding': `${ROW_PADDING}px`,
|
|
327
|
+
'--search-height': `${!hideSearchBar ? SEARCH_HEIGHT : 0}px`,
|
|
328
|
+
'--search-gap': `${!hideSearchBar ? SEARCH_GAP : 2}px`,
|
|
329
|
+
'--map-height': `${MAP_HEIGHT}px`,
|
|
330
|
+
'--timeline-width': `${state.timelineWidth}px`,
|
|
331
|
+
'--timeline-height': `${state.timelineHeight}px`,
|
|
332
|
+
'--timeline-scroll-width': `${Math.round(state.root.duration * state.scale)}px`,
|
|
333
|
+
'--panel-width': `${state.panelWidth}px`,
|
|
334
|
+
'--panel-height': `${state.panelHeight}px`,
|
|
335
|
+
'--height': `${state.height}px`,
|
|
336
|
+
'--scrollbar-width': `${state.scrollbarWidth}px`,
|
|
337
|
+
'--marker-height': `${MARKER_HEIGHT}px`,
|
|
338
|
+
'--marker-notch-height': `${MARKER_NOTCH_HEIGHT}px`,
|
|
339
|
+
} as CSSProperties
|
|
340
|
+
}
|
|
341
|
+
>
|
|
342
|
+
{!hideSearchBar ? <SearchBar /> : null}
|
|
343
|
+
<MiniMap rows={rows} scale={scale} timelineRef={timelineRef} />
|
|
344
|
+
<div className={clsx(styles.traceViewerContent, inert && styles.inert)}>
|
|
345
|
+
<div className={styles.timeline} ref={timelineRef}>
|
|
346
|
+
<div
|
|
347
|
+
style={{
|
|
348
|
+
position: 'relative',
|
|
349
|
+
width: state.timelineWidth,
|
|
350
|
+
height: state.timelineHeight - TIMELINE_PADDING * 2,
|
|
351
|
+
padding: TIMELINE_PADDING,
|
|
352
|
+
paddingBottom: 0,
|
|
353
|
+
}}
|
|
354
|
+
>
|
|
355
|
+
<div
|
|
356
|
+
className={styles.traceNode}
|
|
357
|
+
style={{
|
|
358
|
+
width: state.root.duration * scale || undefined,
|
|
359
|
+
height: timelineHeight - TIMELINE_PADDING * 2,
|
|
360
|
+
}}
|
|
361
|
+
>
|
|
362
|
+
<Markers scale={scale} />
|
|
363
|
+
<EventMarkers events={events} root={state.root} scale={scale} />
|
|
364
|
+
<CursorMarker
|
|
365
|
+
dispatch={dispatch}
|
|
366
|
+
events={events}
|
|
367
|
+
memoCacheRef={state.memoCacheRef}
|
|
368
|
+
root={state.root}
|
|
369
|
+
scale={scale}
|
|
370
|
+
scrollSnapshotRef={scrollSnapshotRef}
|
|
371
|
+
spans={spans}
|
|
372
|
+
timelineRef={timelineRef}
|
|
373
|
+
/>
|
|
374
|
+
<SpanNodes
|
|
375
|
+
cacheKey={memoCache.get('')}
|
|
376
|
+
cache={memoCache}
|
|
377
|
+
customSpanClassNameFunc={state.customSpanClassNameFunc}
|
|
378
|
+
customSpanEventClassNameFunc={
|
|
379
|
+
state.customSpanEventClassNameFunc
|
|
380
|
+
}
|
|
381
|
+
root={state.root}
|
|
382
|
+
scale={scale}
|
|
383
|
+
scrollSnapshotRef={scrollSnapshotRef}
|
|
384
|
+
spans={spans}
|
|
385
|
+
/>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
<div className={styles.zoomButtonTraceViewer}>
|
|
390
|
+
<ZoomButton />
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
{withPanel ? (
|
|
394
|
+
<div
|
|
395
|
+
className={clsx(
|
|
396
|
+
styles.spanDetailPanelTraceViewer,
|
|
397
|
+
!state.selected && styles.hidden,
|
|
398
|
+
state.isMobile && styles.mobile
|
|
399
|
+
)}
|
|
400
|
+
>
|
|
401
|
+
<SpanDetailPanel attached />
|
|
402
|
+
</div>
|
|
403
|
+
) : null}
|
|
404
|
+
</div>
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export function TraceViewerPanel({
|
|
409
|
+
className = '',
|
|
410
|
+
children = null,
|
|
411
|
+
}: {
|
|
412
|
+
className?: string;
|
|
413
|
+
children?: ReactNode;
|
|
414
|
+
}): ReactNode {
|
|
415
|
+
const { state } = useTraceViewer();
|
|
416
|
+
|
|
417
|
+
if (!state.selected) {
|
|
418
|
+
return children;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return (
|
|
422
|
+
<div
|
|
423
|
+
className={clsx(styles.spanDetailPanelTraceViewer, className)}
|
|
424
|
+
style={
|
|
425
|
+
{
|
|
426
|
+
position: 'relative',
|
|
427
|
+
'--search-height': '0',
|
|
428
|
+
'--search-gap': '0',
|
|
429
|
+
'--map-height': '0',
|
|
430
|
+
'--panel-width': `100%`,
|
|
431
|
+
'--panel-height': `100%`,
|
|
432
|
+
'--height': `100%`,
|
|
433
|
+
'--scrollbar-width': `${state.scrollbarWidth}px`,
|
|
434
|
+
} as CSSProperties
|
|
435
|
+
}
|
|
436
|
+
>
|
|
437
|
+
<SpanDetailPanel />
|
|
438
|
+
</div>
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
export function TraceViewer(props: TraceViewerProps): ReactNode {
|
|
443
|
+
return (
|
|
444
|
+
<TraceViewerContextProvider getQuickLinks={props.getQuickLinks} withPanel>
|
|
445
|
+
<TraceViewerTimeline withPanel {...props} />
|
|
446
|
+
</TraceViewerContextProvider>
|
|
447
|
+
);
|
|
448
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type { MutableRefObject, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export type MemoCacheKey = Record<string, never>;
|
|
4
|
+
export type MemoCache = Map<string, MemoCacheKey>;
|
|
5
|
+
|
|
6
|
+
export interface Span {
|
|
7
|
+
name: string;
|
|
8
|
+
kind: number;
|
|
9
|
+
resource: string;
|
|
10
|
+
library: {
|
|
11
|
+
name: string;
|
|
12
|
+
version?: string;
|
|
13
|
+
};
|
|
14
|
+
spanId: string;
|
|
15
|
+
parentSpanId?: string;
|
|
16
|
+
status: {
|
|
17
|
+
code: number;
|
|
18
|
+
};
|
|
19
|
+
traceFlags: number;
|
|
20
|
+
attributes: Record<string, unknown>;
|
|
21
|
+
links: Record<string, unknown>[];
|
|
22
|
+
events: SpanEvent[];
|
|
23
|
+
startTime: [number, number];
|
|
24
|
+
endTime: [number, number];
|
|
25
|
+
duration: [number, number];
|
|
26
|
+
/**
|
|
27
|
+
* The time when the span became active/started executing (optional).
|
|
28
|
+
* If provided and different from startTime, the portion between startTime
|
|
29
|
+
* and activeStartTime will be rendered as a "queued" period with different styling.
|
|
30
|
+
*/
|
|
31
|
+
activeStartTime?: [number, number];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface SpanEvent {
|
|
35
|
+
name: string;
|
|
36
|
+
timestamp: [number, number];
|
|
37
|
+
attributes: Record<string, unknown>;
|
|
38
|
+
/**
|
|
39
|
+
* Optional custom color for this event marker (workflow-specific feature).
|
|
40
|
+
* If provided, this color will be used for the event marker line/diamond.
|
|
41
|
+
*/
|
|
42
|
+
color?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Whether to show a vertical line for this event in the timeline (workflow-specific feature).
|
|
45
|
+
* If false, only the diamond marker on the span will be shown.
|
|
46
|
+
* Defaults to true if not specified.
|
|
47
|
+
*/
|
|
48
|
+
showVerticalLine?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface Resource {
|
|
52
|
+
name: string;
|
|
53
|
+
attributes: Record<string, string>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface Trace {
|
|
57
|
+
traceId: string;
|
|
58
|
+
resources?: Resource[];
|
|
59
|
+
spans: Span[];
|
|
60
|
+
rootSpanId?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface EveryNode {
|
|
64
|
+
startTime: number;
|
|
65
|
+
endTime: number;
|
|
66
|
+
duration: number;
|
|
67
|
+
/**
|
|
68
|
+
* How deep is this node within the tree
|
|
69
|
+
*/
|
|
70
|
+
depth: number;
|
|
71
|
+
/**
|
|
72
|
+
* All direct child nodes of this node
|
|
73
|
+
*/
|
|
74
|
+
children: SpanNode[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface RootNode extends EveryNode {
|
|
78
|
+
/**
|
|
79
|
+
* The depth is always 0 for the root node
|
|
80
|
+
*/
|
|
81
|
+
depth: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface SpanNode extends EveryNode {
|
|
85
|
+
/**
|
|
86
|
+
* This original Span that this node is based on
|
|
87
|
+
*/
|
|
88
|
+
span: Span;
|
|
89
|
+
/**
|
|
90
|
+
* The immediate parent of this node
|
|
91
|
+
*/
|
|
92
|
+
parent: RootNode | SpanNode;
|
|
93
|
+
/**
|
|
94
|
+
* A generated label to use (overrides the span.name) if present
|
|
95
|
+
*/
|
|
96
|
+
label?: string;
|
|
97
|
+
/**
|
|
98
|
+
* OTEL events that are present on this span (e.g. TTFB)
|
|
99
|
+
*/
|
|
100
|
+
events?: SpanNodeEvent[];
|
|
101
|
+
/**
|
|
102
|
+
* Whether this span originated in Vercel's infrastructure.
|
|
103
|
+
*/
|
|
104
|
+
isVercel: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Whether this span matches the current search filter
|
|
107
|
+
*/
|
|
108
|
+
isHighlighted?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Whether this span is a placeholder to hint at where user spans
|
|
111
|
+
* would appear if proper instrumentation were available
|
|
112
|
+
*/
|
|
113
|
+
isInstrumentationHint?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* The index of the resource that this node belongs to (used for color)
|
|
116
|
+
*/
|
|
117
|
+
resourceIndex: number;
|
|
118
|
+
/**
|
|
119
|
+
* The time when execution actually started (in milliseconds).
|
|
120
|
+
* If present and greater than startTime, represents a "queued" period.
|
|
121
|
+
*/
|
|
122
|
+
activeStartTime?: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface SpanNodeEvent {
|
|
126
|
+
/** A unique key for this event to help with rendering in React */
|
|
127
|
+
key: string;
|
|
128
|
+
/** The timestamp of this event in milliseconds */
|
|
129
|
+
timestamp: number;
|
|
130
|
+
/** The original event model */
|
|
131
|
+
event: SpanEvent;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export type TraceNode = RootNode | SpanNode;
|
|
135
|
+
|
|
136
|
+
export interface VisibleSpan extends SpanNode {
|
|
137
|
+
/**
|
|
138
|
+
* The ref for this span's element in the DOM
|
|
139
|
+
*/
|
|
140
|
+
ref?: MutableRefObject<HTMLButtonElement | null>;
|
|
141
|
+
/**
|
|
142
|
+
* The y position of this span (in # of rows)
|
|
143
|
+
*/
|
|
144
|
+
row: number;
|
|
145
|
+
/**
|
|
146
|
+
* Whether the CursorMarker is intersecting this span
|
|
147
|
+
*/
|
|
148
|
+
isHovered: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Whether this is the selected span
|
|
151
|
+
*/
|
|
152
|
+
isSelected: boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Whether this node is visible (based on its size on screen)
|
|
155
|
+
*/
|
|
156
|
+
isVisible: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Events also need to be able to hold a ref to their element in the DOM
|
|
159
|
+
*/
|
|
160
|
+
events?: VisibleSpanEvent[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface VisibleSpanEvent extends SpanNodeEvent {
|
|
164
|
+
/**
|
|
165
|
+
* The ref for this span's element in the DOM
|
|
166
|
+
*/
|
|
167
|
+
ref?: MutableRefObject<HTMLDivElement | null>;
|
|
168
|
+
/**
|
|
169
|
+
* Whether the CursorMarker is intersecting this span
|
|
170
|
+
*/
|
|
171
|
+
isHovered: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface ScrollSnapshot {
|
|
175
|
+
anchorT: number;
|
|
176
|
+
anchorX: number;
|
|
177
|
+
scrollLeft: number;
|
|
178
|
+
scrollTop: number;
|
|
179
|
+
startTime: number;
|
|
180
|
+
endTime: number;
|
|
181
|
+
startRow: number;
|
|
182
|
+
endRow: number;
|
|
183
|
+
scale: number;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export type WorkerRequest = {
|
|
187
|
+
requestId: number;
|
|
188
|
+
} & (
|
|
189
|
+
| {
|
|
190
|
+
type: 'calculateSpanPositions';
|
|
191
|
+
root: RootNode;
|
|
192
|
+
}
|
|
193
|
+
| {
|
|
194
|
+
type: 'filterSpans';
|
|
195
|
+
root: RootNode;
|
|
196
|
+
filter: string;
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
export type WorkerResponse = {
|
|
201
|
+
requestId: number;
|
|
202
|
+
} & (
|
|
203
|
+
| {
|
|
204
|
+
type: 'setRowsResult';
|
|
205
|
+
rows: VisibleSpan[][];
|
|
206
|
+
isEnd: boolean;
|
|
207
|
+
}
|
|
208
|
+
| {
|
|
209
|
+
type: 'updateHighlight';
|
|
210
|
+
matches: Set<string>;
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Represents one link to a page related to the selected
|
|
216
|
+
* span in the detail panel.
|
|
217
|
+
*/
|
|
218
|
+
export interface QuickLink {
|
|
219
|
+
/** Used as a React key and the user-facing name for the link */
|
|
220
|
+
key: string;
|
|
221
|
+
/** Until this Promise is fulfilled, the row will render with a skeleton for the value. */
|
|
222
|
+
value: Promise<QuickLinkValue>;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export interface QuickLinkValue {
|
|
226
|
+
/** The visible components for the right side of this link */
|
|
227
|
+
label: ReactNode;
|
|
228
|
+
/** A special suffix to show for this link, defaults to the ExternalLink icon */
|
|
229
|
+
icon?: ReactNode;
|
|
230
|
+
/** The href that this link will open when clicked */
|
|
231
|
+
href: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export type GetQuickLinks = (node: Span) => QuickLink[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const SEARCH_HEIGHT = 40;
|
|
2
|
+
export const SEARCH_GAP = 8;
|
|
3
|
+
export const MAP_HEIGHT = 56;
|
|
4
|
+
export const TIMELINE_PADDING = 8;
|
|
5
|
+
export const ROW_PADDING = 2;
|
|
6
|
+
export const ROW_HEIGHT = 24;
|
|
7
|
+
export const MARKER_HEIGHT = 24;
|
|
8
|
+
export const MARKER_NOTCH_HEIGHT = 8;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const detectScrollbarWidth = (): number => {
|
|
2
|
+
if (!('document' in globalThis)) return 0;
|
|
3
|
+
const size = 400;
|
|
4
|
+
const container = document.createElement('div');
|
|
5
|
+
container.style.width = `${size}px`;
|
|
6
|
+
container.style.height = `${size}px`;
|
|
7
|
+
container.style.overflow = 'scroll';
|
|
8
|
+
document.body.appendChild(container);
|
|
9
|
+
const scrollbarWidth = size - container.scrollWidth;
|
|
10
|
+
container.remove();
|
|
11
|
+
|
|
12
|
+
return scrollbarWidth;
|
|
13
|
+
};
|