@mastra/playground-ui 38.0.1-alpha.2 → 38.1.0-alpha.3

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 (111) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/components/Columns.cjs.js +1 -1
  3. package/dist/components/Columns.es.js +1 -1
  4. package/dist/ee/signals/components/signal-details-page.cjs.js +224 -87
  5. package/dist/ee/signals/components/signal-details-page.cjs.js.map +1 -1
  6. package/dist/ee/signals/components/signal-details-page.es.js +225 -88
  7. package/dist/ee/signals/components/signal-details-page.es.js.map +1 -1
  8. package/dist/ee/signals/components/signals-entity-filter.cjs.js +27 -0
  9. package/dist/ee/signals/components/signals-entity-filter.cjs.js.map +1 -0
  10. package/dist/ee/signals/components/signals-entity-filter.d.ts +2 -0
  11. package/dist/ee/signals/components/signals-entity-filter.es.js +23 -0
  12. package/dist/ee/signals/components/signals-entity-filter.es.js.map +1 -0
  13. package/dist/ee/signals/components/signals-overview-page.cjs.js +158 -56
  14. package/dist/ee/signals/components/signals-overview-page.cjs.js.map +1 -1
  15. package/dist/ee/signals/components/signals-overview-page.es.js +160 -58
  16. package/dist/ee/signals/components/signals-overview-page.es.js.map +1 -1
  17. package/dist/ee/signals/components.cjs.js +2 -2
  18. package/dist/ee/signals/components.es.js +1 -1
  19. package/dist/ee/signals/hooks/use-entity-learning-config.cjs.js +27 -0
  20. package/dist/ee/signals/hooks/use-entity-learning-config.cjs.js.map +1 -0
  21. package/dist/ee/signals/hooks/use-entity-learning-config.d.ts +2 -0
  22. package/dist/ee/signals/hooks/use-entity-learning-config.es.js +23 -0
  23. package/dist/ee/signals/hooks/use-entity-learning-config.es.js.map +1 -0
  24. package/dist/ee/signals/hooks/use-entity-learning.cjs.js +113 -0
  25. package/dist/ee/signals/hooks/use-entity-learning.cjs.js.map +1 -0
  26. package/dist/ee/signals/hooks/use-entity-learning.d.ts +2 -0
  27. package/dist/ee/signals/hooks/use-entity-learning.es.js +100 -0
  28. package/dist/ee/signals/hooks/use-entity-learning.es.js.map +1 -0
  29. package/dist/ee/signals/hooks.cjs.js +21 -0
  30. package/dist/ee/signals/hooks.cjs.js.map +1 -0
  31. package/dist/ee/signals/hooks.d.ts +2 -0
  32. package/dist/ee/signals/hooks.es.js +3 -0
  33. package/dist/ee/signals/hooks.es.js.map +1 -0
  34. package/dist/ee/signals/services/entity-learning-service.cjs.js +97 -0
  35. package/dist/ee/signals/services/entity-learning-service.cjs.js.map +1 -0
  36. package/dist/ee/signals/services/entity-learning-service.d.ts +2 -0
  37. package/dist/ee/signals/services/entity-learning-service.es.js +93 -0
  38. package/dist/ee/signals/services/entity-learning-service.es.js.map +1 -0
  39. package/dist/ee/signals/services/entity-learning-types.cjs.js +3 -0
  40. package/dist/ee/signals/services/entity-learning-types.cjs.js.map +1 -0
  41. package/dist/ee/signals/services/entity-learning-types.d.ts +1 -0
  42. package/dist/ee/signals/services/entity-learning-types.es.js +2 -0
  43. package/dist/ee/signals/services/entity-learning-types.es.js.map +1 -0
  44. package/dist/ee/signals/services.cjs.js +10 -0
  45. package/dist/ee/signals/services.cjs.js.map +1 -0
  46. package/dist/ee/signals/services.d.ts +2 -0
  47. package/dist/ee/signals/services.es.js +2 -0
  48. package/dist/ee/signals/services.es.js.map +1 -0
  49. package/dist/ee/signals/signals-data.cjs.js +34 -180
  50. package/dist/ee/signals/signals-data.cjs.js.map +1 -1
  51. package/dist/ee/signals/signals-data.es.js +33 -180
  52. package/dist/ee/signals/signals-data.es.js.map +1 -1
  53. package/dist/ee/signals.cjs.js +19 -5
  54. package/dist/ee/signals.cjs.js.map +1 -1
  55. package/dist/ee/signals.es.js +5 -3
  56. package/dist/ee/signals.es.js.map +1 -1
  57. package/dist/ee/topics/components/topic-trace-summary-list.cjs.js +16 -11
  58. package/dist/ee/topics/components/topic-trace-summary-list.cjs.js.map +1 -1
  59. package/dist/ee/topics/components/topic-trace-summary-list.es.js +16 -11
  60. package/dist/ee/topics/components/topic-trace-summary-list.es.js.map +1 -1
  61. package/dist/index.cjs.js +20 -9
  62. package/dist/index.cjs.js.map +1 -1
  63. package/dist/index.css +16 -0
  64. package/dist/index.es.js +6 -5
  65. package/dist/index.es.js.map +1 -1
  66. package/dist/{multi-column-BFzWhWNb.js → multi-column-BR3a4MvZ.js} +1 -2
  67. package/dist/{multi-column-BFzWhWNb.js.map → multi-column-BR3a4MvZ.js.map} +1 -1
  68. package/dist/{multi-column-C7amy3AM.cjs → multi-column-DGAsiBPq.cjs} +1 -2
  69. package/dist/{multi-column-C7amy3AM.cjs.map → multi-column-DGAsiBPq.cjs.map} +1 -1
  70. package/dist/primitives/form-element.cjs.js.map +1 -1
  71. package/dist/primitives/form-element.es.js.map +1 -1
  72. package/dist/src/ds/components/ButtonsGroup/buttons-group.stories.d.ts +1 -1
  73. package/dist/src/ee/signals/components/index.d.ts +1 -1
  74. package/dist/src/ee/signals/components/signal-details-page.d.ts +29 -20
  75. package/dist/src/ee/signals/components/signals-entity-filter.d.ts +13 -0
  76. package/dist/src/ee/signals/components/signals-overview-page.d.ts +15 -9
  77. package/dist/src/ee/signals/hooks/index.d.ts +2 -0
  78. package/dist/src/ee/signals/hooks/use-entity-learning-config.d.ts +14 -0
  79. package/dist/src/ee/signals/hooks/use-entity-learning.d.ts +26 -0
  80. package/dist/src/ee/signals/index.d.ts +2 -1
  81. package/dist/src/ee/signals/services/entity-learning-service.d.ts +40 -0
  82. package/dist/src/ee/signals/services/entity-learning-types.d.ts +136 -0
  83. package/dist/src/ee/signals/services/index.d.ts +2 -0
  84. package/dist/src/ee/signals/signals-data.d.ts +10 -2
  85. package/dist/src/ee/signals/types.d.ts +10 -8
  86. package/dist/src/index.d.ts +0 -1
  87. package/package.json +7 -7
  88. package/dist/components/Searchbar.cjs.js +0 -11
  89. package/dist/components/Searchbar.cjs.js.map +0 -1
  90. package/dist/components/Searchbar.d.ts +0 -2
  91. package/dist/components/Searchbar.es.js +0 -2
  92. package/dist/components/Searchbar.es.js.map +0 -1
  93. package/dist/ee/signals/components/signal-details-utils.cjs.js +0 -12
  94. package/dist/ee/signals/components/signal-details-utils.cjs.js.map +0 -1
  95. package/dist/ee/signals/components/signal-details-utils.d.ts +0 -2
  96. package/dist/ee/signals/components/signal-details-utils.es.js +0 -8
  97. package/dist/ee/signals/components/signal-details-utils.es.js.map +0 -1
  98. package/dist/ee/signals/signals-chart-data.cjs.js +0 -34
  99. package/dist/ee/signals/signals-chart-data.cjs.js.map +0 -1
  100. package/dist/ee/signals/signals-chart-data.d.ts +0 -2
  101. package/dist/ee/signals/signals-chart-data.es.js +0 -30
  102. package/dist/ee/signals/signals-chart-data.es.js.map +0 -1
  103. package/dist/searchbar-B42oQGrT.cjs +0 -105
  104. package/dist/searchbar-B42oQGrT.cjs.map +0 -1
  105. package/dist/searchbar-CY4dg-Im.js +0 -102
  106. package/dist/searchbar-CY4dg-Im.js.map +0 -1
  107. package/dist/src/ds/components/Searchbar/index.d.ts +0 -1
  108. package/dist/src/ds/components/Searchbar/searchbar.d.ts +0 -16
  109. package/dist/src/ds/components/Searchbar/searchbar.stories.d.ts +0 -14
  110. package/dist/src/ee/signals/components/signal-details-utils.d.ts +0 -1
  111. package/dist/src/ee/signals/signals-chart-data.d.ts +0 -10
package/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # @mastra/playground-ui
2
2
 
3
+ ## 38.1.0-alpha.3
4
+
5
+ ### Minor Changes
6
+
7
+ - Removed the `Searchbar` component from `@mastra/playground-ui`. Compose search inputs with `InputGroup` instead so search remains a documented use case of the existing input composition primitive. ([#18727](https://github.com/mastra-ai/mastra/pull/18727))
8
+
9
+ **Before**
10
+
11
+ ```tsx
12
+ import { Searchbar } from '@mastra/playground-ui/components/Searchbar';
13
+
14
+ <Searchbar label="Search tools" placeholder="Search tools..." onSearch={setSearch} />;
15
+ ```
16
+
17
+ **After**
18
+
19
+ ```tsx
20
+ import { InputGroup, InputGroupAddon, InputGroupInput } from '@mastra/playground-ui/components/InputGroup';
21
+ import { SearchIcon } from 'lucide-react';
22
+
23
+ <InputGroup variant="outline">
24
+ <InputGroupAddon align="inline-start">
25
+ <SearchIcon />
26
+ </InputGroupAddon>
27
+ <InputGroupInput
28
+ type="search"
29
+ aria-label="Search tools"
30
+ placeholder="Search tools..."
31
+ onChange={event => setSearch(event.target.value)}
32
+ />
33
+ </InputGroup>;
34
+ ```
35
+
36
+ - **Signals now show live Entity-Learning data** ([#18699](https://github.com/mastra-ai/mastra/pull/18699))
37
+
38
+ The Signals page is no longer static. Select an agent reported by the platform and Signals fetches that agent's signals and their clusters live from the Entity-Learning API, replacing the previous hardcoded mock data. Each available signal loads its real clusters (topics) and traces, with a scatter-plot chart for the selected topics.
39
+
40
+ **What changed**
41
+ - Added an agent filter at the top of the Signals page, mirroring the traces filter, so you can inspect signals for any agent on the server.
42
+ - The Signals overview and details pages now render live Entity-Learning topics, examples, and points directly, with shape-matching skeletons while data loads, centered empty states, and explicit error states.
43
+ - Clicking a cluster card opens its topic by default, and the Signals breadcrumbs preserve the selected entity and topic query params on back-navigation.
44
+ - Signals detail navigation keeps selected clusters, trace examples, and chart filters in sync when moving between signals or entities.
45
+
46
+ **Gating**
47
+
48
+ Studio's served HTML exposes `MASTRA_ORGANIZATION_ID`, `MASTRA_PLATFORM_PROJECT_ID`, and `MASTRA_PLATFORM_OBSERVABILITY_ENDPOINT` to the browser so the Signals page can call the Entity-Learning API. The route is gated on the platform observability config, and the `MASTRA_SIGNALS_UI` flag guards the sidebar Signals nav link.
49
+
50
+ ### Patch Changes
51
+
52
+ - Fixed the Signals page showing empty clusters for every signal except the most recently clustered one. Cluster queries no longer pin the entity-wide latest run id: the API resolves the latest run per signal, and the details page reuses the run resolved by the topics response for its examples and points queries. ([#18786](https://github.com/mastra-ai/mastra/pull/18786))
53
+
54
+ - Updated dependencies [[`700619b`](https://github.com/mastra-ai/mastra/commit/700619b61d572e592cbaaf758121d168844ca4d2), [`0c3d4bc`](https://github.com/mastra-ai/mastra/commit/0c3d4bcae13ea3699d379403e6f350d5cf4efe9f), [`17369b2`](https://github.com/mastra-ai/mastra/commit/17369b25250561e9ed994ae509be1d15bfb33bcb), [`bcae929`](https://github.com/mastra-ai/mastra/commit/bcae929945cbf265bd9f327cc715ecafa072b5b9), [`b33822e`](https://github.com/mastra-ai/mastra/commit/b33822e8d470884954b02f7b0745407ee4ef74b1), [`d5c11e3`](https://github.com/mastra-ai/mastra/commit/d5c11e3ba5045969caa7272a7bd1fd141c93ab6c), [`ff80671`](https://github.com/mastra-ai/mastra/commit/ff8067185e208b27198b4e5b71803013175c3643), [`dab1257`](https://github.com/mastra-ai/mastra/commit/dab1257b64e4ed576dc5038bb7a3f7072338bc9f), [`705ff39`](https://github.com/mastra-ai/mastra/commit/705ff3969e57214ff2fdaf3815d751dd558886ed), [`e6fbd5b`](https://github.com/mastra-ai/mastra/commit/e6fbd5bfdc28e92c0c0433f29aa1bc152d3430f6), [`6f2026c`](https://github.com/mastra-ai/mastra/commit/6f2026cdf114ff1e21e49133ca774ec7d5085059), [`ff80671`](https://github.com/mastra-ai/mastra/commit/ff8067185e208b27198b4e5b71803013175c3643), [`f890eda`](https://github.com/mastra-ai/mastra/commit/f890eda2c8a2ae83d9b30bc6d85842f93b6c266b)]:
55
+ - @mastra/core@1.49.0-alpha.3
56
+ - @mastra/memory@1.22.1-alpha.1
57
+ - @mastra/client-js@1.29.1-alpha.3
58
+ - @mastra/react@1.2.2-alpha.3
59
+
3
60
  ## 38.0.1-alpha.2
4
61
 
5
62
  ### Patch Changes
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- const multiColumn = require('../multi-column-C7amy3AM.cjs');
5
+ const multiColumn = require('../multi-column-DGAsiBPq.cjs');
6
6
 
7
7
 
8
8
 
@@ -1,2 +1,2 @@
1
- export { C as Column, a as Columns, M as MultiColumn } from '../multi-column-BFzWhWNb.js';
1
+ export { C as Column, a as Columns, M as MultiColumn } from '../multi-column-BR3a4MvZ.js';
2
2
  //# sourceMappingURL=Columns.es.js.map
@@ -3,33 +3,36 @@
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const jsxRuntime = require('react/jsx-runtime');
6
+ const lucideReact = require('lucide-react');
6
7
  const React = require('react');
7
- require('@mastra/react');
8
- require('@tanstack/react-query');
9
- const domains_traces_hooks_useTraces = require('../../../domains/traces/hooks/use-traces.cjs.js');
10
- require('../../../domains/traces/trace-filters.cjs.js');
8
+ const Button = require('../../../Button-66ghjQV8.cjs');
9
+ const dataList = require('../../../data-list-DDQRmA6L.cjs');
10
+ const inputGroup = require('../../../input-group-CF6DB97L.cjs');
11
11
  const scatterPlotChart = require('../../../scatter-plot-chart-CFZO31md.cjs');
12
+ const skeleton = require('../../../skeleton-D5zq7rhk.cjs');
12
13
  const tabsTab = require('../../../tabs-tab-B7Ziuuh8.cjs');
13
14
  const tabsContent = require('../../../tabs-content-ohtjaVdC.cjs');
14
- const utils_colors = require('../../../utils/colors.cjs.js');
15
15
  const utils_cn = require('../../../cn-vA5sWo9W.cjs');
16
16
  const ee_topics_components_topicsLayout = require('../../topics/components/topics-layout.cjs.js');
17
- const ee_topics_components_topicTraceSummaryList = require('../../topics/components/topic-trace-summary-list.cjs.js');
18
17
  const ee_topics_components_topicTraceDetailsPanel = require('../../topics/components/topic-trace-details-panel.cjs.js');
19
- const ee_signals_signalsChartData = require('../signals-chart-data.cjs.js');
18
+ const ee_signals_hooks_useEntityLearning = require('../hooks/use-entity-learning.cjs.js');
20
19
  const ee_signals_signalsData = require('../signals-data.cjs.js');
21
20
 
22
- const SignalTraceSummaryList = ee_topics_components_topicTraceSummaryList.TopicTraceSummaryList;
23
21
  const SignalTraceDetailsPanel = ee_topics_components_topicTraceDetailsPanel.TopicTraceDetailsPanel;
24
22
  const SignalsLayout = ee_topics_components_topicsLayout.TopicsLayout;
25
- function findClusterByTraceId(signal, traceId) {
26
- if (!signal || !traceId) return void 0;
27
- return signal.clusters.find((cluster) => cluster.traceSummaries.some((trace) => trace.id === traceId));
23
+ function clusterColor(topicId) {
24
+ let hash = 0;
25
+ for (let i = 0; i < topicId.length; i++) {
26
+ hash = topicId.charCodeAt(i) + ((hash << 5) - hash);
27
+ hash = hash & hash;
28
+ }
29
+ const hue = Math.abs(hash * 137.508) % 360;
30
+ return `hsl(${hue}, 70%, 55%)`;
28
31
  }
29
32
  function SignalClusterSidebar({
30
- signal,
31
- selectedClusterIds,
32
- onClusterSelect,
33
+ topics,
34
+ selectedTopicIds,
35
+ onTopicSelect,
33
36
  multiple = false,
34
37
  ariaLabel = "Signal clusters"
35
38
  }) {
@@ -38,8 +41,8 @@ function SignalClusterSidebar({
38
41
  {
39
42
  className: "min-h-0 w-72 shrink-0 overflow-y-auto border-r border-border1/60 pr-4 py-4",
40
43
  "aria-label": ariaLabel,
41
- children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", role: multiple ? "group" : void 0, children: signal.clusters.map((cluster) => {
42
- const selected = selectedClusterIds.includes(cluster.id);
44
+ children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", role: multiple ? "group" : void 0, children: topics.map((topic) => {
45
+ const selected = selectedTopicIds.includes(topic.topicId);
43
46
  return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
44
47
  "button",
45
48
  {
@@ -48,13 +51,13 @@ function SignalClusterSidebar({
48
51
  "aria-checked": multiple ? selected : void 0,
49
52
  "aria-pressed": multiple ? void 0 : selected,
50
53
  className: "group cursor-pointer w-full rounded-xl px-3 py-2 text-left transition-colors hover:bg-surface3 aria-pressed:bg-surface3 aria-checked:bg-surface3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent1",
51
- onClick: () => onClusterSelect(cluster.id),
54
+ onClick: () => onTopicSelect(topic.topicId),
52
55
  children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-start gap-2", children: [
53
56
  /* @__PURE__ */ jsxRuntime.jsx(
54
57
  "span",
55
58
  {
56
59
  className: utils_cn.cn("mt-1.5 h-2 w-2 shrink-0 rounded-full", multiple && !selected && "invisible"),
57
- style: { backgroundColor: utils_colors.stringToColor(cluster.name) }
60
+ style: { backgroundColor: clusterColor(topic.topicId) }
58
61
  }
59
62
  ),
60
63
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 space-y-1", children: [
@@ -65,7 +68,7 @@ function SignalClusterSidebar({
65
68
  "block text-sm font-medium",
66
69
  multiple && !selected ? "text-neutral3" : "text-neutral5"
67
70
  ),
68
- children: cluster.name
71
+ children: topic.name
69
72
  }
70
73
  ),
71
74
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -75,44 +78,123 @@ function SignalClusterSidebar({
75
78
  "line-clamp-2 block text-sm",
76
79
  multiple && !selected ? "text-neutral1" : "text-neutral2"
77
80
  ),
78
- children: cluster.description
81
+ children: topic.description
79
82
  }
80
83
  )
81
84
  ] })
82
85
  ] })
83
86
  }
84
- ) }, cluster.id);
87
+ ) }, topic.topicId);
85
88
  }) })
86
89
  }
87
90
  );
88
91
  }
92
+ function SignalTraceListSkeleton({ rows = 8 }) {
93
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1 px-2 py-1", "aria-label": "Loading traces", "aria-busy": "true", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-9 w-full rounded-lg" }, index)) });
94
+ }
95
+ function SignalClusterSidebarSkeleton({ rows = 5 }) {
96
+ return /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "min-h-0 w-72 shrink-0 overflow-y-auto border-r border-border1/60 pr-4 py-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-2 px-3 py-2", children: [
97
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "mt-1.5 h-2 w-2 shrink-0 rounded-full" }),
98
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
99
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-1/2" }),
100
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-full" })
101
+ ] })
102
+ ] }, index)) }) });
103
+ }
104
+ function SignalDetailsSkeleton() {
105
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex h-full min-w-0 flex-col gap-4", "aria-label": "Loading signal", "aria-busy": "true", children: [
106
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "space-y-2", children: [
107
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-7 w-48" }),
108
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-64" })
109
+ ] }),
110
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-6 border-b border-border1/60", children: [
111
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "mb-2 h-5 w-20" }),
112
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "mb-2 h-5 w-16" })
113
+ ] }),
114
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 gap-6 overflow-hidden", children: [
115
+ /* @__PURE__ */ jsxRuntime.jsx(SignalClusterSidebarSkeleton, {}),
116
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-4 py-4", children: [
117
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-9 w-full rounded-lg" }),
118
+ /* @__PURE__ */ jsxRuntime.jsx(SignalTraceListSkeleton, {})
119
+ ] })
120
+ ] })
121
+ ] });
122
+ }
89
123
  function SignalTraceListTab({
90
- cluster,
124
+ examples,
91
125
  selectedTraceId,
92
- onTraceSelect
126
+ onTraceSelect,
127
+ loading = false,
128
+ pageSize = 25
93
129
  }) {
94
- return /* @__PURE__ */ jsxRuntime.jsx(
95
- SignalTraceSummaryList,
96
- {
97
- traces: cluster.traceSummaries,
98
- selectedTraceId,
99
- onTraceSelect
100
- }
101
- );
130
+ const [search, setSearch] = React.useState("");
131
+ const [page, setPage] = React.useState(1);
132
+ const filtered = React.useMemo(() => {
133
+ const query = search.trim().toLowerCase();
134
+ if (!query) return examples;
135
+ return examples.filter((example) => example.signalText.toLowerCase().includes(query));
136
+ }, [examples, search]);
137
+ const visible = React.useMemo(() => filtered.slice(0, page * pageSize), [filtered, page, pageSize]);
138
+ const hasMore = visible.length < filtered.length;
139
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex min-h-0 flex-1 flex-col gap-4", "aria-label": "Topic trace summaries", children: [
140
+ /* @__PURE__ */ jsxRuntime.jsxs(inputGroup.InputGroup, { variant: "outline", children: [
141
+ /* @__PURE__ */ jsxRuntime.jsx(inputGroup.InputGroupAddon, { align: "inline-start", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, {}) }),
142
+ /* @__PURE__ */ jsxRuntime.jsx(
143
+ inputGroup.InputGroupInput,
144
+ {
145
+ type: "search",
146
+ "aria-label": "Search traces",
147
+ placeholder: "Search traces",
148
+ onChange: (event) => {
149
+ setSearch(event.target.value);
150
+ setPage(1);
151
+ }
152
+ }
153
+ )
154
+ ] }),
155
+ /* @__PURE__ */ jsxRuntime.jsxs(
156
+ dataList.DataList,
157
+ {
158
+ columns: "minmax(12rem,1fr)",
159
+ className: "min-h-0 flex-1 overflow-hidden rounded-lg border border-border1/60",
160
+ children: [
161
+ /* @__PURE__ */ jsxRuntime.jsx(dataList.DataList.Top, { children: /* @__PURE__ */ jsxRuntime.jsx(dataList.DataList.TopCells, { children: /* @__PURE__ */ jsxRuntime.jsx(dataList.DataList.TopCell, { children: "Trace summary" }) }) }),
162
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(SignalTraceListSkeleton, {}) : visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(dataList.DataList.NoMatch, { message: "No traces match this subtopic." }) : visible.map((example) => /* @__PURE__ */ jsxRuntime.jsx(
163
+ dataList.DataList.RowButton,
164
+ {
165
+ featured: selectedTraceId === example.traceId,
166
+ onClick: () => onTraceSelect(example.traceId),
167
+ "aria-pressed": selectedTraceId === example.traceId,
168
+ children: /* @__PURE__ */ jsxRuntime.jsx(dataList.DataList.TextCell, { children: example.signalText })
169
+ },
170
+ example.exampleId
171
+ ))
172
+ ]
173
+ }
174
+ ),
175
+ hasMore && !loading ? /* @__PURE__ */ jsxRuntime.jsxs(Button.Button, { variant: "outline", size: "sm", onClick: () => setPage((currentPage) => currentPage + 1), children: [
176
+ "Load more traces (",
177
+ visible.length,
178
+ " of ",
179
+ filtered.length,
180
+ ")"
181
+ ] }) : null
182
+ ] });
102
183
  }
103
- function SignalChartTab({ signal, selectedClusterIds, onClusterToggle }) {
104
- const selectedClusters = React.useMemo(
105
- () => signal.clusters.filter((cluster) => selectedClusterIds.includes(cluster.id)),
106
- [signal.clusters, selectedClusterIds]
184
+ function SignalChartTab({ topics, points, selectedTopicIds, onTopicToggle }) {
185
+ const chartData = React.useMemo(
186
+ () => points.filter(
187
+ (point) => point.topicId !== void 0 && selectedTopicIds.includes(point.topicId)
188
+ ).map((point) => ({ ...point, color: clusterColor(point.topicId) })),
189
+ [points, selectedTopicIds]
107
190
  );
108
- const chartData = React.useMemo(() => ee_signals_signalsChartData.getSignalChartData(selectedClusters), [selectedClusters]);
109
191
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-w-0 gap-6", children: [
110
192
  /* @__PURE__ */ jsxRuntime.jsx(
111
193
  SignalClusterSidebar,
112
194
  {
113
- signal,
114
- selectedClusterIds,
115
- onClusterSelect: onClusterToggle,
195
+ topics,
196
+ selectedTopicIds,
197
+ onTopicSelect: onTopicToggle,
116
198
  multiple: true,
117
199
  ariaLabel: "Chart cluster filters"
118
200
  }
@@ -121,29 +203,30 @@ function SignalChartTab({ signal, selectedClusterIds, onClusterToggle }) {
121
203
  scatterPlotChart.ScatterPlotChart,
122
204
  {
123
205
  data: chartData,
124
- xKey: "duration",
125
- yKey: "spans",
126
- nameKey: "name",
206
+ xKey: "x",
207
+ yKey: "y",
208
+ nameKey: "topicId",
127
209
  colorKey: "color",
128
210
  height: "100%",
129
211
  className: "h-full",
130
- xLabel: "Duration",
131
- yLabel: "Spans",
132
- formatX: (value) => `${value}ms`,
133
- formatY: (value) => `${value} spans`
212
+ xLabel: "X",
213
+ yLabel: "Y"
134
214
  }
135
215
  ) })
136
216
  ] });
137
217
  }
138
218
  function SignalClusterTabs({
139
- signal,
140
- selectedCluster,
219
+ topics,
220
+ examples,
221
+ examplesLoading,
222
+ points,
223
+ selectedTopicId,
141
224
  selectedTraceId,
142
- selectedChartClusterIds,
225
+ selectedChartTopicIds,
143
226
  activeTab,
144
227
  onActiveTabChange,
145
- onClusterSelect,
146
- onChartClusterToggle,
228
+ onTopicSelect,
229
+ onChartTopicToggle,
147
230
  onTraceSelect
148
231
  }) {
149
232
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -159,18 +242,12 @@ function SignalClusterTabs({
159
242
  /* @__PURE__ */ jsxRuntime.jsx(tabsTab.Tab, { value: "chart", children: "Chart" })
160
243
  ] }),
161
244
  /* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "trace-list", className: "min-h-0 flex-1 overflow-hidden py-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-w-0 gap-6", children: [
162
- /* @__PURE__ */ jsxRuntime.jsx(
163
- SignalClusterSidebar,
164
- {
165
- signal,
166
- selectedClusterIds: [selectedCluster.id],
167
- onClusterSelect
168
- }
169
- ),
245
+ /* @__PURE__ */ jsxRuntime.jsx(SignalClusterSidebar, { topics, selectedTopicIds: [selectedTopicId], onTopicSelect }),
170
246
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1 overflow-hidden py-4", children: /* @__PURE__ */ jsxRuntime.jsx(
171
247
  SignalTraceListTab,
172
248
  {
173
- cluster: selectedCluster,
249
+ examples,
250
+ loading: examplesLoading,
174
251
  selectedTraceId,
175
252
  onTraceSelect
176
253
  }
@@ -179,54 +256,114 @@ function SignalClusterTabs({
179
256
  /* @__PURE__ */ jsxRuntime.jsx(tabsContent.TabContent, { value: "chart", className: "min-h-0 flex-1 overflow-hidden py-0", children: /* @__PURE__ */ jsxRuntime.jsx(
180
257
  SignalChartTab,
181
258
  {
182
- signal,
183
- selectedClusterIds: selectedChartClusterIds,
184
- onClusterToggle: onChartClusterToggle
259
+ topics,
260
+ points,
261
+ selectedTopicIds: selectedChartTopicIds,
262
+ onTopicToggle: onChartTopicToggle
185
263
  }
186
264
  ) })
187
265
  ]
188
266
  }
189
267
  );
190
268
  }
191
- function SignalDetailsPage({ signalId, selectedTraceId, tracePanel, onTraceSelect }) {
192
- const selectedSignal = React.useMemo(() => ee_signals_signalsData.signals.find((signal) => signal.id === signalId), [signalId]);
193
- const initialCluster = findClusterByTraceId(selectedSignal, selectedTraceId ?? void 0) ?? selectedSignal?.clusters[0];
194
- const [selectedClusterId, setSelectedClusterId] = React.useState(() => initialCluster?.id ?? null);
195
- const [selectedChartClusterIds, setSelectedChartClusterIds] = React.useState(
196
- () => selectedSignal?.clusters.map((cluster) => cluster.id) ?? []
197
- );
269
+ function SignalDetailsPage({
270
+ signalId,
271
+ entity,
272
+ selectedTraceId,
273
+ initialTopicId,
274
+ tracePanel,
275
+ onTraceSelect
276
+ }) {
277
+ const { data: entities = [], isLoading: entitiesLoading, isError: entitiesError } = ee_signals_hooks_useEntityLearning.useEntities();
278
+ const resolvedEntity = entities.find((item) => item.entityId === entity?.entityId);
279
+ const {
280
+ data: topicsData,
281
+ isLoading: topicsLoading,
282
+ isError: topicsError
283
+ } = ee_signals_hooks_useEntityLearning.useEntityTopics(resolvedEntity?.entityId, signalId);
284
+ const topics = React.useMemo(() => topicsData?.topics ?? [], [topicsData?.topics]);
285
+ const runId = topicsData?.run?.runId;
286
+ const topicSelectionScope = `${signalId ?? ""}:${entity?.entityId ?? ""}:${runId ?? ""}:${initialTopicId ?? ""}`;
287
+ const chartSelectionScope = `${signalId ?? ""}:${entity?.entityId ?? ""}:${runId ?? ""}`;
288
+ const topicIds = React.useMemo(() => topics.map((topic) => topic.topicId), [topics]);
289
+ const topicIdSet = React.useMemo(() => new Set(topicIds), [topicIds]);
290
+ const [selectedTopic, setSelectedTopic] = React.useState(() => ({
291
+ scope: topicSelectionScope,
292
+ topicId: initialTopicId ?? null
293
+ }));
294
+ const [selectedChartTopics, setSelectedChartTopics] = React.useState(() => ({
295
+ scope: chartSelectionScope,
296
+ topicIds: null
297
+ }));
198
298
  const [activeTab, setActiveTab] = React.useState("trace-list");
199
- const selectedCluster = selectedSignal?.clusters.find((cluster) => cluster.id === selectedClusterId) ?? initialCluster;
200
- const { data: tracesData } = domains_traces_hooks_useTraces.useTraces({});
201
- const resolvedTraceId = tracesData?.spans[0]?.traceId ?? null;
202
- const handleTraceSelect = () => {
203
- if (!selectedSignal || !resolvedTraceId) return;
204
- onTraceSelect(selectedSignal.id, resolvedTraceId);
299
+ const requestedTopicId = selectedTopic.scope === topicSelectionScope ? selectedTopic.topicId : initialTopicId ?? null;
300
+ const resolvedTopicId = requestedTopicId && topicIdSet.has(requestedTopicId) ? requestedTopicId : topics[0]?.topicId;
301
+ const selectedTopicData = topics.find((topic) => topic.topicId === resolvedTopicId);
302
+ const examplesEnabled = Boolean(resolvedEntity?.entityId && signalId && runId && selectedTopicData);
303
+ const pointsEnabled = Boolean(resolvedEntity?.entityId && signalId && runId);
304
+ const chartTopicIds = selectedChartTopics.scope === chartSelectionScope && selectedChartTopics.topicIds ? selectedChartTopics.topicIds.filter((topicId) => topicIdSet.has(topicId)) : topicIds;
305
+ const {
306
+ data: examplesData,
307
+ isLoading: examplesLoading,
308
+ isFetching: examplesFetching,
309
+ isError: examplesError
310
+ } = ee_signals_hooks_useEntityLearning.useEntityTopicExamples(
311
+ resolvedEntity?.entityId,
312
+ selectedTopicData?.topicId,
313
+ examplesEnabled && runId && signalId ? { signalName: signalId, runId } : void 0
314
+ );
315
+ const examples = examplesData?.examples ?? [];
316
+ const examplesPending = examplesLoading || examplesFetching && examplesData === void 0;
317
+ const { data: pointsData, isError: pointsError } = ee_signals_hooks_useEntityLearning.useEntityPoints(
318
+ resolvedEntity?.entityId,
319
+ pointsEnabled && runId && signalId ? { signalName: signalId, runId, includeOutliers: true } : void 0
320
+ );
321
+ const points = pointsData?.points ?? [];
322
+ const handleTraceSelect = (traceId) => {
323
+ if (!signalId) return;
324
+ onTraceSelect(signalId, traceId);
205
325
  };
206
- const handleChartClusterToggle = (clusterId) => {
207
- setSelectedChartClusterIds(
208
- (current) => current.includes(clusterId) ? current.filter((id) => id !== clusterId) : [...current, clusterId]
209
- );
326
+ const handleTopicSelect = (topicId) => {
327
+ setSelectedTopic({ scope: topicSelectionScope, topicId });
210
328
  };
211
- if (!selectedSignal || !selectedCluster) {
329
+ const handleChartTopicToggle = (topicId) => {
330
+ setSelectedChartTopics((current) => {
331
+ const base = current.scope === chartSelectionScope && current.topicIds ? current.topicIds : topicIds;
332
+ return {
333
+ scope: chartSelectionScope,
334
+ topicIds: base.includes(topicId) ? base.filter((id) => id !== topicId) : [...base, topicId]
335
+ };
336
+ });
337
+ };
338
+ if (entitiesLoading || topicsLoading) {
339
+ return /* @__PURE__ */ jsxRuntime.jsx(SignalsLayout, { sidebar: null, children: /* @__PURE__ */ jsxRuntime.jsx(SignalDetailsSkeleton, {}) });
340
+ }
341
+ if (entitiesError || topicsError || examplesEnabled && examplesError || pointsEnabled && pointsError) {
342
+ return /* @__PURE__ */ jsxRuntime.jsx(SignalsLayout, { sidebar: null, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-ui-md text-accent2", children: "Failed to load this signal from the observability endpoint." }) });
343
+ }
344
+ if (!resolvedEntity || !selectedTopicData) {
212
345
  return /* @__PURE__ */ jsxRuntime.jsx(SignalsLayout, { sidebar: null, children: "Signal not found" });
213
346
  }
347
+ const signalName = ee_signals_signalsData.getSignalCatalogEntry(signalId ?? "").name;
214
348
  return /* @__PURE__ */ jsxRuntime.jsx(SignalsLayout, { sidebar: null, tracePanel: activeTab === "trace-list" ? tracePanel : void 0, children: /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex h-full min-w-0 flex-col gap-4", children: [
215
349
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "space-y-1", children: [
216
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-icon-xl font-semibold text-neutral6", children: selectedSignal.name }),
350
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-icon-xl font-semibold text-neutral6", children: signalName }),
217
351
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-ui-sm text-neutral3", children: "Explore trace patterns by cluster." })
218
352
  ] }),
219
353
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
220
354
  SignalClusterTabs,
221
355
  {
222
- signal: selectedSignal,
223
- selectedCluster,
356
+ topics,
357
+ examples,
358
+ examplesLoading: examplesPending,
359
+ points,
360
+ selectedTopicId: selectedTopicData.topicId,
224
361
  selectedTraceId,
225
- selectedChartClusterIds,
362
+ selectedChartTopicIds: chartTopicIds,
226
363
  activeTab,
227
364
  onActiveTabChange: setActiveTab,
228
- onClusterSelect: setSelectedClusterId,
229
- onChartClusterToggle: handleChartClusterToggle,
365
+ onTopicSelect: handleTopicSelect,
366
+ onChartTopicToggle: handleChartTopicToggle,
230
367
  onTraceSelect: handleTraceSelect
231
368
  }
232
369
  ) })