@photon-ai/pho-ui 2.16.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js +75 -0
  2. package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js.map +1 -0
  3. package/dist/chunks/IconChevronUp-CrpWSgIl.js +11 -0
  4. package/dist/chunks/IconChevronUp-CrpWSgIl.js.map +1 -0
  5. package/dist/chunks/{bar-chart-BJfr3eyd.js → bar-chart-DIALC2_z.js} +2 -2
  6. package/dist/chunks/bar-chart-DIALC2_z.js.map +1 -0
  7. package/dist/chunks/basic-page-CogcwGx3.js +1749 -0
  8. package/dist/chunks/basic-page-CogcwGx3.js.map +1 -0
  9. package/dist/chunks/card-DhDwtSi9.js +56 -0
  10. package/dist/chunks/card-DhDwtSi9.js.map +1 -0
  11. package/dist/chunks/code-block-BuDIo8Q0.js +197 -0
  12. package/dist/chunks/code-block-BuDIo8Q0.js.map +1 -0
  13. package/dist/chunks/collapsible-if7ncPbI.js +28 -0
  14. package/dist/chunks/collapsible-if7ncPbI.js.map +1 -0
  15. package/dist/chunks/{command-Ck8IAgV7.js → command-CTYrSz9a.js} +2 -2
  16. package/dist/chunks/{command-Ck8IAgV7.js.map → command-CTYrSz9a.js.map} +1 -1
  17. package/dist/chunks/data-table-DcwCgXJU.js +293 -0
  18. package/dist/chunks/data-table-DcwCgXJU.js.map +1 -0
  19. package/dist/chunks/date-range-picker-DwFDUNRL.js +88 -0
  20. package/dist/chunks/date-range-picker-DwFDUNRL.js.map +1 -0
  21. package/dist/chunks/{dialog-BxKACOj5.js → dialog-BwfUFn6B.js} +2 -2
  22. package/dist/chunks/{dialog-BxKACOj5.js.map → dialog-BwfUFn6B.js.map} +1 -1
  23. package/dist/chunks/{filter-bar-Cjjq38xo.js → filter-bar-BsvdXwzc.js} +2 -2
  24. package/dist/chunks/{filter-bar-Cjjq38xo.js.map → filter-bar-BsvdXwzc.js.map} +1 -1
  25. package/dist/chunks/ghost-search-BvBFa9su.js +25 -0
  26. package/dist/chunks/ghost-search-BvBFa9su.js.map +1 -0
  27. package/dist/chunks/{line-chart-CUR3AxrR.js → line-chart-VuMYKzW3.js} +2 -2
  28. package/dist/chunks/{line-chart-CUR3AxrR.js.map → line-chart-VuMYKzW3.js.map} +1 -1
  29. package/dist/chunks/{log-list-0AXnjFrk.js → log-list-BERiO4UJ.js} +2 -2
  30. package/dist/chunks/{log-list-0AXnjFrk.js.map → log-list-BERiO4UJ.js.map} +1 -1
  31. package/dist/chunks/scroll-area-Zik8t1Mk.js +168 -0
  32. package/dist/chunks/scroll-area-Zik8t1Mk.js.map +1 -0
  33. package/dist/chunks/sidebar-DRPe5CAh.js +306 -0
  34. package/dist/chunks/sidebar-DRPe5CAh.js.map +1 -0
  35. package/dist/chunks/{toast-iSf6NuAS.js → toast-72Wwlzg9.js} +2 -2
  36. package/dist/chunks/{toast-iSf6NuAS.js.map → toast-72Wwlzg9.js.map} +1 -1
  37. package/dist/chunks/trace-Ba1RMBfk.js +1645 -0
  38. package/dist/chunks/trace-Ba1RMBfk.js.map +1 -0
  39. package/dist/chunks/use-measure-C-i54AC6.js +629 -0
  40. package/dist/chunks/use-measure-C-i54AC6.js.map +1 -0
  41. package/dist/components/bar-chart.js +1 -1
  42. package/dist/components/card.js +1 -1
  43. package/dist/components/code-block.js +1 -1
  44. package/dist/components/collapsible.js +2 -25
  45. package/dist/components/command.js +1 -1
  46. package/dist/components/data-table.js +9 -8
  47. package/dist/components/date-range-picker.js +10 -0
  48. package/dist/components/dialog.js +1 -1
  49. package/dist/components/filter-bar.js +1 -1
  50. package/dist/components/line-chart.js +1 -1
  51. package/dist/components/log-list.js +1 -1
  52. package/dist/components/scroll-area.js +1 -1
  53. package/dist/components/toast.js +1 -1
  54. package/dist/components/trace.js +41 -6
  55. package/dist/index.js +166 -121
  56. package/dist/primitives.js +2 -2
  57. package/dist/sections/basic-page.js +5 -5
  58. package/dist/sections/sidebar.js +9 -6
  59. package/dist/src/components/card/card.d.ts +5 -1
  60. package/dist/src/components/chart/scale.d.ts +6 -1
  61. package/dist/src/components/code-block/code-block.d.ts +24 -5
  62. package/dist/src/components/code-block/index.d.ts +1 -1
  63. package/dist/src/components/data-table/data-table.d.ts +54 -13
  64. package/dist/src/components/date-range-picker/date-range-picker.d.ts +31 -0
  65. package/dist/src/components/date-range-picker/index.d.ts +1 -0
  66. package/dist/src/components/scroll-area/scroll-area.d.ts +9 -1
  67. package/dist/src/components/trace/decorations.d.ts +32 -0
  68. package/dist/src/components/trace/index.d.ts +5 -2
  69. package/dist/src/components/trace/layout.d.ts +57 -29
  70. package/dist/src/components/trace/span-primitive.d.ts +168 -0
  71. package/dist/src/components/trace/span-tree.d.ts +148 -0
  72. package/dist/src/components/trace/trace.d.ts +98 -16
  73. package/dist/src/index.d.ts +1 -0
  74. package/dist/src/sections/basic-page/basic-page.d.ts +95 -7
  75. package/dist/src/sections/basic-page/index.d.ts +1 -1
  76. package/dist/src/sections/sidebar/index.d.ts +1 -1
  77. package/dist/src/sections/sidebar/sidebar.d.ts +72 -0
  78. package/dist/src/utils/ghost-search.d.ts +11 -0
  79. package/package.json +5 -1
  80. package/dist/chunks/bar-chart-BJfr3eyd.js.map +0 -1
  81. package/dist/chunks/basic-page-CMJuM5iA.js +0 -1650
  82. package/dist/chunks/basic-page-CMJuM5iA.js.map +0 -1
  83. package/dist/chunks/card-DSW3Uhag.js +0 -56
  84. package/dist/chunks/card-DSW3Uhag.js.map +0 -1
  85. package/dist/chunks/code-block-CdozzaHM.js +0 -139
  86. package/dist/chunks/code-block-CdozzaHM.js.map +0 -1
  87. package/dist/chunks/data-table-CHLJfGkS.js +0 -279
  88. package/dist/chunks/data-table-CHLJfGkS.js.map +0 -1
  89. package/dist/chunks/scroll-area-BO-9PMM7.js +0 -167
  90. package/dist/chunks/scroll-area-BO-9PMM7.js.map +0 -1
  91. package/dist/chunks/sidebar-DVzZsCts.js +0 -223
  92. package/dist/chunks/sidebar-DVzZsCts.js.map +0 -1
  93. package/dist/chunks/trace-CbH0IohX.js +0 -314
  94. package/dist/chunks/trace-CbH0IohX.js.map +0 -1
  95. package/dist/chunks/use-measure-CMVgLouO.js +0 -616
  96. package/dist/chunks/use-measure-CMVgLouO.js.map +0 -1
  97. package/dist/components/collapsible.js.map +0 -1
@@ -0,0 +1,32 @@
1
+ import { Icon } from '@tabler/icons-react';
2
+ export interface SpanPill {
3
+ /** The attribute the value came from — the tooltip and the label for readers. */
4
+ label: string;
5
+ value: string;
6
+ /** The value is a failure (a 5xx status). */
7
+ error?: boolean;
8
+ }
9
+ export interface SpanDecorationIcon {
10
+ icon: Icon;
11
+ /** What the icon means, for readers and the tooltip; absent for a plain namespace icon. */
12
+ label?: string;
13
+ }
14
+ export type GenAIKind = "agent" | "llm" | "tool" | "retrieval" | "generic";
15
+ type Attributes = Readonly<Record<string, unknown>> | undefined;
16
+ export declare const GEN_AI_KINDS: Record<GenAIKind, {
17
+ icon: Icon;
18
+ label: string;
19
+ }>;
20
+ /** An attribute's value as text; objects as JSON, nothing for null. */
21
+ export declare function attributeText(value: unknown): string;
22
+ /** The first of `keys` with a non-empty value, as text. */
23
+ export declare function attribute(attributes: Attributes, keys: readonly string[]): string | null;
24
+ /** The GenAI kind of a span, from `gen_ai.operation.name`; `generic` for any other `gen_ai.*`. */
25
+ export declare function genAIKind(attributes: Attributes): GenAIKind | null;
26
+ /** The one icon for a span, GenAI kind first, then the first namespace with one. */
27
+ export declare function spanDecorationIcon(attributes: Attributes): SpanDecorationIcon | null;
28
+ /** The pills for a span, in registry order. */
29
+ export declare function spanPills(attributes: Attributes): SpanPill[];
30
+ /** `peer.service` — the service a client span called, when it named one. */
31
+ export declare function peerService(attributes: Attributes): string | null;
32
+ export {};
@@ -1,2 +1,5 @@
1
- export { Trace, type TraceRootProps, type TraceLogsProps, type TraceLog, type TraceLogLevel, } from './trace';
2
- export { layoutTrace, niceStep, formatDuration, formatTick, type TraceSpan, type TraceRow, type TraceLayout, } from './layout';
1
+ export { Trace, traceBulletInset, footerTotals, type TraceWaterfallProps, type TraceWaterfallShortcuts, type WaterfallFooterProps, type TraceLogsProps, type TraceLog, type TraceLogLevel, } from './trace';
2
+ export { SpanPrimitive, useSpan, useSpanTree, type SpanTreeContextValue, type SpanProviderProps, type SpanChildrenProps, type SpanRootProps, type SpanIndentProps, type SpanCollapseToggleProps, type SpanStatusIndicatorProps, type SpanTypeBadgeProps, type SpanNameProps, type SpanTimelineProps, type SpanTimelineBarProps, } from './span-primitive';
3
+ export { deriveSpanTree, visibleSpans, buildSpanTree, ancestorIds, collapseAllIds, collapseOneLevel, expandOneLevel, allCollapsed, traceRange, clampView, viewToRange, zoomView, panView, viewFraction, isFullView, spanTimelineBarVars, filterSpans, FULL_VIEW, MIN_VIEW_WIDTH, type SpanData, type SpanStatus, type SpanKind, type SpanItemState, type SpanTree, type SpanTimelineRange, type SpanView, } from './span-tree';
4
+ export { spanDecorationIcon, spanPills, genAIKind, peerService, attribute, attributeText, GEN_AI_KINDS, type SpanPill, type SpanDecorationIcon, type GenAIKind, } from './decorations';
5
+ export { normalizeSpans, spanDuration, barGeometry, axisTicks, niceStep, formatDuration, formatTick, labeledTicks, type AxisTick, type TraceWaterfallSpan, type TraceSpanStatus, type TraceSpanKind, type TraceRange, } from './layout';
@@ -1,48 +1,76 @@
1
+ import { SpanData, SpanKind, SpanStatus, SpanTimelineRange } from './span-tree';
2
+ export type TraceSpanStatus = SpanStatus;
3
+ export type TraceSpanKind = SpanKind;
4
+ export type TraceRange = SpanTimelineRange;
1
5
  /**
2
- * The waterfall's arithmetic, apart from the drawing: spans in, rows out
3
- * — each with its depth and its bar's place along the trace's length —
4
- * plus the tick marks for the time axis.
6
+ * A span as the waterfall takes it — `SpanData` with its derivable
7
+ * fields optional. A `SpanData` passes through unchanged.
5
8
  */
6
- export interface TraceSpan {
9
+ export interface TraceWaterfallSpan {
7
10
  id: string;
8
11
  /** The span this one runs inside. Absent (or unknown) means a root. */
9
- parentId?: string | null;
12
+ parentSpanId?: string | null;
10
13
  name: string;
14
+ /** The category — http, db, llm, tool. Shows after the service as a hint. */
15
+ type?: string;
16
+ /** `completed` with an end, `running` without, unless told otherwise. */
17
+ status?: TraceSpanStatus;
18
+ /** OpenTelemetry kind. A folded `client` names its `server` child. */
19
+ kind?: TraceSpanKind;
11
20
  /** Start, in ms, on any shared clock — only the differences matter. */
12
- startMs: number;
13
- durationMs: number;
14
- status?: "ok" | "error" | "unset";
21
+ startedAt: number;
22
+ /** End, in ms; `null` (or absent) while the span still runs. */
23
+ endedAt?: number | null;
24
+ /** The measured duration; `endedAt - startedAt` when absent. */
25
+ latencyMs?: number | null;
15
26
  /** A hint after the name — the service, the host. */
16
27
  service?: string;
17
- /** A hint after the service — client, server, db. */
18
- kind?: string;
28
+ /**
29
+ * Flat OpenTelemetry attributes. `http.response.status_code`,
30
+ * `db.system`, `gen_ai.request.model` become pills; the namespace
31
+ * picks the icon; `peer.service` names an uninstrumented callee; all
32
+ * of them are searchable.
33
+ */
34
+ attributes?: Readonly<Record<string, unknown>>;
19
35
  }
20
- export interface TraceRow {
21
- span: TraceSpan;
22
- depth: number;
23
- /** The bar's start, as a fraction of the trace's length. */
36
+ /** Fill in what the tree requires and the input left implicit. */
37
+ export declare function normalizeSpans(spans: readonly TraceWaterfallSpan[]): SpanData[];
38
+ /** How long a span took — or has taken so far, given `now`. */
39
+ export declare function spanDuration(span: Pick<SpanData, "startedAt" | "endedAt" | "latencyMs">, now?: number): number | null;
40
+ /**
41
+ * A bar's start and length as fractions of the range — the same numbers
42
+ * `SpanPrimitive.TimelineBar` draws with, for placing the label beside it.
43
+ */
44
+ export declare function barGeometry(span: Pick<SpanData, "startedAt" | "endedAt">, range: TraceRange, now?: number): {
24
45
  left: number;
25
- /** The bar's length, as a fraction of the trace's length. */
26
46
  width: number;
27
- children: string[];
28
- /** Every span beneath this one, at any depth. */
29
- descendants: number;
30
- }
31
- export interface TraceLayout {
32
- /** Every span, root first, each parent before its children. */
33
- rows: TraceRow[];
34
- startMs: number;
35
- endMs: number;
36
- durationMs: number;
37
- /** Tick marks along the axis, in ms from the start. */
38
- ticks: number[];
39
- }
47
+ };
40
48
  /** A tick step from the 1 / 2 / 5 ladder so the axis has at most `max` ticks. */
41
49
  export declare function niceStep(durationMs: number, max?: number): number;
42
- export declare function layoutTrace(spans: readonly TraceSpan[]): TraceLayout;
50
+ export interface AxisTick {
51
+ /** Where along the track, as a fraction. */
52
+ at: number;
53
+ /** The time it marks, in ms from the trace's start. */
54
+ ms: number;
55
+ }
56
+ /**
57
+ * Tick marks for the window `[startMs, endMs]` of a trace, in ms from
58
+ * the trace's start: round multiples of a nice step, so a zoomed axis
59
+ * still reads `20 ms, 25 ms, 30 ms`. `[{ at: 0, ms: startMs }]` for a
60
+ * window with no length.
61
+ */
62
+ export declare function axisTicks(startMs: number, endMs: number): AxisTick[];
43
63
  /** "0.42 ms", "59.2 ms", "1.25 s" — the precision follows the size. */
44
64
  export declare function formatDuration(ms: number): string;
45
65
  /** An axis tick's label: whole numbers where the step allows, "2 s" past a second. */
46
66
  export declare function formatTick(ms: number): string;
67
+ /**
68
+ * Which tick marks get a label at this track width. Marks themselves
69
+ * always draw; a label hides when it would overlap the previous one.
70
+ * The last tick is treated as right-aligned so it never runs past the
71
+ * track's edge — at a narrow axis that often means dropping the label
72
+ * before it (`40 ms` next to `50 ms` on a ~335px track).
73
+ */
74
+ export declare function labeledTicks(ticks: readonly AxisTick[], trackPx: number): number[];
47
75
  /** A fraction as a CSS percentage, rounded so floats never leak into styles. */
48
76
  export declare function percent(fraction: number): string;
@@ -0,0 +1,168 @@
1
+ import { ReactNode } from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import { SpanData, SpanItemState, SpanTimelineRange, SpanView } from './span-tree';
4
+ /**
5
+ * SpanPrimitive — headless parts for a tree of spans: the pieces a
6
+ * waterfall, a timeline, or a run inspector is composed from, with no
7
+ * styling of their own.
8
+ *
9
+ * Modelled on `@assistant-ui/react-o11y`'s `SpanPrimitive` (same data
10
+ * attributes, same CSS variables, same part names) so a host that knows
11
+ * that shape can style either — but with no store behind it: the tree is
12
+ * derived once per change and shared through plain context, folding is
13
+ * controllable, and every part takes Base UI's `render` prop in place of
14
+ * Radix's `asChild`. The tree's edge cases and the fold, search, and
15
+ * zoom arithmetic come from Jaeger UI's trace view; see `span-tree.ts`.
16
+ *
17
+ * - `Provider` takes the flat `SpanData[]`, derives the tree (depth,
18
+ * order, descendants and their errors, orphans, repaired times) and
19
+ * the time range, and owns the fold, the search matches, and the zoom
20
+ * window — each uncontrolled by default, controlled with a prop.
21
+ * - `Children` renders each visible span in turn, root first, parents
22
+ * before their children, siblings by start; a folded parent hides its
23
+ * subtree. Inside it, `useSpan()` is the current span and
24
+ * `useSpanTree()` the whole tree with its actions.
25
+ * - `Root`, `Indent`, `CollapseToggle`, `StatusIndicator`, `TypeBadge`,
26
+ * `Name` are the row's parts; `Timeline` supplies the (zoomed) range
27
+ * as CSS variables and `TimelineBar` places the current span along it.
28
+ */
29
+ export interface SpanTreeContextValue {
30
+ /** The visible rows, in reading order. */
31
+ spans: readonly SpanItemState[];
32
+ /** Every span, folded or not, in reading order. */
33
+ all: readonly SpanItemState[];
34
+ byId: ReadonlyMap<string, SpanItemState>;
35
+ /** Spans whose parent the trace does not have. */
36
+ orphans: number;
37
+ /** Spans whose start or end had to be repaired. */
38
+ repaired: number;
39
+ /** The whole trace. */
40
+ range: SpanTimelineRange;
41
+ /** The zoom window, as fractions of the trace. */
42
+ view: SpanView;
43
+ /** The part of the range the window shows. */
44
+ viewRange: SpanTimelineRange;
45
+ zoomed: boolean;
46
+ now: number | undefined;
47
+ collapsed: ReadonlySet<string>;
48
+ toggle: (id: string) => void;
49
+ setCollapsed: (ids: readonly string[]) => void;
50
+ expandAll: () => void;
51
+ collapseAll: () => void;
52
+ /** Open the shallowest folded parent on every branch. */
53
+ expandOne: () => void;
54
+ /** Fold the deepest open parent on every branch. */
55
+ collapseOne: () => void;
56
+ canExpand: boolean;
57
+ canCollapse: boolean;
58
+ query: string;
59
+ /** The spans the query names; `null` with no query. */
60
+ matches: ReadonlySet<string> | null;
61
+ setView: (view: SpanView) => void;
62
+ /** Scale the window; below 1 zooms in. `anchor` is a fraction of the window. */
63
+ zoom: (factor: number, anchor?: number) => void;
64
+ /** Slide the window by a fraction of its own width. */
65
+ pan: (delta: number) => void;
66
+ resetView: () => void;
67
+ }
68
+ /** The whole tree: visible spans, the ranges, and the fold / search / zoom actions. */
69
+ export declare function useSpanTree(): SpanTreeContextValue;
70
+ /** The span this part belongs to — set by `SpanPrimitive.Children`. */
71
+ export declare function useSpan(): SpanItemState;
72
+ export interface SpanProviderProps {
73
+ spans: readonly SpanData[];
74
+ /** Spans folded at first (uncontrolled). */
75
+ defaultCollapsed?: readonly string[];
76
+ /** Spans folded (controlled). */
77
+ collapsed?: readonly string[];
78
+ onCollapsedChange?: (ids: string[]) => void;
79
+ /** The current time on the spans' clock — where a running span ends. */
80
+ now?: number;
81
+ /**
82
+ * A search over the spans (see `filterSpans`). Matching spans are
83
+ * `matches`; their folded ancestors open so every match is in view.
84
+ */
85
+ query?: string;
86
+ /** Leave folded ancestors of matches folded. */
87
+ keepFoldsOnMatch?: boolean;
88
+ /** The zoom window at first (uncontrolled). */
89
+ defaultView?: SpanView;
90
+ /** The zoom window (controlled). */
91
+ view?: SpanView;
92
+ onViewChange?: (view: SpanView) => void;
93
+ children: ReactNode;
94
+ }
95
+ declare function Provider({ spans, defaultCollapsed, collapsed: collapsedProp, onCollapsedChange, now, query, keepFoldsOnMatch, defaultView, view: viewProp, onViewChange, children, }: SpanProviderProps): import("react").JSX.Element;
96
+ export interface SpanChildrenProps {
97
+ /** Rendered once per visible span; `useSpan()` inside reads that span. */
98
+ children: (span: SpanItemState) => ReactNode;
99
+ }
100
+ declare function Children({ children }: SpanChildrenProps): import("react").JSX.Element[];
101
+ export type SpanRootProps = useRender.ComponentProps<"div">;
102
+ /**
103
+ * The row: a div carrying the span's state as data attributes —
104
+ * `data-span-id`, `-status`, `-type`, `-depth`, `-kind`, `data-collapsed`,
105
+ * `data-match` while the search names it, `data-orphan` for a span
106
+ * whose parent the trace lacks.
107
+ */
108
+ declare function Root({ render, ref, ...props }: SpanRootProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
109
+ export type SpanIndentProps = useRender.ComponentProps<"div"> & {
110
+ /** Padding at depth 0, in px. @default 8 */
111
+ baseIndent?: number;
112
+ /** Padding added per level, in px. @default 12 */
113
+ indentPerLevel?: number;
114
+ };
115
+ /** A div padded on the left for the span's depth. */
116
+ declare function Indent({ render, ref, baseIndent, indentPerLevel, style, ...props }: SpanIndentProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
117
+ export type SpanCollapseToggleProps = useRender.ComponentProps<"button">;
118
+ /** The fold button; renders nothing for a span with no children. */
119
+ declare function CollapseToggle({ render, ref, onClick, ...props }: SpanCollapseToggleProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | null;
120
+ export type SpanStatusIndicatorProps = useRender.ComponentProps<"span">;
121
+ /**
122
+ * A span carrying `data-span-status`, for a dot or an icon — and
123
+ * `data-descendant-errors` while a fold hides failed spans beneath it.
124
+ */
125
+ declare function StatusIndicator({ render, ref, ...props }: SpanStatusIndicatorProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
126
+ export type SpanTypeBadgeProps = useRender.ComponentProps<"span">;
127
+ /** The span's type as text, unless given children. */
128
+ declare function TypeBadge({ render, ref, children, ...props }: SpanTypeBadgeProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
129
+ export type SpanNameProps = useRender.ComponentProps<"span">;
130
+ /** The span's name as text, unless given children. */
131
+ declare function Name({ render, ref, children, ...props }: SpanNameProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
132
+ export type SpanTimelineProps = useRender.ComponentProps<"div"> & {
133
+ /** The range to draw against. @default the tree's zoom window */
134
+ timeRange?: SpanTimelineRange;
135
+ /** Room after the end, as a fraction of the range. @default 0 */
136
+ paddingEnd?: number;
137
+ };
138
+ /**
139
+ * The track every bar inside it is placed along. Exposes the range as
140
+ * `--span-timeline-min-ms` / `-max-ms` / `-range-ms`.
141
+ */
142
+ declare function Timeline({ render, ref, timeRange, paddingEnd, style, ...props }: SpanTimelineProps): import("react").JSX.Element;
143
+ export type SpanTimelineBarProps = useRender.ComponentProps<"div"> & {
144
+ /** Where a running span ends. @default the tree's `now`, else the range's end */
145
+ now?: number;
146
+ /** @default the nearest Timeline's range */
147
+ timeRange?: SpanTimelineRange;
148
+ };
149
+ /**
150
+ * The current span's bar, positioned absolutely from
151
+ * `--span-timeline-left` and sized from `--span-timeline-width` (never
152
+ * under `--span-timeline-min-width`, when the host sets one). Carries
153
+ * `data-clipped-start` / `data-clipped-end` when the range cuts it off.
154
+ */
155
+ declare function TimelineBar({ render, ref, now, timeRange, style, ...props }: SpanTimelineBarProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
156
+ export declare const SpanPrimitive: {
157
+ Provider: typeof Provider;
158
+ Children: typeof Children;
159
+ Root: typeof Root;
160
+ Indent: typeof Indent;
161
+ CollapseToggle: typeof CollapseToggle;
162
+ StatusIndicator: typeof StatusIndicator;
163
+ TypeBadge: typeof TypeBadge;
164
+ Name: typeof Name;
165
+ Timeline: typeof Timeline;
166
+ TimelineBar: typeof TimelineBar;
167
+ };
168
+ export {};
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The span tree, apart from React: the shape a waterfall needs from a flat
3
+ * list of spans, and the arithmetic on it. Everything here is pure and
4
+ * runs the same on the server.
5
+ *
6
+ * The edge cases follow Jaeger UI's trace model (Apache-2.0, reimplemented
7
+ * from its behaviour, not its code): a parent the trace does not have makes
8
+ * an orphan, not a crash; a cycle is broken where it closes; a span with no
9
+ * usable start inherits its parent's instead of dragging the axis to the
10
+ * epoch; an error under a folded parent stays countable; a client span
11
+ * remembers its server child so a fold can still name the peer.
12
+ */
13
+ export type SpanStatus = "running" | "completed" | "failed" | "skipped";
14
+ /** OpenTelemetry's span kinds, lower-cased. */
15
+ export type SpanKind = "client" | "server" | "producer" | "consumer" | "internal";
16
+ export interface SpanData {
17
+ id: string;
18
+ /** The span this one runs inside; `null` for a root. */
19
+ parentSpanId: string | null;
20
+ name: string;
21
+ /** The category — http, db, llm, tool. */
22
+ type: string;
23
+ status: SpanStatus;
24
+ /** Start, in ms, on any shared clock — only the differences matter. */
25
+ startedAt: number;
26
+ /** End, in ms; `null` while the span still runs. */
27
+ endedAt: number | null;
28
+ /** The measured duration, when the tracer reports one. */
29
+ latencyMs: number | null;
30
+ /** OpenTelemetry kind, when known — a `client` fold can name its server. */
31
+ kind?: SpanKind;
32
+ /** The service (resource) the span ran in. */
33
+ service?: string;
34
+ /** Flat OpenTelemetry attributes — `http.response.status_code`, `db.system`. */
35
+ attributes?: Readonly<Record<string, unknown>>;
36
+ }
37
+ /** A span as the tree knows it: its data plus its place in the tree. */
38
+ export interface SpanItemState extends SpanData {
39
+ depth: number;
40
+ hasChildren: boolean;
41
+ isCollapsed: boolean;
42
+ /** Every span beneath this one, at any depth, folded or not. */
43
+ descendants: number;
44
+ /** How many of those failed. */
45
+ descendantErrors: number;
46
+ /** Named a parent the trace does not have (or one in a cycle); shown as a root. */
47
+ orphan: boolean;
48
+ /** Its start or end was missing or not a number and was repaired. */
49
+ repaired: boolean;
50
+ /** For a `client` span: the first direct child that is a `server` span. */
51
+ serverChildId: string | null;
52
+ }
53
+ export interface SpanTimelineRange {
54
+ min: number;
55
+ max: number;
56
+ }
57
+ /** A zoom window, as fractions of the trace's range. `[0, 1]` is all of it. */
58
+ export type SpanView = readonly [start: number, end: number];
59
+ export declare const FULL_VIEW: SpanView;
60
+ /** The narrowest a zoom window goes, as a fraction of the trace. */
61
+ export declare const MIN_VIEW_WIDTH = 0.001;
62
+ export interface SpanTree {
63
+ /** Every span, root first, each parent before its children, siblings by start. */
64
+ spans: readonly SpanItemState[];
65
+ byId: ReadonlyMap<string, SpanItemState>;
66
+ /** Spans whose parent the trace does not have. */
67
+ orphans: number;
68
+ /** Spans whose start or end had to be repaired. */
69
+ repaired: number;
70
+ }
71
+ /**
72
+ * Derive the tree once from the flat list: depth, order, descendants and
73
+ * their errors, orphans, repaired times, and each client's server child.
74
+ * Nothing here depends on folding; see `visibleSpans` for that.
75
+ */
76
+ export declare function deriveSpanTree(spans: readonly SpanData[]): SpanTree;
77
+ /**
78
+ * The visible rows: the tree in reading order with every folded parent's
79
+ * subtree left out. Untouched items keep their identity; a folded parent
80
+ * is a copy with `isCollapsed` set.
81
+ */
82
+ export declare function visibleSpans(tree: SpanTree, collapsed: ReadonlySet<string>): SpanItemState[];
83
+ /** Derive and fold in one step — `visibleSpans(deriveSpanTree(spans), collapsed)`. */
84
+ export declare function buildSpanTree(spans: readonly SpanData[], collapsed?: ReadonlySet<string>): SpanItemState[];
85
+ /** The ids above a span, nearest parent first. */
86
+ export declare function ancestorIds(byId: ReadonlyMap<string, Pick<SpanItemState, "parentSpanId">>, id: string): string[];
87
+ /** Every parent — the fold state after "collapse all". */
88
+ export declare function collapseAllIds(spans: readonly SpanItemState[]): string[];
89
+ /** True when every parent is already folded, so "collapse" has nothing to do. */
90
+ export declare function allCollapsed(spans: readonly SpanItemState[], collapsed: ReadonlySet<string>): boolean;
91
+ /**
92
+ * Fold one level: the deepest open parent on every branch closes. Pressed
93
+ * again, the level above; and so on up to the roots.
94
+ */
95
+ export declare function collapseOneLevel(spans: readonly SpanItemState[], collapsed: ReadonlySet<string>): string[];
96
+ /**
97
+ * Open one level: the shallowest folded parent on every branch opens.
98
+ * The inverse of `collapseOneLevel`.
99
+ */
100
+ export declare function expandOneLevel(spans: readonly SpanItemState[], collapsed: ReadonlySet<string>): string[];
101
+ /**
102
+ * The trace runs from the earliest start to the latest end. A running
103
+ * span ends at `now` when there is one; otherwise it counts only its
104
+ * start, and its bar stretches to whatever the rest of the trace spans.
105
+ */
106
+ export declare function traceRange(spans: readonly Pick<SpanData, "startedAt" | "endedAt">[], now?: number): SpanTimelineRange;
107
+ /** A zoom window made sane: ordered, inside `[0, 1]`, never thinner than the minimum. */
108
+ export declare function clampView(view: SpanView): SpanView;
109
+ /** The window's part of the range, in the range's units. */
110
+ export declare function viewToRange(range: SpanTimelineRange, view: SpanView): SpanTimelineRange;
111
+ /**
112
+ * Scale the window by `factor` (below 1 zooms in) around `anchor`, a
113
+ * fraction of the *window*; the point under the anchor stays put.
114
+ */
115
+ export declare function zoomView(view: SpanView, factor: number, anchor?: number): SpanView;
116
+ /** Slide the window by `delta` of its own width; it stops at either end. */
117
+ export declare function panView(view: SpanView, delta: number): SpanView;
118
+ /** Map a window-relative fraction (a pointer on the axis) to a trace fraction. */
119
+ export declare function viewFraction(view: SpanView, at: number): number;
120
+ export declare function isFullView(view: SpanView): boolean;
121
+ /**
122
+ * Where a span's bar sits along a range, in percent. A running span ends
123
+ * at `now`, or at the range's end without one; everything clamps to the
124
+ * range so a bar never leaves the track, and the clipped flags say when
125
+ * it did.
126
+ */
127
+ export declare function spanTimelineBarVars({ startedAt, endedAt, timeRange, now, }: {
128
+ startedAt: number;
129
+ endedAt: number | null;
130
+ timeRange: SpanTimelineRange;
131
+ now?: number;
132
+ }): {
133
+ leftPercent: number;
134
+ endPercent: number;
135
+ widthPercent: number;
136
+ durationMs: number;
137
+ effectiveEnd: number;
138
+ clippedStart: boolean;
139
+ clippedEnd: boolean;
140
+ };
141
+ /**
142
+ * Which spans a query names. Space-separated terms, any of which may
143
+ * match; `"a phrase"` keeps its spaces; `-key` leaves an attribute out
144
+ * of the matching. A term matches the name, the service, the type, the
145
+ * kind, the exact id, or an attribute's key, value, or `key=value`.
146
+ * `null` for a blank query.
147
+ */
148
+ export declare function filterSpans(query: string | null | undefined, spans: readonly SpanData[]): Set<string> | null;
@@ -1,21 +1,107 @@
1
1
  import { ComponentProps, ReactNode, Ref } from 'react';
2
- import { TraceSpan } from './layout';
3
- export interface TraceRootProps extends Omit<ComponentProps<"div">, "children" | "onSelect" | "title"> {
4
- spans: readonly TraceSpan[];
2
+ import { SpanView } from './span-tree';
3
+ import { TraceWaterfallSpan } from './layout';
4
+ /**
5
+ * Left edge of a row's bullet, in px, from the card. The detail panel
6
+ * uses this so its content starts under that dot at any depth.
7
+ */
8
+ export declare function traceBulletInset(depth: number): string;
9
+ export type TraceWaterfallShortcuts = "focus" | "global" | false;
10
+ export interface TraceWaterfallProps extends Omit<ComponentProps<"section">, "children" | "onSelect" | "title"> {
11
+ spans: readonly TraceWaterfallSpan[];
12
+ /**
13
+ * The current time on the spans' clock, for running spans: their bars
14
+ * and durations grow to it. Omit and the waterfall ticks on its own
15
+ * while any span runs; pass it to drive the redraw yourself.
16
+ */
17
+ now?: number;
5
18
  /** The span whose details are open — it keeps the wash. */
6
19
  selectedId?: string | null;
7
- /** Rows select on click when given. */
8
- onSelect?: (id: string) => void;
20
+ /**
21
+ * Rows select on click when given. A second click on the selected
22
+ * row, or Escape, passes `null` so the host can close the detail.
23
+ */
24
+ onSelect?: (id: string | null) => void;
25
+ /**
26
+ * Facts for the selected span, drawn as a full-width panel under that
27
+ * row. Omit (or return `null`) for selection without a panel.
28
+ */
29
+ renderSpanDetail?: (span: TraceWaterfallSpan) => ReactNode;
9
30
  /** Spans folded at first (uncontrolled). */
10
31
  defaultCollapsed?: readonly string[];
11
32
  /** Spans folded (controlled). */
12
33
  collapsed?: readonly string[];
13
34
  onCollapsedChange?: (ids: string[]) => void;
14
- /** A title row above the axis — "Waterfall". Omit for none. */
35
+ /**
36
+ * The fold controls in the header — one level and all, each way.
37
+ * Shown while the trace has a parent to fold. @default true
38
+ */
39
+ foldControls?: boolean;
40
+ /**
41
+ * A search box in a toolbar band above the header — `true`, or the
42
+ * placeholder it should show. Terms are space-separated and any may
43
+ * match; `"a phrase"` keeps its spaces; `-key` leaves an attribute out;
44
+ * `key=value` matches exactly. Matches take a wash and their folded
45
+ * ancestors open. Pass `query` with `onQueryChange` to own the text.
46
+ */
47
+ search?: boolean | string;
48
+ query?: string;
49
+ onQueryChange?: (query: string) => void;
50
+ /** The zoom window at first (uncontrolled), as fractions of the trace. */
51
+ defaultView?: SpanView;
52
+ /** The zoom window (controlled). */
53
+ view?: SpanView;
54
+ onViewChange?: (view: SpanView) => void;
55
+ /**
56
+ * Where the keyboard shortcuts listen: `"focus"` while focus is inside
57
+ * the card (click it, or tab to a row), `"global"` anywhere on the page
58
+ * outside a field, `false` for none. @default "focus"
59
+ */
60
+ shortcuts?: TraceWaterfallShortcuts;
61
+ /** The lead on the axis row — "Waterfall". Omit for none. */
15
62
  title?: ReactNode;
16
- ref?: Ref<HTMLDivElement>;
63
+ /**
64
+ * Optional copy after `title` on the axis row. Totals live in the
65
+ * footer by default; pass a node here only to put something else
66
+ * beside the title.
67
+ */
68
+ summary?: ReactNode;
69
+ /**
70
+ * Wall-clock start of the trace, in ms. The footer prints
71
+ * `Started 12:59:07.206` when this is a readable time.
72
+ */
73
+ startedAt?: number;
74
+ /**
75
+ * The legend and totals under the rows. Default when there are
76
+ * spans; pass `null` to hide it, or a node (`<Trace.Waterfall.Footer />`)
77
+ * to replace it.
78
+ */
79
+ footer?: ReactNode;
80
+ ref?: Ref<HTMLElement>;
81
+ }
82
+ declare function Waterfall({ spans, now: nowProp, selectedId, onSelect, renderSpanDetail, defaultCollapsed, collapsed, onCollapsedChange, foldControls, search, query: queryProp, onQueryChange, defaultView, view, onViewChange, shortcuts, title, summary, startedAt, footer, className, ...props }: TraceWaterfallProps): import("react").JSX.Element;
83
+ export declare function footerTotals({ spanCount, errorCount, orphanCount, durationMs, window, startedAt, }: {
84
+ spanCount: number;
85
+ errorCount: number;
86
+ orphanCount?: number;
87
+ durationMs: number;
88
+ /** The zoom window, in ms from the trace's start, when zoomed. */
89
+ window?: {
90
+ startMs: number;
91
+ endMs: number;
92
+ } | null;
93
+ startedAt?: number;
94
+ }): string[];
95
+ export interface WaterfallFooterProps extends ComponentProps<"div"> {
96
+ /** Wall-clock start; falls back to the waterfall's `startedAt`. */
97
+ startedAt?: number;
17
98
  }
18
- declare function Root({ spans, selectedId, onSelect, defaultCollapsed, collapsed: collapsedProp, onCollapsedChange, title, className, ...props }: TraceRootProps): import("react").JSX.Element;
99
+ /**
100
+ * The waterfall's legend and totals. Renders inside `Trace.Waterfall`
101
+ * so it can read the spans; pass it as `footer` to keep the default
102
+ * chrome when replacing the slot.
103
+ */
104
+ declare function WaterfallFooter({ startedAt: startedAtProp, className, ...props }: WaterfallFooterProps): import("react").JSX.Element;
19
105
  export type TraceLogLevel = "debug" | "info" | "warn" | "error";
20
106
  export interface TraceLog {
21
107
  id?: string;
@@ -29,7 +115,7 @@ export interface TraceLog {
29
115
  export interface TraceLogsProps extends Omit<ComponentProps<"section">, "children" | "title"> {
30
116
  logs?: readonly TraceLog[] | null;
31
117
  /** The spans, to name the one each line was written in. */
32
- spans?: readonly TraceSpan[];
118
+ spans?: readonly Pick<TraceWaterfallSpan, "id" | "name">[];
33
119
  /** @default "Logs" */
34
120
  title?: ReactNode;
35
121
  ref?: Ref<HTMLElement>;
@@ -40,14 +126,10 @@ export interface TraceLogsProps extends Omit<ComponentProps<"section">, "childre
40
126
  * trace with no logs shows no empty block.
41
127
  */
42
128
  declare function Logs({ logs, spans, title, className, ...props }: TraceLogsProps): import("react").JSX.Element | null;
43
- /**
44
- * ```tsx
45
- * <Trace.Root spans={spans} selectedId={id} onSelect={setId} title="Waterfall" />
46
- * <Trace.Logs logs={logs} spans={spans} />
47
- * ```
48
- */
49
129
  export declare const Trace: {
50
- Root: typeof Root;
130
+ Waterfall: typeof Waterfall & {
131
+ Footer: typeof WaterfallFooter;
132
+ };
51
133
  Logs: typeof Logs;
52
134
  };
53
135
  export {};
@@ -8,6 +8,7 @@
8
8
  export * from './utils';
9
9
  export * from './motion';
10
10
  export * from './components/button';
11
+ export * from './components/date-range-picker';
11
12
  export * from './components/input';
12
13
  export * from './components/input-group';
13
14
  export * from './components/card';