@mastra/playground-ui 51.4.0-alpha.6 → 51.4.0-alpha.7

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.
@@ -9,11 +9,12 @@ const domains_traces_hooks_getAllSpanIds = require('../hooks/get-all-span-ids.cj
9
9
  const domains_traces_hooks_useDownloadTraceJson = require('../hooks/use-download-trace-json.cjs.js');
10
10
  const domains_traces_hooks_useTraceSearch = require('../hooks/use-trace-search.cjs.js');
11
11
  const domains_traces_components_formatHierarchicalSpans = require('./format-hierarchical-spans.cjs.js');
12
- const domains_traces_components_traceKeysAndValues = require('./trace-keys-and-values.cjs.js');
12
+ const domains_traces_components_traceSummaryDescription = require('./trace-summary-description.cjs.js');
13
13
  const domains_traces_components_traceTimeline = require('./trace-timeline.cjs.js');
14
14
  const Button = require('../../../Button-D10WB4vc.cjs');
15
15
  const buttonsGroup = require('../../../buttons-group-Cn36DWYX.cjs');
16
16
  const dataPanel = require('../../../data-panel-DEatwExN.cjs');
17
+ const dropdownMenu = require('../../../dropdown-menu-qsDhHNES.cjs');
17
18
  const searchFieldBlock = require('../../../search-field-block-CiinIsub.cjs');
18
19
  const Notice = require('../../../Notice-D_ji361h.cjs');
19
20
  const tabsRoot = require('../../../tabs-root-BNcLC-s6.cjs');
@@ -26,7 +27,6 @@ const utils_truncateString = require('../../../utils/truncate-string.cjs.js');
26
27
  function TraceDataPanelView({
27
28
  traceId,
28
29
  spans,
29
- usage,
30
30
  isLoading,
31
31
  onClose,
32
32
  onSpanSelect,
@@ -42,6 +42,8 @@ function TraceDataPanelView({
42
42
  timelineChartWidth = "default",
43
43
  LinkComponent,
44
44
  traceHref,
45
+ entityHref,
46
+ usage,
45
47
  anchorSpanId,
46
48
  showUnavailableFeaturesMsg = true,
47
49
  scoresTabSlot,
@@ -96,67 +98,70 @@ function TraceDataPanelView({
96
98
  () => anchorSpanId ? spans?.find((s) => s.spanId === anchorSpanId) : spans?.find((s) => s.parentSpanId == null),
97
99
  [spans, anchorSpanId]
98
100
  );
99
- const isSubtrace = anchorSpanId !== void 0 && rootSpan?.parentSpanId != null;
100
101
  const handleSpanClick = (id) => {
101
102
  const newId = selectedSpanId === id ? void 0 : id;
102
103
  setSelectedSpanId(newId);
103
104
  onSpanSelect?.(newId);
104
105
  };
105
- const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;
106
- const downloadTraceButton = /* @__PURE__ */ jsxRuntime.jsx(
107
- Button.Button,
108
- {
109
- size: "md",
110
- tooltip: "Download trace JSON",
111
- "aria-label": "Download trace JSON",
112
- disabled: isDownloadingTrace,
113
- onClick: () => downloadTraceJson(traceId),
114
- children: isDownloadingTrace ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, {})
115
- }
116
- );
106
+ const traceActionsMenu = /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu, { children: [
107
+ /* @__PURE__ */ jsxRuntime.jsx(
108
+ dropdownMenu.DropdownMenu.Trigger,
109
+ {
110
+ render: /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { size: "md", tooltip: "Trace actions", "aria-label": "Trace actions", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontalIcon, {}) })
111
+ }
112
+ ),
113
+ /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Content, { align: "end", children: [
114
+ !isOnTracePage && onCollapsedChange && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { onSelect: () => setCollapsed(!collapsed), children: [
115
+ collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUpIcon, {}),
116
+ collapsed ? "Expand panel" : "Collapse panel"
117
+ ] }),
118
+ !isOnTracePage && onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { onSelect: onEvaluateTrace, children: [
119
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}),
120
+ "Evaluate trace"
121
+ ] }),
122
+ !isOnTracePage && onSaveAsDatasetItem && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { onSelect: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }), children: [
123
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SaveIcon, {}),
124
+ "Add full trace to dataset"
125
+ ] }),
126
+ !isOnTracePage && onAddTraceMocksToItem && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { onSelect: () => onAddTraceMocksToItem({ traceId }), children: [
127
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WrenchIcon, {}),
128
+ "Add tool mocks to item"
129
+ ] }),
130
+ !isOnTracePage && LinkComponent && traceHref && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { render: /* @__PURE__ */ jsxRuntime.jsx(LinkComponent, { href: traceHref }), children: [
131
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2Icon, {}),
132
+ "Open trace page"
133
+ ] }),
134
+ /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { disabled: isDownloadingTrace, onSelect: () => downloadTraceJson(traceId), children: [
135
+ isDownloadingTrace ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, {}),
136
+ "Download trace JSON"
137
+ ] })
138
+ ] })
139
+ ] });
117
140
  return /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel, { collapsed, className, children: [
118
141
  /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Header, { children: isOnTracePage ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
119
142
  /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Heading, { children: "Trace Timeline" }),
120
- /* @__PURE__ */ jsxRuntime.jsx(buttonsGroup.ButtonsGroup, { className: "ml-auto shrink-0", children: downloadTraceButton })
143
+ /* @__PURE__ */ jsxRuntime.jsx(buttonsGroup.ButtonsGroup, { className: "ml-auto shrink-0", children: traceActionsMenu })
121
144
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
122
- /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Heading, { children: [
123
- "Trace ",
124
- /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
125
- "# ",
126
- utils_truncateString.truncateString(traceId, 12)
127
- ] })
128
- ] }),
129
- /* @__PURE__ */ jsxRuntime.jsxs(buttonsGroup.ButtonsGroup, { className: "ml-auto shrink-0", children: [
130
- onCollapsedChange && /* @__PURE__ */ jsxRuntime.jsx(
131
- Button.Button,
145
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
146
+ /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Heading, { children: [
147
+ "Trace ",
148
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
149
+ "# ",
150
+ utils_truncateString.truncateString(traceId, 12)
151
+ ] })
152
+ ] }),
153
+ !collapsed && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(
154
+ domains_traces_components_traceSummaryDescription.TraceSummaryDescription,
132
155
  {
133
- size: "md",
134
- tooltip: collapsed ? "Expand panel" : "Collapse panel",
135
- onClick: () => setCollapsed(!collapsed),
136
- children: collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUpIcon, {})
156
+ rootSpan,
157
+ usage,
158
+ entityHref,
159
+ LinkComponent
137
160
  }
138
- ),
139
- onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { size: "md", tooltip: "Evaluate trace", "aria-label": "Evaluate trace", onClick: onEvaluateTrace, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}) }),
140
- onSaveAsDatasetItem && /* @__PURE__ */ jsxRuntime.jsx(
141
- Button.Button,
142
- {
143
- size: "md",
144
- tooltip: "Add full trace to dataset",
145
- "aria-label": "Add full trace to dataset",
146
- onClick: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }),
147
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SaveIcon, {})
148
- }
149
- ),
150
- onAddTraceMocksToItem && /* @__PURE__ */ jsxRuntime.jsx(
151
- Button.Button,
152
- {
153
- size: "md",
154
- tooltip: "Add tool mocks to item",
155
- "aria-label": "Add tool mocks to item",
156
- onClick: () => onAddTraceMocksToItem({ traceId }),
157
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WrenchIcon, {})
158
- }
159
- ),
161
+ )
162
+ ] }),
163
+ /* @__PURE__ */ jsxRuntime.jsxs(buttonsGroup.ButtonsGroup, { className: "ml-auto shrink-0 self-start", children: [
164
+ traceActionsMenu,
160
165
  (onPrevious || onNext) && /* @__PURE__ */ jsxRuntime.jsx(
161
166
  dataPanel.DataPanel.NextPrevNav,
162
167
  {
@@ -166,24 +171,11 @@ function TraceDataPanelView({
166
171
  nextLabel: "Next trace"
167
172
  }
168
173
  ),
169
- showOpenTracePageLink && /* @__PURE__ */ jsxRuntime.jsx(
170
- Button.Button,
171
- {
172
- as: LinkComponent,
173
- href: traceHref,
174
- size: "md",
175
- tooltip: "Open trace page",
176
- "aria-label": "Open trace page",
177
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2Icon, {})
178
- }
179
- ),
180
- downloadTraceButton,
181
174
  /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.CloseButton, { onClick: onClose })
182
175
  ] })
183
176
  ] }) }),
184
177
  !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: (() => {
185
178
  const detailsBody = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
186
- !isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(domains_traces_components_traceKeysAndValues.TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
187
179
  !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)." }) }),
188
180
  /* @__PURE__ */ jsxRuntime.jsx(
189
181
  domains_traces_components_traceTimeline.TraceTimeline,
@@ -223,7 +215,7 @@ function TraceDataPanelView({
223
215
  className: activeTab === "scores" || activeTab === "feedback" ? "grid h-full min-h-0 grid-rows-[auto_1fr]" : void 0,
224
216
  children: [
225
217
  /* @__PURE__ */ jsxRuntime.jsxs(tabsRoot.TabList, { variant: "pill-ghost", className: "px-0", children: [
226
- /* @__PURE__ */ jsxRuntime.jsx(tabsTab.Tab, { value: "details", children: "Details" }),
218
+ /* @__PURE__ */ jsxRuntime.jsx(tabsTab.Tab, { value: "details", children: "Spans" }),
227
219
  scoresTabSlot && /* @__PURE__ */ jsxRuntime.jsxs(tabsTab.Tab, { value: "scores", children: [
228
220
  "Evaluations ",
229
221
  scoresTabBadge != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -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 { 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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"}
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 MoreHorizontalIcon,\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 { TraceSummaryDescription } from './trace-summary-description';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { DropdownMenu } from '@/ds/components/DropdownMenu';\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 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 /** When provided, the entity name in the trace summary links to the entity's page. */\n entityHref?: string;\n /** Token and estimated-cost totals shown in the compact trace summary. */\n usage?: TraceUsageSummary;\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 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 entityHref,\n usage,\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 handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const traceActionsMenu = (\n <DropdownMenu>\n <DropdownMenu.Trigger\n render={\n <Button size=\"md\" tooltip=\"Trace actions\" aria-label=\"Trace actions\">\n <MoreHorizontalIcon />\n </Button>\n }\n />\n <DropdownMenu.Content align=\"end\">\n {!isOnTracePage && onCollapsedChange && (\n <DropdownMenu.Item onSelect={() => setCollapsed(!collapsed)}>\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n {collapsed ? 'Expand panel' : 'Collapse panel'}\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && onEvaluateTrace && (\n <DropdownMenu.Item onSelect={onEvaluateTrace}>\n <CircleGaugeIcon />\n Evaluate trace\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && onSaveAsDatasetItem && (\n <DropdownMenu.Item onSelect={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <SaveIcon />\n Add full trace to dataset\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && onAddTraceMocksToItem && (\n <DropdownMenu.Item onSelect={() => onAddTraceMocksToItem({ traceId })}>\n <WrenchIcon />\n Add tool mocks to item\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && LinkComponent && traceHref && (\n <DropdownMenu.Item render={<LinkComponent href={traceHref} />}>\n <Link2Icon />\n Open trace page\n </DropdownMenu.Item>\n )}\n <DropdownMenu.Item disabled={isDownloadingTrace} onSelect={() => downloadTraceJson(traceId)}>\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n Download trace JSON\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu>\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\">{traceActionsMenu}</ButtonsGroup>\n </>\n ) : (\n <>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n {!collapsed && rootSpan && (\n <TraceSummaryDescription\n rootSpan={rootSpan}\n usage={usage}\n entityHref={entityHref}\n LinkComponent={LinkComponent}\n />\n )}\n </div>\n <ButtonsGroup className=\"ml-auto shrink-0 self-start\">\n {traceActionsMenu}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\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 &&\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\">Spans</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","DropdownMenu","jsx","Button","MoreHorizontalIcon","jsxs","ChevronsUpDownIcon","ChevronsDownUpIcon","CircleGaugeIcon","SaveIcon","WrenchIcon","Link2Icon","Loader2Icon","DownloadIcon","DataPanel","Fragment","ButtonsGroup","truncateString","TraceSummaryDescription","Notice","TraceTimeline","SearchFieldBlock","Tabs","TabList","Tab","TabContent","useTextHighlight","useScrollToFirstHighlight"],"mappings":"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"}
@@ -1,15 +1,16 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { ChevronsUpDownIcon, ChevronsDownUpIcon, CircleGaugeIcon, SaveIcon, WrenchIcon, Link2Icon, Loader2Icon, DownloadIcon } from 'lucide-react';
2
+ import { MoreHorizontalIcon, ChevronsUpDownIcon, ChevronsDownUpIcon, CircleGaugeIcon, SaveIcon, WrenchIcon, Link2Icon, Loader2Icon, DownloadIcon } from 'lucide-react';
3
3
  import { useState, useEffect, useId, useMemo } from 'react';
4
4
  import { getAllSpanIds } from '../hooks/get-all-span-ids.es.js';
5
5
  import { useDownloadTraceJson } from '../hooks/use-download-trace-json.es.js';
6
6
  import { useTraceSearch } from '../hooks/use-trace-search.es.js';
7
7
  import { formatHierarchicalSpans } from './format-hierarchical-spans.es.js';
8
- import { TraceKeysAndValues } from './trace-keys-and-values.es.js';
8
+ import { TraceSummaryDescription } from './trace-summary-description.es.js';
9
9
  import { TraceTimeline } from './trace-timeline.es.js';
10
10
  import { B as Button } from '../../../Button-BsfLQEC6.js';
11
11
  import { B as ButtonsGroup } from '../../../buttons-group-BjM12HPx.js';
12
12
  import { D as DataPanel } from '../../../data-panel-2Da0Utgy.js';
13
+ import { D as DropdownMenu } from '../../../dropdown-menu-BYTyEuSa.js';
13
14
  import { S as SearchFieldBlock } from '../../../search-field-block-D51aN1d9.js';
14
15
  import { N as Notice } from '../../../Notice-DSUAUUYU.js';
15
16
  import { a as Tabs, T as TabList } from '../../../tabs-root-BnwVjJbD.js';
@@ -22,7 +23,6 @@ import { truncateString } from '../../../utils/truncate-string.es.js';
22
23
  function TraceDataPanelView({
23
24
  traceId,
24
25
  spans,
25
- usage,
26
26
  isLoading,
27
27
  onClose,
28
28
  onSpanSelect,
@@ -38,6 +38,8 @@ function TraceDataPanelView({
38
38
  timelineChartWidth = "default",
39
39
  LinkComponent,
40
40
  traceHref,
41
+ entityHref,
42
+ usage,
41
43
  anchorSpanId,
42
44
  showUnavailableFeaturesMsg = true,
43
45
  scoresTabSlot,
@@ -92,67 +94,70 @@ function TraceDataPanelView({
92
94
  () => anchorSpanId ? spans?.find((s) => s.spanId === anchorSpanId) : spans?.find((s) => s.parentSpanId == null),
93
95
  [spans, anchorSpanId]
94
96
  );
95
- const isSubtrace = anchorSpanId !== void 0 && rootSpan?.parentSpanId != null;
96
97
  const handleSpanClick = (id) => {
97
98
  const newId = selectedSpanId === id ? void 0 : id;
98
99
  setSelectedSpanId(newId);
99
100
  onSpanSelect?.(newId);
100
101
  };
101
- const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;
102
- const downloadTraceButton = /* @__PURE__ */ jsx(
103
- Button,
104
- {
105
- size: "md",
106
- tooltip: "Download trace JSON",
107
- "aria-label": "Download trace JSON",
108
- disabled: isDownloadingTrace,
109
- onClick: () => downloadTraceJson(traceId),
110
- children: isDownloadingTrace ? /* @__PURE__ */ jsx(Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(DownloadIcon, {})
111
- }
112
- );
102
+ const traceActionsMenu = /* @__PURE__ */ jsxs(DropdownMenu, { children: [
103
+ /* @__PURE__ */ jsx(
104
+ DropdownMenu.Trigger,
105
+ {
106
+ render: /* @__PURE__ */ jsx(Button, { size: "md", tooltip: "Trace actions", "aria-label": "Trace actions", children: /* @__PURE__ */ jsx(MoreHorizontalIcon, {}) })
107
+ }
108
+ ),
109
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "end", children: [
110
+ !isOnTracePage && onCollapsedChange && /* @__PURE__ */ jsxs(DropdownMenu.Item, { onSelect: () => setCollapsed(!collapsed), children: [
111
+ collapsed ? /* @__PURE__ */ jsx(ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsx(ChevronsDownUpIcon, {}),
112
+ collapsed ? "Expand panel" : "Collapse panel"
113
+ ] }),
114
+ !isOnTracePage && onEvaluateTrace && /* @__PURE__ */ jsxs(DropdownMenu.Item, { onSelect: onEvaluateTrace, children: [
115
+ /* @__PURE__ */ jsx(CircleGaugeIcon, {}),
116
+ "Evaluate trace"
117
+ ] }),
118
+ !isOnTracePage && onSaveAsDatasetItem && /* @__PURE__ */ jsxs(DropdownMenu.Item, { onSelect: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }), children: [
119
+ /* @__PURE__ */ jsx(SaveIcon, {}),
120
+ "Add full trace to dataset"
121
+ ] }),
122
+ !isOnTracePage && onAddTraceMocksToItem && /* @__PURE__ */ jsxs(DropdownMenu.Item, { onSelect: () => onAddTraceMocksToItem({ traceId }), children: [
123
+ /* @__PURE__ */ jsx(WrenchIcon, {}),
124
+ "Add tool mocks to item"
125
+ ] }),
126
+ !isOnTracePage && LinkComponent && traceHref && /* @__PURE__ */ jsxs(DropdownMenu.Item, { render: /* @__PURE__ */ jsx(LinkComponent, { href: traceHref }), children: [
127
+ /* @__PURE__ */ jsx(Link2Icon, {}),
128
+ "Open trace page"
129
+ ] }),
130
+ /* @__PURE__ */ jsxs(DropdownMenu.Item, { disabled: isDownloadingTrace, onSelect: () => downloadTraceJson(traceId), children: [
131
+ isDownloadingTrace ? /* @__PURE__ */ jsx(Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(DownloadIcon, {}),
132
+ "Download trace JSON"
133
+ ] })
134
+ ] })
135
+ ] });
113
136
  return /* @__PURE__ */ jsxs(DataPanel, { collapsed, className, children: [
114
137
  /* @__PURE__ */ jsx(DataPanel.Header, { children: isOnTracePage ? /* @__PURE__ */ jsxs(Fragment, { children: [
115
138
  /* @__PURE__ */ jsx(DataPanel.Heading, { children: "Trace Timeline" }),
116
- /* @__PURE__ */ jsx(ButtonsGroup, { className: "ml-auto shrink-0", children: downloadTraceButton })
139
+ /* @__PURE__ */ jsx(ButtonsGroup, { className: "ml-auto shrink-0", children: traceActionsMenu })
117
140
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
118
- /* @__PURE__ */ jsxs(DataPanel.Heading, { children: [
119
- "Trace ",
120
- /* @__PURE__ */ jsxs("b", { children: [
121
- "# ",
122
- truncateString(traceId, 12)
123
- ] })
124
- ] }),
125
- /* @__PURE__ */ jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
126
- onCollapsedChange && /* @__PURE__ */ jsx(
127
- Button,
141
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
142
+ /* @__PURE__ */ jsxs(DataPanel.Heading, { children: [
143
+ "Trace ",
144
+ /* @__PURE__ */ jsxs("b", { children: [
145
+ "# ",
146
+ truncateString(traceId, 12)
147
+ ] })
148
+ ] }),
149
+ !collapsed && rootSpan && /* @__PURE__ */ jsx(
150
+ TraceSummaryDescription,
128
151
  {
129
- size: "md",
130
- tooltip: collapsed ? "Expand panel" : "Collapse panel",
131
- onClick: () => setCollapsed(!collapsed),
132
- children: collapsed ? /* @__PURE__ */ jsx(ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsx(ChevronsDownUpIcon, {})
152
+ rootSpan,
153
+ usage,
154
+ entityHref,
155
+ LinkComponent
133
156
  }
134
- ),
135
- onEvaluateTrace && /* @__PURE__ */ jsx(Button, { size: "md", tooltip: "Evaluate trace", "aria-label": "Evaluate trace", onClick: onEvaluateTrace, children: /* @__PURE__ */ jsx(CircleGaugeIcon, {}) }),
136
- onSaveAsDatasetItem && /* @__PURE__ */ jsx(
137
- Button,
138
- {
139
- size: "md",
140
- tooltip: "Add full trace to dataset",
141
- "aria-label": "Add full trace to dataset",
142
- onClick: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }),
143
- children: /* @__PURE__ */ jsx(SaveIcon, {})
144
- }
145
- ),
146
- onAddTraceMocksToItem && /* @__PURE__ */ jsx(
147
- Button,
148
- {
149
- size: "md",
150
- tooltip: "Add tool mocks to item",
151
- "aria-label": "Add tool mocks to item",
152
- onClick: () => onAddTraceMocksToItem({ traceId }),
153
- children: /* @__PURE__ */ jsx(WrenchIcon, {})
154
- }
155
- ),
157
+ )
158
+ ] }),
159
+ /* @__PURE__ */ jsxs(ButtonsGroup, { className: "ml-auto shrink-0 self-start", children: [
160
+ traceActionsMenu,
156
161
  (onPrevious || onNext) && /* @__PURE__ */ jsx(
157
162
  DataPanel.NextPrevNav,
158
163
  {
@@ -162,24 +167,11 @@ function TraceDataPanelView({
162
167
  nextLabel: "Next trace"
163
168
  }
164
169
  ),
165
- showOpenTracePageLink && /* @__PURE__ */ jsx(
166
- Button,
167
- {
168
- as: LinkComponent,
169
- href: traceHref,
170
- size: "md",
171
- tooltip: "Open trace page",
172
- "aria-label": "Open trace page",
173
- children: /* @__PURE__ */ jsx(Link2Icon, {})
174
- }
175
- ),
176
- downloadTraceButton,
177
170
  /* @__PURE__ */ jsx(DataPanel.CloseButton, { onClick: onClose })
178
171
  ] })
179
172
  ] }) }),
180
173
  !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: (() => {
181
174
  const detailsBody = /* @__PURE__ */ jsxs(Fragment, { children: [
182
- !isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
183
175
  !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)." }) }),
184
176
  /* @__PURE__ */ jsx(
185
177
  TraceTimeline,
@@ -219,7 +211,7 @@ function TraceDataPanelView({
219
211
  className: activeTab === "scores" || activeTab === "feedback" ? "grid h-full min-h-0 grid-rows-[auto_1fr]" : void 0,
220
212
  children: [
221
213
  /* @__PURE__ */ jsxs(TabList, { variant: "pill-ghost", className: "px-0", children: [
222
- /* @__PURE__ */ jsx(Tab, { value: "details", children: "Details" }),
214
+ /* @__PURE__ */ jsx(Tab, { value: "details", children: "Spans" }),
223
215
  scoresTabSlot && /* @__PURE__ */ jsxs(Tab, { value: "scores", children: [
224
216
  "Evaluations ",
225
217
  scoresTabBadge != null && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -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 { 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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"}
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 MoreHorizontalIcon,\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 { TraceSummaryDescription } from './trace-summary-description';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { DropdownMenu } from '@/ds/components/DropdownMenu';\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 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 /** When provided, the entity name in the trace summary links to the entity's page. */\n entityHref?: string;\n /** Token and estimated-cost totals shown in the compact trace summary. */\n usage?: TraceUsageSummary;\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 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 entityHref,\n usage,\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 handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const traceActionsMenu = (\n <DropdownMenu>\n <DropdownMenu.Trigger\n render={\n <Button size=\"md\" tooltip=\"Trace actions\" aria-label=\"Trace actions\">\n <MoreHorizontalIcon />\n </Button>\n }\n />\n <DropdownMenu.Content align=\"end\">\n {!isOnTracePage && onCollapsedChange && (\n <DropdownMenu.Item onSelect={() => setCollapsed(!collapsed)}>\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n {collapsed ? 'Expand panel' : 'Collapse panel'}\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && onEvaluateTrace && (\n <DropdownMenu.Item onSelect={onEvaluateTrace}>\n <CircleGaugeIcon />\n Evaluate trace\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && onSaveAsDatasetItem && (\n <DropdownMenu.Item onSelect={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <SaveIcon />\n Add full trace to dataset\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && onAddTraceMocksToItem && (\n <DropdownMenu.Item onSelect={() => onAddTraceMocksToItem({ traceId })}>\n <WrenchIcon />\n Add tool mocks to item\n </DropdownMenu.Item>\n )}\n {!isOnTracePage && LinkComponent && traceHref && (\n <DropdownMenu.Item render={<LinkComponent href={traceHref} />}>\n <Link2Icon />\n Open trace page\n </DropdownMenu.Item>\n )}\n <DropdownMenu.Item disabled={isDownloadingTrace} onSelect={() => downloadTraceJson(traceId)}>\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n Download trace JSON\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu>\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\">{traceActionsMenu}</ButtonsGroup>\n </>\n ) : (\n <>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n {!collapsed && rootSpan && (\n <TraceSummaryDescription\n rootSpan={rootSpan}\n usage={usage}\n entityHref={entityHref}\n LinkComponent={LinkComponent}\n />\n )}\n </div>\n <ButtonsGroup className=\"ml-auto shrink-0 self-start\">\n {traceActionsMenu}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\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 &&\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\">Spans</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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"}
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const jsxRuntime = require('react/jsx-runtime');
6
+ const lucideReact = require('lucide-react');
7
+ const domains_traces_utils_spanUtils = require('../utils/span-utils.cjs.js');
8
+ const domains_metrics_components_metricsUtils = require('../../metrics/components/metrics-utils.cjs.js');
9
+ const tooltip = require('../../../tooltip-DIi_oOxO.cjs');
10
+ const icons_AgentIcon = require('../../../icons/AgentIcon.cjs.js');
11
+ const utils_cn = require('../../../cn-DCPcv4xv.cjs');
12
+ const icons_WorkflowIcon = require('../../../icons/WorkflowIcon.cjs.js');
13
+
14
+ function formatEntityType(entityType) {
15
+ return entityType.split("_").map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(" ");
16
+ }
17
+ function SummaryItem({ label, children }) {
18
+ return /* @__PURE__ */ jsxRuntime.jsxs(tooltip.Tooltip, { children: [
19
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
20
+ "span",
21
+ {
22
+ tabIndex: 0,
23
+ className: "flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap",
24
+ "aria-label": label,
25
+ children
26
+ }
27
+ ) }),
28
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipContent, { children: label })
29
+ ] });
30
+ }
31
+ function TraceSummaryDescription({
32
+ rootSpan,
33
+ usage,
34
+ entityHref,
35
+ LinkComponent,
36
+ className
37
+ }) {
38
+ const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
39
+ const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
40
+ const duration = domains_traces_utils_spanUtils.formatSpanDuration(startedAt, endedAt);
41
+ const exactDuration = domains_traces_utils_spanUtils.formatSpanDurationExact(startedAt, endedAt);
42
+ const startedAtTimestamp = domains_traces_utils_spanUtils.formatSpanTimestamp(startedAt);
43
+ const exactStartedAtTimestamp = domains_traces_utils_spanUtils.formatSpanTimestampExact(startedAt);
44
+ const entityName = rootSpan.entityName || rootSpan.entityId;
45
+ const entityType = rootSpan.entityType;
46
+ const formattedEntityType = entityType ? formatEntityType(entityType) : "Entity";
47
+ const EntityIcon = entityType?.includes("workflow") ? icons_WorkflowIcon.WorkflowIcon : icons_AgentIcon.AgentIcon;
48
+ const Link = LinkComponent ?? "a";
49
+ return /* @__PURE__ */ jsxRuntime.jsxs(
50
+ "div",
51
+ {
52
+ className: utils_cn.cn(
53
+ "flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-ui-xs leading-ui-xs text-neutral3",
54
+ className
55
+ ),
56
+ children: [
57
+ entityName && /* @__PURE__ */ jsxRuntime.jsxs(tooltip.Tooltip, { children: [
58
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipTrigger, { asChild: true, children: entityHref ? /* @__PURE__ */ jsxRuntime.jsxs(
59
+ Link,
60
+ {
61
+ href: entityHref,
62
+ className: "text-neutral4 hover:text-neutral5 flex shrink-0 items-center gap-1 whitespace-nowrap hover:underline",
63
+ children: [
64
+ /* @__PURE__ */ jsxRuntime.jsx(EntityIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
65
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: entityName }),
66
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLinkIcon, { className: "size-3 shrink-0", "aria-hidden": "true" })
67
+ ]
68
+ }
69
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("span", { tabIndex: 0, className: "flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap", children: [
70
+ /* @__PURE__ */ jsxRuntime.jsx(EntityIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
71
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: entityName })
72
+ ] }) }),
73
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.TooltipContent, { children: formattedEntityType })
74
+ ] }),
75
+ startedAtTimestamp && exactStartedAtTimestamp && /* @__PURE__ */ jsxRuntime.jsxs(SummaryItem, { label: `Started at ${exactStartedAtTimestamp}`, children: [
76
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarClockIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
77
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: startedAtTimestamp })
78
+ ] }),
79
+ duration && exactDuration && /* @__PURE__ */ jsxRuntime.jsxs(SummaryItem, { label: `Duration ${exactDuration}`, children: [
80
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TimerIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
81
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: duration })
82
+ ] }),
83
+ usage && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
84
+ /* @__PURE__ */ jsxRuntime.jsxs(SummaryItem, { label: "Input tokens", children: [
85
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownToLineIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
86
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: usage.inputTokens === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCompact(usage.inputTokens) })
87
+ ] }),
88
+ /* @__PURE__ */ jsxRuntime.jsxs(SummaryItem, { label: "Output tokens", children: [
89
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpFromLineIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
90
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: usage.outputTokens === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCompact(usage.outputTokens) })
91
+ ] }),
92
+ /* @__PURE__ */ jsxRuntime.jsxs(SummaryItem, { label: "Estimated cost", children: [
93
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDollarSignIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
94
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: usage.estimatedCost === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCost(usage.estimatedCost, usage.costUnit) })
95
+ ] })
96
+ ] })
97
+ ]
98
+ }
99
+ );
100
+ }
101
+
102
+ exports.TraceSummaryDescription = TraceSummaryDescription;
103
+ //# sourceMappingURL=trace-summary-description.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-summary-description.cjs.js","sources":["../../../../src/domains/traces/components/trace-summary-description.tsx"],"sourcesContent":["import {\n ArrowDownToLineIcon,\n ArrowUpFromLineIcon,\n CalendarClockIcon,\n CircleDollarSignIcon,\n ExternalLinkIcon,\n TimerIcon,\n} from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport {\n formatSpanDuration,\n formatSpanDurationExact,\n formatSpanTimestamp,\n formatSpanTimestampExact,\n} from '../utils/span-utils';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/ds/components/Tooltip';\nimport { AgentIcon, WorkflowIcon } from '@/ds/icons';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { cn } from '@/lib/utils';\n\nfunction formatEntityType(entityType: string): string {\n return entityType\n .split('_')\n .map(word => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)\n .join(' ');\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n};\n\nexport interface TraceSummaryDescriptionProps {\n rootSpan: RootSpanSummary;\n usage?: TraceUsageSummary;\n /** When provided (with `LinkComponent`), the entity name links to the entity's page. */\n entityHref?: string;\n LinkComponent?: LinkComponent;\n className?: string;\n}\n\nfunction SummaryItem({ label, children }: { label: string; children: ReactNode }) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n tabIndex={0}\n className=\"flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap\"\n aria-label={label}\n >\n {children}\n </span>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** Compact trace metadata shown under the trace side-panel heading. */\nexport function TraceSummaryDescription({\n rootSpan,\n usage,\n entityHref,\n LinkComponent,\n className,\n}: TraceSummaryDescriptionProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const duration = formatSpanDuration(startedAt, endedAt);\n const exactDuration = formatSpanDurationExact(startedAt, endedAt);\n const startedAtTimestamp = formatSpanTimestamp(startedAt);\n const exactStartedAtTimestamp = formatSpanTimestampExact(startedAt);\n\n const entityName = rootSpan.entityName || rootSpan.entityId;\n const entityType = rootSpan.entityType;\n const formattedEntityType = entityType ? formatEntityType(entityType) : 'Entity';\n const EntityIcon = entityType?.includes('workflow') ? WorkflowIcon : AgentIcon;\n const Link = LinkComponent ?? 'a';\n\n return (\n <div\n className={cn(\n 'flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-ui-xs leading-ui-xs text-neutral3',\n className,\n )}\n >\n {entityName && (\n <Tooltip>\n <TooltipTrigger asChild>\n {entityHref ? (\n <Link\n href={entityHref}\n className=\"text-neutral4 hover:text-neutral5 flex shrink-0 items-center gap-1 whitespace-nowrap hover:underline\"\n >\n <EntityIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{entityName}</span>\n <ExternalLinkIcon className=\"size-3 shrink-0\" aria-hidden=\"true\" />\n </Link>\n ) : (\n <span tabIndex={0} className=\"flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap\">\n <EntityIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{entityName}</span>\n </span>\n )}\n </TooltipTrigger>\n <TooltipContent>{formattedEntityType}</TooltipContent>\n </Tooltip>\n )}\n {startedAtTimestamp && exactStartedAtTimestamp && (\n <SummaryItem label={`Started at ${exactStartedAtTimestamp}`}>\n <CalendarClockIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{startedAtTimestamp}</span>\n </SummaryItem>\n )}\n {duration && exactDuration && (\n <SummaryItem label={`Duration ${exactDuration}`}>\n <TimerIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{duration}</span>\n </SummaryItem>\n )}\n {usage && (\n <>\n <SummaryItem label=\"Input tokens\">\n <ArrowDownToLineIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{usage.inputTokens === undefined ? '—' : formatCompact(usage.inputTokens)}</span>\n </SummaryItem>\n <SummaryItem label=\"Output tokens\">\n <ArrowUpFromLineIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{usage.outputTokens === undefined ? '—' : formatCompact(usage.outputTokens)}</span>\n </SummaryItem>\n <SummaryItem label=\"Estimated cost\">\n <CircleDollarSignIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{usage.estimatedCost === undefined ? '—' : formatCost(usage.estimatedCost, usage.costUnit)}</span>\n </SummaryItem>\n </>\n )}\n </div>\n );\n}\n"],"names":["Tooltip","jsx","TooltipTrigger","TooltipContent","formatSpanDuration","formatSpanDurationExact","formatSpanTimestamp","formatSpanTimestampExact","WorkflowIcon","AgentIcon","jsxs","cn","ExternalLinkIcon","CalendarClockIcon","TimerIcon","Fragment","ArrowDownToLineIcon","formatCompact","ArrowUpFromLineIcon","CircleDollarSignIcon","formatCost"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from '../../../src/domains/traces/components/trace-summary-description'
2
+ export {}
@@ -0,0 +1,99 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { ExternalLinkIcon, CalendarClockIcon, TimerIcon, ArrowDownToLineIcon, ArrowUpFromLineIcon, CircleDollarSignIcon } from 'lucide-react';
3
+ import { formatSpanDuration, formatSpanDurationExact, formatSpanTimestamp, formatSpanTimestampExact } from '../utils/span-utils.es.js';
4
+ import { formatCompact, formatCost } from '../../metrics/components/metrics-utils.es.js';
5
+ import { T as Tooltip, c as TooltipTrigger, a as TooltipContent } from '../../../tooltip-Bi0pDO5P.js';
6
+ import { AgentIcon } from '../../../icons/AgentIcon.es.js';
7
+ import { c as cn } from '../../../cn-B4oPhFx9.js';
8
+ import { WorkflowIcon } from '../../../icons/WorkflowIcon.es.js';
9
+
10
+ function formatEntityType(entityType) {
11
+ return entityType.split("_").map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(" ");
12
+ }
13
+ function SummaryItem({ label, children }) {
14
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
15
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
16
+ "span",
17
+ {
18
+ tabIndex: 0,
19
+ className: "flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap",
20
+ "aria-label": label,
21
+ children
22
+ }
23
+ ) }),
24
+ /* @__PURE__ */ jsx(TooltipContent, { children: label })
25
+ ] });
26
+ }
27
+ function TraceSummaryDescription({
28
+ rootSpan,
29
+ usage,
30
+ entityHref,
31
+ LinkComponent,
32
+ className
33
+ }) {
34
+ const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
35
+ const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
36
+ const duration = formatSpanDuration(startedAt, endedAt);
37
+ const exactDuration = formatSpanDurationExact(startedAt, endedAt);
38
+ const startedAtTimestamp = formatSpanTimestamp(startedAt);
39
+ const exactStartedAtTimestamp = formatSpanTimestampExact(startedAt);
40
+ const entityName = rootSpan.entityName || rootSpan.entityId;
41
+ const entityType = rootSpan.entityType;
42
+ const formattedEntityType = entityType ? formatEntityType(entityType) : "Entity";
43
+ const EntityIcon = entityType?.includes("workflow") ? WorkflowIcon : AgentIcon;
44
+ const Link = LinkComponent ?? "a";
45
+ return /* @__PURE__ */ jsxs(
46
+ "div",
47
+ {
48
+ className: cn(
49
+ "flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-ui-xs leading-ui-xs text-neutral3",
50
+ className
51
+ ),
52
+ children: [
53
+ entityName && /* @__PURE__ */ jsxs(Tooltip, { children: [
54
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: entityHref ? /* @__PURE__ */ jsxs(
55
+ Link,
56
+ {
57
+ href: entityHref,
58
+ className: "text-neutral4 hover:text-neutral5 flex shrink-0 items-center gap-1 whitespace-nowrap hover:underline",
59
+ children: [
60
+ /* @__PURE__ */ jsx(EntityIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
61
+ /* @__PURE__ */ jsx("span", { children: entityName }),
62
+ /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "size-3 shrink-0", "aria-hidden": "true" })
63
+ ]
64
+ }
65
+ ) : /* @__PURE__ */ jsxs("span", { tabIndex: 0, className: "flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap", children: [
66
+ /* @__PURE__ */ jsx(EntityIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
67
+ /* @__PURE__ */ jsx("span", { children: entityName })
68
+ ] }) }),
69
+ /* @__PURE__ */ jsx(TooltipContent, { children: formattedEntityType })
70
+ ] }),
71
+ startedAtTimestamp && exactStartedAtTimestamp && /* @__PURE__ */ jsxs(SummaryItem, { label: `Started at ${exactStartedAtTimestamp}`, children: [
72
+ /* @__PURE__ */ jsx(CalendarClockIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
73
+ /* @__PURE__ */ jsx("span", { children: startedAtTimestamp })
74
+ ] }),
75
+ duration && exactDuration && /* @__PURE__ */ jsxs(SummaryItem, { label: `Duration ${exactDuration}`, children: [
76
+ /* @__PURE__ */ jsx(TimerIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
77
+ /* @__PURE__ */ jsx("span", { children: duration })
78
+ ] }),
79
+ usage && /* @__PURE__ */ jsxs(Fragment, { children: [
80
+ /* @__PURE__ */ jsxs(SummaryItem, { label: "Input tokens", children: [
81
+ /* @__PURE__ */ jsx(ArrowDownToLineIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
82
+ /* @__PURE__ */ jsx("span", { children: usage.inputTokens === void 0 ? "—" : formatCompact(usage.inputTokens) })
83
+ ] }),
84
+ /* @__PURE__ */ jsxs(SummaryItem, { label: "Output tokens", children: [
85
+ /* @__PURE__ */ jsx(ArrowUpFromLineIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
86
+ /* @__PURE__ */ jsx("span", { children: usage.outputTokens === void 0 ? "—" : formatCompact(usage.outputTokens) })
87
+ ] }),
88
+ /* @__PURE__ */ jsxs(SummaryItem, { label: "Estimated cost", children: [
89
+ /* @__PURE__ */ jsx(CircleDollarSignIcon, { className: "size-3.5 shrink-0", "aria-hidden": "true" }),
90
+ /* @__PURE__ */ jsx("span", { children: usage.estimatedCost === void 0 ? "—" : formatCost(usage.estimatedCost, usage.costUnit) })
91
+ ] })
92
+ ] })
93
+ ]
94
+ }
95
+ );
96
+ }
97
+
98
+ export { TraceSummaryDescription };
99
+ //# sourceMappingURL=trace-summary-description.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-summary-description.es.js","sources":["../../../../src/domains/traces/components/trace-summary-description.tsx"],"sourcesContent":["import {\n ArrowDownToLineIcon,\n ArrowUpFromLineIcon,\n CalendarClockIcon,\n CircleDollarSignIcon,\n ExternalLinkIcon,\n TimerIcon,\n} from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport {\n formatSpanDuration,\n formatSpanDurationExact,\n formatSpanTimestamp,\n formatSpanTimestampExact,\n} from '../utils/span-utils';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/ds/components/Tooltip';\nimport { AgentIcon, WorkflowIcon } from '@/ds/icons';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { cn } from '@/lib/utils';\n\nfunction formatEntityType(entityType: string): string {\n return entityType\n .split('_')\n .map(word => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)\n .join(' ');\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n};\n\nexport interface TraceSummaryDescriptionProps {\n rootSpan: RootSpanSummary;\n usage?: TraceUsageSummary;\n /** When provided (with `LinkComponent`), the entity name links to the entity's page. */\n entityHref?: string;\n LinkComponent?: LinkComponent;\n className?: string;\n}\n\nfunction SummaryItem({ label, children }: { label: string; children: ReactNode }) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n tabIndex={0}\n className=\"flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap\"\n aria-label={label}\n >\n {children}\n </span>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** Compact trace metadata shown under the trace side-panel heading. */\nexport function TraceSummaryDescription({\n rootSpan,\n usage,\n entityHref,\n LinkComponent,\n className,\n}: TraceSummaryDescriptionProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const duration = formatSpanDuration(startedAt, endedAt);\n const exactDuration = formatSpanDurationExact(startedAt, endedAt);\n const startedAtTimestamp = formatSpanTimestamp(startedAt);\n const exactStartedAtTimestamp = formatSpanTimestampExact(startedAt);\n\n const entityName = rootSpan.entityName || rootSpan.entityId;\n const entityType = rootSpan.entityType;\n const formattedEntityType = entityType ? formatEntityType(entityType) : 'Entity';\n const EntityIcon = entityType?.includes('workflow') ? WorkflowIcon : AgentIcon;\n const Link = LinkComponent ?? 'a';\n\n return (\n <div\n className={cn(\n 'flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 text-ui-xs leading-ui-xs text-neutral3',\n className,\n )}\n >\n {entityName && (\n <Tooltip>\n <TooltipTrigger asChild>\n {entityHref ? (\n <Link\n href={entityHref}\n className=\"text-neutral4 hover:text-neutral5 flex shrink-0 items-center gap-1 whitespace-nowrap hover:underline\"\n >\n <EntityIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{entityName}</span>\n <ExternalLinkIcon className=\"size-3 shrink-0\" aria-hidden=\"true\" />\n </Link>\n ) : (\n <span tabIndex={0} className=\"flex shrink-0 cursor-help items-center gap-1 whitespace-nowrap\">\n <EntityIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{entityName}</span>\n </span>\n )}\n </TooltipTrigger>\n <TooltipContent>{formattedEntityType}</TooltipContent>\n </Tooltip>\n )}\n {startedAtTimestamp && exactStartedAtTimestamp && (\n <SummaryItem label={`Started at ${exactStartedAtTimestamp}`}>\n <CalendarClockIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{startedAtTimestamp}</span>\n </SummaryItem>\n )}\n {duration && exactDuration && (\n <SummaryItem label={`Duration ${exactDuration}`}>\n <TimerIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{duration}</span>\n </SummaryItem>\n )}\n {usage && (\n <>\n <SummaryItem label=\"Input tokens\">\n <ArrowDownToLineIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{usage.inputTokens === undefined ? '—' : formatCompact(usage.inputTokens)}</span>\n </SummaryItem>\n <SummaryItem label=\"Output tokens\">\n <ArrowUpFromLineIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{usage.outputTokens === undefined ? '—' : formatCompact(usage.outputTokens)}</span>\n </SummaryItem>\n <SummaryItem label=\"Estimated cost\">\n <CircleDollarSignIcon className=\"size-3.5 shrink-0\" aria-hidden=\"true\" />\n <span>{usage.estimatedCost === undefined ? '—' : formatCost(usage.estimatedCost, usage.costUnit)}</span>\n </SummaryItem>\n </>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -8,12 +8,6 @@ export interface TraceDataPanelViewProps {
8
8
  traceId: string;
9
9
  /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */
10
10
  spans: SearchableSpan[] | undefined;
11
- /**
12
- * Token and estimated-cost totals for the trace (from `useTraceUsage`).
13
- * Rendered in the trace summary when the panel is in the list side-panel
14
- * placement; the trace page renders its own `TraceKeysAndValues` instead.
15
- */
16
- usage?: TraceUsageSummary;
17
11
  isLoading?: boolean;
18
12
  onClose: () => void;
19
13
  onSpanSelect?: (spanId: string | undefined) => void;
@@ -37,6 +31,10 @@ export interface TraceDataPanelViewProps {
37
31
  /** When both are provided, renders an "Open trace page" button. */
38
32
  LinkComponent?: LinkComponent;
39
33
  traceHref?: string;
34
+ /** When provided, the entity name in the trace summary links to the entity's page. */
35
+ entityHref?: string;
36
+ /** Token and estimated-cost totals shown in the compact trace summary. */
37
+ usage?: TraceUsageSummary;
40
38
  /**
41
39
  * Span treated as the displayed root of the timeline. Required for branch
42
40
  * subtrees from `getBranch` where the anchor has a real parent that's outside
@@ -80,4 +78,4 @@ export interface TraceDataPanelViewProps {
80
78
  /** Extra classes applied to the panel root (e.g. `h-full` on the trace page). */
81
79
  className?: string;
82
80
  }
83
- export declare function TraceDataPanelView({ traceId, spans, usage, isLoading, onClose, onSpanSelect, onEvaluateTrace, onSaveAsDatasetItem, onAddTraceMocksToItem, initialSpanId, onPrevious, onNext, collapsed: controlledCollapsed, onCollapsedChange, placement, timelineChartWidth, LinkComponent, traceHref, anchorSpanId, showUnavailableFeaturesMsg, scoresTabSlot, scoresTabBadge, feedbackTabSlot, feedbackTabBadge, activeTab, onTabChange, spanPanelSlot, className, }: TraceDataPanelViewProps): import("react").JSX.Element;
81
+ export declare function TraceDataPanelView({ traceId, spans, isLoading, onClose, onSpanSelect, onEvaluateTrace, onSaveAsDatasetItem, onAddTraceMocksToItem, initialSpanId, onPrevious, onNext, collapsed: controlledCollapsed, onCollapsedChange, placement, timelineChartWidth, LinkComponent, traceHref, entityHref, usage, anchorSpanId, showUnavailableFeaturesMsg, scoresTabSlot, scoresTabBadge, feedbackTabSlot, feedbackTabBadge, activeTab, onTabChange, spanPanelSlot, className, }: TraceDataPanelViewProps): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { TraceUsageSummary } from '../trace-list-columns';
2
+ import { LinkComponent } from '../../../ds/types/link-component';
3
+ /** Lightweight root-span fields available from `useTraceLightSpans`. */
4
+ type RootSpanSummary = {
5
+ entityId?: string | null;
6
+ entityName?: string | null;
7
+ entityType?: string | null;
8
+ startedAt: Date | string;
9
+ endedAt?: Date | string | null;
10
+ };
11
+ export interface TraceSummaryDescriptionProps {
12
+ rootSpan: RootSpanSummary;
13
+ usage?: TraceUsageSummary;
14
+ /** When provided (with `LinkComponent`), the entity name links to the entity's page. */
15
+ entityHref?: string;
16
+ LinkComponent?: LinkComponent;
17
+ className?: string;
18
+ }
19
+ /** Compact trace metadata shown under the trace side-panel heading. */
20
+ export declare function TraceSummaryDescription({ rootSpan, usage, entityHref, LinkComponent, className, }: TraceSummaryDescriptionProps): import("react").JSX.Element;
21
+ export {};
package/dist/style.css CHANGED
@@ -7700,6 +7700,10 @@
7700
7700
  color: var(--color-white);
7701
7701
  }
7702
7702
 
7703
+ .hover\:underline:hover {
7704
+ text-decoration-line: underline;
7705
+ }
7706
+
7703
7707
  .hover\:opacity-70:hover {
7704
7708
  opacity: .7;
7705
7709
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mastra/playground-ui",
3
3
  "type": "module",
4
- "version": "51.4.0-alpha.6",
4
+ "version": "51.4.0-alpha.7",
5
5
  "description": "Mastra Playground components",
6
6
  "sideEffects": [
7
7
  "**/*.css"
@@ -160,8 +160,8 @@
160
160
  "react": ">=19.0.0",
161
161
  "react-dom": ">=19.0.0",
162
162
  "tailwindcss": "^4.0.0",
163
- "@mastra/client-js": "^1.42.5-alpha.3",
164
- "@mastra/react": "1.4.10-alpha.4"
163
+ "@mastra/react": "1.4.10-alpha.5",
164
+ "@mastra/client-js": "^1.42.5-alpha.4"
165
165
  },
166
166
  "devDependencies": {
167
167
  "@storybook/addon-a11y": "^10.4.1",
@@ -203,9 +203,9 @@
203
203
  "vite-plugin-lib-inject-css": "^2.2.2",
204
204
  "vitest": "4.1.10",
205
205
  "@internal/lint": "0.0.129",
206
- "@mastra/client-js": "^1.42.5-alpha.3",
207
- "@mastra/react": "1.4.10-alpha.4",
208
- "@mastra/core": "1.64.0-alpha.3",
206
+ "@mastra/client-js": "^1.42.5-alpha.4",
207
+ "@mastra/core": "1.64.0-alpha.4",
208
+ "@mastra/react": "1.4.10-alpha.5",
209
209
  "@mastra/memory": "1.28.2-alpha.1"
210
210
  },
211
211
  "homepage": "https://mastra.ai",