@flanksource/clicky-ui
Version:
Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.
158 lines (157 loc) • 8.32 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
import "react";
import { Icon } from "../Icon.js";
import { parseInlineJsonContextValue, parseDiagnosticsStackTrace, isApplicationStackFrame, compactStackPath } from "./error-diagnostics.js";
function ErrorDetails({ diagnostics, renderJsonContext }) {
const scalarContext = diagnostics.context.filter(
([, value]) => !parseInlineJsonContextValue(value)
);
const jsonContext = diagnostics.context.map(([label, value]) => ({ label, value, data: parseInlineJsonContextValue(value) })).filter(
(entry) => entry.data !== null
);
return /* @__PURE__ */ jsxs("details", { className: "group rounded-md border border-destructive/30 bg-destructive/5", children: [
/* @__PURE__ */ jsxs("summary", { className: "flex cursor-pointer list-none items-start gap-2 p-3", children: [
/* @__PURE__ */ jsx(Icon, { name: "lucide:triangle-alert", className: "mt-0.5 shrink-0 text-destructive" }),
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-destructive", children: "Error" }),
/* @__PURE__ */ jsx("div", { className: "mt-1 whitespace-pre-wrap text-sm text-destructive", children: diagnostics.message })
] }),
/* @__PURE__ */ jsx(
Icon,
{
name: "lucide:chevron-right",
className: "mt-0.5 shrink-0 text-muted-foreground transition-transform group-open:rotate-90"
}
)
] }),
/* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-t border-destructive/20 p-3 pt-2", children: [
(diagnostics.trace || diagnostics.time) && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-wrap gap-2", children: [
diagnostics.trace && /* @__PURE__ */ jsx(CopyBadge, { label: "Trace", value: diagnostics.trace, className: "max-w-full" }),
diagnostics.time && /* @__PURE__ */ jsxs("span", { className: "inline-flex max-w-full items-center overflow-hidden rounded-md border border-border bg-background/80 text-xs", children: [
/* @__PURE__ */ jsx("span", { className: "shrink-0 bg-muted px-2 py-1 font-medium text-muted-foreground", children: "Time" }),
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate px-2 py-1 font-mono text-foreground", children: diagnostics.time })
] })
] }),
diagnostics.context.length > 0 && /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
/* @__PURE__ */ jsx("div", { className: "mb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Context" }),
scalarContext.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: scalarContext.map(([label, value]) => /* @__PURE__ */ jsx(CopyBadge, { label, value }, `${label}:${value}`)) }),
jsonContext.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 grid gap-2", children: jsonContext.map(
(entry) => renderJsonContext ? /* @__PURE__ */ jsx("span", { children: renderJsonContext(entry) }, `${entry.label}:${entry.value}`) : /* @__PURE__ */ jsx(
CopyBadge,
{
label: entry.label,
value: entry.value
},
`${entry.label}:${entry.value}`
)
) })
] }),
diagnostics.stacktrace && /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
/* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex min-w-0 items-center justify-between gap-3", children: [
/* @__PURE__ */ jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Stack trace" }),
/* @__PURE__ */ jsxs(
"button",
{
type: "button",
onClick: () => copyText(diagnostics.stacktrace ?? ""),
className: "inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground",
children: [
/* @__PURE__ */ jsx(Icon, { name: "lucide:copy" }),
"copy"
]
}
)
] }),
/* @__PURE__ */ jsx(PrettyStackTrace, { stacktrace: diagnostics.stacktrace })
] })
] })
] });
}
function PrettyStackTrace({ stacktrace }) {
const parsed = parseDiagnosticsStackTrace(stacktrace);
if (parsed.frames.length === 0) {
return /* @__PURE__ */ jsx("pre", { className: "max-h-72 overflow-auto whitespace-pre-wrap rounded-md bg-slate-950 p-3 font-mono text-xs leading-5 text-slate-200", children: stacktrace });
}
return /* @__PURE__ */ jsxs("div", { className: "max-h-96 min-h-40 overflow-auto rounded-md border border-border bg-background p-2", children: [
/* @__PURE__ */ jsx("div", { className: "mb-2 flex items-center justify-between gap-2 text-[11px] text-muted-foreground", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
/* @__PURE__ */ jsx("span", { className: "rounded-full bg-red-100 px-2 py-0.5 text-red-700", children: "error" }),
/* @__PURE__ */ jsxs("span", { children: [
parsed.frames.length,
" frames"
] })
] }) }),
parsed.headline && /* @__PURE__ */ jsx("div", { className: "mb-2 rounded-md bg-red-50 px-2 py-1.5 font-mono text-[11px] leading-4 text-red-700", children: parsed.headline }),
/* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: parsed.frames.map((frame, index) => /* @__PURE__ */ jsx(StackFrameRow, { frame, index }, `${frame.file}:${frame.line}:${index}`)) }),
parsed.unparsed.length > 0 && /* @__PURE__ */ jsx("pre", { className: "mt-2 whitespace-pre-wrap rounded bg-muted p-2 font-mono text-[11px] leading-4 text-muted-foreground", children: parsed.unparsed.join("\n") })
] });
}
function StackFrameRow({ frame, index }) {
const appFrame = isApplicationStackFrame(frame.file);
return /* @__PURE__ */ jsx(
"button",
{
type: "button",
onClick: () => copyText(frame.raw),
title: "Copy stack frame",
className: [
"block w-full rounded px-1.5 py-1 text-left hover:bg-accent/50",
appFrame ? "text-foreground" : "text-muted-foreground"
].join(" "),
children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-1.5", children: [
/* @__PURE__ */ jsx(
Icon,
{
name: appFrame ? "codicon:symbol-method" : "codicon:debug-step-over",
className: "mt-0.5 shrink-0 text-[11px]"
}
),
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "break-all font-mono text-[11px] font-semibold leading-4", children: [
/* @__PURE__ */ jsxs("span", { className: "mr-2 text-[10px] font-normal opacity-60", children: [
"#",
index + 1
] }),
frame.functionName || "unknown function",
/* @__PURE__ */ jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-80", children: [
compactStackPath(frame.file),
":",
frame.line
] })
] }) })
] })
}
);
}
function CopyBadge({
label,
value,
className = ""
}) {
return /* @__PURE__ */ jsxs(
"button",
{
type: "button",
onClick: () => copyText(value),
title: `Copy ${label}`,
className: [
"inline-flex max-w-full items-center overflow-hidden rounded-md border border-border bg-background/80 text-left text-xs hover:border-primary/40 hover:bg-background",
className
].filter(Boolean).join(" "),
children: [
/* @__PURE__ */ jsx("span", { className: "shrink-0 bg-muted px-2 py-1 font-medium text-muted-foreground", children: label }),
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate px-2 py-1 font-mono text-foreground", children: value }),
/* @__PURE__ */ jsx(Icon, { name: "lucide:copy", className: "mr-1.5 h-3 w-3 shrink-0 text-muted-foreground" })
]
}
);
}
function copyText(value) {
if (typeof navigator !== "undefined" && navigator.clipboard) {
void navigator.clipboard.writeText(value);
}
}
export {
CopyBadge,
ErrorDetails,
PrettyStackTrace
};
//# sourceMappingURL=ErrorDetails.js.map