@assistant-ui/react-o11y 0.0.16 → 0.0.18
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/context/SpanByIndexProvider.js.map +1 -1
- package/dist/primitives/span/SpanChildren.js +1 -1
- package/dist/primitives/span/SpanChildren.js.map +1 -1
- package/dist/primitives/span/SpanCollapseToggle.js +1 -1
- package/dist/primitives/span/SpanCollapseToggle.js.map +1 -1
- package/dist/primitives/span/SpanIndent.js +1 -1
- package/dist/primitives/span/SpanName.js +1 -1
- package/dist/primitives/span/SpanRoot.js +1 -1
- package/dist/primitives/span/SpanStatusIndicator.js +1 -1
- package/dist/primitives/span/SpanTypeBadge.js +1 -1
- package/dist/resources/SpanResource.d.ts.map +1 -1
- package/dist/resources/SpanResource.js +9 -8
- package/dist/resources/SpanResource.js.map +1 -1
- package/package.json +7 -7
- package/src/resources/SpanResource.tsx +93 -92
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpanByIndexProvider.js","names":[],"sources":["../../src/context/SpanByIndexProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport { useAui, AuiProvider, Derived } from \"@assistant-ui/store\";\n\nexport const SpanByIndexProvider: FC<PropsWithChildren<{ index: number }>> = ({\n index,\n children,\n}) => {\n const parentAui = useAui();\n\n const aui = useAui({\n span: Derived({\n source: \"span\",\n query: { index },\n get: () => parentAui.span().child({ index }),\n }),\n });\n\n return <AuiProvider value={aui}>{children}</AuiProvider>;\n};\n"],"mappings":";;;AAGA,MAAa,uBAAiE,EAC5E,OACA,eACI;CACJ,MAAM,YAAY,OAAO;CAUzB,OAAO,oBAAC,aAAD;EAAa,OARR,OAAO,EACjB,MAAM,QAAQ;GACZ,QAAQ;GACR,OAAO,EAAE,MAAM;GACf,WAAW,UAAU,KAAK,
|
|
1
|
+
{"version":3,"file":"SpanByIndexProvider.js","names":[],"sources":["../../src/context/SpanByIndexProvider.tsx"],"sourcesContent":["import type { FC, PropsWithChildren } from \"react\";\nimport { useAui, AuiProvider, Derived } from \"@assistant-ui/store\";\n\nexport const SpanByIndexProvider: FC<PropsWithChildren<{ index: number }>> = ({\n index,\n children,\n}) => {\n const parentAui = useAui();\n\n const aui = useAui({\n span: Derived({\n source: \"span\",\n query: { index },\n get: () => parentAui.span().child({ index }),\n }),\n });\n\n return <AuiProvider value={aui}>{children}</AuiProvider>;\n};\n"],"mappings":";;;AAGA,MAAa,uBAAiE,EAC5E,OACA,eACI;CACJ,MAAM,YAAY,OAAO;CAUzB,OAAO,oBAAC,aAAD;EAAa,OARR,OAAO,EACjB,MAAM,QAAQ;GACZ,QAAQ;GACR,OAAO,EAAE,MAAM;GACf,WAAW,UAAU,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC;EAC7C,CAAC,EACH,CAE6B;EAAI;CAAsB,CAAA;AACzD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SpanByIndexProvider } from "../../context/SpanByIndexProvider.js";
|
|
2
|
-
import { memo, useMemo } from "react";
|
|
2
|
+
import { memo, useMemo } from "@assistant-ui/tap/react-shim";
|
|
3
3
|
import { RenderChildrenWithAccessor, useAuiState } from "@assistant-ui/store";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/primitives/span/SpanChildren.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpanChildren.js","names":[],"sources":["../../../src/primitives/span/SpanChildren.tsx"],"sourcesContent":["import {\n type ComponentType,\n type FC,\n type ReactNode,\n memo,\n useMemo,\n} from \"react\";\nimport { RenderChildrenWithAccessor, useAuiState } from \"@assistant-ui/store\";\nimport type { SpanState } from \"../../o11y-scope\";\nimport { SpanByIndexProvider } from \"../../context/SpanByIndexProvider\";\n\ntype SpanChildrenComponentConfig = {\n Span: ComponentType;\n};\n\nexport namespace SpanPrimitiveChildren {\n export type Props =\n | {\n components: SpanChildrenComponentConfig;\n children?: never;\n }\n | {\n /** Render function called for each child span. Receives the span. */\n children: (value: { span: SpanState }) => ReactNode;\n components?: never;\n };\n}\n\nexport namespace SpanPrimitiveChildByIndex {\n export type Props = {\n index: number;\n components: SpanChildrenComponentConfig;\n };\n}\n\nexport const SpanPrimitiveChildByIndex: FC<SpanPrimitiveChildByIndex.Props> =\n memo(\n ({ index, components }) => {\n return (\n <SpanByIndexProvider index={index}>\n <components.Span />\n </SpanByIndexProvider>\n );\n },\n (prev, next) =>\n prev.index === next.index &&\n prev.components.Span === next.components.Span,\n );\n\nSpanPrimitiveChildByIndex.displayName = \"SpanPrimitive.ChildByIndex\";\n\nconst SpanPrimitiveChildrenInner: FC<{\n children: (value: { span: SpanState }) => ReactNode;\n}> = ({ children }) => {\n const childrenLength = useAuiState((s) => s.span.children.length);\n\n return useMemo(() => {\n if (childrenLength === 0) return null;\n return Array.from({ length: childrenLength }, (_, index) => (\n <SpanByIndexProvider key={index} index={index}>\n <RenderChildrenWithAccessor\n getItemState={(aui) => aui.span().getState()}\n >\n {(getItem) =>\n children({\n get span() {\n return getItem();\n },\n })\n }\n </RenderChildrenWithAccessor>\n </SpanByIndexProvider>\n ));\n }, [childrenLength, children]);\n};\n\nconst SpanPrimitiveChildrenImpl: FC<SpanPrimitiveChildren.Props> = ({\n components,\n children,\n}) => {\n if (components) {\n return (\n <SpanPrimitiveChildrenInner>\n {() => <components.Span />}\n </SpanPrimitiveChildrenInner>\n );\n }\n return <SpanPrimitiveChildrenInner>{children}</SpanPrimitiveChildrenInner>;\n};\n\nexport const SpanPrimitiveChildren: FC<SpanPrimitiveChildren.Props> = memo(\n SpanPrimitiveChildrenImpl,\n (prev, next) => {\n if (prev.children || next.children) {\n return prev.children === next.children;\n }\n return prev.components!.Span === next.components!.Span;\n },\n);\n\nSpanPrimitiveChildren.displayName = \"SpanPrimitive.Children\";\n"],"mappings":";;;;;AAmCA,MAAa,4BACX,MACG,EAAE,OAAO,iBAAiB;CACzB,OACE,oBAAC,qBAAD;EAA4B;YAC1B,oBAAC,WAAW,MAAZ,CAAkB,CAAA;CACC,CAAA;AAEzB,IACC,MAAM,SACL,KAAK,UAAU,KAAK,SACpB,KAAK,WAAW,SAAS,KAAK,WAAW,IAC7C;AAEF,0BAA0B,cAAc;AAExC,MAAM,8BAEA,EAAE,eAAe;CACrB,MAAM,iBAAiB,aAAa,MAAM,EAAE,KAAK,SAAS,MAAM;CAEhE,OAAO,cAAc;EACnB,IAAI,mBAAmB,GAAG,OAAO;EACjC,OAAO,MAAM,KAAK,EAAE,QAAQ,eAAe,IAAI,GAAG,UAChD,oBAAC,qBAAD;GAAwC;aACtC,oBAAC,4BAAD;IACE,eAAe,QAAQ,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"SpanChildren.js","names":[],"sources":["../../../src/primitives/span/SpanChildren.tsx"],"sourcesContent":["import {\n type ComponentType,\n type FC,\n type ReactNode,\n memo,\n useMemo,\n} from \"react\";\nimport { RenderChildrenWithAccessor, useAuiState } from \"@assistant-ui/store\";\nimport type { SpanState } from \"../../o11y-scope\";\nimport { SpanByIndexProvider } from \"../../context/SpanByIndexProvider\";\n\ntype SpanChildrenComponentConfig = {\n Span: ComponentType;\n};\n\nexport namespace SpanPrimitiveChildren {\n export type Props =\n | {\n components: SpanChildrenComponentConfig;\n children?: never;\n }\n | {\n /** Render function called for each child span. Receives the span. */\n children: (value: { span: SpanState }) => ReactNode;\n components?: never;\n };\n}\n\nexport namespace SpanPrimitiveChildByIndex {\n export type Props = {\n index: number;\n components: SpanChildrenComponentConfig;\n };\n}\n\nexport const SpanPrimitiveChildByIndex: FC<SpanPrimitiveChildByIndex.Props> =\n memo(\n ({ index, components }) => {\n return (\n <SpanByIndexProvider index={index}>\n <components.Span />\n </SpanByIndexProvider>\n );\n },\n (prev, next) =>\n prev.index === next.index &&\n prev.components.Span === next.components.Span,\n );\n\nSpanPrimitiveChildByIndex.displayName = \"SpanPrimitive.ChildByIndex\";\n\nconst SpanPrimitiveChildrenInner: FC<{\n children: (value: { span: SpanState }) => ReactNode;\n}> = ({ children }) => {\n const childrenLength = useAuiState((s) => s.span.children.length);\n\n return useMemo(() => {\n if (childrenLength === 0) return null;\n return Array.from({ length: childrenLength }, (_, index) => (\n <SpanByIndexProvider key={index} index={index}>\n <RenderChildrenWithAccessor\n getItemState={(aui) => aui.span().getState()}\n >\n {(getItem) =>\n children({\n get span() {\n return getItem();\n },\n })\n }\n </RenderChildrenWithAccessor>\n </SpanByIndexProvider>\n ));\n }, [childrenLength, children]);\n};\n\nconst SpanPrimitiveChildrenImpl: FC<SpanPrimitiveChildren.Props> = ({\n components,\n children,\n}) => {\n if (components) {\n return (\n <SpanPrimitiveChildrenInner>\n {() => <components.Span />}\n </SpanPrimitiveChildrenInner>\n );\n }\n return <SpanPrimitiveChildrenInner>{children}</SpanPrimitiveChildrenInner>;\n};\n\nexport const SpanPrimitiveChildren: FC<SpanPrimitiveChildren.Props> = memo(\n SpanPrimitiveChildrenImpl,\n (prev, next) => {\n if (prev.children || next.children) {\n return prev.children === next.children;\n }\n return prev.components!.Span === next.components!.Span;\n },\n);\n\nSpanPrimitiveChildren.displayName = \"SpanPrimitive.Children\";\n"],"mappings":";;;;;AAmCA,MAAa,4BACX,MACG,EAAE,OAAO,iBAAiB;CACzB,OACE,oBAAC,qBAAD;EAA4B;YAC1B,oBAAC,WAAW,MAAZ,CAAkB,CAAA;CACC,CAAA;AAEzB,IACC,MAAM,SACL,KAAK,UAAU,KAAK,SACpB,KAAK,WAAW,SAAS,KAAK,WAAW,IAC7C;AAEF,0BAA0B,cAAc;AAExC,MAAM,8BAEA,EAAE,eAAe;CACrB,MAAM,iBAAiB,aAAa,MAAM,EAAE,KAAK,SAAS,MAAM;CAEhE,OAAO,cAAc;EACnB,IAAI,mBAAmB,GAAG,OAAO;EACjC,OAAO,MAAM,KAAK,EAAE,QAAQ,eAAe,IAAI,GAAG,UAChD,oBAAC,qBAAD;GAAwC;aACtC,oBAAC,4BAAD;IACE,eAAe,QAAQ,IAAI,KAAK,CAAC,CAAC,SAAS;eAEzC,YACA,SAAS,EACP,IAAI,OAAO;KACT,OAAO,QAAQ;IACjB,EACF,CAAC;GAEuB,CAAA;EACT,GAZK,KAYL,CACtB;CACH,GAAG,CAAC,gBAAgB,QAAQ,CAAC;AAC/B;AAEA,MAAM,6BAA8D,EAClE,YACA,eACI;CACJ,IAAI,YACF,OACE,oBAAC,4BAAD,EAAA,gBACS,oBAAC,WAAW,MAAZ,CAAkB,CAAA,EACC,CAAA;CAGhC,OAAO,oBAAC,4BAAD,EAA6B,SAAqC,CAAA;AAC3E;AAEA,MAAa,wBAAyD,KACpE,4BACC,MAAM,SAAS;CACd,IAAI,KAAK,YAAY,KAAK,UACxB,OAAO,KAAK,aAAa,KAAK;CAEhC,OAAO,KAAK,WAAY,SAAS,KAAK,WAAY;AACpD,CACF;AAEA,sBAAsB,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpanCollapseToggle.js","names":[],"sources":["../../../src/primitives/span/SpanCollapseToggle.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n forwardRef,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\n\nexport namespace SpanPrimitiveCollapseToggle {\n export type Element = ComponentRef<typeof Primitive.button>;\n export type Props = ComponentPropsWithoutRef<typeof Primitive.button>;\n}\n\nexport const SpanPrimitiveCollapseToggle = forwardRef<\n SpanPrimitiveCollapseToggle.Element,\n SpanPrimitiveCollapseToggle.Props\n>((props, ref) => {\n const hasChildren = useAuiState((s) => s.span.hasChildren);\n const isCollapsed = useAuiState((s) => s.span.isCollapsed);\n const aui = useAui();\n\n if (!hasChildren) return null;\n\n return (\n <Primitive.button\n type=\"button\"\n {...props}\n ref={ref}\n data-collapsed={isCollapsed}\n onClick={(e) => {\n e.stopPropagation();\n aui.span().toggleCollapse();\n props.onClick?.(e);\n }}\n />\n );\n});\n\nSpanPrimitiveCollapseToggle.displayName = \"SpanPrimitive.CollapseToggle\";\n"],"mappings":";;;;;AAaA,MAAa,8BAA8B,YAGxC,OAAO,QAAQ;CAChB,MAAM,cAAc,aAAa,MAAM,EAAE,KAAK,WAAW;CACzD,MAAM,cAAc,aAAa,MAAM,EAAE,KAAK,WAAW;CACzD,MAAM,MAAM,OAAO;CAEnB,IAAI,CAAC,aAAa,OAAO;CAEzB,OACE,oBAAC,UAAU,QAAX;EACE,MAAK;EACL,GAAI;EACC;EACL,kBAAgB;EAChB,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"SpanCollapseToggle.js","names":[],"sources":["../../../src/primitives/span/SpanCollapseToggle.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n forwardRef,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\n\nexport namespace SpanPrimitiveCollapseToggle {\n export type Element = ComponentRef<typeof Primitive.button>;\n export type Props = ComponentPropsWithoutRef<typeof Primitive.button>;\n}\n\nexport const SpanPrimitiveCollapseToggle = forwardRef<\n SpanPrimitiveCollapseToggle.Element,\n SpanPrimitiveCollapseToggle.Props\n>((props, ref) => {\n const hasChildren = useAuiState((s) => s.span.hasChildren);\n const isCollapsed = useAuiState((s) => s.span.isCollapsed);\n const aui = useAui();\n\n if (!hasChildren) return null;\n\n return (\n <Primitive.button\n type=\"button\"\n {...props}\n ref={ref}\n data-collapsed={isCollapsed}\n onClick={(e) => {\n e.stopPropagation();\n aui.span().toggleCollapse();\n props.onClick?.(e);\n }}\n />\n );\n});\n\nSpanPrimitiveCollapseToggle.displayName = \"SpanPrimitive.CollapseToggle\";\n"],"mappings":";;;;;AAaA,MAAa,8BAA8B,YAGxC,OAAO,QAAQ;CAChB,MAAM,cAAc,aAAa,MAAM,EAAE,KAAK,WAAW;CACzD,MAAM,cAAc,aAAa,MAAM,EAAE,KAAK,WAAW;CACzD,MAAM,MAAM,OAAO;CAEnB,IAAI,CAAC,aAAa,OAAO;CAEzB,OACE,oBAAC,UAAU,QAAX;EACE,MAAK;EACL,GAAI;EACC;EACL,kBAAgB;EAChB,UAAU,MAAM;GACd,EAAE,gBAAgB;GAClB,IAAI,KAAK,CAAC,CAAC,eAAe;GAC1B,MAAM,UAAU,CAAC;EACnB;CACD,CAAA;AAEL,CAAC;AAED,4BAA4B,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpanResource.d.ts","names":[],"sources":["../../src/resources/SpanResource.tsx"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"SpanResource.d.ts","names":[],"sources":["../../src/resources/SpanResource.tsx"],"mappings":";;;KAOY,QAAA;EACV,EAAA;EACA,YAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA;EACA,SAAA;EACA,OAAA;EACA,SAAA;AAAA;AAAA,cA0HW,YAAA,GAAY,KAAA;SAGhB,QAAA;AAAA;SAAA,QAAA;AAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useMemo, useState } from "@assistant-ui/tap/react-shim";
|
|
2
|
+
import { useClientLookup } from "@assistant-ui/store";
|
|
3
|
+
import { resource, withKey } from "@assistant-ui/tap";
|
|
3
4
|
//#region src/resources/SpanResource.tsx
|
|
4
5
|
function calculateDepth(spanId, spanMap, cache) {
|
|
5
6
|
const cached = cache.get(spanId);
|
|
@@ -73,7 +74,7 @@ function buildFlatList(allSpans, collapsedIds) {
|
|
|
73
74
|
dfs(null);
|
|
74
75
|
return result;
|
|
75
76
|
}
|
|
76
|
-
const SpanChildResource = resource(({ span, timeRange, onToggleCollapse })
|
|
77
|
+
const SpanChildResource = resource(function SpanChildResource({ span, timeRange, onToggleCollapse }) {
|
|
77
78
|
const state = {
|
|
78
79
|
...span,
|
|
79
80
|
children: [],
|
|
@@ -89,10 +90,10 @@ const SpanChildResource = resource(({ span, timeRange, onToggleCollapse }) => {
|
|
|
89
90
|
}
|
|
90
91
|
};
|
|
91
92
|
});
|
|
92
|
-
const SpanResource = resource(({ spans })
|
|
93
|
-
const { allSpans, timeRange } =
|
|
94
|
-
const [collapsedIds, setCollapsedIds] =
|
|
95
|
-
const visibleSpans =
|
|
93
|
+
const SpanResource = resource(function SpanResource({ spans }) {
|
|
94
|
+
const { allSpans, timeRange } = useMemo(() => enrichSpans(spans), [spans]);
|
|
95
|
+
const [collapsedIds, setCollapsedIds] = useState(() => /* @__PURE__ */ new Set());
|
|
96
|
+
const visibleSpans = useMemo(() => buildFlatList(allSpans, collapsedIds), [allSpans, collapsedIds]);
|
|
96
97
|
const toggleCollapse = (spanId) => {
|
|
97
98
|
setCollapsedIds((prev) => {
|
|
98
99
|
const next = new Set(prev);
|
|
@@ -101,7 +102,7 @@ const SpanResource = resource(({ spans }) => {
|
|
|
101
102
|
return next;
|
|
102
103
|
});
|
|
103
104
|
};
|
|
104
|
-
const lookup =
|
|
105
|
+
const lookup = useClientLookup(() => visibleSpans.map((span) => withKey(span.id, SpanChildResource({
|
|
105
106
|
span,
|
|
106
107
|
timeRange,
|
|
107
108
|
onToggleCollapse: toggleCollapse
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SpanResource.js","names":[],"sources":["../../src/resources/SpanResource.tsx"],"sourcesContent":["import \"../o11y-scope\";\n\nimport {
|
|
1
|
+
{"version":3,"file":"SpanResource.js","names":[],"sources":["../../src/resources/SpanResource.tsx"],"sourcesContent":["import \"../o11y-scope\";\n\nimport { useMemo, useState } from \"react\";\nimport { resource, withKey } from \"@assistant-ui/tap\";\nimport { useClientLookup, type ClientOutput } from \"@assistant-ui/store\";\nimport type { SpanItemState, SpanState } from \"../o11y-scope\";\n\nexport type SpanData = {\n id: string;\n parentSpanId: string | null;\n name: string;\n type: string;\n status: \"running\" | \"completed\" | \"failed\" | \"skipped\";\n startedAt: number;\n endedAt: number | null;\n latencyMs: number | null;\n};\n\nfunction calculateDepth(\n spanId: string,\n spanMap: Map<string, SpanData>,\n cache: Map<string, number>,\n): number {\n const cached = cache.get(spanId);\n if (cached !== undefined) return cached;\n\n const span = spanMap.get(spanId);\n if (!span?.parentSpanId) {\n cache.set(spanId, 0);\n return 0;\n }\n\n const depth = calculateDepth(span.parentSpanId, spanMap, cache) + 1;\n cache.set(spanId, depth);\n return depth;\n}\n\nfunction enrichSpans(rawSpans: SpanData[]): {\n allSpans: Map<string, SpanItemState>;\n timeRange: { min: number; max: number };\n} {\n const spanMap = new Map<string, SpanData>();\n for (const span of rawSpans) {\n spanMap.set(span.id, span);\n }\n\n const depthCache = new Map<string, number>();\n const childrenCount = new Map<string, number>();\n for (const span of rawSpans) {\n if (span.parentSpanId) {\n childrenCount.set(\n span.parentSpanId,\n (childrenCount.get(span.parentSpanId) ?? 0) + 1,\n );\n }\n }\n\n const allSpans = new Map<string, SpanItemState>();\n let min = Infinity;\n let max = -Infinity;\n\n for (const span of rawSpans) {\n const depth = calculateDepth(span.id, spanMap, depthCache);\n const hasChildren = (childrenCount.get(span.id) ?? 0) > 0;\n allSpans.set(span.id, { ...span, depth, hasChildren, isCollapsed: false });\n\n if (span.startedAt < min) min = span.startedAt;\n const end = span.endedAt ?? Date.now();\n if (end > max) max = end;\n }\n\n if (min === Infinity) min = Date.now();\n if (max === -Infinity) max = Date.now();\n if (max === min) max = min + 100;\n\n return { allSpans, timeRange: { min, max } };\n}\n\nfunction buildFlatList(\n allSpans: Map<string, SpanItemState>,\n collapsedIds: Set<string>,\n): SpanItemState[] {\n const children = new Map<string | null, SpanItemState[]>();\n for (const span of allSpans.values()) {\n const parent = span.parentSpanId ?? null;\n let group = children.get(parent);\n if (!group) {\n group = [];\n children.set(parent, group);\n }\n group.push(span);\n }\n\n for (const group of children.values()) {\n group.sort((a, b) => a.startedAt - b.startedAt);\n }\n\n const result: SpanItemState[] = [];\n function dfs(parentId: string | null) {\n const kids = children.get(parentId);\n if (!kids) return;\n for (const span of kids) {\n result.push({ ...span, isCollapsed: collapsedIds.has(span.id) });\n if (!collapsedIds.has(span.id)) {\n dfs(span.id);\n }\n }\n }\n dfs(null);\n return result;\n}\n\nconst SpanChildResource = resource(function SpanChildResource({\n span,\n timeRange,\n onToggleCollapse,\n}: {\n span: SpanItemState;\n timeRange: { min: number; max: number };\n onToggleCollapse: (spanId: string) => void;\n}): ClientOutput<\"span\"> {\n const state: SpanState = {\n ...span,\n children: [],\n timeRange,\n };\n return {\n getState: () => state,\n child: () => {\n throw new Error(\"child spans do not have children in flat mode\");\n },\n toggleCollapse: () => {\n onToggleCollapse(span.id);\n },\n };\n});\n\nexport const SpanResource = resource(function SpanResource({\n spans,\n}: {\n spans: SpanData[];\n}): ClientOutput<\"span\"> {\n const { allSpans, timeRange } = useMemo(() => enrichSpans(spans), [spans]);\n\n const [collapsedIds, setCollapsedIds] = useState<Set<string>>(\n () => new Set(),\n );\n\n const visibleSpans = useMemo(\n () => buildFlatList(allSpans, collapsedIds),\n [allSpans, collapsedIds],\n );\n\n const toggleCollapse = (spanId: string) => {\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(spanId)) {\n next.delete(spanId);\n } else {\n next.add(spanId);\n }\n return next;\n });\n };\n\n const lookup = useClientLookup(\n () =>\n visibleSpans.map((span) =>\n withKey(\n span.id,\n SpanChildResource({\n span,\n timeRange,\n onToggleCollapse: toggleCollapse,\n }),\n ),\n ),\n [visibleSpans, timeRange, toggleCollapse],\n );\n\n const rootState: SpanState = {\n id: \"__root__\",\n parentSpanId: null,\n name: \"\",\n type: \"root\",\n status: \"completed\",\n startedAt: timeRange.min,\n endedAt: timeRange.max,\n latencyMs: timeRange.max - timeRange.min,\n depth: -1,\n hasChildren: lookup.state.length > 0,\n isCollapsed: false,\n children: lookup.state,\n timeRange,\n };\n\n return {\n getState: () => rootState,\n child: lookup.get,\n toggleCollapse: () => {\n // Root span collapse is a no-op\n },\n };\n});\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-o11y",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Observability primitives for @assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"observability",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
],
|
|
29
29
|
"sideEffects": false,
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@radix-ui/react-primitive": "^2.1.
|
|
32
|
-
"@assistant-ui/store": "0.2.
|
|
33
|
-
"@assistant-ui/tap": "0.
|
|
31
|
+
"@radix-ui/react-primitive": "^2.1.5",
|
|
32
|
+
"@assistant-ui/store": "0.2.14",
|
|
33
|
+
"@assistant-ui/tap": "0.6.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@types/react": "*",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@types/react": "^19.2.
|
|
46
|
-
"react": "^19.2.
|
|
47
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
45
|
+
"@types/react": "^19.2.17",
|
|
46
|
+
"react": "^19.2.7",
|
|
47
|
+
"@assistant-ui/x-buildutils": "0.0.12"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import "../o11y-scope";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { resource, withKey } from "@assistant-ui/tap";
|
|
5
|
+
import { useClientLookup, type ClientOutput } from "@assistant-ui/store";
|
|
5
6
|
import type { SpanItemState, SpanState } from "../o11y-scope";
|
|
6
7
|
|
|
7
8
|
export type SpanData = {
|
|
@@ -109,95 +110,95 @@ function buildFlatList(
|
|
|
109
110
|
return result;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
const SpanChildResource = resource(
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
const SpanChildResource = resource(function SpanChildResource({
|
|
114
|
+
span,
|
|
115
|
+
timeRange,
|
|
116
|
+
onToggleCollapse,
|
|
117
|
+
}: {
|
|
118
|
+
span: SpanItemState;
|
|
119
|
+
timeRange: { min: number; max: number };
|
|
120
|
+
onToggleCollapse: (spanId: string) => void;
|
|
121
|
+
}): ClientOutput<"span"> {
|
|
122
|
+
const state: SpanState = {
|
|
123
|
+
...span,
|
|
124
|
+
children: [],
|
|
115
125
|
timeRange,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
visibleSpans.map((span) =>
|
|
167
|
-
withKey(
|
|
168
|
-
span.id,
|
|
169
|
-
SpanChildResource({
|
|
170
|
-
span,
|
|
171
|
-
timeRange,
|
|
172
|
-
onToggleCollapse: toggleCollapse,
|
|
173
|
-
}),
|
|
174
|
-
),
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
getState: () => state,
|
|
129
|
+
child: () => {
|
|
130
|
+
throw new Error("child spans do not have children in flat mode");
|
|
131
|
+
},
|
|
132
|
+
toggleCollapse: () => {
|
|
133
|
+
onToggleCollapse(span.id);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export const SpanResource = resource(function SpanResource({
|
|
139
|
+
spans,
|
|
140
|
+
}: {
|
|
141
|
+
spans: SpanData[];
|
|
142
|
+
}): ClientOutput<"span"> {
|
|
143
|
+
const { allSpans, timeRange } = useMemo(() => enrichSpans(spans), [spans]);
|
|
144
|
+
|
|
145
|
+
const [collapsedIds, setCollapsedIds] = useState<Set<string>>(
|
|
146
|
+
() => new Set(),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const visibleSpans = useMemo(
|
|
150
|
+
() => buildFlatList(allSpans, collapsedIds),
|
|
151
|
+
[allSpans, collapsedIds],
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const toggleCollapse = (spanId: string) => {
|
|
155
|
+
setCollapsedIds((prev) => {
|
|
156
|
+
const next = new Set(prev);
|
|
157
|
+
if (next.has(spanId)) {
|
|
158
|
+
next.delete(spanId);
|
|
159
|
+
} else {
|
|
160
|
+
next.add(spanId);
|
|
161
|
+
}
|
|
162
|
+
return next;
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const lookup = useClientLookup(
|
|
167
|
+
() =>
|
|
168
|
+
visibleSpans.map((span) =>
|
|
169
|
+
withKey(
|
|
170
|
+
span.id,
|
|
171
|
+
SpanChildResource({
|
|
172
|
+
span,
|
|
173
|
+
timeRange,
|
|
174
|
+
onToggleCollapse: toggleCollapse,
|
|
175
|
+
}),
|
|
175
176
|
),
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
);
|
|
177
|
+
),
|
|
178
|
+
[visibleSpans, timeRange, toggleCollapse],
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
const rootState: SpanState = {
|
|
182
|
+
id: "__root__",
|
|
183
|
+
parentSpanId: null,
|
|
184
|
+
name: "",
|
|
185
|
+
type: "root",
|
|
186
|
+
status: "completed",
|
|
187
|
+
startedAt: timeRange.min,
|
|
188
|
+
endedAt: timeRange.max,
|
|
189
|
+
latencyMs: timeRange.max - timeRange.min,
|
|
190
|
+
depth: -1,
|
|
191
|
+
hasChildren: lookup.state.length > 0,
|
|
192
|
+
isCollapsed: false,
|
|
193
|
+
children: lookup.state,
|
|
194
|
+
timeRange,
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
getState: () => rootState,
|
|
199
|
+
child: lookup.get,
|
|
200
|
+
toggleCollapse: () => {
|
|
201
|
+
// Root span collapse is a no-op
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
});
|