@mastra/playground-ui 48.0.0 → 48.1.0-alpha.1

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.
Files changed (133) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/Composer.css +2 -2
  3. package/dist/{code-C5KVVzOZ.js → code-Cj09LVys.js} +2 -2
  4. package/dist/{code-C5KVVzOZ.js.map → code-Cj09LVys.js.map} +1 -1
  5. package/dist/{code-B3WONxnA.cjs → code-FZwLnf_f.cjs} +2 -2
  6. package/dist/{code-B3WONxnA.cjs.map → code-FZwLnf_f.cjs.map} +1 -1
  7. package/dist/code-block-Dn0K3DkE.cjs +88 -0
  8. package/dist/code-block-Dn0K3DkE.cjs.map +1 -0
  9. package/dist/code-block-DqKXZajq.js +86 -0
  10. package/dist/code-block-DqKXZajq.js.map +1 -0
  11. package/dist/components/Code.cjs.js +1 -1
  12. package/dist/components/Code.es.js +1 -1
  13. package/dist/components/CodeBlock.cjs.js +3 -83
  14. package/dist/components/CodeBlock.cjs.js.map +1 -1
  15. package/dist/components/CodeBlock.es.js +1 -85
  16. package/dist/components/CodeBlock.es.js.map +1 -1
  17. package/dist/components/CodeEditor.cjs.js +2 -2
  18. package/dist/components/CodeEditor.es.js +2 -2
  19. package/dist/components/CopyButton.cjs.js +1 -1
  20. package/dist/components/CopyButton.es.js +1 -1
  21. package/dist/components/DataCodeSection.cjs.js +1 -1
  22. package/dist/components/DataCodeSection.es.js +1 -1
  23. package/dist/components/DataDetailsPanel.cjs.js +1 -1
  24. package/dist/components/DataDetailsPanel.es.js +1 -1
  25. package/dist/components/DataPanel.cjs.js +1 -1
  26. package/dist/components/DataPanel.es.js +1 -1
  27. package/dist/components/MarkdownRenderer.cjs.js +1 -1
  28. package/dist/components/MarkdownRenderer.es.js +1 -1
  29. package/dist/components/SideDialog.cjs.js +1 -1
  30. package/dist/components/SideDialog.es.js +1 -1
  31. package/dist/components/Truncate.cjs.js +1 -1
  32. package/dist/components/Truncate.es.js +1 -1
  33. package/dist/components/ai/plan.cjs.js +2 -2
  34. package/dist/components/ai/plan.cjs.js.map +1 -1
  35. package/dist/components/ai/plan.es.js +2 -2
  36. package/dist/components/ai/plan.es.js.map +1 -1
  37. package/dist/components/ai/task-list.cjs.js +44 -18
  38. package/dist/components/ai/task-list.cjs.js.map +1 -1
  39. package/dist/components/ai/task-list.es.js +47 -21
  40. package/dist/components/ai/task-list.es.js.map +1 -1
  41. package/dist/{copy-button-B1GWIQ-x.js → copy-button-BLGUkVE8.js} +4 -2
  42. package/dist/copy-button-BLGUkVE8.js.map +1 -0
  43. package/dist/{copy-button-DwZ3c7D4.cjs → copy-button-BfawWA4t.cjs} +4 -2
  44. package/dist/copy-button-BfawWA4t.cjs.map +1 -0
  45. package/dist/{data-code-section-PJM5l3aS.js → data-code-section-DHbytoQ2.js} +2 -2
  46. package/dist/{data-code-section-PJM5l3aS.js.map → data-code-section-DHbytoQ2.js.map} +1 -1
  47. package/dist/{data-code-section-BjmFgJpC.cjs → data-code-section-bqvIovEN.cjs} +2 -2
  48. package/dist/{data-code-section-BjmFgJpC.cjs.map → data-code-section-bqvIovEN.cjs.map} +1 -1
  49. package/dist/{data-panel-BQqPr6ew.js → data-panel-BX_78wCj.js} +2 -2
  50. package/dist/{data-panel-BQqPr6ew.js.map → data-panel-BX_78wCj.js.map} +1 -1
  51. package/dist/{data-panel-C85h9XvH.cjs → data-panel-DT6LgTVX.cjs} +2 -2
  52. package/dist/{data-panel-C85h9XvH.cjs.map → data-panel-DT6LgTVX.cjs.map} +1 -1
  53. package/dist/domains/logs/components/log-details-view.cjs.js +1 -1
  54. package/dist/domains/logs/components/log-details-view.es.js +1 -1
  55. package/dist/domains/traces/components/span-data-panel-view.cjs.js +1 -1
  56. package/dist/domains/traces/components/span-data-panel-view.es.js +1 -1
  57. package/dist/domains/traces/components/trace-data-panel-view.cjs.js +1 -1
  58. package/dist/domains/traces/components/trace-data-panel-view.es.js +1 -1
  59. package/dist/ee/signals/entity-learning-api.cjs.js +8 -2
  60. package/dist/ee/signals/entity-learning-api.cjs.js.map +1 -1
  61. package/dist/ee/signals/entity-learning-api.es.js +8 -3
  62. package/dist/ee/signals/entity-learning-api.es.js.map +1 -1
  63. package/dist/ee/signals/hooks/use-noise-examples.cjs.js +5 -3
  64. package/dist/ee/signals/hooks/use-noise-examples.cjs.js.map +1 -1
  65. package/dist/ee/signals/hooks/use-noise-examples.es.js +6 -4
  66. package/dist/ee/signals/hooks/use-noise-examples.es.js.map +1 -1
  67. package/dist/ee/signals/hooks/use-theme-examples.cjs.js +6 -3
  68. package/dist/ee/signals/hooks/use-theme-examples.cjs.js.map +1 -1
  69. package/dist/ee/signals/hooks/use-theme-examples.es.js +7 -4
  70. package/dist/ee/signals/hooks/use-theme-examples.es.js.map +1 -1
  71. package/dist/ee/signals/hooks/use-theme-paths.cjs.js +2 -2
  72. package/dist/ee/signals/hooks/use-theme-paths.cjs.js.map +1 -1
  73. package/dist/ee/signals/hooks/use-theme-paths.es.js +3 -3
  74. package/dist/ee/signals/hooks/use-theme-paths.es.js.map +1 -1
  75. package/dist/ee/signals/lifeline-row.cjs.js +1 -1
  76. package/dist/ee/signals/lifeline-row.cjs.js.map +1 -1
  77. package/dist/ee/signals/lifeline-row.es.js +1 -1
  78. package/dist/ee/signals/lifeline-row.es.js.map +1 -1
  79. package/dist/ee/signals/noise-detail-panel.cjs.js +18 -5
  80. package/dist/ee/signals/noise-detail-panel.cjs.js.map +1 -1
  81. package/dist/ee/signals/noise-detail-panel.es.js +18 -5
  82. package/dist/ee/signals/noise-detail-panel.es.js.map +1 -1
  83. package/dist/ee/signals/sankey-signals.cjs.js +50 -34
  84. package/dist/ee/signals/sankey-signals.cjs.js.map +1 -1
  85. package/dist/ee/signals/sankey-signals.es.js +52 -36
  86. package/dist/ee/signals/sankey-signals.es.js.map +1 -1
  87. package/dist/ee/signals/signal-delta-column.cjs.js +1 -1
  88. package/dist/ee/signals/signal-delta-column.cjs.js.map +1 -1
  89. package/dist/ee/signals/signal-delta-column.es.js +1 -1
  90. package/dist/ee/signals/signal-delta-column.es.js.map +1 -1
  91. package/dist/ee/signals/theme-detail-panel.cjs.js +11 -4
  92. package/dist/ee/signals/theme-detail-panel.cjs.js.map +1 -1
  93. package/dist/ee/signals/theme-detail-panel.es.js +11 -4
  94. package/dist/ee/signals/theme-detail-panel.es.js.map +1 -1
  95. package/dist/ee/signals/theme-drilldown-data.cjs.js +41 -13
  96. package/dist/ee/signals/theme-drilldown-data.cjs.js.map +1 -1
  97. package/dist/ee/signals/theme-drilldown-data.es.js +40 -14
  98. package/dist/ee/signals/theme-drilldown-data.es.js.map +1 -1
  99. package/dist/ee/signals/theme-filter-banner.cjs.js +53 -28
  100. package/dist/ee/signals/theme-filter-banner.cjs.js.map +1 -1
  101. package/dist/ee/signals/theme-filter-banner.es.js +53 -28
  102. package/dist/ee/signals/theme-filter-banner.es.js.map +1 -1
  103. package/dist/{highlight-C2uRVhiA.cjs → highlight-CEt2vhD8.cjs} +20 -3
  104. package/dist/highlight-CEt2vhD8.cjs.map +1 -0
  105. package/dist/{highlight-Dis62bkj.js → highlight-CSJjjoqh.js} +20 -3
  106. package/dist/highlight-CSJjjoqh.js.map +1 -0
  107. package/dist/markdown-renderer-D1vSFfp9.cjs +86 -0
  108. package/dist/markdown-renderer-D1vSFfp9.cjs.map +1 -0
  109. package/dist/markdown-renderer-DmYYQHxu.js +84 -0
  110. package/dist/markdown-renderer-DmYYQHxu.js.map +1 -0
  111. package/dist/markdown-renderer.css +182 -0
  112. package/dist/src/ds/components/CopyButton/copy-button.d.ts +2 -1
  113. package/dist/src/ds/components/MarkdownRenderer/markdown-renderer.d.ts +9 -5
  114. package/dist/src/ds/components/ai/task-list/task-list.d.ts +4 -2
  115. package/dist/src/ds/components/ai/task-list/task-list.stories.d.ts +2 -0
  116. package/dist/src/ee/signals/entity-learning-api.d.ts +4 -2
  117. package/dist/src/ee/signals/hooks/use-noise-examples.d.ts +2 -1
  118. package/dist/src/ee/signals/hooks/use-theme-examples.d.ts +2 -1
  119. package/dist/src/ee/signals/hooks/use-theme-paths.d.ts +1 -1
  120. package/dist/src/ee/signals/noise-detail-panel.d.ts +4 -1
  121. package/dist/src/ee/signals/theme-detail-panel.d.ts +5 -3
  122. package/dist/src/ee/signals/theme-drilldown-data.d.ts +17 -4
  123. package/dist/src/ee/signals/theme-filter-banner.d.ts +5 -3
  124. package/dist/style.css +5 -98
  125. package/package.json +7 -7
  126. package/dist/copy-button-B1GWIQ-x.js.map +0 -1
  127. package/dist/copy-button-DwZ3c7D4.cjs.map +0 -1
  128. package/dist/highlight-C2uRVhiA.cjs.map +0 -1
  129. package/dist/highlight-Dis62bkj.js.map +0 -1
  130. package/dist/markdown-renderer-DszxuuNM.js +0 -117
  131. package/dist/markdown-renderer-DszxuuNM.js.map +0 -1
  132. package/dist/markdown-renderer-g8xNLOc0.cjs +0 -119
  133. package/dist/markdown-renderer-g8xNLOc0.cjs.map +0 -1
@@ -21,9 +21,12 @@ function ThemeDetailPanel({
21
21
  snapshotId,
22
22
  snapshotTotal,
23
23
  selection,
24
+ filters = [],
25
+ filteredStats,
24
26
  onClose
25
27
  }) {
26
- const examplesContextKey = `${snapshotId}:${selection?.signalName ?? ""}:${selection?.themeId ?? ""}`;
28
+ const filterKey = filters.map((filter) => `${filter.signalName}:${filter.kind === "theme" ? filter.themeId : "noise"}`).join(",");
29
+ const examplesContextKey = `${snapshotId}:${selection?.signalName ?? ""}:${selection?.themeId ?? ""}:${filterKey}`;
27
30
  const [examplesPage, setExamplesPage] = useState(() => ({ contextKey: examplesContextKey, offset: 0 }));
28
31
  const examplesOffset = examplesPage.contextKey === examplesContextKey ? examplesPage.offset : 0;
29
32
  const [insightTraceId, setInsightTraceId] = useState();
@@ -41,7 +44,8 @@ function ThemeDetailPanel({
41
44
  snapshotId,
42
45
  selection?.themeId,
43
46
  EXAMPLES_PAGE_SIZE,
44
- examplesOffset
47
+ examplesOffset,
48
+ filters
45
49
  );
46
50
  const historyQuery = useThemeHistory(
47
51
  entityId,
@@ -101,7 +105,10 @@ function ThemeDetailPanel({
101
105
  /* @__PURE__ */ jsxs("section", { "aria-labelledby": "theme-summary-heading", children: [
102
106
  /* @__PURE__ */ jsx("h2", { id: "theme-summary-heading", className: "text-neutral3 font-mono text-xs tracking-wider uppercase", children: "Summary" }),
103
107
  /* @__PURE__ */ jsx("p", { className: "text-neutral5 mt-3 text-sm", children: detailQuery.data.theme.description ?? "No description available." }),
104
- /* @__PURE__ */ jsx("p", { className: "text-neutral5 mt-3 font-mono text-sm tabular-nums", children: shareSentence(detailQuery.data.theme.traceCount, detailQuery.data.theme.coverage) })
108
+ /* @__PURE__ */ jsx("p", { className: "text-neutral5 mt-3 font-mono text-sm tabular-nums", children: shareSentence(
109
+ filteredStats?.traceCount ?? detailQuery.data.theme.traceCount,
110
+ filteredStats?.stageShare ?? detailQuery.data.theme.coverage
111
+ ) })
105
112
  ] }),
106
113
  /* @__PURE__ */ jsxs("section", { "aria-labelledby": "theme-examples-heading", children: [
107
114
  /* @__PURE__ */ jsx(
@@ -128,7 +135,7 @@ function ThemeDetailPanel({
128
135
  /* @__PURE__ */ jsx(
129
136
  ExamplesPager,
130
137
  {
131
- traceCount: detailQuery.data.theme.traceCount,
138
+ traceCount: filteredStats?.traceCount ?? detailQuery.data.theme.traceCount,
132
139
  offset: examplesOffset,
133
140
  onOffsetChange: (offset) => setExamplesPage({ contextKey: examplesContextKey, offset })
134
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"theme-detail-panel.es.js","sources":["../../../src/ee/signals/theme-detail-panel.tsx"],"sourcesContent":["import { useState } from 'react';\n\nimport { EXAMPLES_PAGE_SIZE, ExamplesPager } from './examples-pager';\nimport { useThemeDetail, useThemeExamples, useThemeHistory } from './hooks';\nimport { getSignalHue } from './signal-colors';\nimport { formatSnapshotDate, shareSentence, SIGNAL_DESCRIPTIONS } from './signal-formatting';\nimport type { ThemeSelection } from './theme-drilldown-data';\nimport { chronologicalHistoryPoints, themeTrendDirection } from './theme-trend';\nimport { ThemeTrendChart } from './theme-trend-chart';\nimport { TraceInsightView } from './trace-insight-view';\nimport {\n Drawer,\n DrawerBody,\n DrawerContent,\n DrawerDescription,\n DrawerHeader,\n DrawerTitle,\n} from '@/ds/components/Drawer';\nimport { nodeColor } from '@/ds/components/SankeyChart';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/ds/components/Tooltip';\n\ninterface ThemeDetailPanelProps {\n entityId: string;\n entityType: string;\n snapshotId: string;\n snapshotTotal: number;\n selection: ThemeSelection | undefined;\n onClose: () => void;\n}\n\nexport function ThemeDetailPanel({\n entityId,\n entityType,\n snapshotId,\n snapshotTotal,\n selection,\n onClose,\n}: ThemeDetailPanelProps) {\n const examplesContextKey = `${snapshotId}:${selection?.signalName ?? ''}:${selection?.themeId ?? ''}`;\n const [examplesPage, setExamplesPage] = useState(() => ({ contextKey: examplesContextKey, offset: 0 }));\n const examplesOffset = examplesPage.contextKey === examplesContextKey ? examplesPage.offset : 0;\n const [insightTraceId, setInsightTraceId] = useState<string>();\n const detailQuery = useThemeDetail(\n entityId,\n entityType,\n selection?.signalName ?? 'goal',\n snapshotId,\n selection?.themeId,\n );\n const examplesQuery = useThemeExamples(\n entityId,\n entityType,\n selection?.signalName ?? 'goal',\n snapshotId,\n selection?.themeId,\n EXAMPLES_PAGE_SIZE,\n examplesOffset,\n );\n const historyQuery = useThemeHistory(\n entityId,\n entityType,\n selection?.signalName ?? 'goal',\n snapshotTotal > 1 ? selection?.themeId : undefined,\n );\n const title = detailQuery.data?.theme?.label ?? selection?.label ?? 'Theme details';\n const signalName = selection?.signalName;\n const historyPoints = historyQuery.data ? chronologicalHistoryPoints(historyQuery.data.points) : [];\n const oldestHistoryPoint = historyPoints[0];\n\n return (\n <Drawer\n onOpenChange={open => {\n if (!open) {\n setExamplesPage({ contextKey: '', offset: 0 });\n setInsightTraceId(undefined);\n onClose();\n }\n }}\n open={selection !== undefined}\n overlay=\"none\"\n side=\"right\"\n variant=\"floating\"\n >\n <DrawerContent>\n <DrawerHeader className=\"border-border1 border-b\">\n {signalName !== undefined && (\n <span\n className=\"font-mono text-xs font-semibold tracking-widest\"\n style={{ color: nodeColor(getSignalHue(signalName)) }}\n >\n <Tooltip>\n <TooltipTrigger className=\"cursor-default uppercase\">{signalName}</TooltipTrigger>\n <TooltipContent>{SIGNAL_DESCRIPTIONS[signalName]}</TooltipContent>\n </Tooltip>\n </span>\n )}\n <DrawerTitle>{title}</DrawerTitle>\n <DrawerDescription className=\"sr-only\">\n Details for the {signalName ?? 'selected'} theme {title}\n </DrawerDescription>\n </DrawerHeader>\n <DrawerBody className=\"grid content-start gap-6 overflow-y-auto p-6\">\n {insightTraceId !== undefined && (\n <TraceInsightView traceId={insightTraceId} onBack={() => setInsightTraceId(undefined)} />\n )}\n {insightTraceId === undefined && (\n <>\n {detailQuery.isPending && <p className=\"text-neutral3 text-sm\">Loading theme details…</p>}\n {detailQuery.isError && <p className=\"text-sm text-red-500\">Unable to load theme details.</p>}\n {detailQuery.data && !detailQuery.data.theme && (\n <section>\n <h2 className=\"text-neutral6 text-sm font-semibold\">Not present in this snapshot</h2>\n <p className=\"text-neutral3 mt-2 text-sm\">This theme has no data in the selected snapshot.</p>\n </section>\n )}\n {detailQuery.data?.theme && (\n <>\n <section aria-labelledby=\"theme-summary-heading\">\n <h2 id=\"theme-summary-heading\" className=\"text-neutral3 font-mono text-xs tracking-wider uppercase\">\n Summary\n </h2>\n <p className=\"text-neutral5 mt-3 text-sm\">\n {detailQuery.data.theme.description ?? 'No description available.'}\n </p>\n <p className=\"text-neutral5 mt-3 font-mono text-sm tabular-nums\">\n {shareSentence(detailQuery.data.theme.traceCount, detailQuery.data.theme.coverage)}\n </p>\n </section>\n\n <section aria-labelledby=\"theme-examples-heading\">\n <h2\n id=\"theme-examples-heading\"\n className=\"text-neutral3 font-mono text-xs tracking-wider uppercase\"\n >\n Examples\n </h2>\n {examplesQuery.isPending && <p className=\"text-neutral3 mt-3 text-sm\">Loading examples…</p>}\n {examplesQuery.isError && <p className=\"mt-3 text-sm text-red-500\">Unable to load examples.</p>}\n {examplesQuery.data && (\n <>\n {examplesQuery.data.examples.length === 0 ? (\n <p className=\"text-neutral3 mt-3 text-sm\">No examples in this snapshot.</p>\n ) : (\n <ul className=\"mt-3 space-y-3\">\n {examplesQuery.data.examples.map(example => (\n <li key={example.traceId}>\n <button\n type=\"button\"\n aria-label={`View trace insight for ${example.signalText}`}\n className=\"border-border1 bg-surface3 text-neutral5 hover:bg-surface5 w-full cursor-pointer rounded-md border p-3 text-left text-sm\"\n onClick={() => setInsightTraceId(example.traceId)}\n >\n {example.signalText}\n </button>\n </li>\n ))}\n </ul>\n )}\n <ExamplesPager\n traceCount={detailQuery.data.theme.traceCount}\n offset={examplesOffset}\n onOffsetChange={offset => setExamplesPage({ contextKey: examplesContextKey, offset })}\n />\n </>\n )}\n </section>\n\n {snapshotTotal > 1 && (\n <section aria-labelledby=\"theme-trend-heading\">\n <h2 id=\"theme-trend-heading\" className=\"text-neutral3 font-mono text-xs tracking-wider uppercase\">\n Trend\n </h2>\n {historyQuery.isPending && <p className=\"text-neutral3 mt-3 text-sm\">Loading trend…</p>}\n {historyQuery.isError && <p className=\"mt-3 text-sm text-red-500\">Unable to load the trend.</p>}\n {oldestHistoryPoint !== undefined && (\n <>\n <p className=\"text-neutral5 mt-3 text-sm\">\n {/* A nextCursor means older points exist beyond the fetched window,\n so the oldest loaded point is a lower bound, not the true origin. */}\n {historyQuery.data?.nextCursor\n ? `Active since at least ${formatSnapshotDate(oldestHistoryPoint.startedAt)} · in ${historyPoints.length}+ snapshots`\n : `First seen ${formatSnapshotDate(oldestHistoryPoint.startedAt)} · in ${historyPoints.length} ${historyPoints.length === 1 ? 'snapshot' : 'snapshots'}`}{' '}\n · {themeTrendDirection(historyPoints)}\n </p>\n {historyPoints.length >= 2 && (\n <ThemeTrendChart\n points={historyPoints}\n color={nodeColor(getSignalHue(signalName ?? 'goal'))}\n />\n )}\n </>\n )}\n </section>\n )}\n </>\n )}\n </>\n )}\n </DrawerBody>\n </DrawerContent>\n </Drawer>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"theme-detail-panel.es.js","sources":["../../../src/ee/signals/theme-detail-panel.tsx"],"sourcesContent":["import { useState } from 'react';\n\nimport { EXAMPLES_PAGE_SIZE, ExamplesPager } from './examples-pager';\nimport { useThemeDetail, useThemeExamples, useThemeHistory } from './hooks';\nimport { getSignalHue } from './signal-colors';\nimport { formatSnapshotDate, shareSentence, SIGNAL_DESCRIPTIONS } from './signal-formatting';\nimport type { SelectedTheme, ThemeSelection, ThemeSelectionStats } from './theme-drilldown-data';\nimport { chronologicalHistoryPoints, themeTrendDirection } from './theme-trend';\nimport { ThemeTrendChart } from './theme-trend-chart';\nimport { TraceInsightView } from './trace-insight-view';\nimport {\n Drawer,\n DrawerBody,\n DrawerContent,\n DrawerDescription,\n DrawerHeader,\n DrawerTitle,\n} from '@/ds/components/Drawer';\nimport { nodeColor } from '@/ds/components/SankeyChart';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@/ds/components/Tooltip';\n\ninterface ThemeDetailPanelProps {\n entityId: string;\n entityType: string;\n snapshotId: string;\n snapshotTotal: number;\n selection: SelectedTheme | undefined;\n filters?: ThemeSelection[];\n filteredStats?: ThemeSelectionStats;\n onClose: () => void;\n}\n\nexport function ThemeDetailPanel({\n entityId,\n entityType,\n snapshotId,\n snapshotTotal,\n selection,\n filters = [],\n filteredStats,\n onClose,\n}: ThemeDetailPanelProps) {\n const filterKey = filters\n .map(filter => `${filter.signalName}:${filter.kind === 'theme' ? filter.themeId : 'noise'}`)\n .join(',');\n const examplesContextKey = `${snapshotId}:${selection?.signalName ?? ''}:${selection?.themeId ?? ''}:${filterKey}`;\n const [examplesPage, setExamplesPage] = useState(() => ({ contextKey: examplesContextKey, offset: 0 }));\n const examplesOffset = examplesPage.contextKey === examplesContextKey ? examplesPage.offset : 0;\n const [insightTraceId, setInsightTraceId] = useState<string>();\n const detailQuery = useThemeDetail(\n entityId,\n entityType,\n selection?.signalName ?? 'goal',\n snapshotId,\n selection?.themeId,\n );\n const examplesQuery = useThemeExamples(\n entityId,\n entityType,\n selection?.signalName ?? 'goal',\n snapshotId,\n selection?.themeId,\n EXAMPLES_PAGE_SIZE,\n examplesOffset,\n filters,\n );\n const historyQuery = useThemeHistory(\n entityId,\n entityType,\n selection?.signalName ?? 'goal',\n snapshotTotal > 1 ? selection?.themeId : undefined,\n );\n const title = detailQuery.data?.theme?.label ?? selection?.label ?? 'Theme details';\n const signalName = selection?.signalName;\n const historyPoints = historyQuery.data ? chronologicalHistoryPoints(historyQuery.data.points) : [];\n const oldestHistoryPoint = historyPoints[0];\n\n return (\n <Drawer\n onOpenChange={open => {\n if (!open) {\n setExamplesPage({ contextKey: '', offset: 0 });\n setInsightTraceId(undefined);\n onClose();\n }\n }}\n open={selection !== undefined}\n overlay=\"none\"\n side=\"right\"\n variant=\"floating\"\n >\n <DrawerContent>\n <DrawerHeader className=\"border-border1 border-b\">\n {signalName !== undefined && (\n <span\n className=\"font-mono text-xs font-semibold tracking-widest\"\n style={{ color: nodeColor(getSignalHue(signalName)) }}\n >\n <Tooltip>\n <TooltipTrigger className=\"cursor-default uppercase\">{signalName}</TooltipTrigger>\n <TooltipContent>{SIGNAL_DESCRIPTIONS[signalName]}</TooltipContent>\n </Tooltip>\n </span>\n )}\n <DrawerTitle>{title}</DrawerTitle>\n <DrawerDescription className=\"sr-only\">\n Details for the {signalName ?? 'selected'} theme {title}\n </DrawerDescription>\n </DrawerHeader>\n <DrawerBody className=\"grid content-start gap-6 overflow-y-auto p-6\">\n {insightTraceId !== undefined && (\n <TraceInsightView traceId={insightTraceId} onBack={() => setInsightTraceId(undefined)} />\n )}\n {insightTraceId === undefined && (\n <>\n {detailQuery.isPending && <p className=\"text-neutral3 text-sm\">Loading theme details…</p>}\n {detailQuery.isError && <p className=\"text-sm text-red-500\">Unable to load theme details.</p>}\n {detailQuery.data && !detailQuery.data.theme && (\n <section>\n <h2 className=\"text-neutral6 text-sm font-semibold\">Not present in this snapshot</h2>\n <p className=\"text-neutral3 mt-2 text-sm\">This theme has no data in the selected snapshot.</p>\n </section>\n )}\n {detailQuery.data?.theme && (\n <>\n <section aria-labelledby=\"theme-summary-heading\">\n <h2 id=\"theme-summary-heading\" className=\"text-neutral3 font-mono text-xs tracking-wider uppercase\">\n Summary\n </h2>\n <p className=\"text-neutral5 mt-3 text-sm\">\n {detailQuery.data.theme.description ?? 'No description available.'}\n </p>\n <p className=\"text-neutral5 mt-3 font-mono text-sm tabular-nums\">\n {shareSentence(\n filteredStats?.traceCount ?? detailQuery.data.theme.traceCount,\n filteredStats?.stageShare ?? detailQuery.data.theme.coverage,\n )}\n </p>\n </section>\n\n <section aria-labelledby=\"theme-examples-heading\">\n <h2\n id=\"theme-examples-heading\"\n className=\"text-neutral3 font-mono text-xs tracking-wider uppercase\"\n >\n Examples\n </h2>\n {examplesQuery.isPending && <p className=\"text-neutral3 mt-3 text-sm\">Loading examples…</p>}\n {examplesQuery.isError && <p className=\"mt-3 text-sm text-red-500\">Unable to load examples.</p>}\n {examplesQuery.data && (\n <>\n {examplesQuery.data.examples.length === 0 ? (\n <p className=\"text-neutral3 mt-3 text-sm\">No examples in this snapshot.</p>\n ) : (\n <ul className=\"mt-3 space-y-3\">\n {examplesQuery.data.examples.map(example => (\n <li key={example.traceId}>\n <button\n type=\"button\"\n aria-label={`View trace insight for ${example.signalText}`}\n className=\"border-border1 bg-surface3 text-neutral5 hover:bg-surface5 w-full cursor-pointer rounded-md border p-3 text-left text-sm\"\n onClick={() => setInsightTraceId(example.traceId)}\n >\n {example.signalText}\n </button>\n </li>\n ))}\n </ul>\n )}\n <ExamplesPager\n traceCount={filteredStats?.traceCount ?? detailQuery.data.theme.traceCount}\n offset={examplesOffset}\n onOffsetChange={offset => setExamplesPage({ contextKey: examplesContextKey, offset })}\n />\n </>\n )}\n </section>\n\n {snapshotTotal > 1 && (\n <section aria-labelledby=\"theme-trend-heading\">\n <h2 id=\"theme-trend-heading\" className=\"text-neutral3 font-mono text-xs tracking-wider uppercase\">\n Trend\n </h2>\n {historyQuery.isPending && <p className=\"text-neutral3 mt-3 text-sm\">Loading trend…</p>}\n {historyQuery.isError && <p className=\"mt-3 text-sm text-red-500\">Unable to load the trend.</p>}\n {oldestHistoryPoint !== undefined && (\n <>\n <p className=\"text-neutral5 mt-3 text-sm\">\n {/* A nextCursor means older points exist beyond the fetched window,\n so the oldest loaded point is a lower bound, not the true origin. */}\n {historyQuery.data?.nextCursor\n ? `Active since at least ${formatSnapshotDate(oldestHistoryPoint.startedAt)} · in ${historyPoints.length}+ snapshots`\n : `First seen ${formatSnapshotDate(oldestHistoryPoint.startedAt)} · in ${historyPoints.length} ${historyPoints.length === 1 ? 'snapshot' : 'snapshots'}`}{' '}\n · {themeTrendDirection(historyPoints)}\n </p>\n {historyPoints.length >= 2 && (\n <ThemeTrendChart\n points={historyPoints}\n color={nodeColor(getSignalHue(signalName ?? 'goal'))}\n />\n )}\n </>\n )}\n </section>\n )}\n </>\n )}\n </>\n )}\n </DrawerBody>\n </DrawerContent>\n </Drawer>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -2,23 +2,50 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
+ function findSelectionStats(flow, drillStack, selection) {
6
+ if (!selection) return void 0;
7
+ if (drillStack.some((filter) => filter.signalName === selection.signalName)) {
8
+ return { traceCount: flow.snapshot.traceCount, stageShare: flow.snapshot.traceCount > 0 ? 1 : 0 };
9
+ }
10
+ const stage = flow.stages.find((candidate) => candidate.signalName === selection.signalName);
11
+ const node = stage?.nodes.find(
12
+ (candidate) => selection.kind === "theme" ? candidate.kind === "theme" && candidate.themeId === selection.themeId : candidate.kind === "noise"
13
+ );
14
+ return node ? { traceCount: node.traceCount, stageShare: node.stageShare } : { traceCount: 0, stageShare: 0 };
15
+ }
16
+ function mergeVisibleSignalOrder(signalNames, nextVisibleSignalNames) {
17
+ const visibleSignalNames = new Set(nextVisibleSignalNames);
18
+ let nextVisibleIndex = 0;
19
+ return signalNames.map((signalName) => {
20
+ if (!visibleSignalNames.has(signalName)) return signalName;
21
+ return nextVisibleSignalNames[nextVisibleIndex++] ?? signalName;
22
+ });
23
+ }
5
24
  function findThemeSelection(flow, signalName, nodeId) {
6
25
  const stage = flow.stages.find((candidate) => candidate.signalName === signalName);
7
26
  if (!stage) return void 0;
8
27
  const node = stage.nodes.find((candidate) => candidate.nodeId === String(nodeId));
9
28
  if (node?.kind !== "theme" || !node.themeId || !/^\d+$/.test(node.themeId)) return void 0;
10
- return { signalName: stage.signalName, themeId: node.themeId, label: node.label };
29
+ return { kind: "theme", signalName: stage.signalName, themeId: node.themeId, label: node.label };
11
30
  }
12
31
  function findNoiseSelection(flow, signalName, nodeId) {
13
32
  const stage = flow.stages.find((candidate) => candidate.signalName === signalName);
14
33
  const node = stage?.nodes.find((candidate) => candidate.nodeId === String(nodeId));
15
- return node?.kind === "noise" ? stage?.signalName : void 0;
34
+ return node?.kind === "noise" && stage ? { kind: "noise", signalName: stage.signalName } : void 0;
16
35
  }
17
- function buildDrilledThemeFlow(flow, pathsResponse, selection) {
18
- const selectedNodeKey = Object.entries(pathsResponse.themes).find(
19
- ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId
20
- )?.[0];
21
- const filteredPaths = selectedNodeKey ? pathsResponse.paths.filter((path) => path.assignments[selection.signalName] === selectedNodeKey) : [];
36
+ function buildDrilledThemeFlow(flow, pathsResponse, selections) {
37
+ const selectedAssignments = selections.map((selection) => {
38
+ if (selection.kind === "noise") return { signalName: selection.signalName, assignment: "noise" };
39
+ const assignment = Object.entries(pathsResponse.themes).find(
40
+ ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId
41
+ )?.[0];
42
+ return { signalName: selection.signalName, assignment };
43
+ });
44
+ const filteredPaths = selectedAssignments.some((selection) => selection.assignment === void 0) ? [] : pathsResponse.paths.filter(
45
+ (path) => selectedAssignments.every((selection) => path.assignments[selection.signalName] === selection.assignment)
46
+ );
47
+ const drilledSignals = new Set(selections.map((selection) => selection.signalName));
48
+ const visibleSignals = pathsResponse.signals.filter((signalName) => !drilledSignals.has(signalName));
22
49
  const flowNodesBySignalAndTheme = /* @__PURE__ */ new Map();
23
50
  const noiseNodeIds = /* @__PURE__ */ new Map();
24
51
  for (const stage of flow.stages) {
@@ -29,7 +56,6 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
29
56
  }
30
57
  flowNodesBySignalAndTheme.set(stage.signalName, themes);
31
58
  }
32
- let localThemeIndex = 0;
33
59
  const nodesBySignalAndAssignment = /* @__PURE__ */ new Map();
34
60
  const nodeCounts = /* @__PURE__ */ new Map();
35
61
  const links = /* @__PURE__ */ new Map();
@@ -41,7 +67,7 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
41
67
  const theme = pathsResponse.themes[assignment];
42
68
  const flowNode = theme ? flowNodesBySignalAndTheme.get(signalName)?.get(theme.themeId) : void 0;
43
69
  const node = theme ? {
44
- nodeId: flowNode?.nodeId ?? `drilled-theme-${localThemeIndex++}`,
70
+ nodeId: flowNode?.nodeId ?? `drilled-theme-${signalName}-${theme.themeId}`,
45
71
  kind: "theme",
46
72
  themeId: theme.themeId,
47
73
  label: theme.label,
@@ -59,14 +85,14 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
59
85
  return node;
60
86
  };
61
87
  for (const path of filteredPaths) {
62
- for (let index = 0; index < pathsResponse.signals.length; index += 1) {
63
- const signalName = pathsResponse.signals[index];
88
+ for (let index = 0; index < visibleSignals.length; index += 1) {
89
+ const signalName = visibleSignals[index];
64
90
  if (!signalName) continue;
65
91
  const assignment = path.assignments[signalName];
66
92
  if (!assignment) continue;
67
93
  const node = resolveNode(signalName, assignment);
68
94
  nodeCounts.set(node.nodeId, (nodeCounts.get(node.nodeId) ?? 0) + 1);
69
- const targetSignalName = pathsResponse.signals[index + 1];
95
+ const targetSignalName = visibleSignals[index + 1];
70
96
  if (!targetSignalName) continue;
71
97
  const targetAssignment = path.assignments[targetSignalName];
72
98
  if (!targetAssignment) continue;
@@ -86,7 +112,7 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
86
112
  }
87
113
  }
88
114
  }
89
- const stages = pathsResponse.signals.map((signalName) => {
115
+ const stages = visibleSignals.map((signalName) => {
90
116
  const traceCount = filteredPaths.filter((path) => path.assignments[signalName] !== void 0).length;
91
117
  const uniqueNodes = /* @__PURE__ */ new Map();
92
118
  for (const node of nodesBySignalAndAssignment.get(signalName)?.values() ?? []) uniqueNodes.set(node.nodeId, node);
@@ -111,5 +137,7 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
111
137
 
112
138
  exports.buildDrilledThemeFlow = buildDrilledThemeFlow;
113
139
  exports.findNoiseSelection = findNoiseSelection;
140
+ exports.findSelectionStats = findSelectionStats;
114
141
  exports.findThemeSelection = findThemeSelection;
142
+ exports.mergeVisibleSignalOrder = mergeVisibleSignalOrder;
115
143
  //# sourceMappingURL=theme-drilldown-data.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-drilldown-data.cjs.js","sources":["../../../src/ee/signals/theme-drilldown-data.ts"],"sourcesContent":["import type { ThemeFlowResponse, ThemeNode, ThemePathsResponse, TraceSignalName } from './types';\n\nexport type ThemeSelection = {\n signalName: TraceSignalName;\n themeId: string;\n label: string;\n};\n\nexport function findThemeSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): ThemeSelection | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n if (!stage) return undefined;\n const node = stage.nodes.find(candidate => candidate.nodeId === String(nodeId));\n if (node?.kind !== 'theme' || !node.themeId || !/^\\d+$/.test(node.themeId)) return undefined;\n return { signalName: stage.signalName, themeId: node.themeId, label: node.label };\n}\n\n/** Resolves a chart node to its trace signal when the node is that stage's noise bucket. */\nexport function findNoiseSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): TraceSignalName | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n const node = stage?.nodes.find(candidate => candidate.nodeId === String(nodeId));\n return node?.kind === 'noise' ? stage?.signalName : undefined;\n}\n\nexport function buildDrilledThemeFlow(\n flow: ThemeFlowResponse,\n pathsResponse: ThemePathsResponse,\n selection: ThemeSelection,\n): ThemeFlowResponse {\n const selectedNodeKey = Object.entries(pathsResponse.themes).find(\n ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId,\n )?.[0];\n const filteredPaths = selectedNodeKey\n ? pathsResponse.paths.filter(path => path.assignments[selection.signalName] === selectedNodeKey)\n : [];\n const flowNodesBySignalAndTheme = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const noiseNodeIds = new Map<TraceSignalName, string>();\n\n for (const stage of flow.stages) {\n const themes = new Map<string, ThemeNode>();\n for (const node of stage.nodes) {\n if (node.kind === 'theme' && node.themeId) themes.set(node.themeId, node);\n if (node.kind === 'noise') noiseNodeIds.set(stage.signalName, node.nodeId);\n }\n flowNodesBySignalAndTheme.set(stage.signalName, themes);\n }\n\n let localThemeIndex = 0;\n const nodesBySignalAndAssignment = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const nodeCounts = new Map<string, number>();\n const links = new Map<\n string,\n { sourceNodeId: string; targetNodeId: string; traceCount: number; sourceShare: number; targetShare: number }\n >();\n\n const resolveNode = (signalName: TraceSignalName, assignment: string) => {\n const nodesByAssignment = nodesBySignalAndAssignment.get(signalName) ?? new Map<string, ThemeNode>();\n nodesBySignalAndAssignment.set(signalName, nodesByAssignment);\n const existingNode = nodesByAssignment.get(assignment);\n if (existingNode) return existingNode;\n\n const theme = pathsResponse.themes[assignment];\n const flowNode = theme ? flowNodesBySignalAndTheme.get(signalName)?.get(theme.themeId) : undefined;\n const node: ThemeNode = theme\n ? {\n nodeId: flowNode?.nodeId ?? `drilled-theme-${localThemeIndex++}`,\n kind: 'theme',\n themeId: theme.themeId,\n label: theme.label,\n description: theme.description,\n traceCount: 0,\n stageShare: 0,\n }\n : {\n nodeId: noiseNodeIds.get(signalName) ?? `drilled-noise-${signalName}`,\n kind: 'noise',\n label: 'Noise',\n traceCount: 0,\n stageShare: 0,\n };\n nodesByAssignment.set(assignment, node);\n return node;\n };\n\n for (const path of filteredPaths) {\n for (let index = 0; index < pathsResponse.signals.length; index += 1) {\n const signalName = pathsResponse.signals[index];\n if (!signalName) continue;\n const assignment = path.assignments[signalName];\n if (!assignment) continue;\n const node = resolveNode(signalName, assignment);\n nodeCounts.set(node.nodeId, (nodeCounts.get(node.nodeId) ?? 0) + 1);\n\n const targetSignalName = pathsResponse.signals[index + 1];\n if (!targetSignalName) continue;\n const targetAssignment = path.assignments[targetSignalName];\n if (!targetAssignment) continue;\n const targetNode = resolveNode(targetSignalName, targetAssignment);\n const linkId = JSON.stringify([node.nodeId, targetNode.nodeId]);\n const link = links.get(linkId);\n if (link) {\n link.traceCount += 1;\n } else {\n links.set(linkId, {\n sourceNodeId: node.nodeId,\n targetNodeId: targetNode.nodeId,\n traceCount: 1,\n sourceShare: 0,\n targetShare: 0,\n });\n }\n }\n }\n\n const stages = pathsResponse.signals.map(signalName => {\n const traceCount = filteredPaths.filter(path => path.assignments[signalName] !== undefined).length;\n const uniqueNodes = new Map<string, ThemeNode>();\n for (const node of nodesBySignalAndAssignment.get(signalName)?.values() ?? []) uniqueNodes.set(node.nodeId, node);\n const nodes = [...uniqueNodes.values()].map(node => {\n const count = nodeCounts.get(node.nodeId) ?? 0;\n return { ...node, traceCount: count, stageShare: traceCount > 0 ? count / traceCount : 0 };\n });\n return { signalName, traceCount, nodes };\n });\n\n const countsByNodeId = new Map(stages.flatMap(stage => stage.nodes.map(node => [node.nodeId, node.traceCount])));\n const drilledLinks = [...links.values()].map(link => ({\n ...link,\n sourceShare: link.traceCount / (countsByNodeId.get(link.sourceNodeId) ?? link.traceCount),\n targetShare: link.traceCount / (countsByNodeId.get(link.targetNodeId) ?? link.traceCount),\n }));\n\n return {\n snapshot: { ...flow.snapshot, traceCount: filteredPaths.length },\n stages,\n links: drilledLinks,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"theme-drilldown-data.cjs.js","sources":["../../../src/ee/signals/theme-drilldown-data.ts"],"sourcesContent":["import type { ThemeFlowResponse, ThemeNode, ThemePathsResponse, TraceSignalName } from './types';\n\nexport type ThemeSelection =\n | {\n kind: 'theme';\n signalName: TraceSignalName;\n themeId: string;\n label: string;\n }\n | {\n kind: 'noise';\n signalName: TraceSignalName;\n };\n\nexport type SelectedTheme = Extract<ThemeSelection, { kind: 'theme' }>;\n\nexport interface ThemeSelectionStats {\n traceCount: number;\n stageShare: number;\n}\n\nexport function findSelectionStats(\n flow: ThemeFlowResponse,\n drillStack: ThemeSelection[],\n selection: ThemeSelection | undefined,\n): ThemeSelectionStats | undefined {\n if (!selection) return undefined;\n if (drillStack.some(filter => filter.signalName === selection.signalName)) {\n return { traceCount: flow.snapshot.traceCount, stageShare: flow.snapshot.traceCount > 0 ? 1 : 0 };\n }\n const stage = flow.stages.find(candidate => candidate.signalName === selection.signalName);\n const node = stage?.nodes.find(candidate =>\n selection.kind === 'theme'\n ? candidate.kind === 'theme' && candidate.themeId === selection.themeId\n : candidate.kind === 'noise',\n );\n return node ? { traceCount: node.traceCount, stageShare: node.stageShare } : { traceCount: 0, stageShare: 0 };\n}\n\nexport function mergeVisibleSignalOrder(\n signalNames: TraceSignalName[],\n nextVisibleSignalNames: TraceSignalName[],\n): TraceSignalName[] {\n const visibleSignalNames = new Set(nextVisibleSignalNames);\n let nextVisibleIndex = 0;\n return signalNames.map(signalName => {\n if (!visibleSignalNames.has(signalName)) return signalName;\n return nextVisibleSignalNames[nextVisibleIndex++] ?? signalName;\n });\n}\n\nexport function findThemeSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): SelectedTheme | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n if (!stage) return undefined;\n const node = stage.nodes.find(candidate => candidate.nodeId === String(nodeId));\n if (node?.kind !== 'theme' || !node.themeId || !/^\\d+$/.test(node.themeId)) return undefined;\n return { kind: 'theme', signalName: stage.signalName, themeId: node.themeId, label: node.label };\n}\n\n/** Resolves a chart node to a noise selection when the node is that stage's noise bucket. */\nexport function findNoiseSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): ThemeSelection | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n const node = stage?.nodes.find(candidate => candidate.nodeId === String(nodeId));\n return node?.kind === 'noise' && stage ? { kind: 'noise', signalName: stage.signalName } : undefined;\n}\n\nexport function buildDrilledThemeFlow(\n flow: ThemeFlowResponse,\n pathsResponse: ThemePathsResponse,\n selections: ThemeSelection[],\n): ThemeFlowResponse {\n const selectedAssignments = selections.map(selection => {\n if (selection.kind === 'noise') return { signalName: selection.signalName, assignment: 'noise' };\n\n const assignment = Object.entries(pathsResponse.themes).find(\n ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId,\n )?.[0];\n return { signalName: selection.signalName, assignment };\n });\n const filteredPaths = selectedAssignments.some(selection => selection.assignment === undefined)\n ? []\n : pathsResponse.paths.filter(path =>\n selectedAssignments.every(selection => path.assignments[selection.signalName] === selection.assignment),\n );\n const drilledSignals = new Set(selections.map(selection => selection.signalName));\n const visibleSignals = pathsResponse.signals.filter(signalName => !drilledSignals.has(signalName));\n const flowNodesBySignalAndTheme = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const noiseNodeIds = new Map<TraceSignalName, string>();\n\n for (const stage of flow.stages) {\n const themes = new Map<string, ThemeNode>();\n for (const node of stage.nodes) {\n if (node.kind === 'theme' && node.themeId) themes.set(node.themeId, node);\n if (node.kind === 'noise') noiseNodeIds.set(stage.signalName, node.nodeId);\n }\n flowNodesBySignalAndTheme.set(stage.signalName, themes);\n }\n\n const nodesBySignalAndAssignment = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const nodeCounts = new Map<string, number>();\n const links = new Map<\n string,\n { sourceNodeId: string; targetNodeId: string; traceCount: number; sourceShare: number; targetShare: number }\n >();\n\n const resolveNode = (signalName: TraceSignalName, assignment: string) => {\n const nodesByAssignment = nodesBySignalAndAssignment.get(signalName) ?? new Map<string, ThemeNode>();\n nodesBySignalAndAssignment.set(signalName, nodesByAssignment);\n const existingNode = nodesByAssignment.get(assignment);\n if (existingNode) return existingNode;\n\n const theme = pathsResponse.themes[assignment];\n const flowNode = theme ? flowNodesBySignalAndTheme.get(signalName)?.get(theme.themeId) : undefined;\n const node: ThemeNode = theme\n ? {\n nodeId: flowNode?.nodeId ?? `drilled-theme-${signalName}-${theme.themeId}`,\n kind: 'theme',\n themeId: theme.themeId,\n label: theme.label,\n description: theme.description,\n traceCount: 0,\n stageShare: 0,\n }\n : {\n nodeId: noiseNodeIds.get(signalName) ?? `drilled-noise-${signalName}`,\n kind: 'noise',\n label: 'Noise',\n traceCount: 0,\n stageShare: 0,\n };\n nodesByAssignment.set(assignment, node);\n return node;\n };\n\n for (const path of filteredPaths) {\n for (let index = 0; index < visibleSignals.length; index += 1) {\n const signalName = visibleSignals[index];\n if (!signalName) continue;\n const assignment = path.assignments[signalName];\n if (!assignment) continue;\n const node = resolveNode(signalName, assignment);\n nodeCounts.set(node.nodeId, (nodeCounts.get(node.nodeId) ?? 0) + 1);\n\n const targetSignalName = visibleSignals[index + 1];\n if (!targetSignalName) continue;\n const targetAssignment = path.assignments[targetSignalName];\n if (!targetAssignment) continue;\n const targetNode = resolveNode(targetSignalName, targetAssignment);\n const linkId = JSON.stringify([node.nodeId, targetNode.nodeId]);\n const link = links.get(linkId);\n if (link) {\n link.traceCount += 1;\n } else {\n links.set(linkId, {\n sourceNodeId: node.nodeId,\n targetNodeId: targetNode.nodeId,\n traceCount: 1,\n sourceShare: 0,\n targetShare: 0,\n });\n }\n }\n }\n\n const stages = visibleSignals.map(signalName => {\n const traceCount = filteredPaths.filter(path => path.assignments[signalName] !== undefined).length;\n const uniqueNodes = new Map<string, ThemeNode>();\n for (const node of nodesBySignalAndAssignment.get(signalName)?.values() ?? []) uniqueNodes.set(node.nodeId, node);\n const nodes = [...uniqueNodes.values()].map(node => {\n const count = nodeCounts.get(node.nodeId) ?? 0;\n return { ...node, traceCount: count, stageShare: traceCount > 0 ? count / traceCount : 0 };\n });\n return { signalName, traceCount, nodes };\n });\n\n const countsByNodeId = new Map(stages.flatMap(stage => stage.nodes.map(node => [node.nodeId, node.traceCount])));\n const drilledLinks = [...links.values()].map(link => ({\n ...link,\n sourceShare: link.traceCount / (countsByNodeId.get(link.sourceNodeId) ?? link.traceCount),\n targetShare: link.traceCount / (countsByNodeId.get(link.targetNodeId) ?? link.traceCount),\n }));\n\n return {\n snapshot: { ...flow.snapshot, traceCount: filteredPaths.length },\n stages,\n links: drilledLinks,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1,20 +1,47 @@
1
+ function findSelectionStats(flow, drillStack, selection) {
2
+ if (!selection) return void 0;
3
+ if (drillStack.some((filter) => filter.signalName === selection.signalName)) {
4
+ return { traceCount: flow.snapshot.traceCount, stageShare: flow.snapshot.traceCount > 0 ? 1 : 0 };
5
+ }
6
+ const stage = flow.stages.find((candidate) => candidate.signalName === selection.signalName);
7
+ const node = stage?.nodes.find(
8
+ (candidate) => selection.kind === "theme" ? candidate.kind === "theme" && candidate.themeId === selection.themeId : candidate.kind === "noise"
9
+ );
10
+ return node ? { traceCount: node.traceCount, stageShare: node.stageShare } : { traceCount: 0, stageShare: 0 };
11
+ }
12
+ function mergeVisibleSignalOrder(signalNames, nextVisibleSignalNames) {
13
+ const visibleSignalNames = new Set(nextVisibleSignalNames);
14
+ let nextVisibleIndex = 0;
15
+ return signalNames.map((signalName) => {
16
+ if (!visibleSignalNames.has(signalName)) return signalName;
17
+ return nextVisibleSignalNames[nextVisibleIndex++] ?? signalName;
18
+ });
19
+ }
1
20
  function findThemeSelection(flow, signalName, nodeId) {
2
21
  const stage = flow.stages.find((candidate) => candidate.signalName === signalName);
3
22
  if (!stage) return void 0;
4
23
  const node = stage.nodes.find((candidate) => candidate.nodeId === String(nodeId));
5
24
  if (node?.kind !== "theme" || !node.themeId || !/^\d+$/.test(node.themeId)) return void 0;
6
- return { signalName: stage.signalName, themeId: node.themeId, label: node.label };
25
+ return { kind: "theme", signalName: stage.signalName, themeId: node.themeId, label: node.label };
7
26
  }
8
27
  function findNoiseSelection(flow, signalName, nodeId) {
9
28
  const stage = flow.stages.find((candidate) => candidate.signalName === signalName);
10
29
  const node = stage?.nodes.find((candidate) => candidate.nodeId === String(nodeId));
11
- return node?.kind === "noise" ? stage?.signalName : void 0;
30
+ return node?.kind === "noise" && stage ? { kind: "noise", signalName: stage.signalName } : void 0;
12
31
  }
13
- function buildDrilledThemeFlow(flow, pathsResponse, selection) {
14
- const selectedNodeKey = Object.entries(pathsResponse.themes).find(
15
- ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId
16
- )?.[0];
17
- const filteredPaths = selectedNodeKey ? pathsResponse.paths.filter((path) => path.assignments[selection.signalName] === selectedNodeKey) : [];
32
+ function buildDrilledThemeFlow(flow, pathsResponse, selections) {
33
+ const selectedAssignments = selections.map((selection) => {
34
+ if (selection.kind === "noise") return { signalName: selection.signalName, assignment: "noise" };
35
+ const assignment = Object.entries(pathsResponse.themes).find(
36
+ ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId
37
+ )?.[0];
38
+ return { signalName: selection.signalName, assignment };
39
+ });
40
+ const filteredPaths = selectedAssignments.some((selection) => selection.assignment === void 0) ? [] : pathsResponse.paths.filter(
41
+ (path) => selectedAssignments.every((selection) => path.assignments[selection.signalName] === selection.assignment)
42
+ );
43
+ const drilledSignals = new Set(selections.map((selection) => selection.signalName));
44
+ const visibleSignals = pathsResponse.signals.filter((signalName) => !drilledSignals.has(signalName));
18
45
  const flowNodesBySignalAndTheme = /* @__PURE__ */ new Map();
19
46
  const noiseNodeIds = /* @__PURE__ */ new Map();
20
47
  for (const stage of flow.stages) {
@@ -25,7 +52,6 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
25
52
  }
26
53
  flowNodesBySignalAndTheme.set(stage.signalName, themes);
27
54
  }
28
- let localThemeIndex = 0;
29
55
  const nodesBySignalAndAssignment = /* @__PURE__ */ new Map();
30
56
  const nodeCounts = /* @__PURE__ */ new Map();
31
57
  const links = /* @__PURE__ */ new Map();
@@ -37,7 +63,7 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
37
63
  const theme = pathsResponse.themes[assignment];
38
64
  const flowNode = theme ? flowNodesBySignalAndTheme.get(signalName)?.get(theme.themeId) : void 0;
39
65
  const node = theme ? {
40
- nodeId: flowNode?.nodeId ?? `drilled-theme-${localThemeIndex++}`,
66
+ nodeId: flowNode?.nodeId ?? `drilled-theme-${signalName}-${theme.themeId}`,
41
67
  kind: "theme",
42
68
  themeId: theme.themeId,
43
69
  label: theme.label,
@@ -55,14 +81,14 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
55
81
  return node;
56
82
  };
57
83
  for (const path of filteredPaths) {
58
- for (let index = 0; index < pathsResponse.signals.length; index += 1) {
59
- const signalName = pathsResponse.signals[index];
84
+ for (let index = 0; index < visibleSignals.length; index += 1) {
85
+ const signalName = visibleSignals[index];
60
86
  if (!signalName) continue;
61
87
  const assignment = path.assignments[signalName];
62
88
  if (!assignment) continue;
63
89
  const node = resolveNode(signalName, assignment);
64
90
  nodeCounts.set(node.nodeId, (nodeCounts.get(node.nodeId) ?? 0) + 1);
65
- const targetSignalName = pathsResponse.signals[index + 1];
91
+ const targetSignalName = visibleSignals[index + 1];
66
92
  if (!targetSignalName) continue;
67
93
  const targetAssignment = path.assignments[targetSignalName];
68
94
  if (!targetAssignment) continue;
@@ -82,7 +108,7 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
82
108
  }
83
109
  }
84
110
  }
85
- const stages = pathsResponse.signals.map((signalName) => {
111
+ const stages = visibleSignals.map((signalName) => {
86
112
  const traceCount = filteredPaths.filter((path) => path.assignments[signalName] !== void 0).length;
87
113
  const uniqueNodes = /* @__PURE__ */ new Map();
88
114
  for (const node of nodesBySignalAndAssignment.get(signalName)?.values() ?? []) uniqueNodes.set(node.nodeId, node);
@@ -105,5 +131,5 @@ function buildDrilledThemeFlow(flow, pathsResponse, selection) {
105
131
  };
106
132
  }
107
133
 
108
- export { buildDrilledThemeFlow, findNoiseSelection, findThemeSelection };
134
+ export { buildDrilledThemeFlow, findNoiseSelection, findSelectionStats, findThemeSelection, mergeVisibleSignalOrder };
109
135
  //# sourceMappingURL=theme-drilldown-data.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-drilldown-data.es.js","sources":["../../../src/ee/signals/theme-drilldown-data.ts"],"sourcesContent":["import type { ThemeFlowResponse, ThemeNode, ThemePathsResponse, TraceSignalName } from './types';\n\nexport type ThemeSelection = {\n signalName: TraceSignalName;\n themeId: string;\n label: string;\n};\n\nexport function findThemeSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): ThemeSelection | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n if (!stage) return undefined;\n const node = stage.nodes.find(candidate => candidate.nodeId === String(nodeId));\n if (node?.kind !== 'theme' || !node.themeId || !/^\\d+$/.test(node.themeId)) return undefined;\n return { signalName: stage.signalName, themeId: node.themeId, label: node.label };\n}\n\n/** Resolves a chart node to its trace signal when the node is that stage's noise bucket. */\nexport function findNoiseSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): TraceSignalName | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n const node = stage?.nodes.find(candidate => candidate.nodeId === String(nodeId));\n return node?.kind === 'noise' ? stage?.signalName : undefined;\n}\n\nexport function buildDrilledThemeFlow(\n flow: ThemeFlowResponse,\n pathsResponse: ThemePathsResponse,\n selection: ThemeSelection,\n): ThemeFlowResponse {\n const selectedNodeKey = Object.entries(pathsResponse.themes).find(\n ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId,\n )?.[0];\n const filteredPaths = selectedNodeKey\n ? pathsResponse.paths.filter(path => path.assignments[selection.signalName] === selectedNodeKey)\n : [];\n const flowNodesBySignalAndTheme = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const noiseNodeIds = new Map<TraceSignalName, string>();\n\n for (const stage of flow.stages) {\n const themes = new Map<string, ThemeNode>();\n for (const node of stage.nodes) {\n if (node.kind === 'theme' && node.themeId) themes.set(node.themeId, node);\n if (node.kind === 'noise') noiseNodeIds.set(stage.signalName, node.nodeId);\n }\n flowNodesBySignalAndTheme.set(stage.signalName, themes);\n }\n\n let localThemeIndex = 0;\n const nodesBySignalAndAssignment = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const nodeCounts = new Map<string, number>();\n const links = new Map<\n string,\n { sourceNodeId: string; targetNodeId: string; traceCount: number; sourceShare: number; targetShare: number }\n >();\n\n const resolveNode = (signalName: TraceSignalName, assignment: string) => {\n const nodesByAssignment = nodesBySignalAndAssignment.get(signalName) ?? new Map<string, ThemeNode>();\n nodesBySignalAndAssignment.set(signalName, nodesByAssignment);\n const existingNode = nodesByAssignment.get(assignment);\n if (existingNode) return existingNode;\n\n const theme = pathsResponse.themes[assignment];\n const flowNode = theme ? flowNodesBySignalAndTheme.get(signalName)?.get(theme.themeId) : undefined;\n const node: ThemeNode = theme\n ? {\n nodeId: flowNode?.nodeId ?? `drilled-theme-${localThemeIndex++}`,\n kind: 'theme',\n themeId: theme.themeId,\n label: theme.label,\n description: theme.description,\n traceCount: 0,\n stageShare: 0,\n }\n : {\n nodeId: noiseNodeIds.get(signalName) ?? `drilled-noise-${signalName}`,\n kind: 'noise',\n label: 'Noise',\n traceCount: 0,\n stageShare: 0,\n };\n nodesByAssignment.set(assignment, node);\n return node;\n };\n\n for (const path of filteredPaths) {\n for (let index = 0; index < pathsResponse.signals.length; index += 1) {\n const signalName = pathsResponse.signals[index];\n if (!signalName) continue;\n const assignment = path.assignments[signalName];\n if (!assignment) continue;\n const node = resolveNode(signalName, assignment);\n nodeCounts.set(node.nodeId, (nodeCounts.get(node.nodeId) ?? 0) + 1);\n\n const targetSignalName = pathsResponse.signals[index + 1];\n if (!targetSignalName) continue;\n const targetAssignment = path.assignments[targetSignalName];\n if (!targetAssignment) continue;\n const targetNode = resolveNode(targetSignalName, targetAssignment);\n const linkId = JSON.stringify([node.nodeId, targetNode.nodeId]);\n const link = links.get(linkId);\n if (link) {\n link.traceCount += 1;\n } else {\n links.set(linkId, {\n sourceNodeId: node.nodeId,\n targetNodeId: targetNode.nodeId,\n traceCount: 1,\n sourceShare: 0,\n targetShare: 0,\n });\n }\n }\n }\n\n const stages = pathsResponse.signals.map(signalName => {\n const traceCount = filteredPaths.filter(path => path.assignments[signalName] !== undefined).length;\n const uniqueNodes = new Map<string, ThemeNode>();\n for (const node of nodesBySignalAndAssignment.get(signalName)?.values() ?? []) uniqueNodes.set(node.nodeId, node);\n const nodes = [...uniqueNodes.values()].map(node => {\n const count = nodeCounts.get(node.nodeId) ?? 0;\n return { ...node, traceCount: count, stageShare: traceCount > 0 ? count / traceCount : 0 };\n });\n return { signalName, traceCount, nodes };\n });\n\n const countsByNodeId = new Map(stages.flatMap(stage => stage.nodes.map(node => [node.nodeId, node.traceCount])));\n const drilledLinks = [...links.values()].map(link => ({\n ...link,\n sourceShare: link.traceCount / (countsByNodeId.get(link.sourceNodeId) ?? link.traceCount),\n targetShare: link.traceCount / (countsByNodeId.get(link.targetNodeId) ?? link.traceCount),\n }));\n\n return {\n snapshot: { ...flow.snapshot, traceCount: filteredPaths.length },\n stages,\n links: drilledLinks,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"theme-drilldown-data.es.js","sources":["../../../src/ee/signals/theme-drilldown-data.ts"],"sourcesContent":["import type { ThemeFlowResponse, ThemeNode, ThemePathsResponse, TraceSignalName } from './types';\n\nexport type ThemeSelection =\n | {\n kind: 'theme';\n signalName: TraceSignalName;\n themeId: string;\n label: string;\n }\n | {\n kind: 'noise';\n signalName: TraceSignalName;\n };\n\nexport type SelectedTheme = Extract<ThemeSelection, { kind: 'theme' }>;\n\nexport interface ThemeSelectionStats {\n traceCount: number;\n stageShare: number;\n}\n\nexport function findSelectionStats(\n flow: ThemeFlowResponse,\n drillStack: ThemeSelection[],\n selection: ThemeSelection | undefined,\n): ThemeSelectionStats | undefined {\n if (!selection) return undefined;\n if (drillStack.some(filter => filter.signalName === selection.signalName)) {\n return { traceCount: flow.snapshot.traceCount, stageShare: flow.snapshot.traceCount > 0 ? 1 : 0 };\n }\n const stage = flow.stages.find(candidate => candidate.signalName === selection.signalName);\n const node = stage?.nodes.find(candidate =>\n selection.kind === 'theme'\n ? candidate.kind === 'theme' && candidate.themeId === selection.themeId\n : candidate.kind === 'noise',\n );\n return node ? { traceCount: node.traceCount, stageShare: node.stageShare } : { traceCount: 0, stageShare: 0 };\n}\n\nexport function mergeVisibleSignalOrder(\n signalNames: TraceSignalName[],\n nextVisibleSignalNames: TraceSignalName[],\n): TraceSignalName[] {\n const visibleSignalNames = new Set(nextVisibleSignalNames);\n let nextVisibleIndex = 0;\n return signalNames.map(signalName => {\n if (!visibleSignalNames.has(signalName)) return signalName;\n return nextVisibleSignalNames[nextVisibleIndex++] ?? signalName;\n });\n}\n\nexport function findThemeSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): SelectedTheme | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n if (!stage) return undefined;\n const node = stage.nodes.find(candidate => candidate.nodeId === String(nodeId));\n if (node?.kind !== 'theme' || !node.themeId || !/^\\d+$/.test(node.themeId)) return undefined;\n return { kind: 'theme', signalName: stage.signalName, themeId: node.themeId, label: node.label };\n}\n\n/** Resolves a chart node to a noise selection when the node is that stage's noise bucket. */\nexport function findNoiseSelection(\n flow: ThemeFlowResponse,\n signalName: string,\n nodeId: string | number,\n): ThemeSelection | undefined {\n const stage = flow.stages.find(candidate => candidate.signalName === signalName);\n const node = stage?.nodes.find(candidate => candidate.nodeId === String(nodeId));\n return node?.kind === 'noise' && stage ? { kind: 'noise', signalName: stage.signalName } : undefined;\n}\n\nexport function buildDrilledThemeFlow(\n flow: ThemeFlowResponse,\n pathsResponse: ThemePathsResponse,\n selections: ThemeSelection[],\n): ThemeFlowResponse {\n const selectedAssignments = selections.map(selection => {\n if (selection.kind === 'noise') return { signalName: selection.signalName, assignment: 'noise' };\n\n const assignment = Object.entries(pathsResponse.themes).find(\n ([, theme]) => theme.signalName === selection.signalName && theme.themeId === selection.themeId,\n )?.[0];\n return { signalName: selection.signalName, assignment };\n });\n const filteredPaths = selectedAssignments.some(selection => selection.assignment === undefined)\n ? []\n : pathsResponse.paths.filter(path =>\n selectedAssignments.every(selection => path.assignments[selection.signalName] === selection.assignment),\n );\n const drilledSignals = new Set(selections.map(selection => selection.signalName));\n const visibleSignals = pathsResponse.signals.filter(signalName => !drilledSignals.has(signalName));\n const flowNodesBySignalAndTheme = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const noiseNodeIds = new Map<TraceSignalName, string>();\n\n for (const stage of flow.stages) {\n const themes = new Map<string, ThemeNode>();\n for (const node of stage.nodes) {\n if (node.kind === 'theme' && node.themeId) themes.set(node.themeId, node);\n if (node.kind === 'noise') noiseNodeIds.set(stage.signalName, node.nodeId);\n }\n flowNodesBySignalAndTheme.set(stage.signalName, themes);\n }\n\n const nodesBySignalAndAssignment = new Map<TraceSignalName, Map<string, ThemeNode>>();\n const nodeCounts = new Map<string, number>();\n const links = new Map<\n string,\n { sourceNodeId: string; targetNodeId: string; traceCount: number; sourceShare: number; targetShare: number }\n >();\n\n const resolveNode = (signalName: TraceSignalName, assignment: string) => {\n const nodesByAssignment = nodesBySignalAndAssignment.get(signalName) ?? new Map<string, ThemeNode>();\n nodesBySignalAndAssignment.set(signalName, nodesByAssignment);\n const existingNode = nodesByAssignment.get(assignment);\n if (existingNode) return existingNode;\n\n const theme = pathsResponse.themes[assignment];\n const flowNode = theme ? flowNodesBySignalAndTheme.get(signalName)?.get(theme.themeId) : undefined;\n const node: ThemeNode = theme\n ? {\n nodeId: flowNode?.nodeId ?? `drilled-theme-${signalName}-${theme.themeId}`,\n kind: 'theme',\n themeId: theme.themeId,\n label: theme.label,\n description: theme.description,\n traceCount: 0,\n stageShare: 0,\n }\n : {\n nodeId: noiseNodeIds.get(signalName) ?? `drilled-noise-${signalName}`,\n kind: 'noise',\n label: 'Noise',\n traceCount: 0,\n stageShare: 0,\n };\n nodesByAssignment.set(assignment, node);\n return node;\n };\n\n for (const path of filteredPaths) {\n for (let index = 0; index < visibleSignals.length; index += 1) {\n const signalName = visibleSignals[index];\n if (!signalName) continue;\n const assignment = path.assignments[signalName];\n if (!assignment) continue;\n const node = resolveNode(signalName, assignment);\n nodeCounts.set(node.nodeId, (nodeCounts.get(node.nodeId) ?? 0) + 1);\n\n const targetSignalName = visibleSignals[index + 1];\n if (!targetSignalName) continue;\n const targetAssignment = path.assignments[targetSignalName];\n if (!targetAssignment) continue;\n const targetNode = resolveNode(targetSignalName, targetAssignment);\n const linkId = JSON.stringify([node.nodeId, targetNode.nodeId]);\n const link = links.get(linkId);\n if (link) {\n link.traceCount += 1;\n } else {\n links.set(linkId, {\n sourceNodeId: node.nodeId,\n targetNodeId: targetNode.nodeId,\n traceCount: 1,\n sourceShare: 0,\n targetShare: 0,\n });\n }\n }\n }\n\n const stages = visibleSignals.map(signalName => {\n const traceCount = filteredPaths.filter(path => path.assignments[signalName] !== undefined).length;\n const uniqueNodes = new Map<string, ThemeNode>();\n for (const node of nodesBySignalAndAssignment.get(signalName)?.values() ?? []) uniqueNodes.set(node.nodeId, node);\n const nodes = [...uniqueNodes.values()].map(node => {\n const count = nodeCounts.get(node.nodeId) ?? 0;\n return { ...node, traceCount: count, stageShare: traceCount > 0 ? count / traceCount : 0 };\n });\n return { signalName, traceCount, nodes };\n });\n\n const countsByNodeId = new Map(stages.flatMap(stage => stage.nodes.map(node => [node.nodeId, node.traceCount])));\n const drilledLinks = [...links.values()].map(link => ({\n ...link,\n sourceShare: link.traceCount / (countsByNodeId.get(link.sourceNodeId) ?? link.traceCount),\n targetShare: link.traceCount / (countsByNodeId.get(link.targetNodeId) ?? link.traceCount),\n }));\n\n return {\n snapshot: { ...flow.snapshot, traceCount: filteredPaths.length },\n stages,\n links: drilledLinks,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -9,52 +9,77 @@ const ee_signals_signalFormatting = require('./signal-formatting.cjs.js');
9
9
  const Button = require('../../Button-B4Ixj2aW.cjs');
10
10
  const sankeyColor = require('../../sankeyColor-DONd5cg9.cjs');
11
11
 
12
+ function selectionLabel(selection) {
13
+ return `${ee_signals_signalFormatting.formatSignalName(selection.signalName)} · ${selection.kind === "theme" ? selection.label : "Noise"}`;
14
+ }
15
+ function filterSummary({
16
+ selections,
17
+ filteredTraceCount,
18
+ totalTraceCount,
19
+ isUnavailable
20
+ }) {
21
+ if (isUnavailable) return "Filters unavailable for this snapshot";
22
+ if (filteredTraceCount === void 0) return "Loading matching traces…";
23
+ const onlySelection = selections.length === 1 ? selections[0] : void 0;
24
+ if (onlySelection?.kind === "noise") {
25
+ return `Showing the ${filteredTraceCount} of ${totalTraceCount} traces assigned to Noise`;
26
+ }
27
+ if (onlySelection) {
28
+ return `Showing the ${filteredTraceCount} of ${totalTraceCount} traces that flow through this theme`;
29
+ }
30
+ return `Showing the ${filteredTraceCount} of ${totalTraceCount} traces that match these filters`;
31
+ }
12
32
  function ThemeFilterBanner({
13
- selection,
33
+ selections,
14
34
  filteredTraceCount,
15
35
  totalTraceCount,
36
+ isUnavailable,
16
37
  onViewDetails,
38
+ onRemove,
17
39
  onClear
18
40
  }) {
19
- const color = sankeyColor.nodeColor(ee_signals_signalColors.getSignalHue(selection.signalName));
41
+ const colors = selections.map((selection) => sankeyColor.nodeColor(ee_signals_signalColors.getSignalHue(selection.signalName)));
42
+ const latestSelection = selections.at(-1);
43
+ const backgroundGradient = `linear-gradient(90deg, ${colors.map((color) => `color-mix(in srgb, ${color} 8%, transparent)`).join(", ")})`;
44
+ const borderGradient = `linear-gradient(90deg, ${colors.map((color) => `color-mix(in srgb, ${color} 35%, transparent)`).join(", ")})`;
20
45
  return /* @__PURE__ */ jsxRuntime.jsxs(
21
46
  "section",
22
47
  {
23
48
  "aria-label": "Active theme drill-in",
24
- className: "flex flex-wrap items-center gap-x-4 gap-y-2 rounded-lg border px-3 py-2",
25
- style: {
26
- borderColor: `color-mix(in srgb, ${color} 35%, transparent)`,
27
- backgroundColor: `color-mix(in srgb, ${color} 8%, transparent)`
28
- },
49
+ className: "relative flex flex-wrap items-center gap-x-4 gap-y-2 rounded-lg border border-transparent px-3 py-2",
50
+ style: { backgroundImage: `${backgroundGradient}, ${borderGradient}`, backgroundClip: "padding-box, border-box" },
29
51
  children: [
30
- /* @__PURE__ */ jsxRuntime.jsxs(
31
- "button",
32
- {
33
- "aria-label": "Clear theme filter",
34
- className: "border-border1 bg-surface2 text-neutral6 hover:bg-surface4 flex items-center gap-1.5 rounded-full border py-1 pr-2 pl-2.5 text-xs font-medium transition-colors",
35
- onClick: onClear,
36
- type: "button",
37
- children: [
38
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "size-2 rounded-[2px]", style: { backgroundColor: color } }),
39
- ee_signals_signalFormatting.formatSignalName(selection.signalName),
40
- " · ",
41
- selection.label,
42
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": "true", className: "size-3.5" })
43
- ]
44
- }
45
- ),
46
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral4 text-xs", children: filteredTraceCount === void 0 ? "Loading theme traces…" : `Showing the ${filteredTraceCount} of ${totalTraceCount} traces that flow through this theme` }),
47
- /* @__PURE__ */ jsxRuntime.jsx(
52
+ selections.map((selection, index) => {
53
+ const color = colors[index];
54
+ return /* @__PURE__ */ jsxRuntime.jsxs(
55
+ "button",
56
+ {
57
+ "aria-label": selections.length === 1 ? `Clear ${selection.kind} filter` : `Clear filter ${selectionLabel(selection)}`,
58
+ className: "border-border1 bg-surface2 text-neutral6 hover:bg-surface4 flex items-center gap-1.5 rounded-full border py-1 pr-2 pl-2.5 text-xs font-medium transition-colors",
59
+ onClick: () => onRemove(selection.signalName),
60
+ type: "button",
61
+ children: [
62
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "rounded-0.5 size-2", style: { backgroundColor: color } }),
63
+ selectionLabel(selection),
64
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": "true", className: "size-3.5" })
65
+ ]
66
+ },
67
+ selection.signalName
68
+ );
69
+ }),
70
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral4 text-xs", children: filterSummary({ selections, filteredTraceCount, totalTraceCount, isUnavailable }) }),
71
+ !isUnavailable && filteredTraceCount !== void 0 && latestSelection ? /* @__PURE__ */ jsxRuntime.jsx(
48
72
  Button.Button,
49
73
  {
50
- "aria-label": `View theme details for ${selection.label}`,
51
- onClick: onViewDetails,
74
+ "aria-label": latestSelection.kind === "theme" ? `View theme details for ${latestSelection.label}` : `View noise details for ${ee_signals_signalFormatting.formatSignalName(latestSelection.signalName)}`,
75
+ onClick: () => onViewDetails(latestSelection),
52
76
  size: "sm",
53
77
  type: "button",
54
78
  variant: "ghost",
55
79
  children: "Details →"
56
80
  }
57
- )
81
+ ) : null,
82
+ selections.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { onClick: onClear, size: "sm", type: "button", variant: "ghost", children: "Clear all" }) : null
58
83
  ]
59
84
  }
60
85
  );