@mastra/playground-ui 55.0.0 → 55.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DataPanel.cjs.js +1 -1
- package/dist/components/DataPanel.es.js +1 -1
- package/dist/components/MainSidebar.cjs.js +26 -737
- package/dist/components/MainSidebar.cjs.js.map +1 -1
- package/dist/components/MainSidebar.es.js +4 -714
- package/dist/components/MainSidebar.es.js.map +1 -1
- package/dist/{data-panel-tSErqolu.cjs → data-panel-Bzws5n5c.cjs} +25 -8
- package/dist/data-panel-Bzws5n5c.cjs.map +1 -0
- package/dist/{data-panel-5iuux0r_.js → data-panel-C-H4tAEw.js} +25 -8
- package/dist/data-panel-C-H4tAEw.js.map +1 -0
- package/dist/domains/traces/components/span-data-panel-view.cjs.js +3 -2
- package/dist/domains/traces/components/span-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/span-data-panel-view.es.js +3 -2
- package/dist/domains/traces/components/span-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/thread-trace/thread-trace-details.cjs.js +1 -1
- package/dist/domains/traces/components/thread-trace/thread-trace-details.es.js +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +12 -11
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js +13 -12
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/trace-span-timeline.cjs.js +1 -1
- package/dist/domains/traces/components/trace-span-timeline.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-span-timeline.es.js +1 -1
- package/dist/domains/traces/components/trace-span-timeline.es.js.map +1 -1
- package/dist/domains/traces/components/trace-span-tree.cjs.js +1 -1
- package/dist/domains/traces/components/trace-span-tree.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-span-tree.es.js +1 -1
- package/dist/domains/traces/components/trace-span-tree.es.js.map +1 -1
- package/dist/main-sidebar-link-active-BK4RR4Az.js +719 -0
- package/dist/main-sidebar-link-active-BK4RR4Az.js.map +1 -0
- package/dist/main-sidebar-link-active-DLGDYeTJ.cjs +736 -0
- package/dist/main-sidebar-link-active-DLGDYeTJ.cjs.map +1 -0
- package/dist/new/sidebar.cjs.js +457 -0
- package/dist/new/sidebar.cjs.js.map +1 -0
- package/dist/new/sidebar.d.ts +2 -0
- package/dist/new/sidebar.es.js +440 -0
- package/dist/new/sidebar.es.js.map +1 -0
- package/dist/src/ds/components/DataPanel/data-panel-close-button.d.ts +3 -1
- package/dist/src/ds/components/DataPanel/data-panel-content.d.ts +3 -1
- package/dist/src/ds/components/DataPanel/data-panel-next-prev-nav.d.ts +3 -1
- package/dist/src/ds/new/sidebar/index.d.ts +12 -0
- package/dist/src/ds/new/sidebar/sidebar-new-brand.d.ts +6 -0
- package/dist/src/ds/new/sidebar/sidebar-new-footer.d.ts +3 -0
- package/dist/src/ds/new/sidebar/sidebar-new-header.d.ts +3 -0
- package/dist/src/ds/new/sidebar/sidebar-new-meter.d.ts +34 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-header.d.ts +11 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-stack-context.d.ts +8 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-stack-page-classes.d.ts +1 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-stack-root-view.d.ts +3 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-stack-root.d.ts +7 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-stack-view.d.ts +9 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav-stack.d.ts +10 -0
- package/dist/src/ds/new/sidebar/sidebar-new-nav.d.ts +3 -0
- package/dist/src/ds/new/sidebar/sidebar-new-root.d.ts +5 -0
- package/dist/src/ds/new/sidebar/sidebar-new-section-link.d.ts +8 -0
- package/dist/src/ds/new/sidebar/sidebar-new-sections.d.ts +8 -0
- package/dist/src/ds/new/sidebar/sidebar-new-trigger.d.ts +3 -0
- package/dist/src/ds/new/sidebar/sidebar-new.d.ts +36 -0
- package/dist/src/ds/new/sidebar/sidebar-new.stories.d.ts +6 -0
- package/dist/style.css +118 -0
- package/package.json +13 -7
- package/theme.css +48 -0
- package/dist/data-panel-5iuux0r_.js.map +0 -1
- package/dist/data-panel-tSErqolu.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"span-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/span-data-panel-view.tsx"],"sourcesContent":["import type { SpanRecord } from '@mastra/core/storage';\nimport { BracesIcon, FileInputIcon, FileOutputIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { getTokenLimitMessage, isTokenLimitExceeded } from '../utils/span-utils';\nimport { SpanSummaryDescription } from './span-summary-description';\nimport { SpanTokenUsage } from './span-token-usage';\nimport type { TokenUsage } from './span-token-usage';\nimport { TraceIdButton } from './trace-id-button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Tab, TabContent, TabList, Tabs } from '@/ds/components/Tabs';\n\nfunction buildDialogTitle(sectionTitle: string, icon: ReactNode, span: { spanId: string; traceId: string }) {\n return (\n <>\n <span className=\"text-neutral2 flex items-center gap-1.5 tracking-widest uppercase [&>svg]:size-3.5\">\n {icon}\n {sectionTitle}\n </span>\n <span>\n › Span <b className=\"text-neutral3\">{span.spanId}</b>\n </span>\n <span>\n › Trace <b className=\"text-neutral3\">{span.traceId}</b>\n </span>\n </>\n );\n}\n\nexport interface SpanDataPanelViewProps {\n traceId: string;\n spanId: string;\n /** Full span record. Caller fetches via useSpanDetail. */\n span: SpanRecord | undefined;\n isLoading?: boolean;\n onClose: () => void;\n onPrevious?: () => void;\n onNext?: () => void;\n activeTab?: string;\n onTabChange?: (tab: string) => void;\n /**\n * When provided, a \"Feedback\" tab appears; the slot receives the loaded span and renders\n * whatever feedback UI the consumer wants.\n */\n feedbackTabSlot?: (args: { span: SpanRecord; traceId: string; spanId: string }) => ReactNode;\n /** Optional indicator rendered after the \"Feedback\" tab label (e.g. a needs-review dot). */\n feedbackTabBadge?: ReactNode;\n /**\n * Whether this span is the displayed root of the current view (trace root or\n * branch anchor). Controls visibility of trace-level metadata fields. Defaults\n * to `span.parentSpanId == null` (trace case) when omitted.\n */\n isAnchor?: boolean;\n /** Extra classes for the panel root (e.g. flattening the card when nested in the trace panel). */\n className?: string;\n}\n\nexport function SpanDataPanelView({\n traceId,\n spanId,\n span,\n isLoading,\n onClose,\n onPrevious,\n onNext,\n activeTab,\n onTabChange,\n feedbackTabSlot,\n feedbackTabBadge,\n isAnchor,\n className,\n}: SpanDataPanelViewProps) {\n return (\n <DataPanel className={className}>\n {/* Two-line header (heading + summary); neighbouring panel headers use min-h-16 to stay level. */}\n <DataPanel.Header className=\"min-h-16 py-2\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <DataPanel.Heading className=\"items-center whitespace-nowrap\">\n Span\n <TraceIdButton id={spanId} />\n </DataPanel.Heading>\n {span && <SpanSummaryDescription span={span} />}\n </div>\n <ButtonsGroup className=\"ml-auto shrink-0 self-start\">\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous span\"\n nextLabel=\"Next span\"\n />\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </DataPanel.Header>\n\n {isLoading ? (\n <DataPanel.LoadingData>Loading span details...</DataPanel.LoadingData>\n ) : !span ? (\n <DataPanel.NoData>Span not found.</DataPanel.NoData>\n ) : (\n <SpanDataPanelContent\n span={span}\n traceId={traceId}\n spanId={spanId}\n activeTab={activeTab}\n onTabChange={onTabChange}\n feedbackTabSlot={feedbackTabSlot}\n feedbackTabBadge={feedbackTabBadge}\n isAnchor={isAnchor}\n />\n )}\n </DataPanel>\n );\n}\n\nfunction SpanDataPanelContent({\n span,\n traceId,\n spanId,\n activeTab,\n onTabChange,\n feedbackTabSlot,\n feedbackTabBadge,\n isAnchor,\n}: {\n span: SpanRecord;\n traceId: string;\n spanId: string;\n activeTab?: string;\n onTabChange?: (tab: string) => void;\n feedbackTabSlot?: (args: { span: SpanRecord; traceId: string; spanId: string }) => ReactNode;\n feedbackTabBadge?: ReactNode;\n isAnchor?: boolean;\n}) {\n const usage = span.attributes?.usage as TokenUsage | undefined;\n\n const detailsBody = (\n <>\n {isTokenLimitExceeded(span) && (\n <div className=\"mb-3\">\n <Notice variant=\"warning\" title=\"Token Limit Exceeded\">\n <Notice.Message>{getTokenLimitMessage(span)}</Notice.Message>\n </Notice>\n </div>\n )}\n\n {usage && <SpanTokenUsage usage={usage} className=\"mb-3\" />}\n\n <DataKeysAndValues>\n {/* Anchor-only: rich trace-context fields. Live on the full SpanRecord, not on the\n * lightweight payload, so they only have values once the full span is loaded. */}\n {(isAnchor ?? span.parentSpanId == null) && (\n <>\n {span.tags && span.tags.length > 0 && (\n <>\n <DataKeysAndValues.Key>Tags</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{span.tags.join(', ')}</DataKeysAndValues.Value>\n </>\n )}\n {span.sessionId && (\n <>\n <DataKeysAndValues.Key>Session Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Session Id to clipboard\"\n copyValue={span.sessionId}\n >\n {span.sessionId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.requestId && (\n <>\n <DataKeysAndValues.Key>Request Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Request Id to clipboard\"\n copyValue={span.requestId}\n >\n {span.requestId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.userId && (\n <>\n <DataKeysAndValues.Key>User Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn copyTooltip=\"Copy User Id to clipboard\" copyValue={span.userId}>\n {span.userId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.organizationId && (\n <>\n <DataKeysAndValues.Key>Organization Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Organization Id to clipboard\"\n copyValue={span.organizationId}\n >\n {span.organizationId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.experimentId && (\n <>\n <DataKeysAndValues.Key>Experiment Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Experiment Id to clipboard\"\n copyValue={span.experimentId}\n >\n {span.experimentId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n </>\n )}\n </DataKeysAndValues>\n\n <div className=\"mt-3 grid gap-3\">\n <DataPanel.CodeSection\n title=\"Input\"\n dialogTitle={buildDialogTitle('Input', <FileInputIcon />, { spanId, traceId })}\n icon={<FileInputIcon />}\n codeStr={JSON.stringify(span.input ?? null, null, 2)}\n />\n <DataPanel.CodeSection\n title=\"Output\"\n dialogTitle={buildDialogTitle('Output', <FileOutputIcon />, { spanId, traceId })}\n icon={<FileOutputIcon />}\n codeStr={JSON.stringify(span.output ?? null, null, 2)}\n />\n <DataPanel.CodeSection\n title=\"Metadata\"\n dialogTitle={buildDialogTitle('Metadata', <BracesIcon />, { spanId, traceId })}\n icon={<BracesIcon />}\n codeStr={JSON.stringify(span.metadata ?? null, null, 2)}\n />\n <DataPanel.CodeSection\n title=\"Attributes\"\n dialogTitle={buildDialogTitle('Attributes', <BracesIcon />, { spanId, traceId })}\n icon={<BracesIcon />}\n codeStr={JSON.stringify(span.attributes ?? null, null, 2)}\n />\n </div>\n </>\n );\n\n // No extra tab slots → render details directly without the Tabs/TabList wrapper.\n if (!feedbackTabSlot) {\n return <DataPanel.Content>{detailsBody}</DataPanel.Content>;\n }\n\n return (\n <DataPanel.Content>\n <Tabs defaultTab=\"details\" value={activeTab} onValueChange={onTabChange}>\n <TabList variant=\"pill-ghost\">\n <Tab value=\"details\">Details</Tab>\n <Tab value=\"feedback\">Feedback{feedbackTabBadge}</Tab>\n </TabList>\n\n <TabContent value=\"details\">{detailsBody}</TabContent>\n <TabContent value=\"feedback\">{feedbackTabSlot({ span, traceId, spanId })}</TabContent>\n </Tabs>\n </DataPanel.Content>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"span-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/span-data-panel-view.tsx"],"sourcesContent":["import type { SpanRecord } from '@mastra/core/storage';\nimport { BracesIcon, FileInputIcon, FileOutputIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { getTokenLimitMessage, isTokenLimitExceeded } from '../utils/span-utils';\nimport { SpanSummaryDescription } from './span-summary-description';\nimport { SpanTokenUsage } from './span-token-usage';\nimport type { TokenUsage } from './span-token-usage';\nimport { TraceIdButton } from './trace-id-button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Tab, TabContent, TabList, Tabs } from '@/ds/components/Tabs';\n\nfunction buildDialogTitle(sectionTitle: string, icon: ReactNode, span: { spanId: string; traceId: string }) {\n return (\n <>\n <span className=\"text-neutral2 flex items-center gap-1.5 tracking-widest uppercase [&>svg]:size-3.5\">\n {icon}\n {sectionTitle}\n </span>\n <span>\n › Span <b className=\"text-neutral3\">{span.spanId}</b>\n </span>\n <span>\n › Trace <b className=\"text-neutral3\">{span.traceId}</b>\n </span>\n </>\n );\n}\n\nexport interface SpanDataPanelViewProps {\n traceId: string;\n spanId: string;\n /** Full span record. Caller fetches via useSpanDetail. */\n span: SpanRecord | undefined;\n isLoading?: boolean;\n onClose: () => void;\n onPrevious?: () => void;\n onNext?: () => void;\n activeTab?: string;\n onTabChange?: (tab: string) => void;\n /**\n * When provided, a \"Feedback\" tab appears; the slot receives the loaded span and renders\n * whatever feedback UI the consumer wants.\n */\n feedbackTabSlot?: (args: { span: SpanRecord; traceId: string; spanId: string }) => ReactNode;\n /** Optional indicator rendered after the \"Feedback\" tab label (e.g. a needs-review dot). */\n feedbackTabBadge?: ReactNode;\n /**\n * Whether this span is the displayed root of the current view (trace root or\n * branch anchor). Controls visibility of trace-level metadata fields. Defaults\n * to `span.parentSpanId == null` (trace case) when omitted.\n */\n isAnchor?: boolean;\n /** Extra classes for the panel root (e.g. flattening the card when nested in the trace panel). */\n className?: string;\n}\n\nexport function SpanDataPanelView({\n traceId,\n spanId,\n span,\n isLoading,\n onClose,\n onPrevious,\n onNext,\n activeTab,\n onTabChange,\n feedbackTabSlot,\n feedbackTabBadge,\n isAnchor,\n className,\n}: SpanDataPanelViewProps) {\n return (\n <DataPanel className={className}>\n {/* Two-line header (heading + summary); neighbouring panel headers use min-h-16 to stay level. */}\n <DataPanel.Header className=\"min-h-16 py-2\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <DataPanel.Heading className=\"items-center whitespace-nowrap\">\n Span\n <TraceIdButton id={spanId} />\n </DataPanel.Heading>\n {span && <SpanSummaryDescription span={span} />}\n </div>\n <ButtonsGroup className=\"ml-auto shrink-0 self-start\">\n <DataPanel.NextPrevNav\n variant=\"ghost\"\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous span\"\n nextLabel=\"Next span\"\n />\n <DataPanel.CloseButton variant=\"ghost\" onClick={onClose} />\n </ButtonsGroup>\n </DataPanel.Header>\n\n {isLoading ? (\n <DataPanel.LoadingData>Loading span details...</DataPanel.LoadingData>\n ) : !span ? (\n <DataPanel.NoData>Span not found.</DataPanel.NoData>\n ) : (\n <SpanDataPanelContent\n span={span}\n traceId={traceId}\n spanId={spanId}\n activeTab={activeTab}\n onTabChange={onTabChange}\n feedbackTabSlot={feedbackTabSlot}\n feedbackTabBadge={feedbackTabBadge}\n isAnchor={isAnchor}\n />\n )}\n </DataPanel>\n );\n}\n\nfunction SpanDataPanelContent({\n span,\n traceId,\n spanId,\n activeTab,\n onTabChange,\n feedbackTabSlot,\n feedbackTabBadge,\n isAnchor,\n}: {\n span: SpanRecord;\n traceId: string;\n spanId: string;\n activeTab?: string;\n onTabChange?: (tab: string) => void;\n feedbackTabSlot?: (args: { span: SpanRecord; traceId: string; spanId: string }) => ReactNode;\n feedbackTabBadge?: ReactNode;\n isAnchor?: boolean;\n}) {\n const usage = span.attributes?.usage as TokenUsage | undefined;\n\n const detailsBody = (\n <>\n {isTokenLimitExceeded(span) && (\n <div className=\"mb-3\">\n <Notice variant=\"warning\" title=\"Token Limit Exceeded\">\n <Notice.Message>{getTokenLimitMessage(span)}</Notice.Message>\n </Notice>\n </div>\n )}\n\n {usage && <SpanTokenUsage usage={usage} className=\"mb-3\" />}\n\n <DataKeysAndValues>\n {/* Anchor-only: rich trace-context fields. Live on the full SpanRecord, not on the\n * lightweight payload, so they only have values once the full span is loaded. */}\n {(isAnchor ?? span.parentSpanId == null) && (\n <>\n {span.tags && span.tags.length > 0 && (\n <>\n <DataKeysAndValues.Key>Tags</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{span.tags.join(', ')}</DataKeysAndValues.Value>\n </>\n )}\n {span.sessionId && (\n <>\n <DataKeysAndValues.Key>Session Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Session Id to clipboard\"\n copyValue={span.sessionId}\n >\n {span.sessionId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.requestId && (\n <>\n <DataKeysAndValues.Key>Request Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Request Id to clipboard\"\n copyValue={span.requestId}\n >\n {span.requestId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.userId && (\n <>\n <DataKeysAndValues.Key>User Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn copyTooltip=\"Copy User Id to clipboard\" copyValue={span.userId}>\n {span.userId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.organizationId && (\n <>\n <DataKeysAndValues.Key>Organization Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Organization Id to clipboard\"\n copyValue={span.organizationId}\n >\n {span.organizationId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n {span.experimentId && (\n <>\n <DataKeysAndValues.Key>Experiment Id</DataKeysAndValues.Key>\n <DataKeysAndValues.ValueWithCopyBtn\n copyTooltip=\"Copy Experiment Id to clipboard\"\n copyValue={span.experimentId}\n >\n {span.experimentId}\n </DataKeysAndValues.ValueWithCopyBtn>\n </>\n )}\n </>\n )}\n </DataKeysAndValues>\n\n <div className=\"mt-3 grid gap-3\">\n <DataPanel.CodeSection\n title=\"Input\"\n dialogTitle={buildDialogTitle('Input', <FileInputIcon />, { spanId, traceId })}\n icon={<FileInputIcon />}\n codeStr={JSON.stringify(span.input ?? null, null, 2)}\n />\n <DataPanel.CodeSection\n title=\"Output\"\n dialogTitle={buildDialogTitle('Output', <FileOutputIcon />, { spanId, traceId })}\n icon={<FileOutputIcon />}\n codeStr={JSON.stringify(span.output ?? null, null, 2)}\n />\n <DataPanel.CodeSection\n title=\"Metadata\"\n dialogTitle={buildDialogTitle('Metadata', <BracesIcon />, { spanId, traceId })}\n icon={<BracesIcon />}\n codeStr={JSON.stringify(span.metadata ?? null, null, 2)}\n />\n <DataPanel.CodeSection\n title=\"Attributes\"\n dialogTitle={buildDialogTitle('Attributes', <BracesIcon />, { spanId, traceId })}\n icon={<BracesIcon />}\n codeStr={JSON.stringify(span.attributes ?? null, null, 2)}\n />\n </div>\n </>\n );\n\n // No extra tab slots → render details directly without the Tabs/TabList wrapper.\n if (!feedbackTabSlot) {\n return <DataPanel.Content>{detailsBody}</DataPanel.Content>;\n }\n\n return (\n <DataPanel.Content>\n <Tabs defaultTab=\"details\" value={activeTab} onValueChange={onTabChange}>\n <TabList variant=\"pill-ghost\">\n <Tab value=\"details\">Details</Tab>\n <Tab value=\"feedback\">Feedback{feedbackTabBadge}</Tab>\n </TabList>\n\n <TabContent value=\"details\">{detailsBody}</TabContent>\n <TabContent value=\"feedback\">{feedbackTabSlot({ span, traceId, spanId })}</TabContent>\n </Tabs>\n </DataPanel.Content>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
5
5
|
const jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
const domains_traces_components_threadTrace_threadTraceRow = require('./thread-trace-row.cjs.js');
|
|
7
7
|
const domains_traces_components_threadTrace_threadTraceRowContext = require('./thread-trace-row-context.cjs.js');
|
|
8
|
-
const dataPanel = require('../../../../data-panel-
|
|
8
|
+
const dataPanel = require('../../../../data-panel-Bzws5n5c.cjs');
|
|
9
9
|
const tabsRoot = require('../../../../tabs-root-Dw7gHsnZ.cjs');
|
|
10
10
|
const tabsTab = require('../../../../tabs-tab-CP-kzlvB.cjs');
|
|
11
11
|
const tabsContent = require('../../../../tabs-content-CV7YrtD1.cjs');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { THREAD_TRACE_SPANS_TAB } from './thread-trace-row.es.js';
|
|
3
3
|
import { useThreadTraceRow } from './thread-trace-row-context.es.js';
|
|
4
|
-
import { D as DataPanel } from '../../../../data-panel-
|
|
4
|
+
import { D as DataPanel } from '../../../../data-panel-C-H4tAEw.js';
|
|
5
5
|
import { T as TabList, a as Tabs } from '../../../../tabs-root-BAy8m6GO.js';
|
|
6
6
|
import { T as Tab } from '../../../../tabs-tab-K5mQhs7r.js';
|
|
7
7
|
import { T as TabContent } from '../../../../tabs-content-CW6RtAEV.js';
|
|
@@ -15,7 +15,7 @@ const domains_traces_components_traceSpanTree = require('./trace-span-tree.cjs.j
|
|
|
15
15
|
const domains_traces_components_traceSummaryDescription = require('./trace-summary-description.cjs.js');
|
|
16
16
|
const Button = require('../../../Button-BJOVwaxp.cjs');
|
|
17
17
|
const buttonsGroup = require('../../../buttons-group-jq7kUVlX.cjs');
|
|
18
|
-
const dataPanel = require('../../../data-panel-
|
|
18
|
+
const dataPanel = require('../../../data-panel-Bzws5n5c.cjs');
|
|
19
19
|
const dropdownMenu = require('../../../dropdown-menu-Bfh5ROWe.cjs');
|
|
20
20
|
const searchFieldBlock = require('../../../search-field-block-DnJYUEGi.cjs');
|
|
21
21
|
const Notice = require('../../../Notice-D0Mvqvr0.cjs');
|
|
@@ -116,7 +116,7 @@ function TraceDataPanelView({
|
|
|
116
116
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
117
117
|
dropdownMenu.DropdownMenu.Trigger,
|
|
118
118
|
{
|
|
119
|
-
render: /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { size: "md", tooltip: "Trace actions", "aria-label": "Trace actions", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontalIcon, {}) })
|
|
119
|
+
render: /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { size: "md", variant: "ghost", tooltip: "Trace actions", "aria-label": "Trace actions", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontalIcon, {}) })
|
|
120
120
|
}
|
|
121
121
|
),
|
|
122
122
|
/* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Content, { align: "end", children: [
|
|
@@ -124,10 +124,6 @@ function TraceDataPanelView({
|
|
|
124
124
|
collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUpIcon, {}),
|
|
125
125
|
collapsed ? "Expand panel" : "Collapse panel"
|
|
126
126
|
] }),
|
|
127
|
-
!isOnTracePage && onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { onSelect: onEvaluateTrace, children: [
|
|
128
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}),
|
|
129
|
-
"Evaluate trace"
|
|
130
|
-
] }),
|
|
131
127
|
!isOnTracePage && onSaveAsDatasetItem && /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu.Item, { onSelect: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }), children: [
|
|
132
128
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SaveIcon, {}),
|
|
133
129
|
"Add full trace to dataset"
|
|
@@ -167,17 +163,22 @@ function TraceDataPanelView({
|
|
|
167
163
|
)
|
|
168
164
|
] }),
|
|
169
165
|
/* @__PURE__ */ jsxRuntime.jsxs(buttonsGroup.ButtonsGroup, { className: "ml-auto shrink-0 self-start", children: [
|
|
166
|
+
onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsxs(Button.Button, { variant: "primary", size: "md", onClick: onEvaluateTrace, disabled: !rootSpan, children: [
|
|
167
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}),
|
|
168
|
+
"Score trace"
|
|
169
|
+
] }),
|
|
170
170
|
traceActionsMenu,
|
|
171
171
|
(onPrevious || onNext) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
172
172
|
dataPanel.DataPanel.NextPrevNav,
|
|
173
173
|
{
|
|
174
|
+
variant: "ghost",
|
|
174
175
|
onPrevious,
|
|
175
176
|
onNext,
|
|
176
177
|
previousLabel: "Previous trace",
|
|
177
178
|
nextLabel: "Next trace"
|
|
178
179
|
}
|
|
179
180
|
),
|
|
180
|
-
/* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.CloseButton, { onClick: onClose })
|
|
181
|
+
/* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.CloseButton, { variant: "ghost", onClick: onClose })
|
|
181
182
|
] })
|
|
182
183
|
] }) }),
|
|
183
184
|
!collapsed && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -229,7 +230,7 @@ function TraceDataPanelView({
|
|
|
229
230
|
] })
|
|
230
231
|
] })
|
|
231
232
|
] }) }),
|
|
232
|
-
/* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "details", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Content, { children: [
|
|
233
|
+
/* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "details", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Content, { className: "px-2", children: [
|
|
233
234
|
!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)." }) }),
|
|
234
235
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
235
236
|
domains_traces_components_traceSpanTree.TraceSpanTree,
|
|
@@ -245,7 +246,7 @@ function TraceDataPanelView({
|
|
|
245
246
|
),
|
|
246
247
|
noSearchResults
|
|
247
248
|
] }) }),
|
|
248
|
-
/* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "timeline", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Content, { children: [
|
|
249
|
+
/* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "timeline", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Content, { className: "px-2", children: [
|
|
249
250
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
250
251
|
domains_traces_components_traceSpanTimeline.TraceSpanTimeline,
|
|
251
252
|
{
|
|
@@ -260,8 +261,8 @@ function TraceDataPanelView({
|
|
|
260
261
|
),
|
|
261
262
|
noSearchResults
|
|
262
263
|
] }) }),
|
|
263
|
-
feedbackTabSlot && /* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "feedback", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Content, { children: feedbackTabSlot({ traceId }) }) }),
|
|
264
|
-
scoresTabSlot && /* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "scores", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Content, { children: scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId }) }) })
|
|
264
|
+
feedbackTabSlot && /* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "feedback", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Content, { className: "px-2", children: feedbackTabSlot({ traceId }) }) }),
|
|
265
|
+
scoresTabSlot && /* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "scores", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.Content, { className: "px-2", children: scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId }) }) })
|
|
265
266
|
]
|
|
266
267
|
}
|
|
267
268
|
);
|
|
@@ -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 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 { TraceIdButton } from './trace-id-button';\nimport { TraceSpanTimeline } from './trace-span-timeline';\nimport { TraceSpanTree } from './trace-span-tree';\nimport { TraceSummaryDescription } from './trace-summary-description';\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 { cn } from '@/lib/utils';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'timeline' | '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 /** @deprecated No longer used: the panel renders the span tree with the duration as text. */\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, a \"Scores\" tab appears; the slot renders whatever trace-level\n * 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 indicator rendered after the \"Feedback\" tab label (e.g. a needs-review dot). */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /** Span ids to feature in the timeline; every other span is faded. */\n featuredSpanIds?: string[];\n /**\n * Rendered as a column to the left of the span tree inside the same card\n * (typically the trace as one reconstructed agent turn). Collapsed while the\n * Timeline tab is active, since the timeline needs the width.\n */\n messagesPanelSlot?: ReactNode;\n /**\n * Rendered as a column to the right of the timeline inside the same card;\n * typically the span detail.\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 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 featuredSpanIds,\n messagesPanelSlot,\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 // Tracked locally too (tabs may be uncontrolled) so the messages column knows\n // when to fold away for the Timeline tab.\n const [uncontrolledTab, setUncontrolledTab] = useState<TraceDataPanelTab>('details');\n const currentTab = activeTab ?? uncontrolledTab;\n const handleTabChange = (tab: TraceDataPanelTab) => {\n setUncontrolledTab(tab);\n onTabChange?.(tab);\n };\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 className=\"items-center\">\n Trace\n <TraceIdButton id={traceId} />\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 <TracePanelColumns\n messagesPanelSlot={messagesPanelSlot}\n messagesCollapsed={currentTab === 'timeline'}\n spanPanelSlot={spanPanelSlot}\n highlightQuery={query}\n spanPanelKey={selectedSpanId}\n >\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 (() => {\n // Shared by the Spans and Timeline tabs: both views render the same\n // filtered `hierarchicalSpans`, so one query drives both.\n const searchField = (\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 const noSearchResults = hierarchicalSpans.length === 0 && (\n <DataPanel.NoData>No spans match your search.</DataPanel.NoData>\n );\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={handleTabChange}\n className=\"grid h-full min-h-0 grid-rows-[auto_1fr]\"\n >\n <DataPanel.Header className=\"min-h-0 px-2 py-1\">\n <TabList variant=\"pill-ghost\">\n <Tab value=\"details\">Spans</Tab>\n <Tab value=\"timeline\">Timeline</Tab>\n {feedbackTabSlot && <Tab value=\"feedback\">Feedback{feedbackTabBadge}</Tab>}\n {scoresTabSlot && (\n <Tab value=\"scores\">Scores{scoresTabBadge != null && <> ({scoresTabBadge})</>}</Tab>\n )}\n </TabList>\n </DataPanel.Header>\n\n <TabContent value=\"details\" className=\"min-h-0 py-0\">\n <DataPanel.Content>\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 tree 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 <TraceSpanTree\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n <TabContent value=\"timeline\" className=\"min-h-0 py-0\">\n <DataPanel.Content>\n {/* Same selection + expansion state as the Spans tab, so switching views keeps context. */}\n <TraceSpanTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content>{feedbackTabSlot({ traceId })}</DataPanel.Content>\n </TabContent>\n )}\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content>{scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}</DataPanel.Content>\n </TabContent>\n )}\n </Tabs>\n );\n })()\n )}\n </TracePanelColumns>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Lays out the card body as three columns — `[messages] [trace] [span]` — inside\n * the same card. The messages and span cells always exist and collapse to `0fr`\n * when hidden, so opening/closing them animates via `grid-template-columns`\n * rather than mounting/unmounting a DOM column (which cannot be transitioned).\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 TracePanelColumns({\n messagesPanelSlot,\n messagesCollapsed,\n spanPanelSlot,\n highlightQuery,\n spanPanelKey,\n children,\n}: {\n messagesPanelSlot?: ReactNode;\n /** Folds the messages column away (e.g. while the Timeline tab needs the width). */\n messagesCollapsed: boolean;\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 const showMessages = !!messagesPanelSlot && !messagesCollapsed;\n const columns =\n showMessages && spanPanelSlot\n ? 'grid-cols-[1fr_1fr_1fr]'\n : showMessages\n ? 'grid-cols-[1fr_1fr_0fr]'\n : spanPanelSlot\n ? 'grid-cols-[0fr_1fr_1fr]'\n : 'grid-cols-[0fr_1fr_0fr]';\n\n return (\n <div\n ref={highlightRef}\n data-trace-columns\n className={cn('grid min-h-0 flex-1 transition-[grid-template-columns] duration-300 ease-in-out', columns)}\n >\n <div\n className={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n showMessages && 'animate-in border-r border-border1 duration-300 fade-in-0',\n )}\n >\n {messagesPanelSlot}\n </div>\n <div className=\"flex min-h-0 min-w-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={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n spanPanelSlot && 'animate-in border-l border-border1 duration-300 fade-in-0',\n )}\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","TraceIdButton","TraceSummaryDescription","SearchFieldBlock","Tabs","TabList","Tab","TabContent","Notice","TraceSpanTree","TraceSpanTimeline","useTextHighlight","useScrollToFirstHighlight","cn"],"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 { TraceIdButton } from './trace-id-button';\nimport { TraceSpanTimeline } from './trace-span-timeline';\nimport { TraceSpanTree } from './trace-span-tree';\nimport { TraceSummaryDescription } from './trace-summary-description';\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 { cn } from '@/lib/utils';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'timeline' | '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 /** @deprecated No longer used: the panel renders the span tree with the duration as text. */\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, a \"Scores\" tab appears; the slot renders whatever trace-level\n * 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 indicator rendered after the \"Feedback\" tab label (e.g. a needs-review dot). */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /** Span ids to feature in the timeline; every other span is faded. */\n featuredSpanIds?: string[];\n /**\n * Rendered as a column to the left of the span tree inside the same card\n * (typically the trace as one reconstructed agent turn). Collapsed while the\n * Timeline tab is active, since the timeline needs the width.\n */\n messagesPanelSlot?: ReactNode;\n /**\n * Rendered as a column to the right of the timeline inside the same card;\n * typically the span detail.\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 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 featuredSpanIds,\n messagesPanelSlot,\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 // Tracked locally too (tabs may be uncontrolled) so the messages column knows\n // when to fold away for the Timeline tab.\n const [uncontrolledTab, setUncontrolledTab] = useState<TraceDataPanelTab>('details');\n const currentTab = activeTab ?? uncontrolledTab;\n const handleTabChange = (tab: TraceDataPanelTab) => {\n setUncontrolledTab(tab);\n onTabChange?.(tab);\n };\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\" variant=\"ghost\" 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 && 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 className=\"items-center\">\n Trace\n <TraceIdButton id={traceId} />\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 {onEvaluateTrace && (\n <Button variant=\"primary\" size=\"md\" onClick={onEvaluateTrace} disabled={!rootSpan}>\n <CircleGaugeIcon />\n Score trace\n </Button>\n )}\n {traceActionsMenu}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n variant=\"ghost\"\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n <DataPanel.CloseButton variant=\"ghost\" onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed && (\n <TracePanelColumns\n messagesPanelSlot={messagesPanelSlot}\n messagesCollapsed={currentTab === 'timeline'}\n spanPanelSlot={spanPanelSlot}\n highlightQuery={query}\n spanPanelKey={selectedSpanId}\n >\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 (() => {\n // Shared by the Spans and Timeline tabs: both views render the same\n // filtered `hierarchicalSpans`, so one query drives both.\n const searchField = (\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 const noSearchResults = hierarchicalSpans.length === 0 && (\n <DataPanel.NoData>No spans match your search.</DataPanel.NoData>\n );\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={handleTabChange}\n className=\"grid h-full min-h-0 grid-rows-[auto_1fr]\"\n >\n <DataPanel.Header className=\"min-h-0 px-2 py-1\">\n <TabList variant=\"pill-ghost\">\n <Tab value=\"details\">Spans</Tab>\n <Tab value=\"timeline\">Timeline</Tab>\n {feedbackTabSlot && <Tab value=\"feedback\">Feedback{feedbackTabBadge}</Tab>}\n {scoresTabSlot && (\n <Tab value=\"scores\">Scores{scoresTabBadge != null && <> ({scoresTabBadge})</>}</Tab>\n )}\n </TabList>\n </DataPanel.Header>\n\n {/* Tab contents share the tab list's horizontal padding so their edges line up. */}\n <TabContent value=\"details\" className=\"min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">\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 tree 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 <TraceSpanTree\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n <TabContent value=\"timeline\" className=\"min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">\n {/* Same selection + expansion state as the Spans tab, so switching views keeps context. */}\n <TraceSpanTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">{feedbackTabSlot({ traceId })}</DataPanel.Content>\n </TabContent>\n )}\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">\n {scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}\n </DataPanel.Content>\n </TabContent>\n )}\n </Tabs>\n );\n })()\n )}\n </TracePanelColumns>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Lays out the card body as three columns — `[messages] [trace] [span]` — inside\n * the same card. The messages and span cells always exist and collapse to `0fr`\n * when hidden, so opening/closing them animates via `grid-template-columns`\n * rather than mounting/unmounting a DOM column (which cannot be transitioned).\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 TracePanelColumns({\n messagesPanelSlot,\n messagesCollapsed,\n spanPanelSlot,\n highlightQuery,\n spanPanelKey,\n children,\n}: {\n messagesPanelSlot?: ReactNode;\n /** Folds the messages column away (e.g. while the Timeline tab needs the width). */\n messagesCollapsed: boolean;\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 const showMessages = !!messagesPanelSlot && !messagesCollapsed;\n const columns =\n showMessages && spanPanelSlot\n ? 'grid-cols-[1fr_1fr_1fr]'\n : showMessages\n ? 'grid-cols-[1fr_1fr_0fr]'\n : spanPanelSlot\n ? 'grid-cols-[0fr_1fr_1fr]'\n : 'grid-cols-[0fr_1fr_0fr]';\n\n return (\n <div\n ref={highlightRef}\n data-trace-columns\n className={cn('grid min-h-0 flex-1 transition-[grid-template-columns] duration-300 ease-in-out', columns)}\n >\n <div\n className={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n showMessages && 'animate-in border-r border-border1 duration-300 fade-in-0',\n )}\n >\n {messagesPanelSlot}\n </div>\n <div className=\"flex min-h-0 min-w-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={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n spanPanelSlot && 'animate-in border-l border-border1 duration-300 fade-in-0',\n )}\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","SaveIcon","WrenchIcon","Link2Icon","Loader2Icon","DownloadIcon","DataPanel","Fragment","ButtonsGroup","TraceIdButton","TraceSummaryDescription","CircleGaugeIcon","SearchFieldBlock","Tabs","TabList","Tab","TabContent","Notice","TraceSpanTree","TraceSpanTimeline","useTextHighlight","useScrollToFirstHighlight","cn"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { MoreHorizontalIcon, ChevronsUpDownIcon, ChevronsDownUpIcon,
|
|
2
|
+
import { MoreHorizontalIcon, ChevronsUpDownIcon, ChevronsDownUpIcon, SaveIcon, WrenchIcon, Link2Icon, Loader2Icon, DownloadIcon, CircleGaugeIcon } 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';
|
|
@@ -11,7 +11,7 @@ import { TraceSpanTree } from './trace-span-tree.es.js';
|
|
|
11
11
|
import { TraceSummaryDescription } from './trace-summary-description.es.js';
|
|
12
12
|
import { B as Button } from '../../../Button-BVGwYwHT.js';
|
|
13
13
|
import { B as ButtonsGroup } from '../../../buttons-group-CHyXDQBp.js';
|
|
14
|
-
import { D as DataPanel } from '../../../data-panel-
|
|
14
|
+
import { D as DataPanel } from '../../../data-panel-C-H4tAEw.js';
|
|
15
15
|
import { D as DropdownMenu } from '../../../dropdown-menu-C853KwJJ.js';
|
|
16
16
|
import { S as SearchFieldBlock } from '../../../search-field-block-DhgD7NhZ.js';
|
|
17
17
|
import { N as Notice } from '../../../Notice-CMZ86f1g.js';
|
|
@@ -112,7 +112,7 @@ function TraceDataPanelView({
|
|
|
112
112
|
/* @__PURE__ */ jsx(
|
|
113
113
|
DropdownMenu.Trigger,
|
|
114
114
|
{
|
|
115
|
-
render: /* @__PURE__ */ jsx(Button, { size: "md", tooltip: "Trace actions", "aria-label": "Trace actions", children: /* @__PURE__ */ jsx(MoreHorizontalIcon, {}) })
|
|
115
|
+
render: /* @__PURE__ */ jsx(Button, { size: "md", variant: "ghost", tooltip: "Trace actions", "aria-label": "Trace actions", children: /* @__PURE__ */ jsx(MoreHorizontalIcon, {}) })
|
|
116
116
|
}
|
|
117
117
|
),
|
|
118
118
|
/* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "end", children: [
|
|
@@ -120,10 +120,6 @@ function TraceDataPanelView({
|
|
|
120
120
|
collapsed ? /* @__PURE__ */ jsx(ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsx(ChevronsDownUpIcon, {}),
|
|
121
121
|
collapsed ? "Expand panel" : "Collapse panel"
|
|
122
122
|
] }),
|
|
123
|
-
!isOnTracePage && onEvaluateTrace && /* @__PURE__ */ jsxs(DropdownMenu.Item, { onSelect: onEvaluateTrace, children: [
|
|
124
|
-
/* @__PURE__ */ jsx(CircleGaugeIcon, {}),
|
|
125
|
-
"Evaluate trace"
|
|
126
|
-
] }),
|
|
127
123
|
!isOnTracePage && onSaveAsDatasetItem && /* @__PURE__ */ jsxs(DropdownMenu.Item, { onSelect: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }), children: [
|
|
128
124
|
/* @__PURE__ */ jsx(SaveIcon, {}),
|
|
129
125
|
"Add full trace to dataset"
|
|
@@ -163,17 +159,22 @@ function TraceDataPanelView({
|
|
|
163
159
|
)
|
|
164
160
|
] }),
|
|
165
161
|
/* @__PURE__ */ jsxs(ButtonsGroup, { className: "ml-auto shrink-0 self-start", children: [
|
|
162
|
+
onEvaluateTrace && /* @__PURE__ */ jsxs(Button, { variant: "primary", size: "md", onClick: onEvaluateTrace, disabled: !rootSpan, children: [
|
|
163
|
+
/* @__PURE__ */ jsx(CircleGaugeIcon, {}),
|
|
164
|
+
"Score trace"
|
|
165
|
+
] }),
|
|
166
166
|
traceActionsMenu,
|
|
167
167
|
(onPrevious || onNext) && /* @__PURE__ */ jsx(
|
|
168
168
|
DataPanel.NextPrevNav,
|
|
169
169
|
{
|
|
170
|
+
variant: "ghost",
|
|
170
171
|
onPrevious,
|
|
171
172
|
onNext,
|
|
172
173
|
previousLabel: "Previous trace",
|
|
173
174
|
nextLabel: "Next trace"
|
|
174
175
|
}
|
|
175
176
|
),
|
|
176
|
-
/* @__PURE__ */ jsx(DataPanel.CloseButton, { onClick: onClose })
|
|
177
|
+
/* @__PURE__ */ jsx(DataPanel.CloseButton, { variant: "ghost", onClick: onClose })
|
|
177
178
|
] })
|
|
178
179
|
] }) }),
|
|
179
180
|
!collapsed && /* @__PURE__ */ jsx(
|
|
@@ -225,7 +226,7 @@ function TraceDataPanelView({
|
|
|
225
226
|
] })
|
|
226
227
|
] })
|
|
227
228
|
] }) }),
|
|
228
|
-
/* @__PURE__ */ jsx(TabContent, { value: "details", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxs(DataPanel.Content, { children: [
|
|
229
|
+
/* @__PURE__ */ jsx(TabContent, { value: "details", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxs(DataPanel.Content, { className: "px-2", children: [
|
|
229
230
|
!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)." }) }),
|
|
230
231
|
/* @__PURE__ */ jsx(
|
|
231
232
|
TraceSpanTree,
|
|
@@ -241,7 +242,7 @@ function TraceDataPanelView({
|
|
|
241
242
|
),
|
|
242
243
|
noSearchResults
|
|
243
244
|
] }) }),
|
|
244
|
-
/* @__PURE__ */ jsx(TabContent, { value: "timeline", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxs(DataPanel.Content, { children: [
|
|
245
|
+
/* @__PURE__ */ jsx(TabContent, { value: "timeline", className: "min-h-0 py-0", children: /* @__PURE__ */ jsxs(DataPanel.Content, { className: "px-2", children: [
|
|
245
246
|
/* @__PURE__ */ jsx(
|
|
246
247
|
TraceSpanTimeline,
|
|
247
248
|
{
|
|
@@ -256,8 +257,8 @@ function TraceDataPanelView({
|
|
|
256
257
|
),
|
|
257
258
|
noSearchResults
|
|
258
259
|
] }) }),
|
|
259
|
-
feedbackTabSlot && /* @__PURE__ */ jsx(TabContent, { value: "feedback", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsx(DataPanel.Content, { children: feedbackTabSlot({ traceId }) }) }),
|
|
260
|
-
scoresTabSlot && /* @__PURE__ */ jsx(TabContent, { value: "scores", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsx(DataPanel.Content, { children: scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId }) }) })
|
|
260
|
+
feedbackTabSlot && /* @__PURE__ */ jsx(TabContent, { value: "feedback", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsx(DataPanel.Content, { className: "px-2", children: feedbackTabSlot({ traceId }) }) }),
|
|
261
|
+
scoresTabSlot && /* @__PURE__ */ jsx(TabContent, { value: "scores", className: "h-full min-h-0 py-0", children: /* @__PURE__ */ jsx(DataPanel.Content, { className: "px-2", children: scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId }) }) })
|
|
261
262
|
]
|
|
262
263
|
}
|
|
263
264
|
);
|
|
@@ -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 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 { TraceIdButton } from './trace-id-button';\nimport { TraceSpanTimeline } from './trace-span-timeline';\nimport { TraceSpanTree } from './trace-span-tree';\nimport { TraceSummaryDescription } from './trace-summary-description';\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 { cn } from '@/lib/utils';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'timeline' | '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 /** @deprecated No longer used: the panel renders the span tree with the duration as text. */\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, a \"Scores\" tab appears; the slot renders whatever trace-level\n * 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 indicator rendered after the \"Feedback\" tab label (e.g. a needs-review dot). */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /** Span ids to feature in the timeline; every other span is faded. */\n featuredSpanIds?: string[];\n /**\n * Rendered as a column to the left of the span tree inside the same card\n * (typically the trace as one reconstructed agent turn). Collapsed while the\n * Timeline tab is active, since the timeline needs the width.\n */\n messagesPanelSlot?: ReactNode;\n /**\n * Rendered as a column to the right of the timeline inside the same card;\n * typically the span detail.\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 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 featuredSpanIds,\n messagesPanelSlot,\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 // Tracked locally too (tabs may be uncontrolled) so the messages column knows\n // when to fold away for the Timeline tab.\n const [uncontrolledTab, setUncontrolledTab] = useState<TraceDataPanelTab>('details');\n const currentTab = activeTab ?? uncontrolledTab;\n const handleTabChange = (tab: TraceDataPanelTab) => {\n setUncontrolledTab(tab);\n onTabChange?.(tab);\n };\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 className=\"items-center\">\n Trace\n <TraceIdButton id={traceId} />\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 <TracePanelColumns\n messagesPanelSlot={messagesPanelSlot}\n messagesCollapsed={currentTab === 'timeline'}\n spanPanelSlot={spanPanelSlot}\n highlightQuery={query}\n spanPanelKey={selectedSpanId}\n >\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 (() => {\n // Shared by the Spans and Timeline tabs: both views render the same\n // filtered `hierarchicalSpans`, so one query drives both.\n const searchField = (\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 const noSearchResults = hierarchicalSpans.length === 0 && (\n <DataPanel.NoData>No spans match your search.</DataPanel.NoData>\n );\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={handleTabChange}\n className=\"grid h-full min-h-0 grid-rows-[auto_1fr]\"\n >\n <DataPanel.Header className=\"min-h-0 px-2 py-1\">\n <TabList variant=\"pill-ghost\">\n <Tab value=\"details\">Spans</Tab>\n <Tab value=\"timeline\">Timeline</Tab>\n {feedbackTabSlot && <Tab value=\"feedback\">Feedback{feedbackTabBadge}</Tab>}\n {scoresTabSlot && (\n <Tab value=\"scores\">Scores{scoresTabBadge != null && <> ({scoresTabBadge})</>}</Tab>\n )}\n </TabList>\n </DataPanel.Header>\n\n <TabContent value=\"details\" className=\"min-h-0 py-0\">\n <DataPanel.Content>\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 tree 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 <TraceSpanTree\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n <TabContent value=\"timeline\" className=\"min-h-0 py-0\">\n <DataPanel.Content>\n {/* Same selection + expansion state as the Spans tab, so switching views keeps context. */}\n <TraceSpanTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content>{feedbackTabSlot({ traceId })}</DataPanel.Content>\n </TabContent>\n )}\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content>{scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}</DataPanel.Content>\n </TabContent>\n )}\n </Tabs>\n );\n })()\n )}\n </TracePanelColumns>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Lays out the card body as three columns — `[messages] [trace] [span]` — inside\n * the same card. The messages and span cells always exist and collapse to `0fr`\n * when hidden, so opening/closing them animates via `grid-template-columns`\n * rather than mounting/unmounting a DOM column (which cannot be transitioned).\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 TracePanelColumns({\n messagesPanelSlot,\n messagesCollapsed,\n spanPanelSlot,\n highlightQuery,\n spanPanelKey,\n children,\n}: {\n messagesPanelSlot?: ReactNode;\n /** Folds the messages column away (e.g. while the Timeline tab needs the width). */\n messagesCollapsed: boolean;\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 const showMessages = !!messagesPanelSlot && !messagesCollapsed;\n const columns =\n showMessages && spanPanelSlot\n ? 'grid-cols-[1fr_1fr_1fr]'\n : showMessages\n ? 'grid-cols-[1fr_1fr_0fr]'\n : spanPanelSlot\n ? 'grid-cols-[0fr_1fr_1fr]'\n : 'grid-cols-[0fr_1fr_0fr]';\n\n return (\n <div\n ref={highlightRef}\n data-trace-columns\n className={cn('grid min-h-0 flex-1 transition-[grid-template-columns] duration-300 ease-in-out', columns)}\n >\n <div\n className={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n showMessages && 'animate-in border-r border-border1 duration-300 fade-in-0',\n )}\n >\n {messagesPanelSlot}\n </div>\n <div className=\"flex min-h-0 min-w-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={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n spanPanelSlot && 'animate-in border-l border-border1 duration-300 fade-in-0',\n )}\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 { TraceIdButton } from './trace-id-button';\nimport { TraceSpanTimeline } from './trace-span-timeline';\nimport { TraceSpanTree } from './trace-span-tree';\nimport { TraceSummaryDescription } from './trace-summary-description';\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 { cn } from '@/lib/utils';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport type TraceDataPanelTab = 'details' | 'timeline' | '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 /** @deprecated No longer used: the panel renders the span tree with the duration as text. */\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, a \"Scores\" tab appears; the slot renders whatever trace-level\n * 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 indicator rendered after the \"Feedback\" tab label (e.g. a needs-review dot). */\n feedbackTabBadge?: ReactNode;\n activeTab?: TraceDataPanelTab;\n onTabChange?: (tab: TraceDataPanelTab) => void;\n /** Span ids to feature in the timeline; every other span is faded. */\n featuredSpanIds?: string[];\n /**\n * Rendered as a column to the left of the span tree inside the same card\n * (typically the trace as one reconstructed agent turn). Collapsed while the\n * Timeline tab is active, since the timeline needs the width.\n */\n messagesPanelSlot?: ReactNode;\n /**\n * Rendered as a column to the right of the timeline inside the same card;\n * typically the span detail.\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 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 featuredSpanIds,\n messagesPanelSlot,\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 // Tracked locally too (tabs may be uncontrolled) so the messages column knows\n // when to fold away for the Timeline tab.\n const [uncontrolledTab, setUncontrolledTab] = useState<TraceDataPanelTab>('details');\n const currentTab = activeTab ?? uncontrolledTab;\n const handleTabChange = (tab: TraceDataPanelTab) => {\n setUncontrolledTab(tab);\n onTabChange?.(tab);\n };\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\" variant=\"ghost\" 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 && 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 className=\"items-center\">\n Trace\n <TraceIdButton id={traceId} />\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 {onEvaluateTrace && (\n <Button variant=\"primary\" size=\"md\" onClick={onEvaluateTrace} disabled={!rootSpan}>\n <CircleGaugeIcon />\n Score trace\n </Button>\n )}\n {traceActionsMenu}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n variant=\"ghost\"\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n <DataPanel.CloseButton variant=\"ghost\" onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed && (\n <TracePanelColumns\n messagesPanelSlot={messagesPanelSlot}\n messagesCollapsed={currentTab === 'timeline'}\n spanPanelSlot={spanPanelSlot}\n highlightQuery={query}\n spanPanelKey={selectedSpanId}\n >\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 (() => {\n // Shared by the Spans and Timeline tabs: both views render the same\n // filtered `hierarchicalSpans`, so one query drives both.\n const searchField = (\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 const noSearchResults = hierarchicalSpans.length === 0 && (\n <DataPanel.NoData>No spans match your search.</DataPanel.NoData>\n );\n\n return (\n <Tabs<TraceDataPanelTab>\n defaultTab=\"details\"\n value={activeTab}\n onValueChange={handleTabChange}\n className=\"grid h-full min-h-0 grid-rows-[auto_1fr]\"\n >\n <DataPanel.Header className=\"min-h-0 px-2 py-1\">\n <TabList variant=\"pill-ghost\">\n <Tab value=\"details\">Spans</Tab>\n <Tab value=\"timeline\">Timeline</Tab>\n {feedbackTabSlot && <Tab value=\"feedback\">Feedback{feedbackTabBadge}</Tab>}\n {scoresTabSlot && (\n <Tab value=\"scores\">Scores{scoresTabBadge != null && <> ({scoresTabBadge})</>}</Tab>\n )}\n </TabList>\n </DataPanel.Header>\n\n {/* Tab contents share the tab list's horizontal padding so their edges line up. */}\n <TabContent value=\"details\" className=\"min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">\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 tree 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 <TraceSpanTree\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n <TabContent value=\"timeline\" className=\"min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">\n {/* Same selection + expansion state as the Spans tab, so switching views keeps context. */}\n <TraceSpanTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n featuredSpanIds={featuredSpanIds}\n leadingSlot={searchField}\n />\n {noSearchResults}\n </DataPanel.Content>\n </TabContent>\n {feedbackTabSlot && (\n <TabContent value=\"feedback\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">{feedbackTabSlot({ traceId })}</DataPanel.Content>\n </TabContent>\n )}\n {scoresTabSlot && (\n <TabContent value=\"scores\" className=\"h-full min-h-0 py-0\">\n <DataPanel.Content className=\"px-2\">\n {scoresTabSlot({ traceId, rootSpanId: rootSpan?.spanId })}\n </DataPanel.Content>\n </TabContent>\n )}\n </Tabs>\n );\n })()\n )}\n </TracePanelColumns>\n )}\n </DataPanel>\n );\n}\n\n/**\n * Lays out the card body as three columns — `[messages] [trace] [span]` — inside\n * the same card. The messages and span cells always exist and collapse to `0fr`\n * when hidden, so opening/closing them animates via `grid-template-columns`\n * rather than mounting/unmounting a DOM column (which cannot be transitioned).\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 TracePanelColumns({\n messagesPanelSlot,\n messagesCollapsed,\n spanPanelSlot,\n highlightQuery,\n spanPanelKey,\n children,\n}: {\n messagesPanelSlot?: ReactNode;\n /** Folds the messages column away (e.g. while the Timeline tab needs the width). */\n messagesCollapsed: boolean;\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 const showMessages = !!messagesPanelSlot && !messagesCollapsed;\n const columns =\n showMessages && spanPanelSlot\n ? 'grid-cols-[1fr_1fr_1fr]'\n : showMessages\n ? 'grid-cols-[1fr_1fr_0fr]'\n : spanPanelSlot\n ? 'grid-cols-[0fr_1fr_1fr]'\n : 'grid-cols-[0fr_1fr_0fr]';\n\n return (\n <div\n ref={highlightRef}\n data-trace-columns\n className={cn('grid min-h-0 flex-1 transition-[grid-template-columns] duration-300 ease-in-out', columns)}\n >\n <div\n className={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n showMessages && 'animate-in border-r border-border1 duration-300 fade-in-0',\n )}\n >\n {messagesPanelSlot}\n </div>\n <div className=\"flex min-h-0 min-w-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={cn(\n 'flex min-h-0 min-w-0 flex-col overflow-hidden',\n spanPanelSlot && 'animate-in border-l border-border1 duration-300 fade-in-0',\n )}\n >\n {spanPanelSlot}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|