fumadocs-test-reports 0.1.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.
@@ -0,0 +1,81 @@
1
+ import { Duration, StdoutPanel } from "../../ui/primitives.js";
2
+ import { getLabels } from "./labels.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { Accordion, Accordions } from "fumadocs-ui/components/accordion";
5
+ //#region src/tunit/ui/trace-timeline.tsx
6
+ function TUnitTraceTimeline({ spans, locale }) {
7
+ const labels = getLabels(locale);
8
+ const origin = Math.min(...spans.map((span) => span.startTimeMs));
9
+ const extent = Math.max(...spans.map((span) => span.startTimeMs + span.durationMs)) - origin || 1;
10
+ const byId = new Map(spans.map((span) => [`${span.traceId}:${span.spanId}`, span]));
11
+ function depth(span) {
12
+ const seen = /* @__PURE__ */ new Set();
13
+ let current = span;
14
+ let level = 0;
15
+ while (current?.parentSpanId && level < 8) {
16
+ const key = `${current.traceId}:${current.parentSpanId}`;
17
+ if (seen.has(key)) break;
18
+ seen.add(key);
19
+ current = byId.get(key);
20
+ if (current) level++;
21
+ }
22
+ return level;
23
+ }
24
+ return /* @__PURE__ */ jsx(Accordions, {
25
+ className: "ftr-traces",
26
+ children: spans.toSorted((a, b) => a.startTimeMs - b.startTimeMs).map((span) => /* @__PURE__ */ jsxs(Accordion, {
27
+ className: "ftr-span",
28
+ value: `${span.traceId}:${span.spanId}`,
29
+ title: /* @__PURE__ */ jsxs("span", {
30
+ className: "ftr-span-heading",
31
+ children: [
32
+ /* @__PURE__ */ jsx("span", {
33
+ style: { paddingInlineStart: `${depth(span) * 12}px` },
34
+ children: span.name
35
+ }),
36
+ /* @__PURE__ */ jsx("small", { children: /* @__PURE__ */ jsx(Duration, {
37
+ value: span.durationMs,
38
+ unknownLabel: labels.unknown
39
+ }) }),
40
+ /* @__PURE__ */ jsx("span", {
41
+ className: "ftr-track",
42
+ "aria-hidden": "true",
43
+ children: /* @__PURE__ */ jsx("span", { style: {
44
+ marginInlineStart: `${(span.startTimeMs - origin) / extent * 100}%`,
45
+ width: `${span.durationMs / extent * 100}%`
46
+ } })
47
+ })
48
+ ]
49
+ }),
50
+ children: [
51
+ /* @__PURE__ */ jsxs("dl", {
52
+ className: "ftr-fields",
53
+ children: [
54
+ /* @__PURE__ */ jsx("dt", { children: "Trace ID" }),
55
+ /* @__PURE__ */ jsx("dd", { children: span.traceId }),
56
+ /* @__PURE__ */ jsx("dt", { children: "Span ID" }),
57
+ /* @__PURE__ */ jsx("dd", { children: span.spanId }),
58
+ span.parentSpanId && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Parent ID" }), /* @__PURE__ */ jsx("dd", { children: span.parentSpanId })] }),
59
+ span.source && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: labels.traceSource }), /* @__PURE__ */ jsx("dd", { children: span.source })] }),
60
+ span.kind && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Kind" }), /* @__PURE__ */ jsx("dd", { children: span.kind })] }),
61
+ span.status && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Status" }), /* @__PURE__ */ jsxs("dd", { children: [span.status, span.statusMessage ? `: ${span.statusMessage}` : ""] })] }),
62
+ span.tags?.map((tag, i) => /* @__PURE__ */ jsxs("div", {
63
+ className: "ftr-field",
64
+ children: [/* @__PURE__ */ jsx("dt", { children: tag.key }), /* @__PURE__ */ jsx("dd", { children: tag.value })]
65
+ }, i))
66
+ ]
67
+ }),
68
+ !!span.events?.length && /* @__PURE__ */ jsx(StdoutPanel, {
69
+ content: JSON.stringify(span.events, null, 2),
70
+ title: "Events"
71
+ }),
72
+ !!span.links?.length && /* @__PURE__ */ jsx(StdoutPanel, {
73
+ content: JSON.stringify(span.links, null, 2),
74
+ title: "Links"
75
+ })
76
+ ]
77
+ }, `${span.traceId}:${span.spanId}`))
78
+ });
79
+ }
80
+ //#endregion
81
+ export { TUnitTraceTimeline };
@@ -0,0 +1,2 @@
1
+ import { BadgeTone, Duration, DurationProps, ErrorDetail, ErrorDetailProps, StatusBadge, StatusBadgeProps, StdoutPanel, StdoutPanelProps } from "./primitives.js";
2
+ export { type BadgeTone, Duration, type DurationProps, ErrorDetail, type ErrorDetailProps, StatusBadge, type StatusBadgeProps, StdoutPanel, type StdoutPanelProps };
@@ -0,0 +1,2 @@
1
+ import { Duration, ErrorDetail, StatusBadge, StdoutPanel } from "./primitives.js";
2
+ export { Duration, ErrorDetail, StatusBadge, StdoutPanel };
@@ -0,0 +1,32 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/ui/primitives.d.ts
3
+ /** Visual tone only; the presenter owns the meaning of the framework's status. */
4
+ export type BadgeTone = 'success' | 'danger' | 'neutral' | 'info';
5
+ export interface StatusBadgeProps {
6
+ status: string;
7
+ tone?: BadgeTone;
8
+ className?: string;
9
+ }
10
+ export declare function StatusBadge({ status, tone, className }: StatusBadgeProps): import("react").JSX.Element;
11
+ export interface DurationProps {
12
+ /** Milliseconds. Missing or null means unknown; zero is a known zero. */
13
+ value?: number | null;
14
+ unknownLabel?: string;
15
+ className?: string;
16
+ }
17
+ export declare function Duration({ value, unknownLabel, className }: DurationProps): import("react").JSX.Element;
18
+ export interface ErrorDetailProps {
19
+ message?: string | null;
20
+ type?: string | null;
21
+ stack?: string | null;
22
+ children?: ReactNode;
23
+ }
24
+ export declare function ErrorDetail({ message, type, stack, children }: ErrorDetailProps): import("react").JSX.Element;
25
+ export interface StdoutPanelProps {
26
+ content?: string | null;
27
+ title?: string;
28
+ emptyLabel?: string;
29
+ }
30
+ /** Plain text only, suitable for stdout or stderr. */
31
+ export declare function StdoutPanel({ content, title, emptyLabel }: StdoutPanelProps): import("react").JSX.Element;
32
+ //#endregion
@@ -0,0 +1,48 @@
1
+ import { Callout } from "fumadocs-ui/components/callout";
2
+ import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/ui/primitives.tsx
5
+ function StatusBadge({ status, tone = "neutral", className = "" }) {
6
+ return /* @__PURE__ */ jsx("span", {
7
+ className: `ftr-ui ftr-badge ftr-tone-${tone} ${className}`,
8
+ children: status
9
+ });
10
+ }
11
+ function Duration({ value, unknownLabel = "Unknown", className }) {
12
+ const text = value == null ? unknownLabel : value >= 1e3 ? `${(value / 1e3).toFixed(2)} s` : `${value.toFixed(1)} ms`;
13
+ return /* @__PURE__ */ jsx("span", {
14
+ className,
15
+ children: text
16
+ });
17
+ }
18
+ function ErrorDetail({ message, type, stack, children }) {
19
+ return /* @__PURE__ */ jsxs(Callout, {
20
+ type: "error",
21
+ title: type ?? void 0,
22
+ className: "ftr-ui ftr-error-details",
23
+ children: [
24
+ message != null && /* @__PURE__ */ jsx("p", {
25
+ className: "ftr-error-message",
26
+ children: message
27
+ }),
28
+ stack != null && /* @__PURE__ */ jsx(StdoutPanel, { content: stack }),
29
+ children
30
+ ]
31
+ });
32
+ }
33
+ /** Plain text only, suitable for stdout or stderr. */
34
+ function StdoutPanel({ content, title, emptyLabel = "No output recorded." }) {
35
+ return /* @__PURE__ */ jsx("div", {
36
+ className: "ftr-ui ftr-output-panel",
37
+ children: content == null ? /* @__PURE__ */ jsx("p", {
38
+ className: "ftr-empty",
39
+ children: emptyLabel
40
+ }) : /* @__PURE__ */ jsx(CodeBlock, {
41
+ title,
42
+ className: "ftr-codeblock",
43
+ children: /* @__PURE__ */ jsx(Pre, { children: /* @__PURE__ */ jsx("code", { children: content }) })
44
+ })
45
+ });
46
+ }
47
+ //#endregion
48
+ export { Duration, ErrorDetail, StatusBadge, StdoutPanel };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "fumadocs-test-reports",
3
+ "version": "0.1.0",
4
+ "description": "Test report adapters and React UI for Fumadocs",
5
+ "keywords": [
6
+ "fumadocs",
7
+ "react",
8
+ "test-report",
9
+ "tunit"
10
+ ],
11
+ "license": "MIT",
12
+ "files": [
13
+ "dist",
14
+ "css"
15
+ ],
16
+ "type": "module",
17
+ "sideEffects": [
18
+ "./css/**/*.css"
19
+ ],
20
+ "exports": {
21
+ "./tunit": "./dist/tunit/index.js",
22
+ "./tunit/ui": "./dist/tunit/ui/index.js",
23
+ "./ui": "./dist/ui/index.js",
24
+ "./css/*": "./css/*"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public",
28
+ "registry": "https://registry.npmjs.org/"
29
+ },
30
+ "scripts": {
31
+ "build": "tsdown",
32
+ "clean": "rimraf dist",
33
+ "dev": "tsdown --watch --clean false",
34
+ "prepack": "pnpm build",
35
+ "lint": "oxlint .",
36
+ "types:check": "tsc --noEmit"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "26.6.4",
40
+ "@types/react": "19.3.0",
41
+ "@types/react-dom": "19.3.0",
42
+ "fumadocs-core": "16.16.2",
43
+ "fumadocs-ui": "npm:@fumadocs/base-ui@16.16.2",
44
+ "react": "19.3.0",
45
+ "react-dom": "19.3.0",
46
+ "tsdown": "0.23.0"
47
+ },
48
+ "peerDependencies": {
49
+ "fumadocs-ui": "^16.16.2",
50
+ "react": "^19.2.0"
51
+ }
52
+ }