@mastra/playground-ui 49.1.0-alpha.1 → 49.1.0-alpha.2
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/CHANGELOG.md +28 -0
- package/dist/components/ChatShell.cjs.js +1 -1
- package/dist/components/ChatShell.es.js +1 -1
- package/dist/components/MessageScroller.cjs.js +1 -1
- package/dist/components/MessageScroller.es.js +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +3 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js +3 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/trace-keys-and-values.cjs.js +10 -1
- package/dist/domains/traces/components/trace-keys-and-values.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-keys-and-values.es.js +10 -1
- package/dist/domains/traces/components/trace-keys-and-values.es.js.map +1 -1
- package/dist/{message-scroller-DlVS0FW7.js → message-scroller-D0xet-EH.js} +48 -25
- package/dist/message-scroller-D0xet-EH.js.map +1 -0
- package/dist/{message-scroller-BssU0EKT.cjs → message-scroller-PIxGmJ34.cjs} +48 -25
- package/dist/message-scroller-PIxGmJ34.cjs.map +1 -0
- package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +8 -1
- package/dist/src/domains/traces/components/trace-keys-and-values.d.ts +9 -1
- package/dist/src/ds/components/MessageScroller/message-scroller.d.ts +1 -0
- package/dist/style.css +4 -0
- package/package.json +7 -7
- package/dist/message-scroller-BssU0EKT.cjs.map +0 -1
- package/dist/message-scroller-DlVS0FW7.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @mastra/playground-ui
|
|
2
2
|
|
|
3
|
+
## 49.1.0-alpha.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Improved `MessageScroller` so chat transcripts follow the stream. With `autoScroll` on, the reader is carried with the newest output while they sit at the end, and a new user turn brings them back to it. Only scrolling away stops the following — content growing under the reader, or landing above them, no longer moves them or flashes the jump-to-end button. ([#21523](https://github.com/mastra-ai/mastra/pull/21523))
|
|
8
|
+
|
|
9
|
+
A turn opening animates the scroll only for a reader who had scrolled away. Someone already at the end is carried by whatever the turn grows under itself, so a surface can reserve room under a live turn and let its own transition set the pace:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
<MessageScrollerProvider autoScroll>
|
|
13
|
+
<MessageScrollerViewport>
|
|
14
|
+
<MessageScrollerContent>
|
|
15
|
+
{/* the viewport is a size container, so a live turn can reserve a share of it */}
|
|
16
|
+
<div className="min-h-[70cqh]">{liveTurn}</div>
|
|
17
|
+
</MessageScrollerContent>
|
|
18
|
+
</MessageScrollerViewport>
|
|
19
|
+
</MessageScrollerProvider>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- Added token and estimated cost totals to full trace details in Studio. Opening a trace now shows input tokens, output tokens, and estimated cost in both the trace side panel and the dedicated trace page, including when the trace is opened from a direct link outside the loaded list. Subtrace panels omit these values because they represent totals for the full trace. ([#21541](https://github.com/mastra-ai/mastra/pull/21541))
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [[`7e096f0`](https://github.com/mastra-ai/mastra/commit/7e096f02f0dddbf09b85d306458351245ed2f886), [`8f0a332`](https://github.com/mastra-ai/mastra/commit/8f0a3321bf180368d76fe7b36aa1a8f60f00b6de), [`b098de9`](https://github.com/mastra-ai/mastra/commit/b098de9d7cb9f672e0883a5c716465a3a689693d), [`ef6e295`](https://github.com/mastra-ai/mastra/commit/ef6e295b59bc25a5b61b633a89c97bcfce9fb465), [`208e1b3`](https://github.com/mastra-ai/mastra/commit/208e1b39f30f4b386e494394e9d71d96f0f90241), [`c938d34`](https://github.com/mastra-ai/mastra/commit/c938d34739936c8ecbabd67ad6a4a4396f41c4c6), [`fc76b73`](https://github.com/mastra-ai/mastra/commit/fc76b73b114322ba613c60f138f014b2c0adb414), [`1d9a0ea`](https://github.com/mastra-ai/mastra/commit/1d9a0ea4a9901baee6cd56737243bd6d1f631ac0), [`3667679`](https://github.com/mastra-ai/mastra/commit/3667679db057edfb086846d13369fdda4902ad65), [`49696e8`](https://github.com/mastra-ai/mastra/commit/49696e8e42f870674a0a58f5abcd22cc54dd2864), [`512100a`](https://github.com/mastra-ai/mastra/commit/512100a7d8b7e9c920f2590c6b3612f5de0d3cff), [`9ef432b`](https://github.com/mastra-ai/mastra/commit/9ef432b6faa534b57b0d182a610e13dd9a7123ff), [`b9cf308`](https://github.com/mastra-ai/mastra/commit/b9cf30846f97f99ac1906ee8a68f4f2d117b0378)]:
|
|
27
|
+
- @mastra/core@1.60.0-alpha.2
|
|
28
|
+
- @mastra/client-js@1.40.1-alpha.2
|
|
29
|
+
- @mastra/react@1.4.4-alpha.2
|
|
30
|
+
|
|
3
31
|
## 49.1.0-alpha.1
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
5
|
const jsxRuntime = require('react/jsx-runtime');
|
|
6
|
-
const messageScroller = require('../message-scroller-
|
|
6
|
+
const messageScroller = require('../message-scroller-PIxGmJ34.cjs');
|
|
7
7
|
const utils_cn = require('../cn-vA5sWo9W.cjs');
|
|
8
8
|
|
|
9
9
|
function ChatShellRoot({ className, scroller, ...props }) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { d as MessageScrollerProvider, e as MessageScrollerViewport, M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent } from '../message-scroller-
|
|
2
|
+
import { d as MessageScrollerProvider, e as MessageScrollerViewport, M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent } from '../message-scroller-D0xet-EH.js';
|
|
3
3
|
import { c as cn } from '../cn-BakJzhuv.js';
|
|
4
4
|
|
|
5
5
|
function ChatShellRoot({ className, scroller, ...props }) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
|
-
const messageScroller = require('../message-scroller-
|
|
5
|
+
const messageScroller = require('../message-scroller-PIxGmJ34.cjs');
|
|
6
6
|
const messageScrollerHooks = require('../message-scroller-hooks-BxAf8k0Y.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent, c as MessageScrollerItem, d as MessageScrollerProvider, e as MessageScrollerViewport } from '../message-scroller-
|
|
1
|
+
export { M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent, c as MessageScrollerItem, d as MessageScrollerProvider, e as MessageScrollerViewport } from '../message-scroller-D0xet-EH.js';
|
|
2
2
|
export { u as useMessageScroller, a as useMessageScrollerScrollable, b as useMessageScrollerVisibility, c as useOptionalMessageScroller, d as useOptionalMessageScrollerScrollable, e as useOptionalMessageScrollerVisibility } from '../message-scroller-hooks-D5yxCon2.js';
|
|
3
3
|
//# sourceMappingURL=MessageScroller.es.js.map
|
|
@@ -20,6 +20,7 @@ const utils_truncateString = require('../../../utils/truncate-string.cjs.js');
|
|
|
20
20
|
function TraceDataPanelView({
|
|
21
21
|
traceId,
|
|
22
22
|
spans,
|
|
23
|
+
usage,
|
|
23
24
|
isLoading,
|
|
24
25
|
onClose,
|
|
25
26
|
onSpanSelect,
|
|
@@ -71,6 +72,7 @@ function TraceDataPanelView({
|
|
|
71
72
|
() => anchorSpanId ? spans?.find((s) => s.spanId === anchorSpanId) : spans?.find((s) => s.parentSpanId == null),
|
|
72
73
|
[spans, anchorSpanId]
|
|
73
74
|
);
|
|
75
|
+
const isSubtrace = anchorSpanId !== void 0 && rootSpan?.parentSpanId != null;
|
|
74
76
|
const handleSpanClick = (id) => {
|
|
75
77
|
const newId = selectedSpanId === id ? void 0 : id;
|
|
76
78
|
setSelectedSpanId(newId);
|
|
@@ -135,7 +137,7 @@ function TraceDataPanelView({
|
|
|
135
137
|
] })
|
|
136
138
|
] }) }),
|
|
137
139
|
!collapsed && (isLoading ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Content, { children: [
|
|
138
|
-
!isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(domains_traces_components_traceKeysAndValues.TraceKeysAndValues, { rootSpan, className: "mb-6" }),
|
|
140
|
+
!isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(domains_traces_components_traceKeysAndValues.TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
|
|
139
141
|
!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex flex-wrap items-center justify-between gap-4", children: [
|
|
140
142
|
onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsxs(Button.Button, { size: "sm", onClick: onEvaluateTrace, children: [
|
|
141
143
|
/* @__PURE__ */ jsxRuntime.jsx(icons_Icon.Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-data-panel-view.cjs.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && <TraceKeysAndValues rootSpan={rootSpan} className=\"mb-6\" />}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":["useState","useDownloadTraceJson","useEffect","useMemo","formatHierarchicalSpans","getAllSpanIds","jsx","Button","Loader2Icon","DownloadIcon","jsxs","DataPanel","Fragment","ButtonsGroup","truncateString","ChevronsUpDownIcon","ChevronsDownUpIcon","Link2Icon","TraceKeysAndValues","Icon","CircleGaugeIcon","SaveIcon","WrenchIcon","Notice","TraceTimeline"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"trace-data-panel-view.cjs.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n /**\n * Token and estimated-cost totals for the trace (from `useTraceUsage`).\n * Rendered in the trace summary when the panel is in the list side-panel\n * placement; the trace page renders its own `TraceKeysAndValues` instead.\n */\n usage?: TraceUsageSummary;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n usage,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n const isSubtrace = anchorSpanId !== undefined && rootSpan?.parentSpanId != null;\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\n )}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":["useState","useDownloadTraceJson","useEffect","useMemo","formatHierarchicalSpans","getAllSpanIds","jsx","Button","Loader2Icon","DownloadIcon","jsxs","DataPanel","Fragment","ButtonsGroup","truncateString","ChevronsUpDownIcon","ChevronsDownUpIcon","Link2Icon","TraceKeysAndValues","Icon","CircleGaugeIcon","SaveIcon","WrenchIcon","Notice","TraceTimeline"],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@ import { truncateString } from '../../../utils/truncate-string.es.js';
|
|
|
16
16
|
function TraceDataPanelView({
|
|
17
17
|
traceId,
|
|
18
18
|
spans,
|
|
19
|
+
usage,
|
|
19
20
|
isLoading,
|
|
20
21
|
onClose,
|
|
21
22
|
onSpanSelect,
|
|
@@ -67,6 +68,7 @@ function TraceDataPanelView({
|
|
|
67
68
|
() => anchorSpanId ? spans?.find((s) => s.spanId === anchorSpanId) : spans?.find((s) => s.parentSpanId == null),
|
|
68
69
|
[spans, anchorSpanId]
|
|
69
70
|
);
|
|
71
|
+
const isSubtrace = anchorSpanId !== void 0 && rootSpan?.parentSpanId != null;
|
|
70
72
|
const handleSpanClick = (id) => {
|
|
71
73
|
const newId = selectedSpanId === id ? void 0 : id;
|
|
72
74
|
setSelectedSpanId(newId);
|
|
@@ -131,7 +133,7 @@ function TraceDataPanelView({
|
|
|
131
133
|
] })
|
|
132
134
|
] }) }),
|
|
133
135
|
!collapsed && (isLoading ? /* @__PURE__ */ jsx(DataPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsx(DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxs(DataPanel.Content, { children: [
|
|
134
|
-
!isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, className: "mb-6" }),
|
|
136
|
+
!isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
|
|
135
137
|
!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && /* @__PURE__ */ jsxs("div", { className: "mb-6 flex flex-wrap items-center justify-between gap-4", children: [
|
|
136
138
|
onEvaluateTrace && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: onEvaluateTrace, children: [
|
|
137
139
|
/* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(CircleGaugeIcon, {}) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && <TraceKeysAndValues rootSpan={rootSpan} className=\"mb-6\" />}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"trace-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n /**\n * Token and estimated-cost totals for the trace (from `useTraceUsage`).\n * Rendered in the trace summary when the panel is in the list side-panel\n * placement; the trace page renders its own `TraceKeysAndValues` instead.\n */\n usage?: TraceUsageSummary;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n usage,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n const isSubtrace = anchorSpanId !== undefined && rootSpan?.parentSpanId != null;\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\n )}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
4
4
|
|
|
5
5
|
const jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
const dateFns = require('date-fns');
|
|
7
|
+
const domains_metrics_components_metricsUtils = require('../../metrics/components/metrics-utils.cjs.js');
|
|
7
8
|
const dataKeysAndValues = require('../../../data-keys-and-values-sjag88jf.cjs');
|
|
8
9
|
|
|
9
10
|
function computeTraceStatus(span) {
|
|
@@ -11,7 +12,7 @@ function computeTraceStatus(span) {
|
|
|
11
12
|
if (span.endedAt == null) return "running" /* RUNNING */;
|
|
12
13
|
return "success" /* SUCCESS */;
|
|
13
14
|
}
|
|
14
|
-
function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
|
|
15
|
+
function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }) {
|
|
15
16
|
const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
|
|
16
17
|
const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
|
|
17
18
|
const status = computeTraceStatus(rootSpan);
|
|
@@ -38,6 +39,14 @@ function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
|
|
|
38
39
|
endedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
39
40
|
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Ended at" }),
|
|
40
41
|
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: dateFns.format(endedAt, "MMM dd, h:mm:ss.SSS aaa") })
|
|
42
|
+
] }),
|
|
43
|
+
usage && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Trace input tokens" }),
|
|
45
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: usage.inputTokens === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCompact(usage.inputTokens) }),
|
|
46
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Trace output tokens" }),
|
|
47
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: usage.outputTokens === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCompact(usage.outputTokens) }),
|
|
48
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Trace est. cost" }),
|
|
49
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: usage.estimatedCost === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCost(usage.estimatedCost, usage.costUnit) })
|
|
41
50
|
] })
|
|
42
51
|
] });
|
|
43
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-keys-and-values.cjs.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":["jsxs","DataKeysAndValues","Fragment","jsx","format"],"mappings":"
|
|
1
|
+
{"version":3,"file":"trace-keys-and-values.cjs.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n /**\n * Token and estimated-cost totals aggregated across the trace's model spans\n * (from `useTraceUsage`). When provided, token and cost rows are rendered —\n * with `—` for values the metrics store couldn't produce (e.g. no pricing\n * match or mixed cost units).\n */\n usage?: TraceUsageSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {usage && (\n <>\n <DataKeysAndValues.Key>Trace input tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.inputTokens === undefined ? '—' : formatCompact(usage.inputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace output tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.outputTokens === undefined ? '—' : formatCompact(usage.outputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace est. cost</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.estimatedCost === undefined ? '—' : formatCost(usage.estimatedCost, usage.costUnit)}\n </DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":["jsxs","DataKeysAndValues","Fragment","jsx","format","formatCompact","formatCost"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { format } from 'date-fns';
|
|
3
|
+
import { formatCompact, formatCost } from '../../metrics/components/metrics-utils.es.js';
|
|
3
4
|
import { D as DataKeysAndValues } from '../../../data-keys-and-values-BJynhd6V.js';
|
|
4
5
|
|
|
5
6
|
function computeTraceStatus(span) {
|
|
@@ -7,7 +8,7 @@ function computeTraceStatus(span) {
|
|
|
7
8
|
if (span.endedAt == null) return "running" /* RUNNING */;
|
|
8
9
|
return "success" /* SUCCESS */;
|
|
9
10
|
}
|
|
10
|
-
function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
|
|
11
|
+
function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }) {
|
|
11
12
|
const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
|
|
12
13
|
const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
|
|
13
14
|
const status = computeTraceStatus(rootSpan);
|
|
@@ -34,6 +35,14 @@ function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
|
|
|
34
35
|
endedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
35
36
|
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Ended at" }),
|
|
36
37
|
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: format(endedAt, "MMM dd, h:mm:ss.SSS aaa") })
|
|
38
|
+
] }),
|
|
39
|
+
usage && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
40
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace input tokens" }),
|
|
41
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: usage.inputTokens === void 0 ? "—" : formatCompact(usage.inputTokens) }),
|
|
42
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace output tokens" }),
|
|
43
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: usage.outputTokens === void 0 ? "—" : formatCompact(usage.outputTokens) }),
|
|
44
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace est. cost" }),
|
|
45
|
+
/* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: usage.estimatedCost === void 0 ? "—" : formatCost(usage.estimatedCost, usage.costUnit) })
|
|
37
46
|
] })
|
|
38
47
|
] });
|
|
39
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-keys-and-values.es.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"trace-keys-and-values.es.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n /**\n * Token and estimated-cost totals aggregated across the trace's model spans\n * (from `useTraceUsage`). When provided, token and cost rows are rendered —\n * with `—` for values the metrics store couldn't produce (e.g. no pricing\n * match or mixed cost units).\n */\n usage?: TraceUsageSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {usage && (\n <>\n <DataKeysAndValues.Key>Trace input tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.inputTokens === undefined ? '—' : formatCompact(usage.inputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace output tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.outputTokens === undefined ? '—' : formatCompact(usage.outputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace est. cost</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.estimatedCost === undefined ? '—' : formatCost(usage.estimatedCost, usage.costUnit)}\n </DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -126,6 +126,9 @@ function MessageScrollerProvider({
|
|
|
126
126
|
const [scrollable, setScrollable] = React.useState(DEFAULT_SCROLLABLE);
|
|
127
127
|
const [visibility, setVisibility] = React.useState(DEFAULT_VISIBILITY);
|
|
128
128
|
const atEndRef = React.useRef(true);
|
|
129
|
+
const followingRef = React.useRef(true);
|
|
130
|
+
const travellingToEndRef = React.useRef(false);
|
|
131
|
+
const lastScrollTopRef = React.useRef(0);
|
|
129
132
|
const reachStartArmedRef = React.useRef(false);
|
|
130
133
|
const reachStartFiredRef = React.useRef(false);
|
|
131
134
|
const prependAnchorRef = React.useRef(null);
|
|
@@ -152,19 +155,29 @@ function MessageScrollerProvider({
|
|
|
152
155
|
const publishVisibility = React.useCallback((nextVisibility) => {
|
|
153
156
|
setVisibility((current) => visibilityMatches(current, nextVisibility) ? current : nextVisibility);
|
|
154
157
|
}, []);
|
|
155
|
-
const updateScrollable = React.useCallback(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
158
|
+
const updateScrollable = React.useCallback(
|
|
159
|
+
({ fromScroll = false } = {}) => {
|
|
160
|
+
if (!viewportElement) {
|
|
161
|
+
atEndRef.current = true;
|
|
162
|
+
publishScrollable(DEFAULT_SCROLLABLE);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const { clientHeight, scrollHeight, scrollTop } = viewportElement;
|
|
166
|
+
const remainingScroll = scrollHeight - scrollTop - clientHeight;
|
|
167
|
+
const wentBack = scrollTop < lastScrollTopRef.current;
|
|
168
|
+
atEndRef.current = remainingScroll < AUTO_SCROLL_ATTACH_THRESHOLD;
|
|
169
|
+
if (atEndRef.current || wentBack) travellingToEndRef.current = false;
|
|
170
|
+
lastScrollTopRef.current = scrollTop;
|
|
171
|
+
if (fromScroll && !travellingToEndRef.current && (wentBack || atEndRef.current)) {
|
|
172
|
+
followingRef.current = atEndRef.current;
|
|
173
|
+
}
|
|
174
|
+
publishScrollable({
|
|
175
|
+
start: scrollTop > scrollEdgeThreshold,
|
|
176
|
+
end: remainingScroll > scrollEdgeThreshold && !(autoScroll && followingRef.current)
|
|
177
|
+
});
|
|
178
|
+
},
|
|
179
|
+
[autoScroll, publishScrollable, scrollEdgeThreshold, viewportElement]
|
|
180
|
+
);
|
|
168
181
|
const getOrderedItems = React.useCallback(() => {
|
|
169
182
|
orderedItemsRef.current ??= orderItemsByDocumentPosition(Array.from(itemsRegistry.entries()));
|
|
170
183
|
return orderedItemsRef.current;
|
|
@@ -227,7 +240,8 @@ function MessageScrollerProvider({
|
|
|
227
240
|
}, [updateScrollable, updateVisibility]);
|
|
228
241
|
const notifyScroll = React.useCallback(() => {
|
|
229
242
|
const wasScrollable = Boolean(viewportElement && viewportElement.scrollHeight > viewportElement.clientHeight);
|
|
230
|
-
|
|
243
|
+
updateScrollable({ fromScroll: true });
|
|
244
|
+
updateVisibility();
|
|
231
245
|
if (!viewportElement) return;
|
|
232
246
|
if (atEndRef.current && wasScrollable) reachStartArmedRef.current = true;
|
|
233
247
|
if (!reachStartArmedRef.current) return;
|
|
@@ -246,14 +260,14 @@ function MessageScrollerProvider({
|
|
|
246
260
|
};
|
|
247
261
|
}
|
|
248
262
|
onReachStartRef.current();
|
|
249
|
-
}, [preserveScrollOnPrepend, reachStartThreshold,
|
|
263
|
+
}, [preserveScrollOnPrepend, reachStartThreshold, updateScrollable, updateVisibility, viewportElement]);
|
|
250
264
|
const notifyContentResize = React.useCallback(() => {
|
|
251
|
-
const followEnd = autoScroll && defaultScrollAppliedRef.current &&
|
|
265
|
+
const followEnd = autoScroll && defaultScrollAppliedRef.current && followingRef.current && viewportElement;
|
|
252
266
|
if (followEnd) {
|
|
253
267
|
scrollViewportTo(
|
|
254
268
|
viewportElement,
|
|
255
269
|
Math.max(0, viewportElement.scrollHeight - viewportElement.clientHeight),
|
|
256
|
-
"auto"
|
|
270
|
+
travellingToEndRef.current ? "smooth" : "auto"
|
|
257
271
|
);
|
|
258
272
|
}
|
|
259
273
|
syncAfterScroll();
|
|
@@ -292,11 +306,14 @@ function MessageScrollerProvider({
|
|
|
292
306
|
const scrollToEnd = React.useCallback(
|
|
293
307
|
({ behavior = "auto" } = {}) => {
|
|
294
308
|
if (!viewportElement) return false;
|
|
309
|
+
followingRef.current = true;
|
|
310
|
+
travellingToEndRef.current = behavior === "smooth";
|
|
295
311
|
scrollViewportTo(
|
|
296
312
|
viewportElement,
|
|
297
313
|
Math.max(0, viewportElement.scrollHeight - viewportElement.clientHeight),
|
|
298
314
|
behavior
|
|
299
315
|
);
|
|
316
|
+
syncAfterScroll();
|
|
300
317
|
scheduleScrollSync(syncAfterScroll);
|
|
301
318
|
return true;
|
|
302
319
|
},
|
|
@@ -385,6 +402,7 @@ function MessageScrollerProvider({
|
|
|
385
402
|
}
|
|
386
403
|
const applyDefaultScroll = () => {
|
|
387
404
|
const lastAnchorId = getLastAnchorId();
|
|
405
|
+
followingRef.current = false;
|
|
388
406
|
let didScroll = false;
|
|
389
407
|
if (defaultScrollPosition === "start") {
|
|
390
408
|
didScroll = scrollToStart({ behavior: "auto" });
|
|
@@ -427,20 +445,29 @@ function MessageScrollerProvider({
|
|
|
427
445
|
React.useLayoutEffect(() => {
|
|
428
446
|
const lastAnchorId = getLastAnchorId();
|
|
429
447
|
const lastAnchor = lastAnchorId ? itemsRegistry.get(lastAnchorId) : void 0;
|
|
430
|
-
const
|
|
448
|
+
const opensTurn = turnAnchoringArmedRef.current && lastAnchorId !== void 0 && lastAnchor !== void 0 && !seenAnchorIds.has(lastAnchorId) && !seenAnchorElements.has(lastAnchor.element);
|
|
431
449
|
for (const [messageId, item] of getOrderedItems()) {
|
|
432
450
|
if (!item.scrollAnchor) continue;
|
|
433
451
|
seenAnchorIds.add(messageId);
|
|
434
452
|
seenAnchorElements.add(item.element);
|
|
435
453
|
}
|
|
436
454
|
turnAnchoringArmedRef.current = defaultScrollAppliedRef.current;
|
|
437
|
-
if (!
|
|
438
|
-
|
|
455
|
+
if (!autoScroll) {
|
|
456
|
+
if (opensTurn && lastAnchorId) scrollToMessage(lastAnchorId, { align: "start", behavior: "smooth" });
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const wasFollowing = followingRef.current;
|
|
460
|
+
if (opensTurn) followingRef.current = true;
|
|
461
|
+
if (!defaultScrollAppliedRef.current || !followingRef.current) return;
|
|
462
|
+
const catchingUp = opensTurn && !wasFollowing || travellingToEndRef.current;
|
|
463
|
+
scrollToEnd({ behavior: catchingUp ? "smooth" : "auto" });
|
|
439
464
|
}, [
|
|
465
|
+
autoScroll,
|
|
440
466
|
getLastAnchorId,
|
|
441
467
|
getOrderedItems,
|
|
442
468
|
itemsRegistry,
|
|
443
469
|
itemsVersion,
|
|
470
|
+
scrollToEnd,
|
|
444
471
|
scrollToMessage,
|
|
445
472
|
seenAnchorElements,
|
|
446
473
|
seenAnchorIds
|
|
@@ -456,10 +483,6 @@ function MessageScrollerProvider({
|
|
|
456
483
|
const grownBy = viewportElement.scrollHeight - anchor.scrollHeight;
|
|
457
484
|
if (grownBy > 0) viewportElement.scrollTop = anchor.scrollTop + grownBy;
|
|
458
485
|
}, [contentElement, itemsVersion, viewportElement]);
|
|
459
|
-
React.useLayoutEffect(() => {
|
|
460
|
-
if (!autoScroll || !defaultScrollAppliedRef.current || !atEndRef.current) return;
|
|
461
|
-
scrollToEnd({ behavior: "auto" });
|
|
462
|
-
}, [autoScroll, itemsVersion, scrollToEnd]);
|
|
463
486
|
const actionsContextValue = React.useMemo(
|
|
464
487
|
() => ({
|
|
465
488
|
notifyContentResize,
|
|
@@ -643,4 +666,4 @@ const MessageScrollerButton = React.forwardRef(
|
|
|
643
666
|
MessageScrollerButton.displayName = "MessageScrollerButton";
|
|
644
667
|
|
|
645
668
|
export { MessageScroller as M, MessageScrollerButton as a, MessageScrollerContent as b, MessageScrollerItem as c, MessageScrollerProvider as d, MessageScrollerViewport as e };
|
|
646
|
-
//# sourceMappingURL=message-scroller-
|
|
669
|
+
//# sourceMappingURL=message-scroller-D0xet-EH.js.map
|