@workflow/web-shared 5.0.0-beta.2 → 5.0.0-beta.3
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/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/new-trace-viewer/components/copy-button.d.ts +9 -0
- package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/copy-button.js +27 -0
- package/dist/components/new-trace-viewer/components/copy-button.js.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +8 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/event-list.js +35 -0
- package/dist/components/new-trace-viewer/components/event-list.js.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/split-pane.js +100 -0
- package/dist/components/new-trace-viewer/components/split-pane.js.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts +32 -0
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/timeline.js +134 -0
- package/dist/components/new-trace-viewer/components/timeline.js.map +1 -0
- package/dist/components/new-trace-viewer/context.d.ts +15 -0
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/context.js +49 -0
- package/dist/components/new-trace-viewer/context.js.map +1 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts +10 -0
- package/dist/components/new-trace-viewer/detail-panel.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/detail-panel.js +11 -0
- package/dist/components/new-trace-viewer/detail-panel.js.map +1 -0
- package/dist/components/new-trace-viewer/icons.d.ts +6 -0
- package/dist/components/new-trace-viewer/icons.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/icons.js +15 -0
- package/dist/components/new-trace-viewer/icons.js.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts +8 -0
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/trace-viewer.js +329 -0
- package/dist/components/new-trace-viewer/trace-viewer.js.map +1 -0
- package/dist/components/new-trace-viewer/types.d.ts +1 -0
- package/dist/components/new-trace-viewer/types.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/types.js +2 -0
- package/dist/components/new-trace-viewer/types.js.map +1 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts +1 -0
- package/dist/components/new-trace-viewer/util/constants.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/util/constants.js +2 -0
- package/dist/components/new-trace-viewer/util/constants.js.map +1 -0
- package/dist/components/new-trace-viewer/utils.d.ts +47 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/utils.js +358 -0
- package/dist/components/new-trace-viewer/utils.js.map +1 -0
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +42 -23
- package/dist/components/sidebar/attribute-panel.js.map +1 -1
- package/dist/components/sidebar/copyable-data-block.js +1 -1
- package/dist/components/sidebar/copyable-data-block.js.map +1 -1
- package/dist/components/sidebar/detail-card.d.ts.map +1 -1
- package/dist/components/sidebar/detail-card.js +1 -1
- package/dist/components/sidebar/detail-card.js.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.d.ts +1 -3
- package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
- package/dist/components/sidebar/entity-detail-panel.js +3 -25
- package/dist/components/sidebar/entity-detail-panel.js.map +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +2 -2
- package/dist/components/sidebar/events-list.js.map +1 -1
- package/dist/components/sidebar/sidebar-data-context.d.ts +29 -0
- package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar-data-context.js +19 -0
- package/dist/components/sidebar/sidebar-data-context.js.map +1 -0
- package/dist/components/stream-viewer.d.ts +1 -1
- package/dist/components/stream-viewer.d.ts.map +1 -1
- package/dist/components/stream-viewer.js +2 -26
- package/dist/components/stream-viewer.js.map +1 -1
- package/dist/components/trace-viewer-new.d.ts +10 -0
- package/dist/components/trace-viewer-new.d.ts.map +1 -0
- package/dist/components/trace-viewer-new.js +23 -0
- package/dist/components/trace-viewer-new.js.map +1 -0
- package/dist/components/ui/data-inspector.d.ts +21 -0
- package/dist/components/ui/data-inspector.d.ts.map +1 -1
- package/dist/components/ui/data-inspector.js +99 -4
- package/dist/components/ui/data-inspector.js.map +1 -1
- package/dist/components/ui/inspector-theme.d.ts +9 -10
- package/dist/components/ui/inspector-theme.d.ts.map +1 -1
- package/dist/components/ui/inspector-theme.js +38 -71
- package/dist/components/ui/inspector-theme.js.map +1 -1
- package/dist/components/workflow-trace-view.d.ts +1 -3
- package/dist/components/workflow-trace-view.d.ts.map +1 -1
- package/dist/components/workflow-trace-view.js +4 -4
- package/dist/components/workflow-trace-view.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/stream-display.d.ts +18 -0
- package/dist/lib/stream-display.d.ts.map +1 -0
- package/dist/lib/stream-display.js +30 -0
- package/dist/lib/stream-display.js.map +1 -0
- package/dist/lib/utils.d.ts +7 -9
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +17 -22
- package/dist/lib/utils.js.map +1 -1
- package/dist/styles.css +470 -1
- package/package.json +3 -2
- package/src/components/index.ts +5 -0
- package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +109 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +186 -0
- package/src/components/new-trace-viewer/components/timeline.tsx +378 -0
- package/src/components/new-trace-viewer/context.tsx +94 -0
- package/src/components/new-trace-viewer/detail-panel.tsx +57 -0
- package/src/components/new-trace-viewer/icons.tsx +79 -0
- package/src/components/new-trace-viewer/trace-viewer.tsx +585 -0
- package/src/components/new-trace-viewer/types.ts +0 -0
- package/src/components/new-trace-viewer/util/constants.ts +0 -0
- package/src/components/new-trace-viewer/utils.ts +524 -0
- package/src/components/sidebar/attribute-panel.tsx +43 -32
- package/src/components/sidebar/copyable-data-block.tsx +1 -1
- package/src/components/sidebar/detail-card.tsx +1 -19
- package/src/components/sidebar/entity-detail-panel.tsx +0 -71
- package/src/components/sidebar/events-list.tsx +9 -6
- package/src/components/sidebar/sidebar-data-context.tsx +62 -0
- package/src/components/stream-viewer.tsx +18 -40
- package/src/components/trace-viewer-new.tsx +49 -0
- package/src/components/ui/data-inspector.tsx +235 -4
- package/src/components/ui/inspector-theme.ts +39 -81
- package/src/components/workflow-trace-view.tsx +2 -6
- package/src/index.ts +1 -0
- package/src/lib/stream-display.ts +48 -0
- package/src/lib/utils.ts +18 -23
- package/src/styles.css +470 -1
|
@@ -4,6 +4,7 @@ export type { HookActionCallbacks, HookActionsDropdownItemProps, HookResolveModa
|
|
|
4
4
|
export { HookResolveModalWrapper, ResolveHookDropdownItem, ResolveHookModal, useHookActions, } from './hook-actions';
|
|
5
5
|
export { RunTraceView } from './run-trace-view';
|
|
6
6
|
export { ConversationView } from './sidebar/conversation-view';
|
|
7
|
+
export { SidebarDataProvider, type SidebarDataContextValue, } from './sidebar/sidebar-data-context';
|
|
7
8
|
export type { SelectedSpanInfo, SpanSelectionInfo, } from './sidebar/entity-detail-panel';
|
|
8
9
|
export { type StreamChunk, StreamViewer } from './stream-viewer';
|
|
9
10
|
export type { Span, SpanEvent } from './trace-viewer/types';
|
|
@@ -13,4 +14,5 @@ export { LoadMoreButton } from './ui/load-more-button';
|
|
|
13
14
|
export { MenuDropdown, type MenuDropdownOption } from './ui/menu-dropdown';
|
|
14
15
|
export { Spinner } from './ui/spinner';
|
|
15
16
|
export { WorkflowTraceViewer } from './workflow-trace-view';
|
|
17
|
+
export { NewTraceViewer } from './trace-viewer-new';
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,YAAY,EACV,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,YAAY,EACV,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EACL,mBAAmB,EACnB,KAAK,uBAAuB,GAC7B,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/components/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { EventListView } from './event-list-view';
|
|
|
3
3
|
export { HookResolveModalWrapper, ResolveHookDropdownItem, ResolveHookModal, useHookActions, } from './hook-actions';
|
|
4
4
|
export { RunTraceView } from './run-trace-view';
|
|
5
5
|
export { ConversationView } from './sidebar/conversation-view';
|
|
6
|
+
export { SidebarDataProvider, } from './sidebar/sidebar-data-context';
|
|
6
7
|
export { StreamViewer } from './stream-viewer';
|
|
7
8
|
export { DataInspector, DecryptClickContext, } from './ui/data-inspector';
|
|
8
9
|
export { DecryptButton } from './ui/decrypt-button';
|
|
@@ -10,4 +11,5 @@ export { LoadMoreButton } from './ui/load-more-button';
|
|
|
10
11
|
export { MenuDropdown } from './ui/menu-dropdown';
|
|
11
12
|
export { Spinner } from './ui/spinner';
|
|
12
13
|
export { WorkflowTraceViewer } from './workflow-trace-view';
|
|
14
|
+
export { NewTraceViewer } from './trace-viewer-new';
|
|
13
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQlD,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQlD,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EACL,mBAAmB,GAEpB,MAAM,gCAAgC,CAAC;AAKxC,OAAO,EAAoB,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EACL,aAAa,EAEb,mBAAmB,GAEpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAA2B,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["export { ErrorBoundary } from './error-boundary';\nexport { EventListView } from './event-list-view';\nexport type {\n HookActionCallbacks,\n HookActionsDropdownItemProps,\n HookResolveModalProps,\n UseHookActionsOptions,\n UseHookActionsReturn,\n} from './hook-actions';\nexport {\n HookResolveModalWrapper,\n ResolveHookDropdownItem,\n ResolveHookModal,\n useHookActions,\n} from './hook-actions';\nexport { RunTraceView } from './run-trace-view';\nexport { ConversationView } from './sidebar/conversation-view';\nexport {\n SidebarDataProvider,\n type SidebarDataContextValue,\n} from './sidebar/sidebar-data-context';\nexport type {\n SelectedSpanInfo,\n SpanSelectionInfo,\n} from './sidebar/entity-detail-panel';\nexport { type StreamChunk, StreamViewer } from './stream-viewer';\nexport type { Span, SpanEvent } from './trace-viewer/types';\nexport {\n DataInspector,\n type DataInspectorProps,\n DecryptClickContext,\n type DecryptClickContextValue,\n} from './ui/data-inspector';\nexport { DecryptButton } from './ui/decrypt-button';\nexport { LoadMoreButton } from './ui/load-more-button';\nexport { MenuDropdown, type MenuDropdownOption } from './ui/menu-dropdown';\nexport { Spinner } from './ui/spinner';\nexport { WorkflowTraceViewer } from './workflow-trace-view';\nexport { NewTraceViewer } from './trace-viewer-new';\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type JSX } from 'react';
|
|
2
|
+
interface CopyButtonProps {
|
|
3
|
+
copyText: string;
|
|
4
|
+
ariaLabel: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function CopyButton({ copyText, ariaLabel, className, }: CopyButtonProps): JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=copy-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-button.d.ts","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/copy-button.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,GAAG,EAA+B,MAAM,OAAO,CAAC;AAG9D,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,SAAS,EACT,SAAS,GACV,EAAE,eAAe,GAAG,GAAG,CAAC,OAAO,CAmD/B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Check, Copy } from 'lucide-react';
|
|
4
|
+
import { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { cn } from '../../../lib/utils';
|
|
6
|
+
export function CopyButton({ copyText, ariaLabel, className, }) {
|
|
7
|
+
const [copied, setCopied] = useState(false);
|
|
8
|
+
const timeoutRef = useRef(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
return () => {
|
|
11
|
+
if (timeoutRef.current) {
|
|
12
|
+
clearTimeout(timeoutRef.current);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}, []);
|
|
16
|
+
return (_jsx("button", { type: "button", "aria-label": ariaLabel, className: cn('cursor-pointer text-gray-800 hover:text-gray-1000 bg-transparent border-none p-1 m-0', className), onClick: (e) => {
|
|
17
|
+
e.stopPropagation();
|
|
18
|
+
if (timeoutRef.current) {
|
|
19
|
+
clearTimeout(timeoutRef.current);
|
|
20
|
+
}
|
|
21
|
+
void navigator.clipboard.writeText(copyText).then(() => {
|
|
22
|
+
setCopied(true);
|
|
23
|
+
timeoutRef.current = setTimeout(() => setCopied(false), 1000);
|
|
24
|
+
});
|
|
25
|
+
}, children: _jsxs("div", { className: "relative w-3 h-3", children: [_jsx("div", { className: cn('absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out', copied ? 'scale-100 opacity-100' : 'scale-0 opacity-0'), children: _jsx(Check, { className: "w-3 h-3" }) }), _jsx("div", { className: cn('absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out', copied ? 'scale-0 opacity-0' : 'scale-100 opacity-100'), children: _jsx(Copy, { className: "w-3 h-3" }) })] }) }));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=copy-button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-button.js","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/copy-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAY,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAQxC,MAAM,UAAU,UAAU,CAAC,EACzB,QAAQ,EACR,SAAS,EACT,SAAS,GACO;IAChB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,MAAM,CAAuC,IAAI,CAAC,CAAC;IAEtE,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,GAAG,EAAE;YACV,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACvB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,gBACD,SAAS,EACrB,SAAS,EAAE,EAAE,CACX,sFAAsF,EACtF,SAAS,CACV,EACD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACb,CAAC,CAAC,eAAe,EAAE,CAAC;YACpB,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACvB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;YACD,KAAK,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBACrD,SAAS,CAAC,IAAI,CAAC,CAAC;gBAChB,UAAU,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;QACL,CAAC,YAED,eAAK,SAAS,EAAC,kBAAkB,aAC/B,cACE,SAAS,EAAE,EAAE,CACX,wFAAwF,EACxF,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,mBAAmB,CACvD,YAED,KAAC,KAAK,IAAC,SAAS,EAAC,SAAS,GAAG,GACzB,EACN,cACE,SAAS,EAAE,EAAE,CACX,wFAAwF,EACxF,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,uBAAuB,CACvD,YAED,KAAC,IAAI,IAAC,SAAS,EAAC,SAAS,GAAG,GACxB,IACF,GACC,CACV,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport { Check, Copy } from 'lucide-react';\nimport { type JSX, useEffect, useRef, useState } from 'react';\nimport { cn } from '../../../lib/utils';\n\ninterface CopyButtonProps {\n copyText: string;\n ariaLabel: string;\n className?: string;\n}\n\nexport function CopyButton({\n copyText,\n ariaLabel,\n className,\n}: CopyButtonProps): JSX.Element {\n const [copied, setCopied] = useState(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n return (\n <button\n type=\"button\"\n aria-label={ariaLabel}\n className={cn(\n 'cursor-pointer text-gray-800 hover:text-gray-1000 bg-transparent border-none p-1 m-0',\n className\n )}\n onClick={(e) => {\n e.stopPropagation();\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n void navigator.clipboard.writeText(copyText).then(() => {\n setCopied(true);\n timeoutRef.current = setTimeout(() => setCopied(false), 1000);\n });\n }}\n >\n <div className=\"relative w-3 h-3\">\n <div\n className={cn(\n 'absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out',\n copied ? 'scale-100 opacity-100' : 'scale-0 opacity-0'\n )}\n >\n <Check className=\"w-3 h-3\" />\n </div>\n <div\n className={cn(\n 'absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out',\n copied ? 'scale-0 opacity-0' : 'scale-100 opacity-100'\n )}\n >\n <Copy className=\"w-3 h-3\" />\n </div>\n </div>\n </button>\n );\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Span } from '../../trace-viewer/types';
|
|
2
|
+
declare const EventList: ({ spans, activeSpanId, onSelectSpan, }: {
|
|
3
|
+
spans: Span[];
|
|
4
|
+
activeSpanId: string | null;
|
|
5
|
+
onSelectSpan: (spanId: string) => void;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default EventList;
|
|
8
|
+
//# sourceMappingURL=event-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-list.d.ts","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/event-list.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AA6ErD,QAAA,MAAM,SAAS,GAAI,wCAIhB;IACD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,4CAmBA,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Circle } from 'lucide-react';
|
|
3
|
+
import { cn } from '../../../lib/utils';
|
|
4
|
+
import { formatDuration, getHighResInMs } from '../../trace-viewer/util/timing';
|
|
5
|
+
import { WorkflowIcon, WebhookIcon, SleepIcon, StepForwardIcon, } from '../icons';
|
|
6
|
+
const eventStyles = {
|
|
7
|
+
run: { icon: WorkflowIcon, className: 'text-blue-900' },
|
|
8
|
+
step: { icon: StepForwardIcon, className: 'text-green-900' },
|
|
9
|
+
hook: { icon: WebhookIcon, className: 'text-yellow-900' },
|
|
10
|
+
sleep: { icon: SleepIcon, className: 'text-gray-900' },
|
|
11
|
+
};
|
|
12
|
+
const defaultStyle = {
|
|
13
|
+
icon: Circle,
|
|
14
|
+
className: 'text-gray-900',
|
|
15
|
+
};
|
|
16
|
+
function getEventStyle(resource, isErrored) {
|
|
17
|
+
const style = eventStyles[resource] ?? defaultStyle;
|
|
18
|
+
return {
|
|
19
|
+
icon: style.icon,
|
|
20
|
+
className: cn(isErrored ? 'text-red-900' : style.className),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const EventRow = ({ span, isSelected, onSelectSpan, }) => {
|
|
24
|
+
const durationMs = getHighResInMs(span.duration);
|
|
25
|
+
const isErrored = span.attributes.data.status === 'failed';
|
|
26
|
+
const { icon: Icon, className: tagClassName } = getEventStyle(span.resource, isErrored);
|
|
27
|
+
return (_jsx("li", { className: "overflow-clip group", role: "treeitem", "aria-selected": isSelected, "aria-expanded": isSelected, "aria-level": 1, onClick: () => onSelectSpan(span.spanId), children: _jsxs("div", { className: "hover:bg-gray-100 group-aria-selected:bg-gray-100 group-aria-selected:hover:bg-gray-200 hover:aria-selected:bg-gray-100 rounded-sm px-2 h-[34px] py-1.5 flex", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: tagClassName, children: _jsx(Icon, { className: "w-4 h-4" }) }), _jsx("span", { className: "text-label-14", children: span.name })] }), _jsx("div", { className: "ml-auto", children: _jsx("span", { className: "text-label-14 text-gray-900 tabular-nums", children: formatDuration(durationMs) }) })] }) }));
|
|
28
|
+
};
|
|
29
|
+
const EventList = ({ spans, activeSpanId, onSelectSpan, }) => {
|
|
30
|
+
return (_jsx("ul", { id: "event-list", role: "tree", className: "block min-h-0 overflow-visible px-2 py-2", children: spans.map((span) => {
|
|
31
|
+
return (_jsx(EventRow, { span: span, isSelected: span.spanId === activeSpanId, onSelectSpan: onSelectSpan }, span.spanId));
|
|
32
|
+
}) }));
|
|
33
|
+
};
|
|
34
|
+
export default EventList;
|
|
35
|
+
//# sourceMappingURL=event-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-list.js","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/event-list.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChF,OAAO,EACL,YAAY,EACZ,WAAW,EACX,SAAS,EACT,eAAe,GAChB,MAAM,UAAU,CAAC;AAOlB,MAAM,WAAW,GAA+B;IAC9C,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE;IACvD,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,gBAAgB,EAAE;IAC5D,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE;IACzD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE;CACvD,CAAC;AAEF,MAAM,YAAY,GAAe;IAC/B,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,eAAe;CAC3B,CAAC;AAEF,SAAS,aAAa,CAAC,QAAgB,EAAE,SAAkB;IACzD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,YAAY,CAAC;IACpD,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,EAChB,IAAI,EACJ,UAAU,EACV,YAAY,GAKb,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,SAAS,GACZ,IAAI,CAAC,UAAU,CAAC,IAAgC,CAAC,MAAM,KAAK,QAAQ,CAAC;IACxE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,aAAa,CAC3D,IAAI,CAAC,QAAQ,EACb,SAAS,CACV,CAAC;IAEF,OAAO,CACL,aACE,SAAS,EAAC,qBAAqB,EAC/B,IAAI,EAAC,UAAU,mBACA,UAAU,mBACV,UAAU,gBACb,CAAC,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,YAExC,eAAK,SAAS,EAAC,8JAA8J,aAC3K,eAAK,SAAS,EAAC,yBAAyB,aACtC,eAAM,SAAS,EAAE,YAAY,YAC3B,KAAC,IAAI,IAAC,SAAS,EAAC,SAAS,GAAG,GACvB,EACP,eAAM,SAAS,EAAC,eAAe,YAAE,IAAI,CAAC,IAAI,GAAQ,IAC9C,EACN,cAAK,SAAS,EAAC,SAAS,YACtB,eAAM,SAAS,EAAC,0CAA0C,YACvD,cAAc,CAAC,UAAU,CAAC,GACtB,GACH,IACF,GACH,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,EACjB,KAAK,EACL,YAAY,EACZ,YAAY,GAKb,EAAE,EAAE;IACH,OAAO,CACL,aACE,EAAE,EAAC,YAAY,EACf,IAAI,EAAC,MAAM,EACX,SAAS,EAAC,0CAA0C,YAEnD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAClB,OAAO,CACL,KAAC,QAAQ,IAEP,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,IAAI,CAAC,MAAM,KAAK,YAAY,EACxC,YAAY,EAAE,YAAY,IAHrB,IAAI,CAAC,MAAM,CAIhB,CACH,CAAC;QACJ,CAAC,CAAC,GACC,CACN,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,SAAS,CAAC","sourcesContent":["import { Circle } from 'lucide-react';\nimport { cn } from '../../../lib/utils';\nimport type { Span } from '../../trace-viewer/types';\nimport { formatDuration, getHighResInMs } from '../../trace-viewer/util/timing';\nimport {\n WorkflowIcon,\n WebhookIcon,\n SleepIcon,\n StepForwardIcon,\n} from '../icons';\n\ninterface EventStyle {\n icon: React.ComponentType<{ className?: string }>;\n className: string;\n}\n\nconst eventStyles: Record<string, EventStyle> = {\n run: { icon: WorkflowIcon, className: 'text-blue-900' },\n step: { icon: StepForwardIcon, className: 'text-green-900' },\n hook: { icon: WebhookIcon, className: 'text-yellow-900' },\n sleep: { icon: SleepIcon, className: 'text-gray-900' },\n};\n\nconst defaultStyle: EventStyle = {\n icon: Circle,\n className: 'text-gray-900',\n};\n\nfunction getEventStyle(resource: string, isErrored: boolean): EventStyle {\n const style = eventStyles[resource] ?? defaultStyle;\n return {\n icon: style.icon,\n className: cn(isErrored ? 'text-red-900' : style.className),\n };\n}\n\nconst EventRow = ({\n span,\n isSelected,\n onSelectSpan,\n}: {\n span: Span;\n isSelected: boolean;\n onSelectSpan: (spanId: string) => void;\n}) => {\n const durationMs = getHighResInMs(span.duration);\n const isErrored =\n (span.attributes.data as Record<string, unknown>).status === 'failed';\n const { icon: Icon, className: tagClassName } = getEventStyle(\n span.resource,\n isErrored\n );\n\n return (\n <li\n className=\"overflow-clip group\"\n role=\"treeitem\"\n aria-selected={isSelected}\n aria-expanded={isSelected}\n aria-level={1}\n onClick={() => onSelectSpan(span.spanId)}\n >\n <div className=\"hover:bg-gray-100 group-aria-selected:bg-gray-100 group-aria-selected:hover:bg-gray-200 hover:aria-selected:bg-gray-100 rounded-sm px-2 h-[34px] py-1.5 flex\">\n <div className=\"flex items-center gap-2\">\n <span className={tagClassName}>\n <Icon className=\"w-4 h-4\" />\n </span>\n <span className=\"text-label-14\">{span.name}</span>\n </div>\n <div className=\"ml-auto\">\n <span className=\"text-label-14 text-gray-900 tabular-nums\">\n {formatDuration(durationMs)}\n </span>\n </div>\n </div>\n </li>\n );\n};\n\nconst EventList = ({\n spans,\n activeSpanId,\n onSelectSpan,\n}: {\n spans: Span[];\n activeSpanId: string | null;\n onSelectSpan: (spanId: string) => void;\n}) => {\n return (\n <ul\n id=\"event-list\"\n role=\"tree\"\n className=\"block min-h-0 overflow-visible px-2 py-2\"\n >\n {spans.map((span) => {\n return (\n <EventRow\n key={span.spanId}\n span={span}\n isSelected={span.spanId === activeSpanId}\n onSelectSpan={onSelectSpan}\n />\n );\n })}\n </ul>\n );\n};\n\nexport default EventList;\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export declare function Divider(): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export interface SplitPaneProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
/** Fixed pixel width for the start (left) pane. Default 220. */
|
|
7
|
+
defaultStartWidth?: number;
|
|
8
|
+
/** Fixed (non-scrolling) header rendered above the start pane. */
|
|
9
|
+
startHeader?: ReactNode;
|
|
10
|
+
/** Fixed (non-scrolling) header rendered above the end pane. */
|
|
11
|
+
endHeader?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function SplitPane({ children, className, defaultStartWidth, startHeader, endHeader, }: SplitPaneProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=split-pane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-pane.d.ts","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/split-pane.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAQf,wBAAgB,OAAO,4CAEtB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,SAAS,EACT,iBAAoC,EACpC,WAAW,EACX,SAAS,GACV,EAAE,cAAc,2CAkJhB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Children, useCallback, useEffect, useRef, useState, } from 'react';
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
5
|
+
/** Wide enough for comfortable dragging; visual line stays 1px centered. */
|
|
6
|
+
const GUTTER_PX = 9;
|
|
7
|
+
const MIN_PX = 50;
|
|
8
|
+
const DEFAULT_START_PX = 340;
|
|
9
|
+
export function Divider() {
|
|
10
|
+
return _jsx("div", { "aria-hidden": true, className: "h-full w-px shrink-0 bg-gray-alpha-400" });
|
|
11
|
+
}
|
|
12
|
+
export function SplitPane({ children, className, defaultStartWidth = DEFAULT_START_PX, startHeader, endHeader, }) {
|
|
13
|
+
const parts = Children.toArray(children);
|
|
14
|
+
if (parts.length !== 2) {
|
|
15
|
+
throw new Error('SplitPane expects exactly two children');
|
|
16
|
+
}
|
|
17
|
+
const [start, end] = parts;
|
|
18
|
+
const [startPx, setStartPx] = useState(defaultStartWidth);
|
|
19
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
20
|
+
const containerRef = useRef(null);
|
|
21
|
+
const gutterRef = useRef(null);
|
|
22
|
+
const rafRef = useRef(null);
|
|
23
|
+
const pendingPx = useRef(defaultStartWidth);
|
|
24
|
+
const pointerIdRef = useRef(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
return () => {
|
|
27
|
+
if (rafRef.current)
|
|
28
|
+
cancelAnimationFrame(rafRef.current);
|
|
29
|
+
};
|
|
30
|
+
}, []);
|
|
31
|
+
const clampPx = useCallback((px) => {
|
|
32
|
+
const el = containerRef.current;
|
|
33
|
+
if (!el)
|
|
34
|
+
return px;
|
|
35
|
+
const maxPx = el.getBoundingClientRect().width - MIN_PX - GUTTER_PX;
|
|
36
|
+
return Math.min(maxPx, Math.max(MIN_PX, px));
|
|
37
|
+
}, []);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!isDragging)
|
|
40
|
+
return;
|
|
41
|
+
const onPointerMove = (e) => {
|
|
42
|
+
if (e.pointerId !== pointerIdRef.current)
|
|
43
|
+
return;
|
|
44
|
+
const container = containerRef.current;
|
|
45
|
+
if (!container)
|
|
46
|
+
return;
|
|
47
|
+
const rect = container.getBoundingClientRect();
|
|
48
|
+
pendingPx.current = clampPx(e.clientX - rect.left);
|
|
49
|
+
if (!rafRef.current) {
|
|
50
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
51
|
+
rafRef.current = null;
|
|
52
|
+
setStartPx(pendingPx.current);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const onPointerUp = (e) => {
|
|
57
|
+
if (e.pointerId !== pointerIdRef.current)
|
|
58
|
+
return;
|
|
59
|
+
const gutter = gutterRef.current;
|
|
60
|
+
if (gutter?.hasPointerCapture(e.pointerId)) {
|
|
61
|
+
gutter.releasePointerCapture(e.pointerId);
|
|
62
|
+
}
|
|
63
|
+
if (rafRef.current) {
|
|
64
|
+
cancelAnimationFrame(rafRef.current);
|
|
65
|
+
rafRef.current = null;
|
|
66
|
+
}
|
|
67
|
+
pointerIdRef.current = null;
|
|
68
|
+
setIsDragging(false);
|
|
69
|
+
};
|
|
70
|
+
document.addEventListener('pointermove', onPointerMove);
|
|
71
|
+
document.addEventListener('pointerup', onPointerUp);
|
|
72
|
+
document.addEventListener('pointercancel', onPointerUp);
|
|
73
|
+
return () => {
|
|
74
|
+
document.removeEventListener('pointermove', onPointerMove);
|
|
75
|
+
document.removeEventListener('pointerup', onPointerUp);
|
|
76
|
+
document.removeEventListener('pointercancel', onPointerUp);
|
|
77
|
+
};
|
|
78
|
+
}, [isDragging, clampPx]);
|
|
79
|
+
const handlePointerDown = (e) => {
|
|
80
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
81
|
+
pointerIdRef.current = e.pointerId;
|
|
82
|
+
setIsDragging(true);
|
|
83
|
+
};
|
|
84
|
+
const handleLostPointerCapture = () => {
|
|
85
|
+
pointerIdRef.current = null;
|
|
86
|
+
setIsDragging(false);
|
|
87
|
+
if (rafRef.current) {
|
|
88
|
+
cancelAnimationFrame(rafRef.current);
|
|
89
|
+
rafRef.current = null;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const colTemplate = `${startPx}px ${GUTTER_PX}px minmax(${MIN_PX}px, 1fr)`;
|
|
93
|
+
const hasHeaders = startHeader != null || endHeader != null;
|
|
94
|
+
const gutter = (_jsx("div", { ref: gutterRef, className: "relative z-20 isolate flex shrink-0 cursor-col-resize justify-center", onPointerDown: handlePointerDown, onLostPointerCapture: handleLostPointerCapture, children: _jsx("span", { className: "pointer-events-none relative z-10 h-full w-px shrink-0 bg-gray-alpha-400", "aria-hidden": true }) }));
|
|
95
|
+
if (hasHeaders) {
|
|
96
|
+
return (_jsxs("div", { className: cn('flex flex-col h-full min-h-0', className), children: [_jsxs("div", { className: "shrink-0 grid", style: { gridTemplateColumns: colTemplate }, children: [_jsx("div", { children: startHeader }), _jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "h-full w-px bg-gray-alpha-400", "aria-hidden": true }) }), _jsx("div", { children: endHeader })] }), _jsxs("div", { ref: containerRef, className: cn('grid flex-1 min-h-0 content-start overflow-x-hidden overflow-y-auto', isDragging && 'select-none'), style: { gridTemplateColumns: colTemplate }, children: [start, gutter, end] })] }));
|
|
97
|
+
}
|
|
98
|
+
return (_jsxs("div", { ref: containerRef, className: cn('grid h-full min-h-0 content-start overflow-x-hidden overflow-y-auto', isDragging && 'select-none', className), style: { gridTemplateColumns: colTemplate, height: '100%' }, children: [start, gutter, end] }));
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=split-pane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-pane.js","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/split-pane.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport {\n Children,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../../../lib/utils';\n\n/** Wide enough for comfortable dragging; visual line stays 1px centered. */\nconst GUTTER_PX = 9;\nconst MIN_PX = 50;\nconst DEFAULT_START_PX = 340;\n\nexport function Divider() {\n return <div aria-hidden className=\"h-full w-px shrink-0 bg-gray-alpha-400\" />;\n}\n\nexport interface SplitPaneProps {\n children: ReactNode;\n className?: string;\n /** Fixed pixel width for the start (left) pane. Default 220. */\n defaultStartWidth?: number;\n /** Fixed (non-scrolling) header rendered above the start pane. */\n startHeader?: ReactNode;\n /** Fixed (non-scrolling) header rendered above the end pane. */\n endHeader?: ReactNode;\n}\n\nexport function SplitPane({\n children,\n className,\n defaultStartWidth = DEFAULT_START_PX,\n startHeader,\n endHeader,\n}: SplitPaneProps) {\n const parts = Children.toArray(children);\n if (parts.length !== 2) {\n throw new Error('SplitPane expects exactly two children');\n }\n const [start, end] = parts;\n\n const [startPx, setStartPx] = useState(defaultStartWidth);\n const [isDragging, setIsDragging] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const gutterRef = useRef<HTMLDivElement>(null);\n const rafRef = useRef<number | null>(null);\n const pendingPx = useRef(defaultStartWidth);\n const pointerIdRef = useRef<number | null>(null);\n\n useEffect(() => {\n return () => {\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\n };\n }, []);\n\n const clampPx = useCallback((px: number) => {\n const el = containerRef.current;\n if (!el) return px;\n const maxPx = el.getBoundingClientRect().width - MIN_PX - GUTTER_PX;\n return Math.min(maxPx, Math.max(MIN_PX, px));\n }, []);\n\n useEffect(() => {\n if (!isDragging) return;\n\n const onPointerMove = (e: globalThis.PointerEvent) => {\n if (e.pointerId !== pointerIdRef.current) return;\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n pendingPx.current = clampPx(e.clientX - rect.left);\n if (!rafRef.current) {\n rafRef.current = requestAnimationFrame(() => {\n rafRef.current = null;\n setStartPx(pendingPx.current);\n });\n }\n };\n\n const onPointerUp = (e: globalThis.PointerEvent) => {\n if (e.pointerId !== pointerIdRef.current) return;\n const gutter = gutterRef.current;\n if (gutter?.hasPointerCapture(e.pointerId)) {\n gutter.releasePointerCapture(e.pointerId);\n }\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n pointerIdRef.current = null;\n setIsDragging(false);\n };\n\n document.addEventListener('pointermove', onPointerMove);\n document.addEventListener('pointerup', onPointerUp);\n document.addEventListener('pointercancel', onPointerUp);\n\n return () => {\n document.removeEventListener('pointermove', onPointerMove);\n document.removeEventListener('pointerup', onPointerUp);\n document.removeEventListener('pointercancel', onPointerUp);\n };\n }, [isDragging, clampPx]);\n\n const handlePointerDown = (e: ReactPointerEvent<HTMLDivElement>) => {\n e.currentTarget.setPointerCapture(e.pointerId);\n pointerIdRef.current = e.pointerId;\n setIsDragging(true);\n };\n\n const handleLostPointerCapture = () => {\n pointerIdRef.current = null;\n setIsDragging(false);\n if (rafRef.current) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n };\n\n const colTemplate = `${startPx}px ${GUTTER_PX}px minmax(${MIN_PX}px, 1fr)`;\n const hasHeaders = startHeader != null || endHeader != null;\n\n const gutter = (\n <div\n ref={gutterRef}\n className=\"relative z-20 isolate flex shrink-0 cursor-col-resize justify-center\"\n onPointerDown={handlePointerDown}\n onLostPointerCapture={handleLostPointerCapture}\n >\n <span\n className=\"pointer-events-none relative z-10 h-full w-px shrink-0 bg-gray-alpha-400\"\n aria-hidden\n />\n </div>\n );\n\n if (hasHeaders) {\n return (\n <div className={cn('flex flex-col h-full min-h-0', className)}>\n <div\n className=\"shrink-0 grid\"\n style={{ gridTemplateColumns: colTemplate }}\n >\n <div>{startHeader}</div>\n <div className=\"flex justify-center\">\n <span className=\"h-full w-px bg-gray-alpha-400\" aria-hidden />\n </div>\n <div>{endHeader}</div>\n </div>\n <div\n ref={containerRef}\n className={cn(\n 'grid flex-1 min-h-0 content-start overflow-x-hidden overflow-y-auto',\n isDragging && 'select-none'\n )}\n style={{ gridTemplateColumns: colTemplate }}\n >\n {start}\n {gutter}\n {end}\n </div>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className={cn(\n 'grid h-full min-h-0 content-start overflow-x-hidden overflow-y-auto',\n isDragging && 'select-none',\n className\n )}\n style={{ gridTemplateColumns: colTemplate, height: '100%' }}\n >\n {start}\n {gutter}\n {end}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { Span } from '../../trace-viewer/types';
|
|
3
|
+
import type { TimeCompression } from '../utils';
|
|
4
|
+
declare const TimelineBar: import("react").NamedExoticComponent<{
|
|
5
|
+
span: Span;
|
|
6
|
+
compression: TimeCompression;
|
|
7
|
+
containerWidth: number;
|
|
8
|
+
isSelected: boolean;
|
|
9
|
+
onClick: () => void;
|
|
10
|
+
}>;
|
|
11
|
+
export { TimelineBar };
|
|
12
|
+
export declare function TimelineHeader({ viewStart, viewDuration, rootStart, compression, isZoomed, onResetZoom, hoverInfo, }: {
|
|
13
|
+
viewStart: number;
|
|
14
|
+
viewDuration: number;
|
|
15
|
+
rootStart: number;
|
|
16
|
+
compression: TimeCompression;
|
|
17
|
+
isZoomed: boolean;
|
|
18
|
+
onResetZoom: () => void;
|
|
19
|
+
hoverInfo?: {
|
|
20
|
+
fraction: number;
|
|
21
|
+
label: string;
|
|
22
|
+
} | null;
|
|
23
|
+
}): ReactNode;
|
|
24
|
+
export declare function Timeline({ spans, compression, selectedId, onSelect, hoverFraction, altHeld, }: {
|
|
25
|
+
spans: Span[];
|
|
26
|
+
compression: TimeCompression;
|
|
27
|
+
selectedId: string | null;
|
|
28
|
+
onSelect: (spanId: string) => void;
|
|
29
|
+
hoverFraction?: number | null;
|
|
30
|
+
altHeld?: boolean;
|
|
31
|
+
}): ReactNode;
|
|
32
|
+
//# sourceMappingURL=timeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/timeline.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,UAAU,CAAC;AAuE/D,QAAA,MAAM,WAAW;UAOT,IAAI;iBACG,eAAe;oBACZ,MAAM;gBACV,OAAO;aACV,MAAM,IAAI;EAwJnB,CAAC;AAEH,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,YAAY,EACZ,SAAS,EACT,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,GACV,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACxD,GAAG,SAAS,CAgDZ;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,aAAa,EACb,OAAe,GAChB,EAAE;IACD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,WAAW,EAAE,eAAe,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,SAAS,CAoDZ"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { cn } from '../../../lib/utils';
|
|
5
|
+
import { formatDuration, getHighResInMs } from '../../trace-viewer/util/timing';
|
|
6
|
+
import { computeCompressedTimeMarkers, computeSpanGaps, computeSpanSegments, computeTimeMarkers, getResourceColor, } from '../utils';
|
|
7
|
+
const QUEUED_BACKGROUND = 'radial-gradient(circle, var(--ds-gray-400) 2px, transparent 2px) center / 20px 20px space no-repeat, var(--ds-gray-500)';
|
|
8
|
+
const HATCHED_BACKGROUND = 'repeating-linear-gradient(-45deg, var(--ds-gray-400) 0px, var(--ds-gray-400) 3px, var(--ds-gray-500) 3px, var(--ds-gray-500) 6px)';
|
|
9
|
+
const SEGMENT_CONFIG = {
|
|
10
|
+
queued: { style: { background: QUEUED_BACKGROUND } },
|
|
11
|
+
retrying: {
|
|
12
|
+
className: 'box-border bg-gray-500',
|
|
13
|
+
},
|
|
14
|
+
waiting: { style: { background: HATCHED_BACKGROUND } },
|
|
15
|
+
running: { className: 'bg-blue-700' },
|
|
16
|
+
failed: { className: 'bg-red-700' },
|
|
17
|
+
succeeded: { className: 'bg-green-700' },
|
|
18
|
+
sleeping: { className: 'bg-amber-700' },
|
|
19
|
+
received: { className: 'bg-blue-700' },
|
|
20
|
+
};
|
|
21
|
+
const FIXED_BAR_WIDTH_PX = 4;
|
|
22
|
+
const SEGMENT_GAP_PX = 1;
|
|
23
|
+
// Keep this in sync with the rendered row height in the timeline/event list.
|
|
24
|
+
const ROW_HEIGHT = 34;
|
|
25
|
+
const CONTAINER_PAD_Y = 8;
|
|
26
|
+
const END_CAP_HEIGHT = 8;
|
|
27
|
+
const DeltaIndicator = memo(function DeltaIndicator({ leftFrac, rightFrac, label, rowIndex, }) {
|
|
28
|
+
const centerY = CONTAINER_PAD_Y + (rowIndex + 1) * ROW_HEIGHT;
|
|
29
|
+
return (_jsxs("div", { className: "absolute pointer-events-none", style: {
|
|
30
|
+
left: `${leftFrac * 100}%`,
|
|
31
|
+
width: `${(rightFrac - leftFrac) * 100}%`,
|
|
32
|
+
top: centerY - END_CAP_HEIGHT / 2,
|
|
33
|
+
height: END_CAP_HEIGHT,
|
|
34
|
+
}, children: [_jsx("div", { className: "absolute left-0 top-0 w-px h-full bg-amber-800" }), _jsx("div", { className: "absolute left-0 right-0 top-1/2 h-px bg-amber-800" }), _jsx("div", { className: "absolute right-0 top-0 w-px h-full bg-amber-800" }), _jsx("span", { className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-label-12 leading-none whitespace-nowrap rounded-xs px-1 py-0.5 text-gray-100 bg-amber-800", children: label })] }));
|
|
35
|
+
});
|
|
36
|
+
const TimelineBar = memo(function TimelineBar({ span, compression, containerWidth, isSelected, onClick, }) {
|
|
37
|
+
const startTime = getHighResInMs(span.startTime);
|
|
38
|
+
const endTime = getHighResInMs(span.endTime);
|
|
39
|
+
const totalDurationMs = endTime - startTime;
|
|
40
|
+
const leftFrac = compression.toVisual(startTime);
|
|
41
|
+
const rightFrac = compression.toVisual(endTime);
|
|
42
|
+
const widthFrac = rightFrac - leftFrac;
|
|
43
|
+
const leftPct = leftFrac * 100;
|
|
44
|
+
const widthPct = widthFrac * 100;
|
|
45
|
+
const pixelWidth = widthFrac * containerWidth;
|
|
46
|
+
const isCompressed = containerWidth > 0 && pixelWidth < FIXED_BAR_WIDTH_PX;
|
|
47
|
+
const [isRowHovered, setIsRowHovered] = useState(false);
|
|
48
|
+
const segments = useMemo(() => computeSpanSegments(span), [span]);
|
|
49
|
+
const finalSegment = segments[segments.length - 1];
|
|
50
|
+
const workflowStatus = span.attributes.data
|
|
51
|
+
?.status;
|
|
52
|
+
const isErrored = span.status.code === 2 || workflowStatus === 'failed';
|
|
53
|
+
const colors = getResourceColor(span.resource);
|
|
54
|
+
const fallbackColor = isErrored
|
|
55
|
+
? (colors.errorBar ?? 'var(--ds-red-700)')
|
|
56
|
+
: colors.bar;
|
|
57
|
+
const compressedSegmentStatus = isErrored
|
|
58
|
+
? 'failed'
|
|
59
|
+
: span.resource === 'hook'
|
|
60
|
+
? 'received'
|
|
61
|
+
: finalSegment?.status;
|
|
62
|
+
const compressedSegmentStyle = compressedSegmentStatus === 'queued'
|
|
63
|
+
? { background: 'var(--ds-gray-500)' }
|
|
64
|
+
: compressedSegmentStatus
|
|
65
|
+
? SEGMENT_CONFIG[compressedSegmentStatus].style
|
|
66
|
+
: undefined;
|
|
67
|
+
const compressedSegmentClassName = compressedSegmentStatus
|
|
68
|
+
? SEGMENT_CONFIG[compressedSegmentStatus].className
|
|
69
|
+
: undefined;
|
|
70
|
+
const hasCompressedStatus = Boolean(compressedSegmentClassName || compressedSegmentStyle);
|
|
71
|
+
const renderDurationLabel = (label) => (_jsx("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-start overflow-hidden px-1 text-[10px] font-mono font-medium leading-none whitespace-nowrap text-left text-white tabular-nums", style: { textShadow: '0 1px 1px rgba(0, 0, 0, 0.45)' }, children: label }));
|
|
72
|
+
const getMinDurationLabelWidthPx = (label) => Math.max(40, label.length * 6 + 12);
|
|
73
|
+
const totalDurationLabel = formatDuration(totalDurationMs);
|
|
74
|
+
const showBarDurationLabel = isRowHovered &&
|
|
75
|
+
pixelWidth >= getMinDurationLabelWidthPx(totalDurationLabel);
|
|
76
|
+
const barContent = isCompressed ? (_jsx("div", { className: cn('relative h-4 rounded-[0.25rem] top-[3px]', compressedSegmentClassName), style: {
|
|
77
|
+
width: '100%',
|
|
78
|
+
background: hasCompressedStatus ? undefined : fallbackColor,
|
|
79
|
+
...compressedSegmentStyle,
|
|
80
|
+
}, children: showBarDurationLabel ? renderDurationLabel(totalDurationLabel) : null })) : segments.length > 0 ? (_jsx("div", { className: "relative w-full h-4 top-[3px]", children: segments.map((seg, i) => {
|
|
81
|
+
const segPixelWidth = (seg.endFraction - seg.startFraction) * pixelWidth;
|
|
82
|
+
const segDurationLabel = formatDuration((seg.endFraction - seg.startFraction) * totalDurationMs);
|
|
83
|
+
const showSegmentDurationLabel = isRowHovered &&
|
|
84
|
+
segPixelWidth >= getMinDurationLabelWidthPx(segDurationLabel);
|
|
85
|
+
const segStyle = seg.status === 'queued' && segPixelWidth < 20
|
|
86
|
+
? { background: 'var(--ds-gray-500)' }
|
|
87
|
+
: SEGMENT_CONFIG[seg.status].style;
|
|
88
|
+
return (_jsx("div", { className: cn('absolute h-full rounded-[0.25rem]', SEGMENT_CONFIG[seg.status].className), style: {
|
|
89
|
+
left: `calc(${seg.startFraction * 100}% + ${SEGMENT_GAP_PX / 2}px)`,
|
|
90
|
+
width: `calc(${(seg.endFraction - seg.startFraction) * 100}% - ${SEGMENT_GAP_PX}px)`,
|
|
91
|
+
minWidth: 1,
|
|
92
|
+
...segStyle,
|
|
93
|
+
}, children: showSegmentDurationLabel
|
|
94
|
+
? renderDurationLabel(segDurationLabel)
|
|
95
|
+
: null }, `${seg.status}-${i}`));
|
|
96
|
+
}) })) : (_jsx("div", { className: "relative h-4 rounded-[0.25rem] top-[3px]", style: {
|
|
97
|
+
width: '100%',
|
|
98
|
+
minWidth: 4,
|
|
99
|
+
background: fallbackColor,
|
|
100
|
+
}, children: showBarDurationLabel ? renderDurationLabel(totalDurationLabel) : null }));
|
|
101
|
+
return (_jsx("div", { role: "treeitem", "aria-selected": isSelected, "aria-expanded": isSelected, "aria-level": 1, className: cn('h-[34px] relative flex items-center hover:bg-gray-100 aria-selected:bg-gray-100 rounded-sm aria-selected:hover:bg-gray-200'), onMouseEnter: () => setIsRowHovered(true), onMouseLeave: () => setIsRowHovered(false), onClick: onClick, children: _jsx("div", { className: "absolute top-1.5 h-[22px] rounded-sm", style: {
|
|
102
|
+
left: isCompressed
|
|
103
|
+
? `min(${leftPct}%, calc(100% - ${FIXED_BAR_WIDTH_PX}px))`
|
|
104
|
+
: `${leftPct}%`,
|
|
105
|
+
width: isCompressed
|
|
106
|
+
? `${FIXED_BAR_WIDTH_PX}px`
|
|
107
|
+
: `max(${widthPct}%, 4px)`,
|
|
108
|
+
}, children: barContent }) }));
|
|
109
|
+
});
|
|
110
|
+
export { TimelineBar };
|
|
111
|
+
export function TimelineHeader({ viewStart, viewDuration, rootStart, compression, isZoomed, onResetZoom, hoverInfo, }) {
|
|
112
|
+
const viewEnd = viewStart + viewDuration;
|
|
113
|
+
const markers = useMemo(() => compression.isCompressed
|
|
114
|
+
? computeCompressedTimeMarkers(compression, viewStart, viewEnd, rootStart)
|
|
115
|
+
: computeTimeMarkers(viewDuration, viewStart - rootStart), [compression, viewStart, viewEnd, viewDuration, rootStart]);
|
|
116
|
+
return (_jsxs("div", { className: "relative bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-end px-2 pb-1", children: [_jsxs("div", { className: "relative h-full flex-1", children: [markers.map((m, i) => (_jsx("span", { className: "absolute bottom-1 font-mono text-xs font-normal leading-4 text-gray-900 whitespace-nowrap", style: { left: `${m.position * 100}%` }, children: m.label }, i))), hoverInfo && (_jsx("span", { className: "absolute top-1 pointer-events-none z-10 font-mono text-[11px] leading-4 text-gray-1000 whitespace-nowrap bg-background-100 border border-gray-alpha-400 rounded px-1 -translate-x-1/2", style: { left: `${hoverInfo.fraction * 100}%` }, children: hoverInfo.label }))] }), isZoomed && (_jsx("button", { type: "button", className: "absolute right-2 top-1/2 -translate-y-1/2 z-[5] flex items-center py-0.5 px-2 border border-gray-alpha-400 rounded-md bg-background-100 font-sans text-[11px] font-medium text-gray-900 cursor-pointer whitespace-nowrap transition-[color,border-color] duration-[120ms] ease-in-out hover:text-gray-1000 hover:border-gray-600", onClick: onResetZoom, children: "Reset zoom" }))] }));
|
|
117
|
+
}
|
|
118
|
+
export function Timeline({ spans, compression, selectedId, onSelect, hoverFraction, altHeld = false, }) {
|
|
119
|
+
const containerRef = useRef(null);
|
|
120
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const el = containerRef.current;
|
|
123
|
+
if (!el)
|
|
124
|
+
return;
|
|
125
|
+
const ro = new ResizeObserver(([entry]) => {
|
|
126
|
+
setContainerWidth(entry.contentRect.width);
|
|
127
|
+
});
|
|
128
|
+
ro.observe(el);
|
|
129
|
+
return () => ro.disconnect();
|
|
130
|
+
}, []);
|
|
131
|
+
const gaps = useMemo(() => computeSpanGaps(spans, compression), [spans, compression]);
|
|
132
|
+
return (_jsxs("div", { ref: containerRef, className: "relative py-2", children: [hoverFraction != null && (_jsx("div", { className: "absolute top-0 bottom-0 w-px bg-gray-alpha-400 pointer-events-none z-10", style: { left: `${hoverFraction * 100}%` } })), spans.map((span) => (_jsx(TimelineBar, { span: span, compression: compression, containerWidth: containerWidth, isSelected: selectedId === span.spanId, onClick: () => onSelect(span.spanId) }, span.spanId))), altHeld && (_jsx("div", { "aria-hidden": true, className: "absolute inset-0 pointer-events-none", children: gaps.map((gap) => (_jsx(DeltaIndicator, { leftFrac: gap.leftFrac, rightFrac: gap.rightFrac, label: formatDuration(gap.gapMs, true), rowIndex: gap.rowIndex }, gap.rowIndex))) }))] }));
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/components/timeline.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhF,OAAO,EACL,4BAA4B,EAC5B,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAElB,MAAM,iBAAiB,GACrB,yHAAyH,CAAC;AAE5H,MAAM,kBAAkB,GACtB,mIAAmI,CAAC;AAEtI,MAAM,cAAc,GAGhB;IACF,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,EAAE;IACpD,QAAQ,EAAE;QACR,SAAS,EAAE,wBAAwB;KACpC;IACD,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,kBAAkB,EAAE,EAAE;IACtD,OAAO,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE;IACrC,MAAM,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE;IACnC,SAAS,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE;IACxC,QAAQ,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE;IACvC,QAAQ,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE;CACvC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,6EAA6E;AAC7E,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,cAAc,CAAC,EAClD,QAAQ,EACR,SAAS,EACT,KAAK,EACL,QAAQ,GAMT;IACC,MAAM,OAAO,GAAG,eAAe,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC;IAE9D,OAAO,CACL,eACE,SAAS,EAAC,8BAA8B,EACxC,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG;YAC1B,KAAK,EAAE,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC,GAAG,GAAG,GAAG;YACzC,GAAG,EAAE,OAAO,GAAG,cAAc,GAAG,CAAC;YACjC,MAAM,EAAE,cAAc;SACvB,aAED,cAAK,SAAS,EAAC,gDAAgD,GAAG,EAClE,cAAK,SAAS,EAAC,mDAAmD,GAAG,EACrE,cAAK,SAAS,EAAC,iDAAiD,GAAG,EACnE,eAAM,SAAS,EAAC,4JAA4J,YACzK,KAAK,GACD,IACH,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,WAAW,CAAC,EAC5C,IAAI,EACJ,WAAW,EACX,cAAc,EACd,UAAU,EACV,OAAO,GAOR;IACC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,CAAC;IAE5C,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IAEvC,MAAM,OAAO,GAAG,QAAQ,GAAG,GAAG,CAAC;IAC/B,MAAM,QAAQ,GAAG,SAAS,GAAG,GAAG,CAAC;IAEjC,MAAM,UAAU,GAAG,SAAS,GAAG,cAAc,CAAC;IAC9C,MAAM,YAAY,GAAG,cAAc,GAAG,CAAC,IAAI,UAAU,GAAG,kBAAkB,CAAC;IAC3E,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAEnD,MAAM,cAAc,GAAI,IAAI,CAAC,UAAU,CAAC,IAAgC;QACtE,EAAE,MAA4B,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,cAAc,KAAK,QAAQ,CAAC;IACxE,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,aAAa,GAAG,SAAS;QAC7B,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,mBAAmB,CAAC;QAC1C,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IACf,MAAM,uBAAuB,GAAG,SAAS;QACvC,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM;YACxB,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,YAAY,EAAE,MAAM,CAAC;IAC3B,MAAM,sBAAsB,GAC1B,uBAAuB,KAAK,QAAQ;QAClC,CAAC,CAAC,EAAE,UAAU,EAAE,oBAAoB,EAAE;QACtC,CAAC,CAAC,uBAAuB;YACvB,CAAC,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC,KAAK;YAC/C,CAAC,CAAC,SAAS,CAAC;IAClB,MAAM,0BAA0B,GAAG,uBAAuB;QACxD,CAAC,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC,SAAS;QACnD,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,mBAAmB,GAAG,OAAO,CACjC,0BAA0B,IAAI,sBAAsB,CACrD,CAAC;IACF,MAAM,mBAAmB,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAC7C,eACE,SAAS,EAAC,8LAA8L,EACxM,KAAK,EAAE,EAAE,UAAU,EAAE,+BAA+B,EAAE,YAErD,KAAK,GACD,CACR,CAAC;IACF,MAAM,0BAA0B,GAAG,CAAC,KAAa,EAAE,EAAE,CACnD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,kBAAkB,GAAG,cAAc,CAAC,eAAe,CAAC,CAAC;IAC3D,MAAM,oBAAoB,GACxB,YAAY;QACZ,UAAU,IAAI,0BAA0B,CAAC,kBAAkB,CAAC,CAAC;IAE/D,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,CAChC,cACE,SAAS,EAAE,EAAE,CACX,0CAA0C,EAC1C,0BAA0B,CAC3B,EACD,KAAK,EAAE;YACL,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa;YAC3D,GAAG,sBAAsB;SAC1B,YAEA,oBAAoB,CAAC,CAAC,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,GAClE,CACP,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACxB,cAAK,SAAS,EAAC,+BAA+B,YAC3C,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YACvB,MAAM,aAAa,GACjB,CAAC,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,UAAU,CAAC;YACrD,MAAM,gBAAgB,GAAG,cAAc,CACrC,CAAC,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,eAAe,CACxD,CAAC;YACF,MAAM,wBAAwB,GAC5B,YAAY;gBACZ,aAAa,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,CAAC;YAChE,MAAM,QAAQ,GACZ,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,aAAa,GAAG,EAAE;gBAC3C,CAAC,CAAC,EAAE,UAAU,EAAE,oBAAoB,EAAE;gBACtC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;YAEvC,OAAO,CACL,cAEE,SAAS,EAAE,EAAE,CACX,mCAAmC,EACnC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,SAAS,CACrC,EACD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ,GAAG,CAAC,aAAa,GAAG,GAAG,OAAO,cAAc,GAAG,CAAC,KAAK;oBACnE,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,GAAG,OAAO,cAAc,KAAK;oBACpF,QAAQ,EAAE,CAAC;oBACX,GAAG,QAAQ;iBACZ,YAEA,wBAAwB;oBACvB,CAAC,CAAC,mBAAmB,CAAC,gBAAgB,CAAC;oBACvC,CAAC,CAAC,IAAI,IAdH,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAerB,CACP,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC,CAAC,CAAC,CACF,cACE,SAAS,EAAC,0CAA0C,EACpD,KAAK,EAAE;YACL,KAAK,EAAE,MAAM;YACb,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,aAAa;SAC1B,YAEA,oBAAoB,CAAC,CAAC,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,GAClE,CACP,CAAC;IAEF,OAAO,CACL,cACE,IAAI,EAAC,UAAU,mBACA,UAAU,mBACV,UAAU,gBACb,CAAC,EACb,SAAS,EAAE,EAAE,CACX,4HAA4H,CAC7H,EACD,YAAY,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,EACzC,YAAY,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,EAC1C,OAAO,EAAE,OAAO,YAEhB,cACE,SAAS,EAAC,sCAAsC,EAChD,KAAK,EAAE;gBACL,IAAI,EAAE,YAAY;oBAChB,CAAC,CAAC,OAAO,OAAO,kBAAkB,kBAAkB,MAAM;oBAC1D,CAAC,CAAC,GAAG,OAAO,GAAG;gBACjB,KAAK,EAAE,YAAY;oBACjB,CAAC,CAAC,GAAG,kBAAkB,IAAI;oBAC3B,CAAC,CAAC,OAAO,QAAQ,SAAS;aAC7B,YAEA,UAAU,GACP,GACF,CACP,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,MAAM,UAAU,cAAc,CAAC,EAC7B,SAAS,EACT,YAAY,EACZ,SAAS,EACT,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,GASV;IACC,MAAM,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;IAEzC,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CACH,WAAW,CAAC,YAAY;QACtB,CAAC,CAAC,4BAA4B,CAC1B,WAAW,EACX,SAAS,EACT,OAAO,EACP,SAAS,CACV;QACH,CAAC,CAAC,kBAAkB,CAAC,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC,EAC7D,CAAC,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,CAAC,CAC3D,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,kGAAkG,aAC/G,eAAK,SAAS,EAAC,wBAAwB,aACpC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACrB,eAEE,SAAS,EAAC,2FAA2F,EACrG,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,QAAQ,GAAG,GAAG,GAAG,EAAE,YAEtC,CAAC,CAAC,KAAK,IAJH,CAAC,CAKD,CACR,CAAC,EACD,SAAS,IAAI,CACZ,eACE,SAAS,EAAC,uLAAuL,EACjM,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,QAAQ,GAAG,GAAG,GAAG,EAAE,YAE9C,SAAS,CAAC,KAAK,GACX,CACR,IACG,EACL,QAAQ,IAAI,CACX,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kUAAkU,EAC5U,OAAO,EAAE,WAAW,2BAGb,CACV,IACG,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,aAAa,EACb,OAAO,GAAG,KAAK,GAQhB;IACC,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC;QAChC,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,MAAM,EAAE,GAAG,IAAI,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE;YACxC,iBAAiB,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,EACzC,CAAC,KAAK,EAAE,WAAW,CAAC,CACrB,CAAC;IAEF,OAAO,CACL,eAAK,GAAG,EAAE,YAAY,EAAE,SAAS,EAAC,eAAe,aAC9C,aAAa,IAAI,IAAI,IAAI,CACxB,cACE,SAAS,EAAC,yEAAyE,EACnF,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,aAAa,GAAG,GAAG,GAAG,EAAE,GAC1C,CACH,EACA,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,WAAW,IAEV,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC,MAAM,EACtC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAL/B,IAAI,CAAC,MAAM,CAMhB,CACH,CAAC,EACD,OAAO,IAAI,CACV,mCAAiB,SAAS,EAAC,sCAAsC,YAC9D,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,KAAC,cAAc,IAEb,QAAQ,EAAE,GAAG,CAAC,QAAQ,EACtB,SAAS,EAAE,GAAG,CAAC,SAAS,EACxB,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,EACtC,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAJjB,GAAG,CAAC,QAAQ,CAKjB,CACH,CAAC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport type { ReactNode } from 'react';\nimport { memo, useEffect, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../../lib/utils';\nimport type { Span } from '../../trace-viewer/types';\nimport { formatDuration, getHighResInMs } from '../../trace-viewer/util/timing';\nimport type { SegmentStatus, TimeCompression } from '../utils';\nimport {\n computeCompressedTimeMarkers,\n computeSpanGaps,\n computeSpanSegments,\n computeTimeMarkers,\n getResourceColor,\n} from '../utils';\n\nconst QUEUED_BACKGROUND =\n 'radial-gradient(circle, var(--ds-gray-400) 2px, transparent 2px) center / 20px 20px space no-repeat, var(--ds-gray-500)';\n\nconst HATCHED_BACKGROUND =\n 'repeating-linear-gradient(-45deg, var(--ds-gray-400) 0px, var(--ds-gray-400) 3px, var(--ds-gray-500) 3px, var(--ds-gray-500) 6px)';\n\nconst SEGMENT_CONFIG: Record<\n SegmentStatus,\n { className?: string; style?: React.CSSProperties }\n> = {\n queued: { style: { background: QUEUED_BACKGROUND } },\n retrying: {\n className: 'box-border bg-gray-500',\n },\n waiting: { style: { background: HATCHED_BACKGROUND } },\n running: { className: 'bg-blue-700' },\n failed: { className: 'bg-red-700' },\n succeeded: { className: 'bg-green-700' },\n sleeping: { className: 'bg-amber-700' },\n received: { className: 'bg-blue-700' },\n};\n\nconst FIXED_BAR_WIDTH_PX = 4;\nconst SEGMENT_GAP_PX = 1;\n// Keep this in sync with the rendered row height in the timeline/event list.\nconst ROW_HEIGHT = 34;\nconst CONTAINER_PAD_Y = 8;\nconst END_CAP_HEIGHT = 8;\n\nconst DeltaIndicator = memo(function DeltaIndicator({\n leftFrac,\n rightFrac,\n label,\n rowIndex,\n}: {\n leftFrac: number;\n rightFrac: number;\n label: string;\n rowIndex: number;\n}) {\n const centerY = CONTAINER_PAD_Y + (rowIndex + 1) * ROW_HEIGHT;\n\n return (\n <div\n className=\"absolute pointer-events-none\"\n style={{\n left: `${leftFrac * 100}%`,\n width: `${(rightFrac - leftFrac) * 100}%`,\n top: centerY - END_CAP_HEIGHT / 2,\n height: END_CAP_HEIGHT,\n }}\n >\n <div className=\"absolute left-0 top-0 w-px h-full bg-amber-800\" />\n <div className=\"absolute left-0 right-0 top-1/2 h-px bg-amber-800\" />\n <div className=\"absolute right-0 top-0 w-px h-full bg-amber-800\" />\n <span className=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-label-12 leading-none whitespace-nowrap rounded-xs px-1 py-0.5 text-gray-100 bg-amber-800\">\n {label}\n </span>\n </div>\n );\n});\n\nconst TimelineBar = memo(function TimelineBar({\n span,\n compression,\n containerWidth,\n isSelected,\n onClick,\n}: {\n span: Span;\n compression: TimeCompression;\n containerWidth: number;\n isSelected: boolean;\n onClick: () => void;\n}): ReactNode {\n const startTime = getHighResInMs(span.startTime);\n const endTime = getHighResInMs(span.endTime);\n const totalDurationMs = endTime - startTime;\n\n const leftFrac = compression.toVisual(startTime);\n const rightFrac = compression.toVisual(endTime);\n const widthFrac = rightFrac - leftFrac;\n\n const leftPct = leftFrac * 100;\n const widthPct = widthFrac * 100;\n\n const pixelWidth = widthFrac * containerWidth;\n const isCompressed = containerWidth > 0 && pixelWidth < FIXED_BAR_WIDTH_PX;\n const [isRowHovered, setIsRowHovered] = useState(false);\n\n const segments = useMemo(() => computeSpanSegments(span), [span]);\n const finalSegment = segments[segments.length - 1];\n\n const workflowStatus = (span.attributes.data as Record<string, unknown>)\n ?.status as string | undefined;\n const isErrored = span.status.code === 2 || workflowStatus === 'failed';\n const colors = getResourceColor(span.resource);\n const fallbackColor = isErrored\n ? (colors.errorBar ?? 'var(--ds-red-700)')\n : colors.bar;\n const compressedSegmentStatus = isErrored\n ? 'failed'\n : span.resource === 'hook'\n ? 'received'\n : finalSegment?.status;\n const compressedSegmentStyle =\n compressedSegmentStatus === 'queued'\n ? { background: 'var(--ds-gray-500)' }\n : compressedSegmentStatus\n ? SEGMENT_CONFIG[compressedSegmentStatus].style\n : undefined;\n const compressedSegmentClassName = compressedSegmentStatus\n ? SEGMENT_CONFIG[compressedSegmentStatus].className\n : undefined;\n\n const hasCompressedStatus = Boolean(\n compressedSegmentClassName || compressedSegmentStyle\n );\n const renderDurationLabel = (label: string) => (\n <span\n className=\"pointer-events-none absolute inset-0 flex items-center justify-start overflow-hidden px-1 text-[10px] font-mono font-medium leading-none whitespace-nowrap text-left text-white tabular-nums\"\n style={{ textShadow: '0 1px 1px rgba(0, 0, 0, 0.45)' }}\n >\n {label}\n </span>\n );\n const getMinDurationLabelWidthPx = (label: string) =>\n Math.max(40, label.length * 6 + 12);\n const totalDurationLabel = formatDuration(totalDurationMs);\n const showBarDurationLabel =\n isRowHovered &&\n pixelWidth >= getMinDurationLabelWidthPx(totalDurationLabel);\n\n const barContent = isCompressed ? (\n <div\n className={cn(\n 'relative h-4 rounded-[0.25rem] top-[3px]',\n compressedSegmentClassName\n )}\n style={{\n width: '100%',\n background: hasCompressedStatus ? undefined : fallbackColor,\n ...compressedSegmentStyle,\n }}\n >\n {showBarDurationLabel ? renderDurationLabel(totalDurationLabel) : null}\n </div>\n ) : segments.length > 0 ? (\n <div className=\"relative w-full h-4 top-[3px]\">\n {segments.map((seg, i) => {\n const segPixelWidth =\n (seg.endFraction - seg.startFraction) * pixelWidth;\n const segDurationLabel = formatDuration(\n (seg.endFraction - seg.startFraction) * totalDurationMs\n );\n const showSegmentDurationLabel =\n isRowHovered &&\n segPixelWidth >= getMinDurationLabelWidthPx(segDurationLabel);\n const segStyle =\n seg.status === 'queued' && segPixelWidth < 20\n ? { background: 'var(--ds-gray-500)' }\n : SEGMENT_CONFIG[seg.status].style;\n\n return (\n <div\n key={`${seg.status}-${i}`}\n className={cn(\n 'absolute h-full rounded-[0.25rem]',\n SEGMENT_CONFIG[seg.status].className\n )}\n style={{\n left: `calc(${seg.startFraction * 100}% + ${SEGMENT_GAP_PX / 2}px)`,\n width: `calc(${(seg.endFraction - seg.startFraction) * 100}% - ${SEGMENT_GAP_PX}px)`,\n minWidth: 1,\n ...segStyle,\n }}\n >\n {showSegmentDurationLabel\n ? renderDurationLabel(segDurationLabel)\n : null}\n </div>\n );\n })}\n </div>\n ) : (\n <div\n className=\"relative h-4 rounded-[0.25rem] top-[3px]\"\n style={{\n width: '100%',\n minWidth: 4,\n background: fallbackColor,\n }}\n >\n {showBarDurationLabel ? renderDurationLabel(totalDurationLabel) : null}\n </div>\n );\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={isSelected}\n aria-expanded={isSelected}\n aria-level={1}\n className={cn(\n 'h-[34px] relative flex items-center hover:bg-gray-100 aria-selected:bg-gray-100 rounded-sm aria-selected:hover:bg-gray-200'\n )}\n onMouseEnter={() => setIsRowHovered(true)}\n onMouseLeave={() => setIsRowHovered(false)}\n onClick={onClick}\n >\n <div\n className=\"absolute top-1.5 h-[22px] rounded-sm\"\n style={{\n left: isCompressed\n ? `min(${leftPct}%, calc(100% - ${FIXED_BAR_WIDTH_PX}px))`\n : `${leftPct}%`,\n width: isCompressed\n ? `${FIXED_BAR_WIDTH_PX}px`\n : `max(${widthPct}%, 4px)`,\n }}\n >\n {barContent}\n </div>\n </div>\n );\n});\n\nexport { TimelineBar };\n\nexport function TimelineHeader({\n viewStart,\n viewDuration,\n rootStart,\n compression,\n isZoomed,\n onResetZoom,\n hoverInfo,\n}: {\n viewStart: number;\n viewDuration: number;\n rootStart: number;\n compression: TimeCompression;\n isZoomed: boolean;\n onResetZoom: () => void;\n hoverInfo?: { fraction: number; label: string } | null;\n}): ReactNode {\n const viewEnd = viewStart + viewDuration;\n\n const markers = useMemo(\n () =>\n compression.isCompressed\n ? computeCompressedTimeMarkers(\n compression,\n viewStart,\n viewEnd,\n rootStart\n )\n : computeTimeMarkers(viewDuration, viewStart - rootStart),\n [compression, viewStart, viewEnd, viewDuration, rootStart]\n );\n\n return (\n <div className=\"relative bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-end px-2 pb-1\">\n <div className=\"relative h-full flex-1\">\n {markers.map((m, i) => (\n <span\n key={i}\n className=\"absolute bottom-1 font-mono text-xs font-normal leading-4 text-gray-900 whitespace-nowrap\"\n style={{ left: `${m.position * 100}%` }}\n >\n {m.label}\n </span>\n ))}\n {hoverInfo && (\n <span\n className=\"absolute top-1 pointer-events-none z-10 font-mono text-[11px] leading-4 text-gray-1000 whitespace-nowrap bg-background-100 border border-gray-alpha-400 rounded px-1 -translate-x-1/2\"\n style={{ left: `${hoverInfo.fraction * 100}%` }}\n >\n {hoverInfo.label}\n </span>\n )}\n </div>\n {isZoomed && (\n <button\n type=\"button\"\n className=\"absolute right-2 top-1/2 -translate-y-1/2 z-[5] flex items-center py-0.5 px-2 border border-gray-alpha-400 rounded-md bg-background-100 font-sans text-[11px] font-medium text-gray-900 cursor-pointer whitespace-nowrap transition-[color,border-color] duration-[120ms] ease-in-out hover:text-gray-1000 hover:border-gray-600\"\n onClick={onResetZoom}\n >\n Reset zoom\n </button>\n )}\n </div>\n );\n}\n\nexport function Timeline({\n spans,\n compression,\n selectedId,\n onSelect,\n hoverFraction,\n altHeld = false,\n}: {\n spans: Span[];\n compression: TimeCompression;\n selectedId: string | null;\n onSelect: (spanId: string) => void;\n hoverFraction?: number | null;\n altHeld?: boolean;\n}): ReactNode {\n const containerRef = useRef<HTMLDivElement>(null);\n const [containerWidth, setContainerWidth] = useState(0);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const ro = new ResizeObserver(([entry]) => {\n setContainerWidth(entry.contentRect.width);\n });\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const gaps = useMemo(\n () => computeSpanGaps(spans, compression),\n [spans, compression]\n );\n\n return (\n <div ref={containerRef} className=\"relative py-2\">\n {hoverFraction != null && (\n <div\n className=\"absolute top-0 bottom-0 w-px bg-gray-alpha-400 pointer-events-none z-10\"\n style={{ left: `${hoverFraction * 100}%` }}\n />\n )}\n {spans.map((span) => (\n <TimelineBar\n key={span.spanId}\n span={span}\n compression={compression}\n containerWidth={containerWidth}\n isSelected={selectedId === span.spanId}\n onClick={() => onSelect(span.spanId)}\n />\n ))}\n {altHeld && (\n <div aria-hidden className=\"absolute inset-0 pointer-events-none\">\n {gaps.map((gap) => (\n <DeltaIndicator\n key={gap.rowIndex}\n leftFrac={gap.leftFrac}\n rightFrac={gap.rightFrac}\n label={formatDuration(gap.gapMs, true)}\n rowIndex={gap.rowIndex}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { Span } from '../trace-viewer/types';
|
|
3
|
+
interface ActiveSpanContextValue {
|
|
4
|
+
activeSpanId: string | null;
|
|
5
|
+
activeSpan: Span | null;
|
|
6
|
+
setActiveSpan: (spanId: string) => void;
|
|
7
|
+
clearActiveSpan: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function ActiveSpanProvider({ spans, children, }: {
|
|
10
|
+
spans: Span[];
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare const useActiveSpan: () => ActiveSpanContextValue;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/components/new-trace-viewer/context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,UAAU,sBAAsB;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAKD,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAuDA;AAED,eAAO,MAAM,aAAa,QAAO,sBAOhC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
|
|
4
|
+
const ActiveSpanContext = createContext(null);
|
|
5
|
+
ActiveSpanContext.displayName = 'ActiveSpanContext';
|
|
6
|
+
export function ActiveSpanProvider({ spans, children, }) {
|
|
7
|
+
const [activeSpanId, setActiveSpanId] = useState(spans[0]?.spanId ?? null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setActiveSpanId((currentSpanId) => {
|
|
10
|
+
if (spans.length === 0) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
if (currentSpanId) {
|
|
14
|
+
const hasCurrentSpan = spans.some((span) => span.spanId === currentSpanId);
|
|
15
|
+
if (hasCurrentSpan) {
|
|
16
|
+
return currentSpanId;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return spans[0].spanId;
|
|
20
|
+
});
|
|
21
|
+
}, [spans]);
|
|
22
|
+
const activeSpan = useMemo(() => {
|
|
23
|
+
if (!activeSpanId) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return spans.find((span) => span.spanId === activeSpanId) ?? null;
|
|
27
|
+
}, [activeSpanId, spans]);
|
|
28
|
+
const setActiveSpan = useCallback((spanId) => {
|
|
29
|
+
setActiveSpanId(spanId);
|
|
30
|
+
}, []);
|
|
31
|
+
const clearActiveSpan = useCallback(() => {
|
|
32
|
+
setActiveSpanId(null);
|
|
33
|
+
}, []);
|
|
34
|
+
const value = useMemo(() => ({
|
|
35
|
+
activeSpanId,
|
|
36
|
+
activeSpan,
|
|
37
|
+
setActiveSpan,
|
|
38
|
+
clearActiveSpan,
|
|
39
|
+
}), [activeSpanId, activeSpan, setActiveSpan, clearActiveSpan]);
|
|
40
|
+
return (_jsx(ActiveSpanContext.Provider, { value: value, children: children }));
|
|
41
|
+
}
|
|
42
|
+
export const useActiveSpan = () => {
|
|
43
|
+
const context = useContext(ActiveSpanContext);
|
|
44
|
+
if (!context) {
|
|
45
|
+
throw new Error('useActiveSpan must be used within ActiveSpanProvider');
|
|
46
|
+
}
|
|
47
|
+
return context;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=context.js.map
|