@photon-ai/pho-ui 2.16.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js +75 -0
- package/dist/chunks/IconArrowsMinimize-BfPUGuCB.js.map +1 -0
- package/dist/chunks/IconChevronUp-CrpWSgIl.js +11 -0
- package/dist/chunks/IconChevronUp-CrpWSgIl.js.map +1 -0
- package/dist/chunks/{bar-chart-BJfr3eyd.js → bar-chart-DIALC2_z.js} +2 -2
- package/dist/chunks/bar-chart-DIALC2_z.js.map +1 -0
- package/dist/chunks/basic-page-CYDwfVjO.js +1749 -0
- package/dist/chunks/basic-page-CYDwfVjO.js.map +1 -0
- package/dist/chunks/calendar-4OFiCLAv.js +292 -0
- package/dist/chunks/calendar-4OFiCLAv.js.map +1 -0
- package/dist/chunks/card-DhDwtSi9.js +56 -0
- package/dist/chunks/card-DhDwtSi9.js.map +1 -0
- package/dist/chunks/code-block-BuDIo8Q0.js +197 -0
- package/dist/chunks/code-block-BuDIo8Q0.js.map +1 -0
- package/dist/chunks/collapsible-if7ncPbI.js +28 -0
- package/dist/chunks/collapsible-if7ncPbI.js.map +1 -0
- package/dist/chunks/{command-Ck8IAgV7.js → command-CTYrSz9a.js} +2 -2
- package/dist/chunks/{command-Ck8IAgV7.js.map → command-CTYrSz9a.js.map} +1 -1
- package/dist/chunks/data-table-DcwCgXJU.js +293 -0
- package/dist/chunks/data-table-DcwCgXJU.js.map +1 -0
- package/dist/chunks/date-picker-Bwa6J4ik.js +381 -0
- package/dist/chunks/date-picker-Bwa6J4ik.js.map +1 -0
- package/dist/chunks/{dialog-BxKACOj5.js → dialog-BwfUFn6B.js} +2 -2
- package/dist/chunks/{dialog-BxKACOj5.js.map → dialog-BwfUFn6B.js.map} +1 -1
- package/dist/chunks/{error-D0yoFxCv.js → error-BAQgnde7.js} +2 -2
- package/dist/chunks/{error-D0yoFxCv.js.map → error-BAQgnde7.js.map} +1 -1
- package/dist/chunks/{filter-bar-Cjjq38xo.js → filter-bar-D9lBBr4z.js} +3 -3
- package/dist/chunks/{filter-bar-Cjjq38xo.js.map → filter-bar-D9lBBr4z.js.map} +1 -1
- package/dist/chunks/ghost-search-BvBFa9su.js +25 -0
- package/dist/chunks/ghost-search-BvBFa9su.js.map +1 -0
- package/dist/chunks/{line-chart-CUR3AxrR.js → line-chart-VuMYKzW3.js} +2 -2
- package/dist/chunks/{line-chart-CUR3AxrR.js.map → line-chart-VuMYKzW3.js.map} +1 -1
- package/dist/chunks/{log-list-0AXnjFrk.js → log-list-BERiO4UJ.js} +2 -2
- package/dist/chunks/{log-list-0AXnjFrk.js.map → log-list-BERiO4UJ.js.map} +1 -1
- package/dist/chunks/scroll-area-Zik8t1Mk.js +168 -0
- package/dist/chunks/scroll-area-Zik8t1Mk.js.map +1 -0
- package/dist/chunks/sidebar-DRPe5CAh.js +306 -0
- package/dist/chunks/sidebar-DRPe5CAh.js.map +1 -0
- package/dist/chunks/{toast-iSf6NuAS.js → toast-72Wwlzg9.js} +2 -2
- package/dist/chunks/{toast-iSf6NuAS.js.map → toast-72Wwlzg9.js.map} +1 -1
- package/dist/chunks/trace-Ba1RMBfk.js +1645 -0
- package/dist/chunks/trace-Ba1RMBfk.js.map +1 -0
- package/dist/chunks/use-measure-C-i54AC6.js +629 -0
- package/dist/chunks/use-measure-C-i54AC6.js.map +1 -0
- package/dist/components/bar-chart.js +1 -1
- package/dist/components/calendar.js +5 -0
- package/dist/components/card.js +1 -1
- package/dist/components/code-block.js +1 -1
- package/dist/components/collapsible.js +2 -25
- package/dist/components/command.js +1 -1
- package/dist/components/data-table.js +9 -8
- package/dist/components/date-picker.js +6 -0
- package/dist/components/dialog.js +1 -1
- package/dist/components/error.js +1 -1
- package/dist/components/filter-bar.js +1 -1
- package/dist/components/line-chart.js +1 -1
- package/dist/components/log-list.js +1 -1
- package/dist/components/scroll-area.js +1 -1
- package/dist/components/toast.js +1 -1
- package/dist/components/trace.js +41 -6
- package/dist/index.js +164 -121
- package/dist/primitives.js +3 -3
- package/dist/sections/basic-page.js +5 -5
- package/dist/sections/sidebar.js +9 -6
- package/dist/src/components/calendar/calendar.d.ts +36 -0
- package/dist/src/components/calendar/index.d.ts +2 -0
- package/dist/src/components/card/card.d.ts +5 -1
- package/dist/src/components/chart/scale.d.ts +6 -1
- package/dist/src/components/code-block/code-block.d.ts +24 -5
- package/dist/src/components/code-block/index.d.ts +1 -1
- package/dist/src/components/data-table/data-table.d.ts +54 -13
- package/dist/src/components/date-picker/date-picker.d.ts +97 -0
- package/dist/src/components/date-picker/index.d.ts +2 -0
- package/dist/src/components/scroll-area/scroll-area.d.ts +9 -1
- package/dist/src/components/trace/decorations.d.ts +32 -0
- package/dist/src/components/trace/index.d.ts +5 -2
- package/dist/src/components/trace/layout.d.ts +57 -29
- package/dist/src/components/trace/span-primitive.d.ts +168 -0
- package/dist/src/components/trace/span-tree.d.ts +148 -0
- package/dist/src/components/trace/trace.d.ts +98 -16
- package/dist/src/index.d.ts +2 -0
- package/dist/src/sections/basic-page/basic-page.d.ts +95 -7
- package/dist/src/sections/basic-page/index.d.ts +1 -1
- package/dist/src/sections/sidebar/index.d.ts +1 -1
- package/dist/src/sections/sidebar/sidebar.d.ts +72 -0
- package/dist/src/utils/ghost-search.d.ts +11 -0
- package/package.json +10 -1
- package/dist/chunks/bar-chart-BJfr3eyd.js.map +0 -1
- package/dist/chunks/basic-page-CMJuM5iA.js +0 -1650
- package/dist/chunks/basic-page-CMJuM5iA.js.map +0 -1
- package/dist/chunks/card-DSW3Uhag.js +0 -56
- package/dist/chunks/card-DSW3Uhag.js.map +0 -1
- package/dist/chunks/code-block-CdozzaHM.js +0 -139
- package/dist/chunks/code-block-CdozzaHM.js.map +0 -1
- package/dist/chunks/data-table-CHLJfGkS.js +0 -279
- package/dist/chunks/data-table-CHLJfGkS.js.map +0 -1
- package/dist/chunks/scroll-area-BO-9PMM7.js +0 -167
- package/dist/chunks/scroll-area-BO-9PMM7.js.map +0 -1
- package/dist/chunks/sidebar-DVzZsCts.js +0 -223
- package/dist/chunks/sidebar-DVzZsCts.js.map +0 -1
- package/dist/chunks/trace-CbH0IohX.js +0 -314
- package/dist/chunks/trace-CbH0IohX.js.map +0 -1
- package/dist/chunks/use-measure-CMVgLouO.js +0 -616
- package/dist/chunks/use-measure-CMVgLouO.js.map +0 -1
- package/dist/components/collapsible.js.map +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { DateRange, PropsBase } from 'react-day-picker';
|
|
3
|
+
import { InputSize } from '../input';
|
|
4
|
+
/** The trigger wears Input's sizes so the two line up in one form. */
|
|
5
|
+
export type DatePickerSize = InputSize;
|
|
6
|
+
/**
|
|
7
|
+
* How fine the time is asked for, and read back. Omit it for a date alone.
|
|
8
|
+
* The value is always a `Date`; the granularity says which of its parts the
|
|
9
|
+
* viewer sets, and everything below is zeroed.
|
|
10
|
+
*/
|
|
11
|
+
export type DatePickerTime = "hour" | "minute" | "second";
|
|
12
|
+
/**
|
|
13
|
+
* The shape to type, in this locale's own order — `mm/dd/yyyy`,
|
|
14
|
+
* `yyyy-mm-dd`, `dd.mm.yyyy`. Lowercase, the way a browser's own date field
|
|
15
|
+
* writes it, so the two paths read alike.
|
|
16
|
+
*/
|
|
17
|
+
export declare function dateFieldMask(locales?: Intl.LocalesArgument, time?: DatePickerTime): string;
|
|
18
|
+
/**
|
|
19
|
+
* The figures in the field — `09/12/2026`, or `09/10/2026 – 09/13/2026` for a
|
|
20
|
+
* span, in the viewer's locale. An empty or half-finished range prints just
|
|
21
|
+
* the day that is settled; nothing selected prints nothing. Pass `time` to
|
|
22
|
+
* print the clock too, at the precision that was asked for.
|
|
23
|
+
*
|
|
24
|
+
* Figures rather than words (`Sep 12, 2026`) because the field is typed into:
|
|
25
|
+
* a month's name is the one part of a date nobody wants to spell.
|
|
26
|
+
*/
|
|
27
|
+
export declare function formatDateLabel(value: Date | DateRange | undefined, locales?: Intl.LocalesArgument, time?: DatePickerTime): string;
|
|
28
|
+
interface DatePickerBaseProps {
|
|
29
|
+
/** Field label (associated for accessibility). */
|
|
30
|
+
label?: ReactNode;
|
|
31
|
+
/** Helper text below the field; rendered in the error color when `invalid`. */
|
|
32
|
+
hint?: ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* What the field shows until something is chosen.
|
|
35
|
+
* @default the shape to type, in this locale's order (`mm/dd/yyyy`)
|
|
36
|
+
*/
|
|
37
|
+
placeholder?: string;
|
|
38
|
+
/** Render the invalid state (error ring + error-colored hint). */
|
|
39
|
+
invalid?: boolean;
|
|
40
|
+
disabled?: boolean;
|
|
41
|
+
/** Marks the label with the required asterisk. */
|
|
42
|
+
required?: boolean;
|
|
43
|
+
/** Size variant. @default "md" */
|
|
44
|
+
size?: DatePickerSize;
|
|
45
|
+
/**
|
|
46
|
+
* Ask for a time as well as a day, this fine. `hour` sets the hour and
|
|
47
|
+
* zeroes the rest, `minute` the hour and minute, `second` all three. Omit
|
|
48
|
+
* it and the value is midnight on the chosen day.
|
|
49
|
+
*/
|
|
50
|
+
time?: DatePickerTime;
|
|
51
|
+
/** Locale for the trigger's words. Defaults to the viewer's. */
|
|
52
|
+
locales?: Intl.LocalesArgument;
|
|
53
|
+
/**
|
|
54
|
+
* Everything else React DayPicker takes — `disabled` days, `startMonth` /
|
|
55
|
+
* `endMonth`, `numberOfMonths`, `weekStartsOn`, `captionLayout`.
|
|
56
|
+
*/
|
|
57
|
+
calendarProps?: PropsBase;
|
|
58
|
+
/** Id for the trigger, if the page needs its own. */
|
|
59
|
+
id?: string;
|
|
60
|
+
/** Class applied to the trigger. */
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface DatePickerSingleProps extends DatePickerBaseProps {
|
|
64
|
+
/** @default "single" */
|
|
65
|
+
mode?: "single";
|
|
66
|
+
value?: Date;
|
|
67
|
+
defaultValue?: Date;
|
|
68
|
+
onValueChange?: (value: Date | undefined) => void;
|
|
69
|
+
}
|
|
70
|
+
export interface DatePickerRangeProps extends DatePickerBaseProps {
|
|
71
|
+
mode: "range";
|
|
72
|
+
value?: DateRange;
|
|
73
|
+
defaultValue?: DateRange;
|
|
74
|
+
onValueChange?: (value: DateRange | undefined) => void;
|
|
75
|
+
}
|
|
76
|
+
export type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps;
|
|
77
|
+
/**
|
|
78
|
+
* Date Picker — a field that shows the chosen date and opens a `Calendar` to
|
|
79
|
+
* change it. `mode="range"` picks a span instead of a day; the popover stays
|
|
80
|
+
* open until both ends are down.
|
|
81
|
+
*
|
|
82
|
+
* The value is a `Date` (or a `{ from, to }` range), never a string: pass
|
|
83
|
+
* `value` to control it, `defaultValue` to let it keep its own. Clearing is
|
|
84
|
+
* built in — clicking the chosen day again unsets it.
|
|
85
|
+
*
|
|
86
|
+
* `time` asks for the clock as well, to the hour, the minute, or the second.
|
|
87
|
+
*
|
|
88
|
+
* On a touch device the field hands off to the system picker — the OS wheel or
|
|
89
|
+
* dialog, which people already know — as long as the rules the page set are
|
|
90
|
+
* ones it can enforce. A weekday rule or a predicate keeps the calendar, which
|
|
91
|
+
* can; so does `mode="range"`, which no system picker offers.
|
|
92
|
+
*/
|
|
93
|
+
export declare function DatePicker(props: DatePickerProps): import("react").JSX.Element;
|
|
94
|
+
export declare namespace DatePicker {
|
|
95
|
+
var displayName: string;
|
|
96
|
+
}
|
|
97
|
+
export {};
|
|
@@ -17,7 +17,15 @@ declare function Content({ inset, insetTop, insetBottom, style, ref, ...props }:
|
|
|
17
17
|
insetBottom?: number | string;
|
|
18
18
|
ref?: Ref<HTMLDivElement>;
|
|
19
19
|
}): import("react").JSX.Element;
|
|
20
|
-
declare function Root({ className, children, ...props }: StyledProps<typeof BaseScrollArea.Root>
|
|
20
|
+
declare function Root({ className, children, fade, ...props }: StyledProps<typeof BaseScrollArea.Root> & {
|
|
21
|
+
/**
|
|
22
|
+
* Progressive edge fade (blur + wash). Leave on except for code
|
|
23
|
+
* surfaces — CodeBlock is the only caller that turns it off, so
|
|
24
|
+
* glyphs hard-clip at the border.
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
fade?: boolean;
|
|
28
|
+
}): import("react").JSX.Element;
|
|
21
29
|
declare function Viewport({ className, ref, ...props }: StyledProps<typeof BaseScrollArea.Viewport>): import("react").JSX.Element;
|
|
22
30
|
declare function Scrollbar({ className, ...props }: StyledProps<typeof BaseScrollArea.Scrollbar>): import("react").JSX.Element;
|
|
23
31
|
declare function Thumb({ className, ...props }: StyledProps<typeof BaseScrollArea.Thumb>): import("react").JSX.Element;
|
|
@@ -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
|
|
2
|
-
export {
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
|
9
|
+
export interface TraceWaterfallSpan {
|
|
7
10
|
id: string;
|
|
8
11
|
/** The span this one runs inside. Absent (or unknown) means a root. */
|
|
9
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
/**
|
|
18
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
|
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;
|