@mastra/playground-ui 51.3.2-alpha.0 → 51.4.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 +57 -0
- package/dist/Badge-DcllBqFg.cjs +125 -0
- package/dist/Badge-DcllBqFg.cjs.map +1 -0
- package/dist/Badge-uGehUtus.js +123 -0
- package/dist/Badge-uGehUtus.js.map +1 -0
- package/dist/components/Badge.cjs.js +1 -1
- package/dist/components/Badge.es.js +1 -1
- package/dist/components/DataList.cjs.js +4 -4
- package/dist/components/DataList.es.js +4 -4
- package/dist/components/EnvironmentVariablesEditor.cjs.js +1 -1
- package/dist/components/EnvironmentVariablesEditor.es.js +1 -1
- package/dist/components/ItemList.cjs.js +59 -40
- package/dist/components/ItemList.cjs.js.map +1 -1
- package/dist/components/ItemList.es.js +58 -41
- package/dist/components/ItemList.es.js.map +1 -1
- package/dist/components/LogsDataList.cjs.js +2 -2
- package/dist/components/LogsDataList.es.js +2 -2
- package/dist/components/ai/ask-user.cjs.js +3 -3
- package/dist/components/ai/ask-user.cjs.js.map +1 -1
- package/dist/components/ai/ask-user.es.js +3 -3
- package/dist/components/ai/ask-user.es.js.map +1 -1
- package/dist/components/ai/plan.cjs.js +3 -3
- package/dist/components/ai/plan.cjs.js.map +1 -1
- package/dist/components/ai/plan.es.js +3 -3
- package/dist/components/ai/plan.es.js.map +1 -1
- package/dist/{data-list-BOI8fRuk.js → data-list-C3tjx5Vb.js} +2 -2
- package/dist/{data-list-BOI8fRuk.js.map → data-list-C3tjx5Vb.js.map} +1 -1
- package/dist/{data-list-CCacNODd.cjs → data-list-CRDewYj9.cjs} +2 -2
- package/dist/{data-list-CCacNODd.cjs.map → data-list-CRDewYj9.cjs.map} +1 -1
- package/dist/{data-list-skeleton-DDO_OE14.js → data-list-skeleton-BCrkk6wG.js} +2 -2
- package/dist/{data-list-skeleton-DDO_OE14.js.map → data-list-skeleton-BCrkk6wG.js.map} +1 -1
- package/dist/{data-list-skeleton-BHBSIQHN.cjs → data-list-skeleton-CONfqzH2.cjs} +2 -2
- package/dist/{data-list-skeleton-BHBSIQHN.cjs.map → data-list-skeleton-CONfqzH2.cjs.map} +1 -1
- package/dist/{data-list-top-cell-BOXO5s7I.cjs → data-list-top-cell-DAztx3m8.cjs} +6 -1
- package/dist/data-list-top-cell-DAztx3m8.cjs.map +1 -0
- package/dist/{data-list-top-cell-CC5jjv5s.js → data-list-top-cell-hNkk6S-Q.js} +6 -2
- package/dist/data-list-top-cell-hNkk6S-Q.js.map +1 -0
- package/dist/domains/logs/components/logs-list-view.cjs.js +2 -2
- package/dist/domains/logs/components/logs-list-view.es.js +2 -2
- package/dist/domains/metrics/components/memory-card-view.cjs.js +1 -1
- package/dist/domains/metrics/components/memory-card-view.es.js +1 -1
- package/dist/domains/metrics/components/model-usage-cost-card-view.cjs.js +1 -1
- package/dist/domains/metrics/components/model-usage-cost-card-view.es.js +1 -1
- package/dist/domains/metrics/components/scores-card-view.cjs.js +1 -1
- package/dist/domains/metrics/components/scores-card-view.es.js +1 -1
- package/dist/domains/traces/components/format-hierarchical-spans.cjs.js +2 -1
- package/dist/domains/traces/components/format-hierarchical-spans.cjs.js.map +1 -1
- package/dist/domains/traces/components/format-hierarchical-spans.es.js +2 -1
- package/dist/domains/traces/components/format-hierarchical-spans.es.js.map +1 -1
- package/dist/domains/traces/components/timeline-name-col.cjs.js +10 -1
- package/dist/domains/traces/components/timeline-name-col.cjs.js.map +1 -1
- package/dist/domains/traces/components/timeline-name-col.es.js +10 -1
- package/dist/domains/traces/components/timeline-name-col.es.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +17 -5
- 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 +17 -5
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/traces-list-view.cjs.js +7 -9
- package/dist/domains/traces/components/traces-list-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/traces-list-view.es.js +7 -9
- package/dist/domains/traces/components/traces-list-view.es.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-search.cjs.js +10 -4
- package/dist/domains/traces/hooks/use-trace-search.cjs.js.map +1 -1
- package/dist/domains/traces/hooks/use-trace-search.es.js +10 -4
- package/dist/domains/traces/hooks/use-trace-search.es.js.map +1 -1
- package/dist/domains/traces/trace-list-columns.cjs.js +1 -1
- package/dist/domains/traces/trace-list-columns.cjs.js.map +1 -1
- package/dist/domains/traces/trace-list-columns.es.js +1 -1
- package/dist/domains/traces/trace-list-columns.es.js.map +1 -1
- package/dist/domains/traces/types.cjs.js.map +1 -1
- package/dist/domains/traces/types.es.js.map +1 -1
- package/dist/ee/topics/components/topic-trace-summary-list.cjs.js +1 -1
- package/dist/ee/topics/components/topic-trace-summary-list.es.js +1 -1
- package/dist/hooks/use-scroll-to-first-highlight.cjs.js +44 -0
- package/dist/hooks/use-scroll-to-first-highlight.cjs.js.map +1 -0
- package/dist/hooks/use-scroll-to-first-highlight.d.ts +2 -0
- package/dist/hooks/use-scroll-to-first-highlight.es.js +40 -0
- package/dist/hooks/use-scroll-to-first-highlight.es.js.map +1 -0
- package/dist/hooks/use-text-highlight.cjs.js +49 -2
- package/dist/hooks/use-text-highlight.cjs.js.map +1 -1
- package/dist/hooks/use-text-highlight.es.js +48 -3
- package/dist/hooks/use-text-highlight.es.js.map +1 -1
- package/dist/{logs-data-list-Xayqbjw4.cjs → logs-data-list-D88JF2lo.cjs} +2 -2
- package/dist/{logs-data-list-Xayqbjw4.cjs.map → logs-data-list-D88JF2lo.cjs.map} +1 -1
- package/dist/{logs-data-list-DRXJ89IZ.js → logs-data-list-DnAXTwr7.js} +2 -2
- package/dist/{logs-data-list-DRXJ89IZ.js.map → logs-data-list-DnAXTwr7.js.map} +1 -1
- package/dist/src/domains/traces/components/format-hierarchical-spans.d.ts +1 -0
- package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +1 -1
- package/dist/src/domains/traces/hooks/use-trace-search.d.ts +7 -0
- package/dist/src/domains/traces/types.d.ts +5 -0
- package/dist/src/ds/components/Badge/Badge.d.ts +86 -12
- package/dist/src/ds/components/Badge/badge.stories.d.ts +3 -0
- package/dist/src/ds/components/DataList/TracesDataList/traces-data-list.d.ts +2 -3
- package/dist/src/ds/components/DataList/data-list-cells.d.ts +5 -0
- package/dist/src/ds/components/ItemList/helpers.d.ts +8 -0
- package/dist/src/ds/components/ItemList/item-list-link-cell.d.ts +2 -1
- package/dist/src/ds/components/ItemList/item-list-row-button.d.ts +2 -1
- package/dist/src/ds/components/ai/plan/plan.d.ts +1 -1
- package/dist/src/hooks/use-scroll-to-first-highlight.d.ts +20 -0
- package/dist/src/hooks/use-text-highlight.d.ts +18 -0
- package/dist/src/test/highlight-api.d.ts +6 -4
- package/dist/style.css +364 -219
- package/dist/{traces-data-list-BLZgf-Es.cjs → traces-data-list-COksp2d4.cjs} +12 -13
- package/dist/traces-data-list-COksp2d4.cjs.map +1 -0
- package/dist/{traces-data-list-DmXGwe4Q.js → traces-data-list-c5I-8hwt.js} +12 -13
- package/dist/traces-data-list-c5I-8hwt.js.map +1 -0
- package/dist/use-text-highlight.css +8 -0
- package/package.json +7 -7
- package/theme.css +53 -0
- package/dist/Badge-BlJpI3fY.cjs +0 -57
- package/dist/Badge-BlJpI3fY.cjs.map +0 -1
- package/dist/Badge-woV6OD8k.js +0 -55
- package/dist/Badge-woV6OD8k.js.map +0 -1
- package/dist/chip-9P9t0dvN.cjs +0 -68
- package/dist/chip-9P9t0dvN.cjs.map +0 -1
- package/dist/chip-Bg0-95sX.js +0 -66
- package/dist/chip-Bg0-95sX.js.map +0 -1
- package/dist/components/Chip.cjs.js +0 -27
- package/dist/components/Chip.cjs.js.map +0 -1
- package/dist/components/Chip.d.ts +0 -2
- package/dist/components/Chip.es.js +0 -22
- package/dist/components/Chip.es.js.map +0 -1
- package/dist/components/StatusBadge.cjs.js +0 -76
- package/dist/components/StatusBadge.cjs.js.map +0 -1
- package/dist/components/StatusBadge.d.ts +0 -2
- package/dist/components/StatusBadge.es.js +0 -72
- package/dist/components/StatusBadge.es.js.map +0 -1
- package/dist/data-list-top-cell-BOXO5s7I.cjs.map +0 -1
- package/dist/data-list-top-cell-CC5jjv5s.js.map +0 -1
- package/dist/src/ds/components/Chip/chip.d.ts +0 -8
- package/dist/src/ds/components/Chip/chip.stories.d.ts +0 -11
- package/dist/src/ds/components/Chip/chips-group.d.ts +0 -2
- package/dist/src/ds/components/Chip/index.d.ts +0 -2
- package/dist/src/ds/components/StatusBadge/StatusBadge.d.ts +0 -13
- package/dist/src/ds/components/StatusBadge/index.d.ts +0 -2
- package/dist/src/ds/components/StatusBadge/status-badge.stories.d.ts +0 -8
- package/dist/traces-data-list-BLZgf-Es.cjs.map +0 -1
- package/dist/traces-data-list-DmXGwe4Q.js.map +0 -1
|
@@ -19,6 +19,7 @@ const Notice = require('../../../Notice-BoT3Qi4U.cjs');
|
|
|
19
19
|
const tabsRoot = require('../../../tabs-root-VtBc6K2q.cjs');
|
|
20
20
|
const tabsTab = require('../../../tabs-tab-DudcFE6r.cjs');
|
|
21
21
|
const tabsContent = require('../../../tabs-content-wBU5qmb6.cjs');
|
|
22
|
+
const hooks_useScrollToFirstHighlight = require('../../../hooks/use-scroll-to-first-highlight.cjs.js');
|
|
22
23
|
const hooks_useTextHighlight = require('../../../hooks/use-text-highlight.cjs.js');
|
|
23
24
|
const utils_truncateString = require('../../../utils/truncate-string.cjs.js');
|
|
24
25
|
|
|
@@ -75,8 +76,16 @@ function TraceDataPanelView({
|
|
|
75
76
|
}
|
|
76
77
|
}, [initialSpanId, spans, isLoading]);
|
|
77
78
|
const searchFieldName = React.useId();
|
|
78
|
-
const { query, setQuery, results } = domains_traces_hooks_useTraceSearch.useTraceSearch(spans ?? []);
|
|
79
|
-
const hierarchicalSpans = React.useMemo(
|
|
79
|
+
const { query, setQuery, results, payloadOnlyMatchIds } = domains_traces_hooks_useTraceSearch.useTraceSearch(spans ?? []);
|
|
80
|
+
const hierarchicalSpans = React.useMemo(
|
|
81
|
+
() => domains_traces_components_formatHierarchicalSpans.formatHierarchicalSpans(
|
|
82
|
+
// Carried on the span rather than drilled as a prop: the tree is rebuilt here and
|
|
83
|
+
// rendered several components deeper.
|
|
84
|
+
results.map((span) => ({ ...span, matchedInPayloadOnly: payloadOnlyMatchIds.has(span.spanId) })),
|
|
85
|
+
anchorSpanId
|
|
86
|
+
),
|
|
87
|
+
[results, payloadOnlyMatchIds, anchorSpanId]
|
|
88
|
+
);
|
|
80
89
|
const [expandedSpanIds, setExpandedSpanIds] = React.useState([]);
|
|
81
90
|
React.useEffect(() => {
|
|
82
91
|
if (hierarchicalSpans.length > 0) {
|
|
@@ -132,8 +141,8 @@ function TraceDataPanelView({
|
|
|
132
141
|
Button.Button,
|
|
133
142
|
{
|
|
134
143
|
size: "md",
|
|
135
|
-
tooltip: "
|
|
136
|
-
"aria-label": "
|
|
144
|
+
tooltip: "Add full trace to dataset",
|
|
145
|
+
"aria-label": "Add full trace to dataset",
|
|
137
146
|
onClick: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }),
|
|
138
147
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SaveIcon, {})
|
|
139
148
|
}
|
|
@@ -172,7 +181,7 @@ function TraceDataPanelView({
|
|
|
172
181
|
/* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.CloseButton, { onClick: onClose })
|
|
173
182
|
] })
|
|
174
183
|
] }) }),
|
|
175
|
-
!collapsed && /* @__PURE__ */ jsxRuntime.jsx(SplitWithSpanPanel, { spanPanelSlot, highlightQuery: query, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.LoadingData, { children: "Loading trace..." }) : !spans?.length ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Content, { children: (() => {
|
|
184
|
+
!collapsed && /* @__PURE__ */ jsxRuntime.jsx(SplitWithSpanPanel, { spanPanelSlot, highlightQuery: query, spanPanelKey: selectedSpanId, children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.LoadingData, { children: "Loading trace..." }) : !spans?.length ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Content, { children: (() => {
|
|
176
185
|
const detailsBody = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
177
186
|
!isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(domains_traces_components_traceKeysAndValues.TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
|
|
178
187
|
!isOnTracePage && !onEvaluateTrace && !onSaveAsDatasetItem && !onAddTraceMocksToItem && showUnavailableFeaturesMsg && /* @__PURE__ */ jsxRuntime.jsx(Notice.Notice, { variant: "info", className: "mb-6", children: /* @__PURE__ */ jsxRuntime.jsx(Notice.Notice.Message, { children: "Evaluating traces and saving them as dataset items is available in Mastra Studio (local or deployed)." }) }),
|
|
@@ -244,9 +253,11 @@ function TraceDataPanelView({
|
|
|
244
253
|
function SplitWithSpanPanel({
|
|
245
254
|
spanPanelSlot,
|
|
246
255
|
highlightQuery,
|
|
256
|
+
spanPanelKey,
|
|
247
257
|
children
|
|
248
258
|
}) {
|
|
249
259
|
const { ref: highlightRef } = hooks_useTextHighlight.useTextHighlight(highlightQuery);
|
|
260
|
+
const { ref: scrollToMatchRef } = hooks_useScrollToFirstHighlight.useScrollToFirstHighlight(highlightQuery, spanPanelKey);
|
|
250
261
|
if (!spanPanelSlot) {
|
|
251
262
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: highlightRef, className: "flex min-h-0 flex-1 flex-col overflow-hidden", children });
|
|
252
263
|
}
|
|
@@ -255,6 +266,7 @@ function SplitWithSpanPanel({
|
|
|
255
266
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
256
267
|
"div",
|
|
257
268
|
{
|
|
269
|
+
ref: scrollToMatchRef,
|
|
258
270
|
"data-highlight": true,
|
|
259
271
|
className: "animate-in border-border1 fade-in-0 flex min-h-0 flex-col overflow-hidden border-l duration-300",
|
|
260
272
|
children: spanPanelSlot
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-data-panel-view.cjs.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useId, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { useTraceSearch } from '../hooks/use-trace-search';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport type { SearchableSpan } from '../types';\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 { SearchFieldBlock } from '@/ds/components/FormFieldBlocks';\nimport { Notice } from '@/ds/components/Notice';\nimport { Tab, TabContent, TabList, Tabs } from '@/ds/components/Tabs';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { useTextHighlight } from '@/hooks/use-text-highlight';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'scores' | 'feedback';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: SearchableSpan[] | 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 * When provided, the panel content becomes tabbed (\"Details\" / \"Scores\"); the slot\n * renders whatever trace-level scoring UI the consumer wants.\n */\n scoresTabSlot?: (args: { traceId: string; rootSpanId: string | undefined }) => ReactNode;\n /** Optional count shown in the \"Scores\" tab label. */\n scoresTabBadge?: ReactNode;\n /**\n * When provided, a \"Feedback\" tab appears; the slot renders the trace-level\n * feedback UI. Trace feedback is not scoped to a span — the span panel owns that.\n */\n feedbackTabSlot?: (args: { traceId: string }) => ReactNode;\n /** Optional count shown in the \"Feedback\" tab label. */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /**\n * When provided, the panel splits into two columns inside the same card: the\n * trace content on the left, this slot (typically the span detail) on the right.\n */\n spanPanelSlot?: ReactNode;\n /** Extra classes applied to the panel root (e.g. `h-full` on the trace page). */\n className?: string;\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 scoresTabSlot,\n scoresTabBadge,\n feedbackTabSlot,\n feedbackTabBadge,\n activeTab,\n onTabChange,\n spanPanelSlot,\n className,\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 searchFieldName = useId();\n const { query, setQuery, results } = useTraceSearch(spans ?? []);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(results, anchorSpanId), [results, 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} className={className}>\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 {onEvaluateTrace && (\n <Button size=\"md\" tooltip=\"Evaluate trace\" aria-label=\"Evaluate trace\" onClick={onEvaluateTrace}>\n <CircleGaugeIcon />\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button\n size=\"md\"\n tooltip=\"Save as Dataset Item\"\n aria-label=\"Save as Dataset Item\"\n onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}\n >\n <SaveIcon />\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button\n size=\"md\"\n tooltip=\"Add tool mocks to item\"\n aria-label=\"Add tool mocks to item\"\n onClick={() => onAddTraceMocksToItem({ traceId })}\n >\n <WrenchIcon />\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 <SplitWithSpanPanel spanPanelSlot={spanPanelSlot} highlightQuery={query}>\n {isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : !spans?.length ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {(() => {\n const detailsBody = (\n <>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\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 {/* The timeline stays mounted even with no results, because it\n hosts the search field: unmounting it would strand the user\n with a query they can no longer clear. */}\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n leadingSlot={\n <SearchFieldBlock\n name={searchFieldName}\n label=\"Search spans\"\n labelIsHidden\n placeholder=\"Search spans...\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n onReset={() => setQuery('')}\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n />\n }\n />\n\n {hierarchicalSpans.length === 0 && <DataPanel.NoData>No spans match your search.</DataPanel.NoData>}\n </>\n );\n\n // No extra tab slots → render details directly without the Tabs wrapper.\n if (!scoresTabSlot && !feedbackTabSlot) return detailsBody;\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={onTabChange}\n className={\n activeTab === 'scores' || activeTab === 'feedback'\n ? 'grid h-full min-h-0 grid-rows-[auto_1fr]'\n : undefined\n }\n >\n <TabList variant=\"pill-ghost\" className=\"px-0\">\n <Tab value=\"details\">Details</Tab>\n {scoresTabSlot && (\n <Tab value=\"scores\">Evaluations {scoresTabBadge != null && <>({scoresTabBadge})</>}</Tab>\n )}\n {feedbackTabSlot && (\n <Tab value=\"feedback\">Feedback {feedbackTabBadge != null && <>({feedbackTabBadge})</>}</Tab>\n )}\n </TabList>\n\n <TabContent value=\"details\">{detailsBody}</TabContent>\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0\">\n {scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}\n </TabContent>\n )}\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0\">\n {feedbackTabSlot({ traceId })}\n </TabContent>\n )}\n </Tabs>\n );\n })()}\n </DataPanel.Content>\n )}\n </SplitWithSpanPanel>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Renders the trace content as-is, or — when a span panel is provided — as a\n * two-column split inside the same card, with the span detail on the right.\n * Search matches — span names in the timeline tree as well as values in the span\n * detail — are highlighted while a query is active.\n */\nfunction SplitWithSpanPanel({\n spanPanelSlot,\n highlightQuery,\n children,\n}: {\n spanPanelSlot?: ReactNode;\n highlightQuery: string;\n children: ReactNode;\n}) {\n // A single hook call on the common ancestor covers both the timeline tree and\n // the span detail, so span names and payload values highlight together.\n const { ref: highlightRef } = useTextHighlight<HTMLDivElement>(highlightQuery);\n\n if (!spanPanelSlot) {\n return (\n <div ref={highlightRef} className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n {children}\n </div>\n );\n }\n\n return (\n <div ref={highlightRef} className=\"grid min-h-0 flex-1 grid-cols-[1fr_1fr]\">\n <div className=\"flex min-h-0 flex-col overflow-hidden\">{children}</div>\n {/* Searchable: the span detail is where a match hides inside a large payload. */}\n <div\n data-highlight\n className=\"animate-in border-border1 fade-in-0 flex min-h-0 flex-col overflow-hidden border-l duration-300\"\n >\n {spanPanelSlot}\n </div>\n </div>\n );\n}\n"],"names":["useState","useDownloadTraceJson","useEffect","useId","useTraceSearch","useMemo","formatHierarchicalSpans","getAllSpanIds","jsx","Button","Loader2Icon","DownloadIcon","jsxs","DataPanel","Fragment","ButtonsGroup","truncateString","ChevronsUpDownIcon","ChevronsDownUpIcon","CircleGaugeIcon","SaveIcon","WrenchIcon","Link2Icon","TraceKeysAndValues","Notice","TraceTimeline","SearchFieldBlock","Tabs","TabList","Tab","TabContent","useTextHighlight"],"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 {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useId, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { useTraceSearch } from '../hooks/use-trace-search';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport type { SearchableSpan } from '../types';\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 { SearchFieldBlock } from '@/ds/components/FormFieldBlocks';\nimport { Notice } from '@/ds/components/Notice';\nimport { Tab, TabContent, TabList, Tabs } from '@/ds/components/Tabs';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { useScrollToFirstHighlight } from '@/hooks/use-scroll-to-first-highlight';\nimport { useTextHighlight } from '@/hooks/use-text-highlight';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'scores' | 'feedback';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: SearchableSpan[] | 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, an \"Add full trace to dataset\" 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 * When provided, the panel content becomes tabbed (\"Details\" / \"Scores\"); the slot\n * renders whatever trace-level scoring UI the consumer wants.\n */\n scoresTabSlot?: (args: { traceId: string; rootSpanId: string | undefined }) => ReactNode;\n /** Optional count shown in the \"Scores\" tab label. */\n scoresTabBadge?: ReactNode;\n /**\n * When provided, a \"Feedback\" tab appears; the slot renders the trace-level\n * feedback UI. Trace feedback is not scoped to a span — the span panel owns that.\n */\n feedbackTabSlot?: (args: { traceId: string }) => ReactNode;\n /** Optional count shown in the \"Feedback\" tab label. */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /**\n * When provided, the panel splits into two columns inside the same card: the\n * trace content on the left, this slot (typically the span detail) on the right.\n */\n spanPanelSlot?: ReactNode;\n /** Extra classes applied to the panel root (e.g. `h-full` on the trace page). */\n className?: string;\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 scoresTabSlot,\n scoresTabBadge,\n feedbackTabSlot,\n feedbackTabBadge,\n activeTab,\n onTabChange,\n spanPanelSlot,\n className,\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 searchFieldName = useId();\n const { query, setQuery, results, payloadOnlyMatchIds } = useTraceSearch(spans ?? []);\n\n const hierarchicalSpans = useMemo(\n () =>\n formatHierarchicalSpans(\n // Carried on the span rather than drilled as a prop: the tree is rebuilt here and\n // rendered several components deeper.\n results.map(span => ({ ...span, matchedInPayloadOnly: payloadOnlyMatchIds.has(span.spanId) })),\n anchorSpanId,\n ),\n [results, payloadOnlyMatchIds, anchorSpanId],\n );\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} className={className}>\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 {onEvaluateTrace && (\n <Button size=\"md\" tooltip=\"Evaluate trace\" aria-label=\"Evaluate trace\" onClick={onEvaluateTrace}>\n <CircleGaugeIcon />\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button\n size=\"md\"\n tooltip=\"Add full trace to dataset\"\n aria-label=\"Add full trace to dataset\"\n onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}\n >\n <SaveIcon />\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button\n size=\"md\"\n tooltip=\"Add tool mocks to item\"\n aria-label=\"Add tool mocks to item\"\n onClick={() => onAddTraceMocksToItem({ traceId })}\n >\n <WrenchIcon />\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 <SplitWithSpanPanel spanPanelSlot={spanPanelSlot} highlightQuery={query} spanPanelKey={selectedSpanId}>\n {isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : !spans?.length ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {(() => {\n const detailsBody = (\n <>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\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 {/* The timeline stays mounted even with no results, because it\n hosts the search field: unmounting it would strand the user\n with a query they can no longer clear. */}\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n leadingSlot={\n <SearchFieldBlock\n name={searchFieldName}\n label=\"Search spans\"\n labelIsHidden\n placeholder=\"Search spans...\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n onReset={() => setQuery('')}\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n />\n }\n />\n\n {hierarchicalSpans.length === 0 && <DataPanel.NoData>No spans match your search.</DataPanel.NoData>}\n </>\n );\n\n // No extra tab slots → render details directly without the Tabs wrapper.\n if (!scoresTabSlot && !feedbackTabSlot) return detailsBody;\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={onTabChange}\n className={\n activeTab === 'scores' || activeTab === 'feedback'\n ? 'grid h-full min-h-0 grid-rows-[auto_1fr]'\n : undefined\n }\n >\n <TabList variant=\"pill-ghost\" className=\"px-0\">\n <Tab value=\"details\">Details</Tab>\n {scoresTabSlot && (\n <Tab value=\"scores\">Evaluations {scoresTabBadge != null && <>({scoresTabBadge})</>}</Tab>\n )}\n {feedbackTabSlot && (\n <Tab value=\"feedback\">Feedback {feedbackTabBadge != null && <>({feedbackTabBadge})</>}</Tab>\n )}\n </TabList>\n\n <TabContent value=\"details\">{detailsBody}</TabContent>\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0\">\n {scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}\n </TabContent>\n )}\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0\">\n {feedbackTabSlot({ traceId })}\n </TabContent>\n )}\n </Tabs>\n );\n })()}\n </DataPanel.Content>\n )}\n </SplitWithSpanPanel>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Renders the trace content as-is, or — when a span panel is provided — as a\n * two-column split inside the same card, with the span detail on the right.\n * Search matches — span names in the timeline tree as well as values in the span\n * detail — are highlighted while a query is active.\n */\nfunction SplitWithSpanPanel({\n spanPanelSlot,\n highlightQuery,\n spanPanelKey,\n children,\n}: {\n spanPanelSlot?: ReactNode;\n highlightQuery: string;\n /** Identity of the span shown in the panel; changing it re-triggers the match scroll. */\n spanPanelKey?: string;\n children: ReactNode;\n}) {\n // A single hook call on the common ancestor covers both the timeline tree and\n // the span detail, so span names and payload values highlight together.\n const { ref: highlightRef } = useTextHighlight<HTMLDivElement>(highlightQuery);\n\n // Scoped to the span-panel column only: a match deep in a large payload sits below\n // the fold, so the first painted match is brought into view when the panel opens.\n // The timeline column must never be scrolled by this.\n const { ref: scrollToMatchRef } = useScrollToFirstHighlight<HTMLDivElement>(highlightQuery, spanPanelKey);\n\n if (!spanPanelSlot) {\n return (\n <div ref={highlightRef} className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n {children}\n </div>\n );\n }\n\n return (\n <div ref={highlightRef} className=\"grid min-h-0 flex-1 grid-cols-[1fr_1fr]\">\n <div className=\"flex min-h-0 flex-col overflow-hidden\">{children}</div>\n {/* Searchable: the span detail is where a match hides inside a large payload. */}\n <div\n ref={scrollToMatchRef}\n data-highlight\n className=\"animate-in border-border1 fade-in-0 flex min-h-0 flex-col overflow-hidden border-l duration-300\"\n >\n {spanPanelSlot}\n </div>\n </div>\n );\n}\n"],"names":["useState","useDownloadTraceJson","useEffect","useId","useTraceSearch","useMemo","formatHierarchicalSpans","getAllSpanIds","jsx","Button","Loader2Icon","DownloadIcon","jsxs","DataPanel","Fragment","ButtonsGroup","truncateString","ChevronsUpDownIcon","ChevronsDownUpIcon","CircleGaugeIcon","SaveIcon","WrenchIcon","Link2Icon","TraceKeysAndValues","Notice","TraceTimeline","SearchFieldBlock","Tabs","TabList","Tab","TabContent","useTextHighlight","useScrollToFirstHighlight"],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ import { N as Notice } from '../../../Notice-XR_HdGMF.js';
|
|
|
15
15
|
import { a as Tabs, T as TabList } from '../../../tabs-root-BBPou4QC.js';
|
|
16
16
|
import { T as Tab } from '../../../tabs-tab-mZ-Tl7-d.js';
|
|
17
17
|
import { T as TabContent } from '../../../tabs-content-XUh680fO.js';
|
|
18
|
+
import { useScrollToFirstHighlight } from '../../../hooks/use-scroll-to-first-highlight.es.js';
|
|
18
19
|
import { useTextHighlight } from '../../../hooks/use-text-highlight.es.js';
|
|
19
20
|
import { truncateString } from '../../../utils/truncate-string.es.js';
|
|
20
21
|
|
|
@@ -71,8 +72,16 @@ function TraceDataPanelView({
|
|
|
71
72
|
}
|
|
72
73
|
}, [initialSpanId, spans, isLoading]);
|
|
73
74
|
const searchFieldName = useId();
|
|
74
|
-
const { query, setQuery, results } = useTraceSearch(spans ?? []);
|
|
75
|
-
const hierarchicalSpans = useMemo(
|
|
75
|
+
const { query, setQuery, results, payloadOnlyMatchIds } = useTraceSearch(spans ?? []);
|
|
76
|
+
const hierarchicalSpans = useMemo(
|
|
77
|
+
() => formatHierarchicalSpans(
|
|
78
|
+
// Carried on the span rather than drilled as a prop: the tree is rebuilt here and
|
|
79
|
+
// rendered several components deeper.
|
|
80
|
+
results.map((span) => ({ ...span, matchedInPayloadOnly: payloadOnlyMatchIds.has(span.spanId) })),
|
|
81
|
+
anchorSpanId
|
|
82
|
+
),
|
|
83
|
+
[results, payloadOnlyMatchIds, anchorSpanId]
|
|
84
|
+
);
|
|
76
85
|
const [expandedSpanIds, setExpandedSpanIds] = useState([]);
|
|
77
86
|
useEffect(() => {
|
|
78
87
|
if (hierarchicalSpans.length > 0) {
|
|
@@ -128,8 +137,8 @@ function TraceDataPanelView({
|
|
|
128
137
|
Button,
|
|
129
138
|
{
|
|
130
139
|
size: "md",
|
|
131
|
-
tooltip: "
|
|
132
|
-
"aria-label": "
|
|
140
|
+
tooltip: "Add full trace to dataset",
|
|
141
|
+
"aria-label": "Add full trace to dataset",
|
|
133
142
|
onClick: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }),
|
|
134
143
|
children: /* @__PURE__ */ jsx(SaveIcon, {})
|
|
135
144
|
}
|
|
@@ -168,7 +177,7 @@ function TraceDataPanelView({
|
|
|
168
177
|
/* @__PURE__ */ jsx(DataPanel.CloseButton, { onClick: onClose })
|
|
169
178
|
] })
|
|
170
179
|
] }) }),
|
|
171
|
-
!collapsed && /* @__PURE__ */ jsx(SplitWithSpanPanel, { spanPanelSlot, highlightQuery: query, children: isLoading ? /* @__PURE__ */ jsx(DataPanel.LoadingData, { children: "Loading trace..." }) : !spans?.length ? /* @__PURE__ */ jsx(DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsx(DataPanel.Content, { children: (() => {
|
|
180
|
+
!collapsed && /* @__PURE__ */ jsx(SplitWithSpanPanel, { spanPanelSlot, highlightQuery: query, spanPanelKey: selectedSpanId, children: isLoading ? /* @__PURE__ */ jsx(DataPanel.LoadingData, { children: "Loading trace..." }) : !spans?.length ? /* @__PURE__ */ jsx(DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsx(DataPanel.Content, { children: (() => {
|
|
172
181
|
const detailsBody = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
173
182
|
!isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
|
|
174
183
|
!isOnTracePage && !onEvaluateTrace && !onSaveAsDatasetItem && !onAddTraceMocksToItem && showUnavailableFeaturesMsg && /* @__PURE__ */ jsx(Notice, { variant: "info", className: "mb-6", children: /* @__PURE__ */ jsx(Notice.Message, { children: "Evaluating traces and saving them as dataset items is available in Mastra Studio (local or deployed)." }) }),
|
|
@@ -240,9 +249,11 @@ function TraceDataPanelView({
|
|
|
240
249
|
function SplitWithSpanPanel({
|
|
241
250
|
spanPanelSlot,
|
|
242
251
|
highlightQuery,
|
|
252
|
+
spanPanelKey,
|
|
243
253
|
children
|
|
244
254
|
}) {
|
|
245
255
|
const { ref: highlightRef } = useTextHighlight(highlightQuery);
|
|
256
|
+
const { ref: scrollToMatchRef } = useScrollToFirstHighlight(highlightQuery, spanPanelKey);
|
|
246
257
|
if (!spanPanelSlot) {
|
|
247
258
|
return /* @__PURE__ */ jsx("div", { ref: highlightRef, className: "flex min-h-0 flex-1 flex-col overflow-hidden", children });
|
|
248
259
|
}
|
|
@@ -251,6 +262,7 @@ function SplitWithSpanPanel({
|
|
|
251
262
|
/* @__PURE__ */ jsx(
|
|
252
263
|
"div",
|
|
253
264
|
{
|
|
265
|
+
ref: scrollToMatchRef,
|
|
254
266
|
"data-highlight": true,
|
|
255
267
|
className: "animate-in border-border1 fade-in-0 flex min-h-0 flex-col overflow-hidden border-l duration-300",
|
|
256
268
|
children: spanPanelSlot
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useId, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { useTraceSearch } from '../hooks/use-trace-search';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport type { SearchableSpan } from '../types';\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 { SearchFieldBlock } from '@/ds/components/FormFieldBlocks';\nimport { Notice } from '@/ds/components/Notice';\nimport { Tab, TabContent, TabList, Tabs } from '@/ds/components/Tabs';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { useTextHighlight } from '@/hooks/use-text-highlight';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'scores' | 'feedback';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: SearchableSpan[] | 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 * When provided, the panel content becomes tabbed (\"Details\" / \"Scores\"); the slot\n * renders whatever trace-level scoring UI the consumer wants.\n */\n scoresTabSlot?: (args: { traceId: string; rootSpanId: string | undefined }) => ReactNode;\n /** Optional count shown in the \"Scores\" tab label. */\n scoresTabBadge?: ReactNode;\n /**\n * When provided, a \"Feedback\" tab appears; the slot renders the trace-level\n * feedback UI. Trace feedback is not scoped to a span — the span panel owns that.\n */\n feedbackTabSlot?: (args: { traceId: string }) => ReactNode;\n /** Optional count shown in the \"Feedback\" tab label. */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /**\n * When provided, the panel splits into two columns inside the same card: the\n * trace content on the left, this slot (typically the span detail) on the right.\n */\n spanPanelSlot?: ReactNode;\n /** Extra classes applied to the panel root (e.g. `h-full` on the trace page). */\n className?: string;\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 scoresTabSlot,\n scoresTabBadge,\n feedbackTabSlot,\n feedbackTabBadge,\n activeTab,\n onTabChange,\n spanPanelSlot,\n className,\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 searchFieldName = useId();\n const { query, setQuery, results } = useTraceSearch(spans ?? []);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(results, anchorSpanId), [results, 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} className={className}>\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 {onEvaluateTrace && (\n <Button size=\"md\" tooltip=\"Evaluate trace\" aria-label=\"Evaluate trace\" onClick={onEvaluateTrace}>\n <CircleGaugeIcon />\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button\n size=\"md\"\n tooltip=\"Save as Dataset Item\"\n aria-label=\"Save as Dataset Item\"\n onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}\n >\n <SaveIcon />\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button\n size=\"md\"\n tooltip=\"Add tool mocks to item\"\n aria-label=\"Add tool mocks to item\"\n onClick={() => onAddTraceMocksToItem({ traceId })}\n >\n <WrenchIcon />\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 <SplitWithSpanPanel spanPanelSlot={spanPanelSlot} highlightQuery={query}>\n {isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : !spans?.length ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {(() => {\n const detailsBody = (\n <>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\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 {/* The timeline stays mounted even with no results, because it\n hosts the search field: unmounting it would strand the user\n with a query they can no longer clear. */}\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n leadingSlot={\n <SearchFieldBlock\n name={searchFieldName}\n label=\"Search spans\"\n labelIsHidden\n placeholder=\"Search spans...\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n onReset={() => setQuery('')}\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n />\n }\n />\n\n {hierarchicalSpans.length === 0 && <DataPanel.NoData>No spans match your search.</DataPanel.NoData>}\n </>\n );\n\n // No extra tab slots → render details directly without the Tabs wrapper.\n if (!scoresTabSlot && !feedbackTabSlot) return detailsBody;\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={onTabChange}\n className={\n activeTab === 'scores' || activeTab === 'feedback'\n ? 'grid h-full min-h-0 grid-rows-[auto_1fr]'\n : undefined\n }\n >\n <TabList variant=\"pill-ghost\" className=\"px-0\">\n <Tab value=\"details\">Details</Tab>\n {scoresTabSlot && (\n <Tab value=\"scores\">Evaluations {scoresTabBadge != null && <>({scoresTabBadge})</>}</Tab>\n )}\n {feedbackTabSlot && (\n <Tab value=\"feedback\">Feedback {feedbackTabBadge != null && <>({feedbackTabBadge})</>}</Tab>\n )}\n </TabList>\n\n <TabContent value=\"details\">{detailsBody}</TabContent>\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0\">\n {scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}\n </TabContent>\n )}\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0\">\n {feedbackTabSlot({ traceId })}\n </TabContent>\n )}\n </Tabs>\n );\n })()}\n </DataPanel.Content>\n )}\n </SplitWithSpanPanel>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Renders the trace content as-is, or — when a span panel is provided — as a\n * two-column split inside the same card, with the span detail on the right.\n * Search matches — span names in the timeline tree as well as values in the span\n * detail — are highlighted while a query is active.\n */\nfunction SplitWithSpanPanel({\n spanPanelSlot,\n highlightQuery,\n children,\n}: {\n spanPanelSlot?: ReactNode;\n highlightQuery: string;\n children: ReactNode;\n}) {\n // A single hook call on the common ancestor covers both the timeline tree and\n // the span detail, so span names and payload values highlight together.\n const { ref: highlightRef } = useTextHighlight<HTMLDivElement>(highlightQuery);\n\n if (!spanPanelSlot) {\n return (\n <div ref={highlightRef} className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n {children}\n </div>\n );\n }\n\n return (\n <div ref={highlightRef} className=\"grid min-h-0 flex-1 grid-cols-[1fr_1fr]\">\n <div className=\"flex min-h-0 flex-col overflow-hidden\">{children}</div>\n {/* Searchable: the span detail is where a match hides inside a large payload. */}\n <div\n data-highlight\n className=\"animate-in border-border1 fade-in-0 flex min-h-0 flex-col overflow-hidden border-l duration-300\"\n >\n {spanPanelSlot}\n </div>\n </div>\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 {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useId, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { useTraceSearch } from '../hooks/use-trace-search';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport type { SearchableSpan } from '../types';\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 { SearchFieldBlock } from '@/ds/components/FormFieldBlocks';\nimport { Notice } from '@/ds/components/Notice';\nimport { Tab, TabContent, TabList, Tabs } from '@/ds/components/Tabs';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { useScrollToFirstHighlight } from '@/hooks/use-scroll-to-first-highlight';\nimport { useTextHighlight } from '@/hooks/use-text-highlight';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'scores' | 'feedback';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: SearchableSpan[] | 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, an \"Add full trace to dataset\" 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 * When provided, the panel content becomes tabbed (\"Details\" / \"Scores\"); the slot\n * renders whatever trace-level scoring UI the consumer wants.\n */\n scoresTabSlot?: (args: { traceId: string; rootSpanId: string | undefined }) => ReactNode;\n /** Optional count shown in the \"Scores\" tab label. */\n scoresTabBadge?: ReactNode;\n /**\n * When provided, a \"Feedback\" tab appears; the slot renders the trace-level\n * feedback UI. Trace feedback is not scoped to a span — the span panel owns that.\n */\n feedbackTabSlot?: (args: { traceId: string }) => ReactNode;\n /** Optional count shown in the \"Feedback\" tab label. */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /**\n * When provided, the panel splits into two columns inside the same card: the\n * trace content on the left, this slot (typically the span detail) on the right.\n */\n spanPanelSlot?: ReactNode;\n /** Extra classes applied to the panel root (e.g. `h-full` on the trace page). */\n className?: string;\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 scoresTabSlot,\n scoresTabBadge,\n feedbackTabSlot,\n feedbackTabBadge,\n activeTab,\n onTabChange,\n spanPanelSlot,\n className,\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 searchFieldName = useId();\n const { query, setQuery, results, payloadOnlyMatchIds } = useTraceSearch(spans ?? []);\n\n const hierarchicalSpans = useMemo(\n () =>\n formatHierarchicalSpans(\n // Carried on the span rather than drilled as a prop: the tree is rebuilt here and\n // rendered several components deeper.\n results.map(span => ({ ...span, matchedInPayloadOnly: payloadOnlyMatchIds.has(span.spanId) })),\n anchorSpanId,\n ),\n [results, payloadOnlyMatchIds, anchorSpanId],\n );\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} className={className}>\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 {onEvaluateTrace && (\n <Button size=\"md\" tooltip=\"Evaluate trace\" aria-label=\"Evaluate trace\" onClick={onEvaluateTrace}>\n <CircleGaugeIcon />\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button\n size=\"md\"\n tooltip=\"Add full trace to dataset\"\n aria-label=\"Add full trace to dataset\"\n onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}\n >\n <SaveIcon />\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button\n size=\"md\"\n tooltip=\"Add tool mocks to item\"\n aria-label=\"Add tool mocks to item\"\n onClick={() => onAddTraceMocksToItem({ traceId })}\n >\n <WrenchIcon />\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 <SplitWithSpanPanel spanPanelSlot={spanPanelSlot} highlightQuery={query} spanPanelKey={selectedSpanId}>\n {isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : !spans?.length ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {(() => {\n const detailsBody = (\n <>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\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 {/* The timeline stays mounted even with no results, because it\n hosts the search field: unmounting it would strand the user\n with a query they can no longer clear. */}\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n leadingSlot={\n <SearchFieldBlock\n name={searchFieldName}\n label=\"Search spans\"\n labelIsHidden\n placeholder=\"Search spans...\"\n value={query}\n onChange={e => setQuery(e.target.value)}\n onReset={() => setQuery('')}\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n />\n }\n />\n\n {hierarchicalSpans.length === 0 && <DataPanel.NoData>No spans match your search.</DataPanel.NoData>}\n </>\n );\n\n // No extra tab slots → render details directly without the Tabs wrapper.\n if (!scoresTabSlot && !feedbackTabSlot) return detailsBody;\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={onTabChange}\n className={\n activeTab === 'scores' || activeTab === 'feedback'\n ? 'grid h-full min-h-0 grid-rows-[auto_1fr]'\n : undefined\n }\n >\n <TabList variant=\"pill-ghost\" className=\"px-0\">\n <Tab value=\"details\">Details</Tab>\n {scoresTabSlot && (\n <Tab value=\"scores\">Evaluations {scoresTabBadge != null && <>({scoresTabBadge})</>}</Tab>\n )}\n {feedbackTabSlot && (\n <Tab value=\"feedback\">Feedback {feedbackTabBadge != null && <>({feedbackTabBadge})</>}</Tab>\n )}\n </TabList>\n\n <TabContent value=\"details\">{detailsBody}</TabContent>\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0\">\n {scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}\n </TabContent>\n )}\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0\">\n {feedbackTabSlot({ traceId })}\n </TabContent>\n )}\n </Tabs>\n );\n })()}\n </DataPanel.Content>\n )}\n </SplitWithSpanPanel>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Renders the trace content as-is, or — when a span panel is provided — as a\n * two-column split inside the same card, with the span detail on the right.\n * Search matches — span names in the timeline tree as well as values in the span\n * detail — are highlighted while a query is active.\n */\nfunction SplitWithSpanPanel({\n spanPanelSlot,\n highlightQuery,\n spanPanelKey,\n children,\n}: {\n spanPanelSlot?: ReactNode;\n highlightQuery: string;\n /** Identity of the span shown in the panel; changing it re-triggers the match scroll. */\n spanPanelKey?: string;\n children: ReactNode;\n}) {\n // A single hook call on the common ancestor covers both the timeline tree and\n // the span detail, so span names and payload values highlight together.\n const { ref: highlightRef } = useTextHighlight<HTMLDivElement>(highlightQuery);\n\n // Scoped to the span-panel column only: a match deep in a large payload sits below\n // the fold, so the first painted match is brought into view when the panel opens.\n // The timeline column must never be scrolled by this.\n const { ref: scrollToMatchRef } = useScrollToFirstHighlight<HTMLDivElement>(highlightQuery, spanPanelKey);\n\n if (!spanPanelSlot) {\n return (\n <div ref={highlightRef} className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n {children}\n </div>\n );\n }\n\n return (\n <div ref={highlightRef} className=\"grid min-h-0 flex-1 grid-cols-[1fr_1fr]\">\n <div className=\"flex min-h-0 flex-col overflow-hidden\">{children}</div>\n {/* Searchable: the span detail is where a match hides inside a large payload. */}\n <div\n ref={scrollToMatchRef}\n data-highlight\n className=\"animate-in border-border1 fade-in-0 flex min-h-0 flex-col overflow-hidden border-l duration-300\"\n >\n {spanPanelSlot}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -8,9 +8,9 @@ const React = require('react');
|
|
|
8
8
|
const domains_traces_traceListColumns = require('../trace-list-columns.cjs.js');
|
|
9
9
|
const domains_traces_utils_spanUtils = require('../utils/span-utils.cjs.js');
|
|
10
10
|
const domains_metrics_components_metricsUtils = require('../../metrics/components/metrics-utils.cjs.js');
|
|
11
|
-
const dataList = require('../../../data-list-
|
|
12
|
-
const dataListSkeleton = require('../../../data-list-skeleton-
|
|
13
|
-
const tracesDataList = require('../../../traces-data-list-
|
|
11
|
+
const dataList = require('../../../data-list-CRDewYj9.cjs');
|
|
12
|
+
const dataListSkeleton = require('../../../data-list-skeleton-CONfqzH2.cjs');
|
|
13
|
+
const tracesDataList = require('../../../traces-data-list-COksp2d4.cjs');
|
|
14
14
|
const useDataListKeyboard = require('../../../use-data-list-keyboard-k5D-WlNX.cjs');
|
|
15
15
|
const utils_cn = require('../../../cn-vA5sWo9W.cjs');
|
|
16
16
|
|
|
@@ -52,16 +52,15 @@ function TracesListView({
|
|
|
52
52
|
wasLoadingRef.current = isLoading;
|
|
53
53
|
}, [isLoading]);
|
|
54
54
|
if (isLoading) {
|
|
55
|
-
return /* @__PURE__ */ jsxRuntime.jsx(dataListSkeleton.DataListSkeleton, { columns });
|
|
55
|
+
return /* @__PURE__ */ jsxRuntime.jsx(dataListSkeleton.DataListSkeleton, { columns, fit: "container" });
|
|
56
56
|
}
|
|
57
57
|
const virtualItems = virtualizer.getVirtualItems();
|
|
58
58
|
const totalSize = virtualizer.getTotalSize();
|
|
59
59
|
const paddingTop = virtualItems[0]?.start ?? 0;
|
|
60
60
|
const paddingBottom = virtualItems.length > 0 ? Math.max(0, totalSize - (virtualItems[virtualItems.length - 1]?.end ?? 0)) : 0;
|
|
61
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(tracesDataList.TracesDataList, { columns, variant: "striped", scrollRef, className: "min-w-0", children: [
|
|
61
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(tracesDataList.TracesDataList, { columns, variant: "striped", fit: "container", scrollRef, className: "min-w-0", children: [
|
|
62
62
|
/* @__PURE__ */ jsxRuntime.jsxs(tracesDataList.TracesDataList.Top, { children: [
|
|
63
|
-
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TopCell, { children: "
|
|
64
|
-
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TopCell, { children: "Time" }),
|
|
63
|
+
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TopCell, { children: "Created" }),
|
|
65
64
|
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TopCell, { children: "Name" }),
|
|
66
65
|
domains_traces_traceListColumns.hasTraceColumn(columnPreferences, "input") && /* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TopCell, { children: "Input" }),
|
|
67
66
|
domains_traces_traceListColumns.hasTraceColumn(columnPreferences, "entity") && /* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TopCell, { children: "Entity" }),
|
|
@@ -98,8 +97,7 @@ function TracesListView({
|
|
|
98
97
|
featured: isFeatured,
|
|
99
98
|
className: utils_cn.cn(isRecentlyAdded && "animate-row-highlight"),
|
|
100
99
|
children: [
|
|
101
|
-
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.
|
|
102
|
-
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.TimeCell, { timestamp: displayDate }),
|
|
100
|
+
/* @__PURE__ */ jsxRuntime.jsx(tracesDataList.TracesDataList.CreatedCell, { timestamp: displayDate }),
|
|
103
101
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
104
102
|
tracesDataList.TracesDataList.NameCell,
|
|
105
103
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traces-list-view.cjs.js","sources":["../../../../src/domains/traces/components/traces-list-view.tsx"],"sourcesContent":["import { useVirtualizer } from '@tanstack/react-virtual';\nimport { useEffect, useRef } from 'react';\nimport {\n DEFAULT_TRACE_COLUMN_PREFERENCES,\n buildTraceListColumns,\n formatTraceMetadataValue,\n hasTraceColumn,\n} from '../trace-list-columns';\nimport type { TraceColumnPreferences, TraceUsageSummary } from '../trace-list-columns';\nimport { formatSpanDuration, getInputPreview } from '../utils/span-utils';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { DataList, DataListSkeleton, TracesDataList, useDataListKeyboard } from '@/ds/components/DataList';\nimport { cn } from '@/lib/utils';\n\nexport type TracesListViewTrace = {\n traceId: string;\n /** Required for branch rows; absent on plain trace rows (which are root-rooted). */\n spanId?: string | null;\n /** `null`/missing → root span. Drives the Kind column's icon (top-level trace vs nested branch). */\n parentSpanId?: string | null;\n name: string;\n entityType?: string | null;\n entityId?: string | null;\n entityName?: string | null;\n status?: string | null;\n /** Server-rendered preview of `input`. Present on lightweight rows, which omit `input` itself. */\n inputPreview?: string | null;\n input?: unknown;\n metadata?: Record<string, unknown> | null;\n startedAt?: Date | string | null;\n endedAt?: Date | string | null;\n createdAt: Date | string;\n};\n\nconst ROW_HEIGHT = 36;\nconst OVERSCAN = 8;\n\nexport type TracesListViewProps = {\n traces: TracesListViewTrace[];\n isLoading?: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n setEndOfListElement?: (element: HTMLDivElement | null) => void;\n filtersApplied?: boolean;\n /** Currently featured/selected trace — its row gets the highlighted background. */\n featuredTraceId?: string | null;\n /**\n * Required in branches mode to disambiguate rows sharing a `traceId`. When set,\n * a row is featured only when both `traceId` and `spanId` match.\n */\n featuredSpanId?: string | null;\n /** Branches mode mixes root traces with subtraces — enables the Trace/Subtrace tooltip on the\n * level icon in the Name column, which is meaningless when every row is a root. */\n isBranchesMode?: boolean;\n /** Keys (`traceId:spanId`) of rows that just arrived via delta polling. Rows whose key is in\n * this set get a temporary tint to distinguish them from rows present since the last page-mode\n * fetch. Auto-expires upstream (in useTraces) after a short window. */\n recentlyAddedKeys?: Set<string>;\n /** Optional and metadata columns selected for this project. */\n columnPreferences?: TraceColumnPreferences;\n /** Token and estimated-cost totals, aggregated across model spans by trace ID. */\n usageByTraceId?: ReadonlyMap<string, TraceUsageSummary>;\n /** Called when a row is clicked. The current selection logic (toggle on same id) is the consumer's call. */\n onTraceClick: (trace: TracesListViewTrace) => void;\n};\n\n/**\n * Virtualized presentational list. Renders only the visible window via TanStack Virtual, and\n * uses DataList primitives for layout (CSS Grid with subgrid rows).\n */\nexport function TracesListView({\n traces,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n setEndOfListElement,\n filtersApplied,\n featuredTraceId,\n featuredSpanId,\n isBranchesMode,\n recentlyAddedKeys,\n columnPreferences = DEFAULT_TRACE_COLUMN_PREFERENCES,\n usageByTraceId,\n onTraceClick,\n}: TracesListViewProps) {\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const columns = buildTraceListColumns(columnPreferences);\n\n const virtualizer = useVirtualizer({\n count: traces.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => ROW_HEIGHT,\n overscan: OVERSCAN,\n });\n\n const { getRowProps } = useDataListKeyboard({\n count: traces.length,\n containerRef: scrollRef,\n onNavigate: index => virtualizer.scrollToIndex(index),\n });\n\n // Reset scroll to top whenever a fresh query resolves (filter / date range change).\n // `isLoading` only flips on initial fetches — `fetchNextPage` keeps it `false`, so this\n // effect doesn't fire during pagination.\n //\n // Why the manual scroll event: when the skeleton-vs-list branch swaps in the new scroll\n // container, it mounts at `scrollTop = 0`. The virtualizer rebinds its listener but\n // doesn't re-read `scrollTop`, so it keeps the stale `scrollOffset` from the previous\n // element. `scrollToOffset(0)` no-ops because the new element is already at 0 (no scroll\n // event fires). Dispatching a synthetic `scroll` forces the virtualizer's handler to\n // read the fresh `scrollTop` and recompute `virtualItems` with `paddingTop = 0`.\n const wasLoadingRef = useRef(isLoading);\n useEffect(() => {\n if (wasLoadingRef.current && !isLoading) {\n scrollRef.current?.dispatchEvent(new Event('scroll'));\n }\n wasLoadingRef.current = isLoading;\n }, [isLoading]);\n\n if (isLoading) {\n return <DataListSkeleton columns={columns} />;\n }\n\n const virtualItems = virtualizer.getVirtualItems();\n const totalSize = virtualizer.getTotalSize();\n const paddingTop = virtualItems[0]?.start ?? 0;\n const paddingBottom =\n virtualItems.length > 0 ? Math.max(0, totalSize - (virtualItems[virtualItems.length - 1]?.end ?? 0)) : 0;\n\n return (\n <TracesDataList columns={columns} variant=\"striped\" scrollRef={scrollRef} className=\"min-w-0\">\n <TracesDataList.Top>\n <TracesDataList.TopCell>Date</TracesDataList.TopCell>\n <TracesDataList.TopCell>Time</TracesDataList.TopCell>\n <TracesDataList.TopCell>Name</TracesDataList.TopCell>\n {hasTraceColumn(columnPreferences, 'input') && <TracesDataList.TopCell>Input</TracesDataList.TopCell>}\n {hasTraceColumn(columnPreferences, 'entity') && <TracesDataList.TopCell>Entity</TracesDataList.TopCell>}\n <TracesDataList.TopCell>Status</TracesDataList.TopCell>\n {hasTraceColumn(columnPreferences, 'duration') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Duration</TracesDataList.TopCell>\n )}\n {hasTraceColumn(columnPreferences, 'inputTokens') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Input tokens</TracesDataList.TopCell>\n )}\n {hasTraceColumn(columnPreferences, 'outputTokens') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Output tokens</TracesDataList.TopCell>\n )}\n {hasTraceColumn(columnPreferences, 'estimatedCost') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Est. cost</TracesDataList.TopCell>\n )}\n {columnPreferences.metadataKeys.map(key => (\n <TracesDataList.TopCellWithTooltip key={key} tooltip={key}>\n {key}\n </TracesDataList.TopCellWithTooltip>\n ))}\n </TracesDataList.Top>\n\n {traces.length === 0 ? (\n <TracesDataList.NoMatch\n message={filtersApplied ? 'No traces found for applied filters' : 'No traces found yet'}\n />\n ) : (\n <>\n <TracesDataList.Spacer height={paddingTop} />\n {virtualItems.map(vi => {\n const trace = traces[vi.index];\n if (!trace) return null;\n\n const isFeatured =\n trace.traceId === featuredTraceId && (featuredSpanId == null || trace.spanId === featuredSpanId);\n const rowKey = `${trace.traceId}:${trace.spanId ?? ''}`;\n const isRecentlyAdded = recentlyAddedKeys?.has(rowKey) ?? false;\n const displayDate = trace.startedAt ?? trace.createdAt;\n const entityName = trace.entityName || trace.entityId;\n const usage = usageByTraceId?.get(trace.traceId);\n\n return (\n <TracesDataList.RowButton\n key={rowKey}\n ref={virtualizer.measureElement}\n data-index={vi.index}\n {...getRowProps(vi.index)}\n onClick={() => onTraceClick(trace)}\n featured={isFeatured}\n className={cn(isRecentlyAdded && 'animate-row-highlight')}\n >\n <TracesDataList.DateCell timestamp={displayDate} />\n <TracesDataList.TimeCell timestamp={displayDate} />\n <TracesDataList.NameCell\n name={trace.name}\n parentSpanId={trace.parentSpanId}\n showLevelTooltip={isBranchesMode}\n />\n {hasTraceColumn(columnPreferences, 'input') && (\n <TracesDataList.InputCell input={trace.inputPreview ?? getInputPreview(trace.input)} />\n )}\n {hasTraceColumn(columnPreferences, 'entity') && (\n <TracesDataList.EntityCell entityType={trace.entityType} entityName={entityName} />\n )}\n <TracesDataList.StatusCell status={trace.status} />\n {hasTraceColumn(columnPreferences, 'duration') && (\n <DataList.NumberCell>{formatSpanDuration(trace.startedAt, trace.endedAt)}</DataList.NumberCell>\n )}\n {hasTraceColumn(columnPreferences, 'inputTokens') && (\n <DataList.NumberCell>\n {usage?.inputTokens === undefined ? undefined : formatCompact(usage.inputTokens)}\n </DataList.NumberCell>\n )}\n {hasTraceColumn(columnPreferences, 'outputTokens') && (\n <DataList.NumberCell>\n {usage?.outputTokens === undefined ? undefined : formatCompact(usage.outputTokens)}\n </DataList.NumberCell>\n )}\n {hasTraceColumn(columnPreferences, 'estimatedCost') && (\n <DataList.NumberCell>\n {usage?.estimatedCost === undefined ? undefined : formatCost(usage.estimatedCost, usage.costUnit)}\n </DataList.NumberCell>\n )}\n {columnPreferences.metadataKeys.map(key => {\n const value = formatTraceMetadataValue(trace.metadata, key);\n return (\n <DataList.TextCell font=\"mono\" key={key}>\n {value}\n </DataList.TextCell>\n );\n })}\n </TracesDataList.RowButton>\n );\n })}\n <TracesDataList.Spacer height={paddingBottom} />\n <TracesDataList.NextPageLoading\n isLoading={isFetchingNextPage}\n hasMore={hasNextPage}\n setEndOfListElement={setEndOfListElement}\n />\n </>\n )}\n </TracesDataList>\n );\n}\n"],"names":["DEFAULT_TRACE_COLUMN_PREFERENCES","useRef","buildTraceListColumns","useVirtualizer","useDataListKeyboard","useEffect","jsx","DataListSkeleton","TracesDataList","jsxs","hasTraceColumn","Fragment","cn","getInputPreview","DataList","formatSpanDuration","formatCompact","formatCost","formatTraceMetadataValue"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"traces-list-view.cjs.js","sources":["../../../../src/domains/traces/components/traces-list-view.tsx"],"sourcesContent":["import { useVirtualizer } from '@tanstack/react-virtual';\nimport { useEffect, useRef } from 'react';\nimport {\n DEFAULT_TRACE_COLUMN_PREFERENCES,\n buildTraceListColumns,\n formatTraceMetadataValue,\n hasTraceColumn,\n} from '../trace-list-columns';\nimport type { TraceColumnPreferences, TraceUsageSummary } from '../trace-list-columns';\nimport { formatSpanDuration, getInputPreview } from '../utils/span-utils';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { DataList, DataListSkeleton, TracesDataList, useDataListKeyboard } from '@/ds/components/DataList';\nimport { cn } from '@/lib/utils';\n\nexport type TracesListViewTrace = {\n traceId: string;\n /** Required for branch rows; absent on plain trace rows (which are root-rooted). */\n spanId?: string | null;\n /** `null`/missing → root span. Drives the Kind column's icon (top-level trace vs nested branch). */\n parentSpanId?: string | null;\n name: string;\n entityType?: string | null;\n entityId?: string | null;\n entityName?: string | null;\n status?: string | null;\n /** Server-rendered preview of `input`. Present on lightweight rows, which omit `input` itself. */\n inputPreview?: string | null;\n input?: unknown;\n metadata?: Record<string, unknown> | null;\n startedAt?: Date | string | null;\n endedAt?: Date | string | null;\n createdAt: Date | string;\n};\n\nconst ROW_HEIGHT = 36;\nconst OVERSCAN = 8;\n\nexport type TracesListViewProps = {\n traces: TracesListViewTrace[];\n isLoading?: boolean;\n isFetchingNextPage?: boolean;\n hasNextPage?: boolean;\n setEndOfListElement?: (element: HTMLDivElement | null) => void;\n filtersApplied?: boolean;\n /** Currently featured/selected trace — its row gets the highlighted background. */\n featuredTraceId?: string | null;\n /**\n * Required in branches mode to disambiguate rows sharing a `traceId`. When set,\n * a row is featured only when both `traceId` and `spanId` match.\n */\n featuredSpanId?: string | null;\n /** Branches mode mixes root traces with subtraces — enables the Trace/Subtrace tooltip on the\n * level icon in the Name column, which is meaningless when every row is a root. */\n isBranchesMode?: boolean;\n /** Keys (`traceId:spanId`) of rows that just arrived via delta polling. Rows whose key is in\n * this set get a temporary tint to distinguish them from rows present since the last page-mode\n * fetch. Auto-expires upstream (in useTraces) after a short window. */\n recentlyAddedKeys?: Set<string>;\n /** Optional and metadata columns selected for this project. */\n columnPreferences?: TraceColumnPreferences;\n /** Token and estimated-cost totals, aggregated across model spans by trace ID. */\n usageByTraceId?: ReadonlyMap<string, TraceUsageSummary>;\n /** Called when a row is clicked. The current selection logic (toggle on same id) is the consumer's call. */\n onTraceClick: (trace: TracesListViewTrace) => void;\n};\n\n/**\n * Virtualized presentational list. Renders only the visible window via TanStack Virtual, and\n * uses DataList primitives for layout (CSS Grid with subgrid rows).\n */\nexport function TracesListView({\n traces,\n isLoading,\n isFetchingNextPage,\n hasNextPage,\n setEndOfListElement,\n filtersApplied,\n featuredTraceId,\n featuredSpanId,\n isBranchesMode,\n recentlyAddedKeys,\n columnPreferences = DEFAULT_TRACE_COLUMN_PREFERENCES,\n usageByTraceId,\n onTraceClick,\n}: TracesListViewProps) {\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const columns = buildTraceListColumns(columnPreferences);\n\n const virtualizer = useVirtualizer({\n count: traces.length,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => ROW_HEIGHT,\n overscan: OVERSCAN,\n });\n\n const { getRowProps } = useDataListKeyboard({\n count: traces.length,\n containerRef: scrollRef,\n onNavigate: index => virtualizer.scrollToIndex(index),\n });\n\n // Reset scroll to top whenever a fresh query resolves (filter / date range change).\n // `isLoading` only flips on initial fetches — `fetchNextPage` keeps it `false`, so this\n // effect doesn't fire during pagination.\n //\n // Why the manual scroll event: when the skeleton-vs-list branch swaps in the new scroll\n // container, it mounts at `scrollTop = 0`. The virtualizer rebinds its listener but\n // doesn't re-read `scrollTop`, so it keeps the stale `scrollOffset` from the previous\n // element. `scrollToOffset(0)` no-ops because the new element is already at 0 (no scroll\n // event fires). Dispatching a synthetic `scroll` forces the virtualizer's handler to\n // read the fresh `scrollTop` and recompute `virtualItems` with `paddingTop = 0`.\n const wasLoadingRef = useRef(isLoading);\n useEffect(() => {\n if (wasLoadingRef.current && !isLoading) {\n scrollRef.current?.dispatchEvent(new Event('scroll'));\n }\n wasLoadingRef.current = isLoading;\n }, [isLoading]);\n\n if (isLoading) {\n return <DataListSkeleton columns={columns} fit=\"container\" />;\n }\n\n const virtualItems = virtualizer.getVirtualItems();\n const totalSize = virtualizer.getTotalSize();\n const paddingTop = virtualItems[0]?.start ?? 0;\n const paddingBottom =\n virtualItems.length > 0 ? Math.max(0, totalSize - (virtualItems[virtualItems.length - 1]?.end ?? 0)) : 0;\n\n return (\n <TracesDataList columns={columns} variant=\"striped\" fit=\"container\" scrollRef={scrollRef} className=\"min-w-0\">\n <TracesDataList.Top>\n <TracesDataList.TopCell>Created</TracesDataList.TopCell>\n <TracesDataList.TopCell>Name</TracesDataList.TopCell>\n {hasTraceColumn(columnPreferences, 'input') && <TracesDataList.TopCell>Input</TracesDataList.TopCell>}\n {hasTraceColumn(columnPreferences, 'entity') && <TracesDataList.TopCell>Entity</TracesDataList.TopCell>}\n <TracesDataList.TopCell>Status</TracesDataList.TopCell>\n {hasTraceColumn(columnPreferences, 'duration') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Duration</TracesDataList.TopCell>\n )}\n {hasTraceColumn(columnPreferences, 'inputTokens') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Input tokens</TracesDataList.TopCell>\n )}\n {hasTraceColumn(columnPreferences, 'outputTokens') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Output tokens</TracesDataList.TopCell>\n )}\n {hasTraceColumn(columnPreferences, 'estimatedCost') && (\n <TracesDataList.TopCell className=\"justify-end text-right\">Est. cost</TracesDataList.TopCell>\n )}\n {columnPreferences.metadataKeys.map(key => (\n <TracesDataList.TopCellWithTooltip key={key} tooltip={key}>\n {key}\n </TracesDataList.TopCellWithTooltip>\n ))}\n </TracesDataList.Top>\n\n {traces.length === 0 ? (\n <TracesDataList.NoMatch\n message={filtersApplied ? 'No traces found for applied filters' : 'No traces found yet'}\n />\n ) : (\n <>\n <TracesDataList.Spacer height={paddingTop} />\n {virtualItems.map(vi => {\n const trace = traces[vi.index];\n if (!trace) return null;\n\n const isFeatured =\n trace.traceId === featuredTraceId && (featuredSpanId == null || trace.spanId === featuredSpanId);\n const rowKey = `${trace.traceId}:${trace.spanId ?? ''}`;\n const isRecentlyAdded = recentlyAddedKeys?.has(rowKey) ?? false;\n const displayDate = trace.startedAt ?? trace.createdAt;\n const entityName = trace.entityName || trace.entityId;\n const usage = usageByTraceId?.get(trace.traceId);\n\n return (\n <TracesDataList.RowButton\n key={rowKey}\n ref={virtualizer.measureElement}\n data-index={vi.index}\n {...getRowProps(vi.index)}\n onClick={() => onTraceClick(trace)}\n featured={isFeatured}\n className={cn(isRecentlyAdded && 'animate-row-highlight')}\n >\n <TracesDataList.CreatedCell timestamp={displayDate} />\n <TracesDataList.NameCell\n name={trace.name}\n parentSpanId={trace.parentSpanId}\n showLevelTooltip={isBranchesMode}\n />\n {hasTraceColumn(columnPreferences, 'input') && (\n <TracesDataList.InputCell input={trace.inputPreview ?? getInputPreview(trace.input)} />\n )}\n {hasTraceColumn(columnPreferences, 'entity') && (\n <TracesDataList.EntityCell entityType={trace.entityType} entityName={entityName} />\n )}\n <TracesDataList.StatusCell status={trace.status} />\n {hasTraceColumn(columnPreferences, 'duration') && (\n <DataList.NumberCell>{formatSpanDuration(trace.startedAt, trace.endedAt)}</DataList.NumberCell>\n )}\n {hasTraceColumn(columnPreferences, 'inputTokens') && (\n <DataList.NumberCell>\n {usage?.inputTokens === undefined ? undefined : formatCompact(usage.inputTokens)}\n </DataList.NumberCell>\n )}\n {hasTraceColumn(columnPreferences, 'outputTokens') && (\n <DataList.NumberCell>\n {usage?.outputTokens === undefined ? undefined : formatCompact(usage.outputTokens)}\n </DataList.NumberCell>\n )}\n {hasTraceColumn(columnPreferences, 'estimatedCost') && (\n <DataList.NumberCell>\n {usage?.estimatedCost === undefined ? undefined : formatCost(usage.estimatedCost, usage.costUnit)}\n </DataList.NumberCell>\n )}\n {columnPreferences.metadataKeys.map(key => {\n const value = formatTraceMetadataValue(trace.metadata, key);\n return (\n <DataList.TextCell font=\"mono\" key={key}>\n {value}\n </DataList.TextCell>\n );\n })}\n </TracesDataList.RowButton>\n );\n })}\n <TracesDataList.Spacer height={paddingBottom} />\n <TracesDataList.NextPageLoading\n isLoading={isFetchingNextPage}\n hasMore={hasNextPage}\n setEndOfListElement={setEndOfListElement}\n />\n </>\n )}\n </TracesDataList>\n );\n}\n"],"names":["DEFAULT_TRACE_COLUMN_PREFERENCES","useRef","buildTraceListColumns","useVirtualizer","useDataListKeyboard","useEffect","jsx","DataListSkeleton","jsxs","TracesDataList","hasTraceColumn","Fragment","cn","getInputPreview","DataList","formatSpanDuration","formatCompact","formatCost","formatTraceMetadataValue"],"mappings":"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"}
|
|
@@ -4,9 +4,9 @@ import { useRef, useEffect } from 'react';
|
|
|
4
4
|
import { buildTraceListColumns, hasTraceColumn, DEFAULT_TRACE_COLUMN_PREFERENCES, formatTraceMetadataValue } from '../trace-list-columns.es.js';
|
|
5
5
|
import { getInputPreview, formatSpanDuration } from '../utils/span-utils.es.js';
|
|
6
6
|
import { formatCompact, formatCost } from '../../metrics/components/metrics-utils.es.js';
|
|
7
|
-
import { D as DataList } from '../../../data-list-
|
|
8
|
-
import { D as DataListSkeleton } from '../../../data-list-skeleton-
|
|
9
|
-
import { T as TracesDataList } from '../../../traces-data-list-
|
|
7
|
+
import { D as DataList } from '../../../data-list-C3tjx5Vb.js';
|
|
8
|
+
import { D as DataListSkeleton } from '../../../data-list-skeleton-BCrkk6wG.js';
|
|
9
|
+
import { T as TracesDataList } from '../../../traces-data-list-c5I-8hwt.js';
|
|
10
10
|
import { u as useDataListKeyboard } from '../../../use-data-list-keyboard-BzZmvqE_.js';
|
|
11
11
|
import { c as cn } from '../../../cn-BakJzhuv.js';
|
|
12
12
|
|
|
@@ -48,16 +48,15 @@ function TracesListView({
|
|
|
48
48
|
wasLoadingRef.current = isLoading;
|
|
49
49
|
}, [isLoading]);
|
|
50
50
|
if (isLoading) {
|
|
51
|
-
return /* @__PURE__ */ jsx(DataListSkeleton, { columns });
|
|
51
|
+
return /* @__PURE__ */ jsx(DataListSkeleton, { columns, fit: "container" });
|
|
52
52
|
}
|
|
53
53
|
const virtualItems = virtualizer.getVirtualItems();
|
|
54
54
|
const totalSize = virtualizer.getTotalSize();
|
|
55
55
|
const paddingTop = virtualItems[0]?.start ?? 0;
|
|
56
56
|
const paddingBottom = virtualItems.length > 0 ? Math.max(0, totalSize - (virtualItems[virtualItems.length - 1]?.end ?? 0)) : 0;
|
|
57
|
-
return /* @__PURE__ */ jsxs(TracesDataList, { columns, variant: "striped", scrollRef, className: "min-w-0", children: [
|
|
57
|
+
return /* @__PURE__ */ jsxs(TracesDataList, { columns, variant: "striped", fit: "container", scrollRef, className: "min-w-0", children: [
|
|
58
58
|
/* @__PURE__ */ jsxs(TracesDataList.Top, { children: [
|
|
59
|
-
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "
|
|
60
|
-
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Time" }),
|
|
59
|
+
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Created" }),
|
|
61
60
|
/* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Name" }),
|
|
62
61
|
hasTraceColumn(columnPreferences, "input") && /* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Input" }),
|
|
63
62
|
hasTraceColumn(columnPreferences, "entity") && /* @__PURE__ */ jsx(TracesDataList.TopCell, { children: "Entity" }),
|
|
@@ -94,8 +93,7 @@ function TracesListView({
|
|
|
94
93
|
featured: isFeatured,
|
|
95
94
|
className: cn(isRecentlyAdded && "animate-row-highlight"),
|
|
96
95
|
children: [
|
|
97
|
-
/* @__PURE__ */ jsx(TracesDataList.
|
|
98
|
-
/* @__PURE__ */ jsx(TracesDataList.TimeCell, { timestamp: displayDate }),
|
|
96
|
+
/* @__PURE__ */ jsx(TracesDataList.CreatedCell, { timestamp: displayDate }),
|
|
99
97
|
/* @__PURE__ */ jsx(
|
|
100
98
|
TracesDataList.NameCell,
|
|
101
99
|
{
|