@flanksource/clicky-ui 0.3.56 → 0.3.58

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 (145) hide show
  1. package/dist/components/ErrorWrapper.cjs +15 -4
  2. package/dist/components/ErrorWrapper.cjs.map +1 -1
  3. package/dist/components/ErrorWrapper.d.ts +7 -0
  4. package/dist/components/ErrorWrapper.d.ts.map +1 -1
  5. package/dist/components/ErrorWrapper.js +15 -4
  6. package/dist/components/ErrorWrapper.js.map +1 -1
  7. package/dist/data/ai/PromptCatalog/PromptLayerStrip.cjs +6 -3
  8. package/dist/data/ai/PromptCatalog/PromptLayerStrip.cjs.map +1 -1
  9. package/dist/data/ai/PromptCatalog/PromptLayerStrip.js +6 -3
  10. package/dist/data/ai/PromptCatalog/PromptLayerStrip.js.map +1 -1
  11. package/dist/data/ai/PromptCatalog/PromptPage.cjs +2 -1
  12. package/dist/data/ai/PromptCatalog/PromptPage.cjs.map +1 -1
  13. package/dist/data/ai/PromptCatalog/PromptPage.d.ts.map +1 -1
  14. package/dist/data/ai/PromptCatalog/PromptPage.js +2 -1
  15. package/dist/data/ai/PromptCatalog/PromptPage.js.map +1 -1
  16. package/dist/data/ai/PromptCatalog/PromptPageHeader.cjs +9 -6
  17. package/dist/data/ai/PromptCatalog/PromptPageHeader.cjs.map +1 -1
  18. package/dist/data/ai/PromptCatalog/PromptPageHeader.d.ts.map +1 -1
  19. package/dist/data/ai/PromptCatalog/PromptPageHeader.js +9 -6
  20. package/dist/data/ai/PromptCatalog/PromptPageHeader.js.map +1 -1
  21. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.cjs +3 -3
  22. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.cjs.map +1 -1
  23. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.d.ts +2 -1
  24. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.d.ts.map +1 -1
  25. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.js +3 -3
  26. package/dist/data/ai/PromptCatalog/PromptPageSaveBar.js.map +1 -1
  27. package/dist/data/ai/PromptCatalog/prompt-page-model.cjs +4 -3
  28. package/dist/data/ai/PromptCatalog/prompt-page-model.cjs.map +1 -1
  29. package/dist/data/ai/PromptCatalog/prompt-page-model.d.ts +1 -1
  30. package/dist/data/ai/PromptCatalog/prompt-page-model.d.ts.map +1 -1
  31. package/dist/data/ai/PromptCatalog/prompt-page-model.js +4 -3
  32. package/dist/data/ai/PromptCatalog/prompt-page-model.js.map +1 -1
  33. package/dist/data/ai/PromptCatalog/types.d.ts +1 -0
  34. package/dist/data/ai/PromptCatalog/types.d.ts.map +1 -1
  35. package/dist/data/traces/index.d.ts +7 -0
  36. package/dist/data/traces/index.d.ts.map +1 -1
  37. package/dist/data/traces/otel/OperationList.cjs +64 -0
  38. package/dist/data/traces/otel/OperationList.cjs.map +1 -0
  39. package/dist/data/traces/otel/OperationList.d.ts +10 -0
  40. package/dist/data/traces/otel/OperationList.d.ts.map +1 -0
  41. package/dist/data/traces/otel/OperationList.js +64 -0
  42. package/dist/data/traces/otel/OperationList.js.map +1 -0
  43. package/dist/data/traces/otel/OtelTraceDetail.cjs +781 -0
  44. package/dist/data/traces/otel/OtelTraceDetail.cjs.map +1 -0
  45. package/dist/data/traces/otel/OtelTraceDetail.d.ts +7 -0
  46. package/dist/data/traces/otel/OtelTraceDetail.d.ts.map +1 -0
  47. package/dist/data/traces/otel/OtelTraceDetail.js +781 -0
  48. package/dist/data/traces/otel/OtelTraceDetail.js.map +1 -0
  49. package/dist/data/traces/otel/OtelTraceSearch.cjs +145 -0
  50. package/dist/data/traces/otel/OtelTraceSearch.cjs.map +1 -0
  51. package/dist/data/traces/otel/OtelTraceSearch.d.ts +16 -0
  52. package/dist/data/traces/otel/OtelTraceSearch.d.ts.map +1 -0
  53. package/dist/data/traces/otel/OtelTraceSearch.js +145 -0
  54. package/dist/data/traces/otel/OtelTraceSearch.js.map +1 -0
  55. package/dist/data/traces/otel/OtelTraceTable.cjs +47 -0
  56. package/dist/data/traces/otel/OtelTraceTable.cjs.map +1 -0
  57. package/dist/data/traces/otel/OtelTraceTable.d.ts +12 -0
  58. package/dist/data/traces/otel/OtelTraceTable.d.ts.map +1 -0
  59. package/dist/data/traces/otel/OtelTraceTable.js +47 -0
  60. package/dist/data/traces/otel/OtelTraceTable.js.map +1 -0
  61. package/dist/data/traces/otel/QueryBar.cjs +158 -0
  62. package/dist/data/traces/otel/QueryBar.cjs.map +1 -0
  63. package/dist/data/traces/otel/QueryBar.d.ts +12 -0
  64. package/dist/data/traces/otel/QueryBar.d.ts.map +1 -0
  65. package/dist/data/traces/otel/QueryBar.js +158 -0
  66. package/dist/data/traces/otel/QueryBar.js.map +1 -0
  67. package/dist/data/traces/otel/SpanCards.cjs +264 -0
  68. package/dist/data/traces/otel/SpanCards.cjs.map +1 -0
  69. package/dist/data/traces/otel/SpanCards.d.ts +17 -0
  70. package/dist/data/traces/otel/SpanCards.d.ts.map +1 -0
  71. package/dist/data/traces/otel/SpanCards.js +261 -0
  72. package/dist/data/traces/otel/SpanCards.js.map +1 -0
  73. package/dist/data/traces/otel/SpanCategory.cjs +18 -0
  74. package/dist/data/traces/otel/SpanCategory.cjs.map +1 -0
  75. package/dist/data/traces/otel/SpanCategory.d.ts +7 -0
  76. package/dist/data/traces/otel/SpanCategory.d.ts.map +1 -0
  77. package/dist/data/traces/otel/SpanCategory.js +18 -0
  78. package/dist/data/traces/otel/SpanCategory.js.map +1 -0
  79. package/dist/data/traces/otel/TraceResults.cjs +195 -0
  80. package/dist/data/traces/otel/TraceResults.cjs.map +1 -0
  81. package/dist/data/traces/otel/TraceResults.d.ts +19 -0
  82. package/dist/data/traces/otel/TraceResults.d.ts.map +1 -0
  83. package/dist/data/traces/otel/TraceResults.js +193 -0
  84. package/dist/data/traces/otel/TraceResults.js.map +1 -0
  85. package/dist/data/traces/otel/api.cjs +36 -0
  86. package/dist/data/traces/otel/api.cjs.map +1 -0
  87. package/dist/data/traces/otel/api.d.ts +87 -0
  88. package/dist/data/traces/otel/api.d.ts.map +1 -0
  89. package/dist/data/traces/otel/api.js +33 -0
  90. package/dist/data/traces/otel/api.js.map +1 -0
  91. package/dist/data/traces/otel/fixtures.d.ts +4 -0
  92. package/dist/data/traces/otel/fixtures.d.ts.map +1 -0
  93. package/dist/data/traces/otel/metrics.cjs +7 -0
  94. package/dist/data/traces/otel/metrics.cjs.map +1 -0
  95. package/dist/data/traces/otel/metrics.d.ts +2 -0
  96. package/dist/data/traces/otel/metrics.d.ts.map +1 -0
  97. package/dist/data/traces/otel/metrics.js +7 -0
  98. package/dist/data/traces/otel/metrics.js.map +1 -0
  99. package/dist/data/traces/otel/model.cjs +167 -0
  100. package/dist/data/traces/otel/model.cjs.map +1 -0
  101. package/dist/data/traces/otel/model.d.ts +81 -0
  102. package/dist/data/traces/otel/model.d.ts.map +1 -0
  103. package/dist/data/traces/otel/model.js +154 -0
  104. package/dist/data/traces/otel/model.js.map +1 -0
  105. package/dist/data/traces/otel/query.cjs +90 -0
  106. package/dist/data/traces/otel/query.cjs.map +1 -0
  107. package/dist/data/traces/otel/query.d.ts +20 -0
  108. package/dist/data/traces/otel/query.d.ts.map +1 -0
  109. package/dist/data/traces/otel/query.js +86 -0
  110. package/dist/data/traces/otel/query.js.map +1 -0
  111. package/dist/data/traces/otel/result-model.cjs +25 -0
  112. package/dist/data/traces/otel/result-model.cjs.map +1 -0
  113. package/dist/data/traces/otel/result-model.d.ts +5 -0
  114. package/dist/data/traces/otel/result-model.d.ts.map +1 -0
  115. package/dist/data/traces/otel/result-model.js +24 -0
  116. package/dist/data/traces/otel/result-model.js.map +1 -0
  117. package/dist/data/traces/otel/source.cjs +11 -0
  118. package/dist/data/traces/otel/source.cjs.map +1 -0
  119. package/dist/data/traces/otel/source.d.ts +5 -0
  120. package/dist/data/traces/otel/source.d.ts.map +1 -0
  121. package/dist/data/traces/otel/source.js +10 -0
  122. package/dist/data/traces/otel/source.js.map +1 -0
  123. package/dist/data/traces/otel/span-traces.cjs +39 -0
  124. package/dist/data/traces/otel/span-traces.cjs.map +1 -0
  125. package/dist/data/traces/otel/span-traces.d.ts +3 -0
  126. package/dist/data/traces/otel/span-traces.d.ts.map +1 -0
  127. package/dist/data/traces/otel/span-traces.js +39 -0
  128. package/dist/data/traces/otel/span-traces.js.map +1 -0
  129. package/dist/data/version-info.cjs +3 -3
  130. package/dist/data/version-info.js +3 -3
  131. package/dist/data.cjs +11 -0
  132. package/dist/data.js +6 -1
  133. package/dist/index.cjs +11 -0
  134. package/dist/index.js +6 -1
  135. package/dist/profiles/editor/profileEditorSections.cjs +4 -0
  136. package/dist/profiles/editor/profileEditorSections.cjs.map +1 -1
  137. package/dist/profiles/editor/profileEditorSections.d.ts.map +1 -1
  138. package/dist/profiles/editor/profileEditorSections.js +4 -0
  139. package/dist/profiles/editor/profileEditorSections.js.map +1 -1
  140. package/dist/rpc/CommandForm.cjs +1 -1
  141. package/dist/rpc/CommandForm.cjs.map +1 -1
  142. package/dist/rpc/CommandForm.js +1 -1
  143. package/dist/rpc/CommandForm.js.map +1 -1
  144. package/dist/styles.css +1 -1
  145. package/package.json +1 -1
@@ -0,0 +1,781 @@
1
+ const require_UiChevronDown = require("../../../icons/components/UiChevronDown.cjs");
2
+ const require_UiChevronRight = require("../../../icons/components/UiChevronRight.cjs");
3
+ const require_UiCollapseAll = require("../../../icons/components/UiCollapseAll.cjs");
4
+ const require_UiExpandAll = require("../../../icons/components/UiExpandAll.cjs");
5
+ const require_UiCoins = require("../../../icons/components/UiCoins.cjs");
6
+ const require_UiWarningTriangle = require("../../../icons/components/UiWarningTriangle.cjs");
7
+ const require_UiSparkles = require("../../../icons/components/UiSparkles.cjs");
8
+ const require_UiRobotAi = require("../../../icons/components/UiRobotAi.cjs");
9
+ const require_UiDatabase = require("../../../icons/components/UiDatabase.cjs");
10
+ const require_UiClock = require("../../../icons/components/UiClock.cjs");
11
+ const require_Icon = require("../../Icon.cjs");
12
+ const require_button = require("../../../components/button.cjs");
13
+ const require_CopyButton = require("../../../components/CopyButton.cjs");
14
+ const require_Badge = require("../../Badge.cjs");
15
+ const require_SearchInput = require("../../../components/SearchInput.cjs");
16
+ const require_Switch = require("../../../components/Switch.cjs");
17
+ const require_Properties = require("../../Properties.cjs");
18
+ const require_Callout = require("../../Callout.cjs");
19
+ const require_CodeBlock = require("../../CodeBlock.cjs");
20
+ const require_SplitPane = require("../../../layout/SplitPane.cjs");
21
+ const require_Section = require("../../../layout/Section.cjs");
22
+ const require_StatStrip = require("../../StatStrip.cjs");
23
+ const require_SpanCategory = require("./SpanCategory.cjs");
24
+ const require_model = require("./model.cjs");
25
+ const require_metrics = require("./metrics.cjs");
26
+ const require_SpanCards = require("./SpanCards.cjs");
27
+ let react = require("react");
28
+ let react_jsx_runtime = require("react/jsx-runtime");
29
+ // src/data/traces/otel/OtelTraceDetail.tsx
30
+ /**
31
+ * OpenTelemetry waterfall with grouped calls and an adjacent span inspector.
32
+ */
33
+ var CATEGORY_ICON = {
34
+ agent: require_UiRobotAi.UiRobotAi,
35
+ llm: require_UiSparkles.UiSparkles,
36
+ db: require_UiDatabase.UiDatabase,
37
+ other: require_UiClock.UiClock
38
+ };
39
+ var ROW_HEIGHT = 28;
40
+ var NAME_COLUMN = "minmax(15rem, 36%) minmax(0, 1fr)";
41
+ function OtelTraceDetail({ trace: TRACE, selectedSpanId, onSelectSpan }) {
42
+ const index = (0, react.useMemo)(() => require_model.indexTrace(TRACE), [TRACE]);
43
+ const suspects = (0, react.useMemo)(() => require_model.misparented(index), [index]);
44
+ const selected = selectedSpanId ?? TRACE.spans[0]?.spanId ?? "";
45
+ const [collapsed, setCollapsed] = (0, react.useState)(/* @__PURE__ */ new Set());
46
+ const groupOf = (id) => require_model.buildRows(index, {
47
+ collapsed: /* @__PURE__ */ new Set(),
48
+ expanded: /* @__PURE__ */ new Set(),
49
+ group: true
50
+ }).find((row) => row.type === "group" && row.spans.some((span) => span.spanId === id))?.id;
51
+ const [expanded, setExpanded] = (0, react.useState)(() => new Set([groupOf(selected)].filter((id) => id !== void 0)));
52
+ const [group, setGroup] = (0, react.useState)(true);
53
+ const [query, setQuery] = (0, react.useState)("");
54
+ const [categories, setCategories] = (0, react.useState)(/* @__PURE__ */ new Set());
55
+ const [onlySuspects, setOnlySuspects] = (0, react.useState)(false);
56
+ const visible = (0, react.useMemo)(() => {
57
+ const q = query.trim().toLowerCase();
58
+ if (!q && categories.size === 0 && !onlySuspects) return void 0;
59
+ const hits = TRACE.spans.filter((span) => (!q || [
60
+ span.operation,
61
+ span.service,
62
+ ...Object.values(span.attributes ?? {}).map(String)
63
+ ].some((text) => text.toLowerCase().includes(q))) && (categories.size === 0 || categories.has(require_model.category(span))) && (!onlySuspects || suspects.has(span.spanId)));
64
+ return require_model.withAncestors(index, hits.map((span) => span.spanId));
65
+ }, [
66
+ index,
67
+ query,
68
+ categories,
69
+ onlySuspects,
70
+ suspects,
71
+ TRACE
72
+ ]);
73
+ const rows = (0, react.useMemo)(() => require_model.buildRows(index, {
74
+ collapsed,
75
+ expanded,
76
+ group,
77
+ ...visible ? { visible } : {}
78
+ }), [
79
+ index,
80
+ collapsed,
81
+ expanded,
82
+ group,
83
+ visible
84
+ ]);
85
+ const select = (id) => {
86
+ const group = groupOf(id);
87
+ if (group) setExpanded((previous) => new Set(previous).add(group));
88
+ onSelectSpan(id);
89
+ };
90
+ const toggle = (set, id) => set((previous) => {
91
+ const next = new Set(previous);
92
+ if (!next.delete(id)) next.add(id);
93
+ return next;
94
+ });
95
+ const selectedSpan = index.byId.get(selected);
96
+ const selectedGroup = rows.find((row) => row.type === "group" && row.id === selected);
97
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
98
+ className: "space-y-8",
99
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
100
+ className: "space-y-4 rounded-xl border border-border bg-background p-density-4",
101
+ children: [
102
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TraceHeader, {
103
+ index,
104
+ trace: TRACE
105
+ }),
106
+ TRACE.missingParents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
107
+ role: "status",
108
+ children: [
109
+ "Partial trace: ",
110
+ TRACE.missingParents.length,
111
+ " parent spans are missing from this source."
112
+ ]
113
+ }),
114
+ suspects.size > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Callout.Callout, {
115
+ variant: "warning",
116
+ title: `${suspects.size} spans run inside a nested agent but hang off its parent`,
117
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
118
+ className: "text-sm",
119
+ children: [
120
+ "They start and end within ",
121
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: require_model.shortOperation(suspects.values().next().value.operation) }),
122
+ ", yet their parent is the root span, so the nested agent looks like it made a single LLM call. This usually means the agent's context is not propagated to its database client.",
123
+ " ",
124
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_button.Button, {
125
+ size: "sm",
126
+ variant: "link",
127
+ className: "h-auto p-0",
128
+ onClick: () => setOnlySuspects((on) => !on),
129
+ children: onlySuspects ? "Show all spans" : "Show only these spans"
130
+ })
131
+ ]
132
+ })
133
+ }),
134
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Toolbar, {
135
+ trace: TRACE,
136
+ query,
137
+ setQuery,
138
+ categories,
139
+ toggleCategory: (c) => setCategories((previous) => {
140
+ const next = new Set(previous);
141
+ if (!next.delete(c)) next.add(c);
142
+ return next;
143
+ }),
144
+ group,
145
+ setGroup,
146
+ expandAll: () => {
147
+ setCollapsed(/* @__PURE__ */ new Set());
148
+ setExpanded(new Set(rows.filter((row) => row.type === "group").map((row) => row.id)));
149
+ },
150
+ collapseAll: () => {
151
+ setExpanded(/* @__PURE__ */ new Set());
152
+ setCollapsed(new Set(TRACE.spans.filter((span) => index.children.has(span.spanId) && !span.parentId).map((span) => span.spanId)));
153
+ },
154
+ shown: rows.length
155
+ }),
156
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SplitPane.SplitPane, {
157
+ stackOnMobile: true,
158
+ defaultSplit: 62,
159
+ minLeft: 40,
160
+ minRight: 25,
161
+ className: "rounded-lg border border-border",
162
+ left: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Waterfall, {
163
+ index,
164
+ rows,
165
+ selected,
166
+ onSelect: select,
167
+ suspects,
168
+ onToggleSpan: (id) => toggle(setCollapsed, id),
169
+ onToggleGroup: (id) => toggle(setExpanded, id),
170
+ expanded,
171
+ collapsed
172
+ }),
173
+ right: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
174
+ className: "h-72 overflow-auto p-density-3 md:h-[calc(100dvh-14rem)] md:min-h-[30rem]",
175
+ children: selectedGroup ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCards.GroupDetail, {
176
+ index,
177
+ spans: selectedGroup.spans,
178
+ onSelect: select
179
+ }) : selectedSpan ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SpanDetail, {
180
+ index,
181
+ span: selectedSpan,
182
+ host: suspects.get(selectedSpan.spanId),
183
+ onSelect: select
184
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
185
+ className: "text-sm text-muted-foreground",
186
+ children: "Select a span."
187
+ })
188
+ })
189
+ })
190
+ ]
191
+ })
192
+ });
193
+ }
194
+ function TraceHeader({ index, trace: TRACE }) {
195
+ const { summary } = TRACE;
196
+ const by = (c) => TRACE.spans.filter((span) => require_model.category(span) === c);
197
+ const llm = by("llm");
198
+ const db = by("db");
199
+ const sum = (spans, key) => {
200
+ const values = spans.map((span) => require_model.num(span.attributes?.[key])).filter((value) => value !== void 0);
201
+ return values.length ? values.reduce((total, value) => total + value, 0) : void 0;
202
+ };
203
+ const root = index.roots[0];
204
+ const cost = require_model.num(root.attributes?.["captain.cost_usd"]);
205
+ const budget = require_model.num(root.attributes?.["captain.budget.cost_usd"]);
206
+ const tokensIn = sum(llm, "gen_ai.usage.input_tokens");
207
+ const tokensOut = sum(llm, "gen_ai.usage.output_tokens");
208
+ const ms = (spans) => spans.reduce((total, span) => total + span.durationMs, 0);
209
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
210
+ className: "space-y-3",
211
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
212
+ className: "flex flex-wrap items-start justify-between gap-3",
213
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
214
+ className: "min-w-0 space-y-1",
215
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
216
+ className: "flex items-center gap-2 text-xl font-semibold tracking-tight",
217
+ children: [
218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCategory.Tinted, {
219
+ icon: require_UiRobotAi.UiRobotAi,
220
+ color: require_model.CATEGORY_COLOR.agent
221
+ }),
222
+ require_model.shortOperation(summary.operation),
223
+ summary.errors === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge.Badge, {
224
+ tone: "success",
225
+ variant: "soft",
226
+ children: "no errors"
227
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Badge.Badge, {
228
+ tone: "danger",
229
+ variant: "soft",
230
+ children: [summary.errors, " errors"]
231
+ })
232
+ ]
233
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
234
+ className: "flex flex-wrap items-center gap-2 text-xs text-muted-foreground",
235
+ children: [
236
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: summary.traceId }),
237
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CopyButton.CopyButton, {
238
+ value: summary.traceId,
239
+ label: "Copy trace ID"
240
+ }),
241
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
242
+ "· ",
243
+ summary.services.join(", "),
244
+ " · ",
245
+ new Date(summary.startedAt).toLocaleString()
246
+ ] })
247
+ ]
248
+ })]
249
+ })
250
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_StatStrip.StatStrip, { items: [
251
+ {
252
+ label: "Duration",
253
+ value: require_model.duration(summary.durationMs),
254
+ sub: `${summary.spanCount} spans`,
255
+ icon: require_UiClock.UiClock
256
+ },
257
+ {
258
+ label: "LLM",
259
+ value: require_model.duration(ms(llm)),
260
+ sub: `${llm.length} calls · ${require_metrics.metric(tokensIn)} in / ${require_metrics.metric(tokensOut)} out`,
261
+ icon: require_UiSparkles.UiSparkles
262
+ },
263
+ {
264
+ label: "Database",
265
+ value: require_model.duration(ms(db)),
266
+ sub: `${db.length} calls · ${new Set(db.map((span) => span.attributes?.["db.sql.table"])).size} tables`,
267
+ icon: require_UiDatabase.UiDatabase
268
+ },
269
+ {
270
+ label: "Cost",
271
+ value: require_metrics.metric(cost, (value) => `$${value.toFixed(4)}`),
272
+ sub: budget ? `of $${budget} budget` : "budget unavailable",
273
+ icon: require_UiCoins.UiCoins
274
+ },
275
+ {
276
+ label: "Root self-time",
277
+ value: require_model.duration(require_model.selfTimeMs(index, root)),
278
+ sub: "not covered by any child span",
279
+ icon: require_UiRobotAi.UiRobotAi,
280
+ tone: "warning"
281
+ }
282
+ ] })]
283
+ });
284
+ }
285
+ function Toolbar(props) {
286
+ const counts = props.trace.spans.reduce((acc, span) => ({
287
+ ...acc,
288
+ [require_model.category(span)]: (acc[require_model.category(span)] ?? 0) + 1
289
+ }), {});
290
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
291
+ className: "flex flex-wrap items-center gap-2",
292
+ children: [
293
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchInput.SearchInput, {
294
+ className: "w-72",
295
+ placeholder: "Filter by name, table or attribute",
296
+ value: props.query,
297
+ onChange: props.setQuery
298
+ }),
299
+ Object.keys(counts).map((c) => {
300
+ const on = props.categories.has(c);
301
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_button.Button, {
302
+ size: "sm",
303
+ variant: on ? "default" : "outline",
304
+ "aria-pressed": on,
305
+ onClick: () => props.toggleCategory(c),
306
+ children: [
307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
308
+ className: "mr-1.5 inline-block size-2 rounded-full",
309
+ style: { background: require_model.CATEGORY_COLOR[c] }
310
+ }),
311
+ require_model.CATEGORY_LABEL[c],
312
+ " ",
313
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
314
+ className: "ml-1 text-muted-foreground",
315
+ children: counts[c]
316
+ })
317
+ ]
318
+ }, c);
319
+ }),
320
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
321
+ className: "ml-2 inline-flex items-center gap-2 text-xs text-muted-foreground",
322
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Switch.Switch, {
323
+ checked: props.group,
324
+ "aria-label": "Group repeated database calls",
325
+ onChange: props.setGroup
326
+ }), "Group repeated DB calls"]
327
+ }),
328
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
329
+ className: "ml-auto flex items-center gap-1",
330
+ children: [
331
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
332
+ className: "mr-2 text-xs text-muted-foreground",
333
+ children: [props.shown, " rows"]
334
+ }),
335
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_button.Button, {
336
+ size: "sm",
337
+ variant: "ghost",
338
+ onClick: props.expandAll,
339
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
340
+ icon: require_UiExpandAll.UiExpandAll,
341
+ className: "mr-1"
342
+ }), "Expand all"]
343
+ }),
344
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_button.Button, {
345
+ size: "sm",
346
+ variant: "ghost",
347
+ onClick: props.collapseAll,
348
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
349
+ icon: require_UiCollapseAll.UiCollapseAll,
350
+ className: "mr-1"
351
+ }), "Collapse"]
352
+ })
353
+ ]
354
+ })
355
+ ]
356
+ });
357
+ }
358
+ function Waterfall(props) {
359
+ const { index, rows, selected, onSelect } = props;
360
+ const total = Math.max(index.totalMs, .001);
361
+ const step = require_model.niceStep(total);
362
+ const ticks = Array.from({ length: Math.floor(total / step) + 1 }, (_, i) => i * step);
363
+ const scroller = (0, react.useRef)(null);
364
+ (0, react.useEffect)(() => {
365
+ scroller.current?.querySelector(`[data-row-id="${CSS.escape(selected)}"]`)?.scrollIntoView?.({ block: "nearest" });
366
+ }, [selected]);
367
+ const onKey = (event) => {
368
+ const at = rows.findIndex((row) => row.id === selected);
369
+ const next = event.key === "ArrowDown" ? rows[at + 1] : event.key === "ArrowUp" ? rows[at - 1] : void 0;
370
+ const row = rows[at];
371
+ if (next) onSelect(next.id);
372
+ else if (row && (event.key === "ArrowRight" || event.key === "ArrowLeft")) {
373
+ if ((row.type === "group" ? props.expanded.has(row.id) : !props.collapsed.has(row.id)) !== (event.key === "ArrowRight") && (row.type === "group" || row.childCount > 0)) (row.type === "group" ? props.onToggleGroup : props.onToggleSpan)(row.id);
374
+ } else return;
375
+ event.preventDefault();
376
+ };
377
+ const pct = (ms) => `${ms / total * 100}%`;
378
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
379
+ ref: scroller,
380
+ tabIndex: 0,
381
+ onKeyDown: onKey,
382
+ "aria-label": "Span waterfall",
383
+ className: "h-72 overflow-auto text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring md:h-[calc(100dvh-14rem)] md:min-h-[30rem]",
384
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
385
+ className: "min-w-[40rem]",
386
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
387
+ className: "sticky top-0 z-10 grid border-b border-border bg-muted text-muted-foreground",
388
+ style: {
389
+ gridTemplateColumns: NAME_COLUMN,
390
+ height: ROW_HEIGHT
391
+ },
392
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
393
+ className: "flex items-center px-density-2 font-medium",
394
+ children: "Span"
395
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
396
+ className: "relative mr-12",
397
+ children: ticks.map((t) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
398
+ className: "absolute top-1.5 -translate-x-1/2 tabular-nums",
399
+ style: { left: pct(t) },
400
+ children: t === 0 ? "0" : require_model.duration(t)
401
+ }, t))
402
+ })]
403
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
404
+ className: "relative",
405
+ children: [
406
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
407
+ "aria-hidden": true,
408
+ className: "pointer-events-none absolute inset-y-0 grid",
409
+ style: {
410
+ gridTemplateColumns: NAME_COLUMN,
411
+ left: 0,
412
+ right: 0
413
+ },
414
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
415
+ className: "relative mr-12",
416
+ children: ticks.map((t) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
417
+ className: "absolute inset-y-0 border-l border-border",
418
+ style: {
419
+ left: pct(t),
420
+ opacity: .6
421
+ }
422
+ }, t))
423
+ })]
424
+ }),
425
+ rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WaterfallRow, {
426
+ ...props,
427
+ row,
428
+ pct,
429
+ active: row.id === selected
430
+ }, row.id)),
431
+ rows.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
432
+ className: "p-density-4 text-sm text-muted-foreground",
433
+ children: "No spans match these filters."
434
+ })
435
+ ]
436
+ })]
437
+ })
438
+ });
439
+ }
440
+ function WaterfallRow({ index, row, active, pct, onSelect, suspects, onToggleSpan, onToggleGroup, expanded, collapsed }) {
441
+ const indent = { paddingLeft: `${row.depth * 14 + 4}px` };
442
+ const toggleButton = (open, onClick, label) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
443
+ type: "button",
444
+ "aria-label": `${open ? "Collapse" : "Expand"} ${label}`,
445
+ className: "flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted",
446
+ onClick: (event) => {
447
+ event.stopPropagation();
448
+ onClick();
449
+ },
450
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, { icon: open ? require_UiChevronDown.UiChevronDown : require_UiChevronRight.UiChevronRight })
451
+ });
452
+ const rowClass = `relative grid w-full cursor-pointer items-center text-left ${active ? "bg-accent" : "hover:bg-muted"}`;
453
+ if (row.type === "group") {
454
+ const open = expanded.has(row.id);
455
+ const ops = Object.entries(row.spans.reduce((acc, span) => ({
456
+ ...acc,
457
+ [span.operation.replace("gorm.", "")]: (acc[span.operation.replace("gorm.", "")] ?? 0) + 1
458
+ }), {}));
459
+ const first = index.offsetMs(row.spans[0]);
460
+ const last = row.spans.at(-1);
461
+ const end = index.offsetMs(last) + last.durationMs;
462
+ const busy = row.spans.reduce((total, span) => total + span.durationMs, 0);
463
+ const suspectCount = row.spans.filter((span) => suspects.has(span.spanId)).length;
464
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
465
+ role: "button",
466
+ tabIndex: -1,
467
+ "data-row-id": row.id,
468
+ "aria-selected": active,
469
+ className: rowClass,
470
+ style: {
471
+ gridTemplateColumns: NAME_COLUMN,
472
+ height: ROW_HEIGHT
473
+ },
474
+ onClick: () => onSelect(row.id),
475
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
476
+ className: "flex min-w-0 items-center gap-1 pr-2",
477
+ style: indent,
478
+ children: [
479
+ toggleButton(open, () => onToggleGroup(row.id), "database group"),
480
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCategory.Tinted, {
481
+ icon: require_UiDatabase.UiDatabase,
482
+ color: require_model.CATEGORY_COLOR.db
483
+ }),
484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
485
+ className: "truncate",
486
+ children: [
487
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
488
+ className: "font-medium",
489
+ children: [row.spans.length, " DB calls"]
490
+ }),
491
+ " ",
492
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
493
+ className: "text-muted-foreground",
494
+ children: ops.map(([op, n]) => `${op} ×${n}`).join(", ")
495
+ })
496
+ ]
497
+ }),
498
+ suspectCount > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCategory.Tinted, {
499
+ icon: require_UiWarningTriangle.UiWarningTriangle,
500
+ color: "var(--fs-warning)",
501
+ label: `${suspectCount} calls run inside a nested agent but are parented elsewhere`
502
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
503
+ className: "text-muted-foreground",
504
+ children: suspectCount
505
+ })] })
506
+ ]
507
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
508
+ className: "relative mr-12 h-full",
509
+ children: [
510
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
511
+ className: "absolute rounded-sm",
512
+ style: {
513
+ left: pct(first),
514
+ width: pct(end - first),
515
+ top: 11,
516
+ height: 6,
517
+ background: require_model.CATEGORY_COLOR.db,
518
+ opacity: .18
519
+ }
520
+ }),
521
+ row.spans.map((span) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
522
+ className: "absolute rounded-sm",
523
+ style: {
524
+ left: pct(index.offsetMs(span)),
525
+ width: pct(span.durationMs),
526
+ minWidth: 2,
527
+ top: 8,
528
+ height: 12,
529
+ background: require_model.CATEGORY_COLOR.db
530
+ }
531
+ }, span.spanId)),
532
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarLabel, {
533
+ start: first / Math.max(index.totalMs, .001) * 100,
534
+ end: end / Math.max(index.totalMs, .001) * 100,
535
+ text: `${require_model.duration(busy)} busy`
536
+ })
537
+ ]
538
+ })]
539
+ });
540
+ }
541
+ const { span } = row;
542
+ const c = require_model.category(span);
543
+ const parent = span.parentId ? index.byId.get(span.parentId) : void 0;
544
+ const left = index.offsetMs(span) / Math.max(index.totalMs, .001) * 100;
545
+ const width = span.durationMs / Math.max(index.totalMs, .001) * 100;
546
+ const error = require_model.isError(span);
547
+ const label = require_model.shortOperation(span.operation);
548
+ const table = span.attributes?.["db.sql.table"];
549
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
550
+ role: "button",
551
+ tabIndex: -1,
552
+ "data-row-id": row.id,
553
+ "aria-selected": active,
554
+ className: rowClass,
555
+ style: {
556
+ gridTemplateColumns: NAME_COLUMN,
557
+ height: ROW_HEIGHT
558
+ },
559
+ onClick: () => onSelect(row.id),
560
+ title: span.operation,
561
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
562
+ className: "flex min-w-0 items-center gap-1 pr-2",
563
+ style: indent,
564
+ children: [
565
+ row.childCount > 0 ? toggleButton(!collapsed.has(span.spanId), () => onToggleSpan(span.spanId), label) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "size-5 shrink-0" }),
566
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCategory.Tinted, {
567
+ icon: CATEGORY_ICON[c],
568
+ color: require_model.CATEGORY_COLOR[c]
569
+ }),
570
+ parent && parent.service !== span.service && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge.Badge, {
571
+ size: "sm",
572
+ variant: "outline",
573
+ children: span.service
574
+ }),
575
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
576
+ className: `truncate ${c === "db" ? "" : "font-medium"}`,
577
+ children: label
578
+ }),
579
+ typeof table === "string" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
580
+ className: "truncate text-muted-foreground",
581
+ children: table
582
+ }),
583
+ row.childCount > 0 && collapsed.has(span.spanId) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
584
+ className: "text-muted-foreground",
585
+ children: ["+", row.childCount]
586
+ }),
587
+ suspects.has(span.spanId) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCategory.Tinted, {
588
+ icon: require_UiWarningTriangle.UiWarningTriangle,
589
+ color: "var(--fs-warning)",
590
+ label: "Runs inside a nested agent but is parented elsewhere"
591
+ }),
592
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge.Badge, {
593
+ size: "sm",
594
+ tone: "danger",
595
+ variant: "soft",
596
+ children: "error"
597
+ })
598
+ ]
599
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
600
+ className: "relative mr-12 h-full",
601
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
602
+ className: "absolute rounded-sm",
603
+ style: {
604
+ left: `${left}%`,
605
+ width: `${width}%`,
606
+ minWidth: 2,
607
+ top: 7,
608
+ height: 14,
609
+ background: error ? "var(--destructive)" : require_model.CATEGORY_COLOR[c],
610
+ opacity: c === "agent" ? .85 : 1
611
+ }
612
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarLabel, {
613
+ start: left,
614
+ end: left + width,
615
+ inside: width > 14,
616
+ text: require_model.duration(span.durationMs)
617
+ })]
618
+ })]
619
+ });
620
+ }
621
+ /** Duration next to the bar's end — or inside a wide bar — and flipped left of the start near the right edge. */
622
+ function BarLabel({ start, end, inside, text }) {
623
+ if (inside) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
624
+ className: "absolute top-1.5 px-1.5 font-medium text-white tabular-nums",
625
+ style: { left: `${start}%` },
626
+ children: text
627
+ });
628
+ const position = end > 90 ? {
629
+ right: `${100 - start}%`,
630
+ paddingRight: 4
631
+ } : {
632
+ left: `${end}%`,
633
+ paddingLeft: 4
634
+ };
635
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
636
+ className: "absolute top-1.5 whitespace-nowrap tabular-nums text-muted-foreground",
637
+ style: position,
638
+ children: text
639
+ });
640
+ }
641
+ function SpanDetail({ index, span, host, onSelect }) {
642
+ const c = require_model.category(span);
643
+ const ancestors = [];
644
+ for (let p = span.parentId ? index.byId.get(span.parentId) : void 0; p; p = p.parentId ? index.byId.get(p.parentId) : void 0) ancestors.unshift(p);
645
+ const attributes = Object.entries(span.attributes ?? {});
646
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
647
+ className: "space-y-4",
648
+ children: [
649
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
650
+ className: "space-y-1.5",
651
+ children: [
652
+ ancestors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
653
+ className: "flex flex-wrap items-center gap-1 text-xs text-muted-foreground",
654
+ children: ancestors.map((a) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
655
+ className: "inline-flex items-center gap-1",
656
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
657
+ type: "button",
658
+ className: "hover:underline",
659
+ onClick: () => onSelect(a.spanId),
660
+ children: require_model.shortOperation(a.operation)
661
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, { icon: require_UiChevronRight.UiChevronRight })]
662
+ }, a.spanId))
663
+ }),
664
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
665
+ className: "flex items-center gap-2 text-base font-semibold",
666
+ title: span.operation,
667
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCategory.Tinted, {
668
+ icon: CATEGORY_ICON[c],
669
+ color: require_model.CATEGORY_COLOR[c]
670
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
671
+ className: "truncate",
672
+ children: require_model.shortOperation(span.operation)
673
+ })]
674
+ }),
675
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
676
+ className: "flex flex-wrap items-center gap-1.5 text-xs",
677
+ children: [
678
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge.Badge, {
679
+ variant: "soft",
680
+ size: "sm",
681
+ children: require_model.CATEGORY_LABEL[c]
682
+ }),
683
+ span.kind && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge.Badge, {
684
+ variant: "outline",
685
+ size: "sm",
686
+ children: span.kind
687
+ }),
688
+ require_model.isError(span) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Badge.Badge, {
689
+ tone: "danger",
690
+ variant: "soft",
691
+ size: "sm",
692
+ children: "error"
693
+ }),
694
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
695
+ className: "tabular-nums text-muted-foreground",
696
+ children: [
697
+ require_model.duration(span.durationMs),
698
+ " · starts at +",
699
+ require_model.duration(index.offsetMs(span))
700
+ ]
701
+ }),
702
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
703
+ className: "ml-auto inline-flex items-center gap-1 text-muted-foreground",
704
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: span.spanId }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CopyButton.CopyButton, {
705
+ value: span.spanId,
706
+ label: "Copy span ID"
707
+ })]
708
+ })
709
+ ]
710
+ })
711
+ ]
712
+ }),
713
+ host && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Callout.Callout, {
714
+ variant: "warning",
715
+ title: "Likely mis-parented",
716
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
717
+ className: "text-sm",
718
+ children: [
719
+ "Runs entirely inside ",
720
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
721
+ type: "button",
722
+ className: "underline",
723
+ onClick: () => onSelect(host.spanId),
724
+ children: require_model.shortOperation(host.operation)
725
+ }),
726
+ " but its parent is ",
727
+ span.parentId ? require_model.shortOperation(index.byId.get(span.parentId)?.operation ?? span.parentId) : "missing",
728
+ "."
729
+ ]
730
+ })
731
+ }),
732
+ c === "agent" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCards.AgentCard, {
733
+ index,
734
+ span
735
+ }),
736
+ c === "llm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCards.LlmCard, { span }),
737
+ c === "db" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SpanCards.DbCard, { span }),
738
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Section.Section, {
739
+ title: `All attributes (${attributes.length})`,
740
+ defaultOpen: c === "other",
741
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Properties.Properties, {
742
+ renderLabel: (key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
743
+ className: "text-xs",
744
+ children: key
745
+ }),
746
+ items: attributes.map(([key, value]) => ({
747
+ key,
748
+ value
749
+ }))
750
+ })
751
+ }),
752
+ span.otlp && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Section.Section, {
753
+ title: "OpenTelemetry metadata",
754
+ defaultOpen: false,
755
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CodeBlock.CodeBlock, {
756
+ language: "json",
757
+ source: JSON.stringify(span.otlp, null, 2),
758
+ jsonDefaultOpenDepth: 4,
759
+ copyable: true
760
+ })
761
+ }),
762
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Section.Section, {
763
+ title: `Resource (${Object.keys(span.resource ?? {}).length})`,
764
+ defaultOpen: false,
765
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Properties.Properties, {
766
+ renderLabel: (key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
767
+ className: "text-xs",
768
+ children: key
769
+ }),
770
+ items: Object.entries(span.resource ?? {}).map(([key, value]) => ({
771
+ key,
772
+ value
773
+ }))
774
+ })
775
+ })
776
+ ]
777
+ });
778
+ }
779
+ exports.OtelTraceDetail = OtelTraceDetail;
780
+
781
+ //# sourceMappingURL=OtelTraceDetail.cjs.map