@flanksource/clicky-ui
Version:
Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.
196 lines (195 loc) • 6.47 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import { useMemo, useState, useEffect } from "react";
import { Clicky } from "../data/Clicky.js";
import { JsonView } from "../data/JsonView.js";
function CommandOutput({
response,
bare = false,
onTableRowClick,
getTableRowHref,
isTableRowClickable
}) {
const text = response.stdout || response.output || "";
const ct = response.contentType || "application/json";
const parsed = useMemo(() => {
if (response.parsed !== void 0) return response.parsed;
if (!text.trim()) return null;
try {
return JSON.parse(text.trim());
} catch {
return null;
}
}, [response.parsed, text]);
const output = /* @__PURE__ */ jsx(
OutputBody,
{
text,
parsed,
contentType: ct,
bare,
...response.blob ? { blob: response.blob } : {},
...onTableRowClick ? { onTableRowClick } : {},
...getTableRowHref ? { getTableRowHref } : {},
...isTableRowClickable ? { isTableRowClickable } : {}
}
);
if (bare) return output;
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx(
"span",
{
className: response.success ? "rounded-md border px-2 py-0.5 text-xs" : "rounded-md bg-destructive px-2 py-0.5 text-xs text-destructive-foreground",
children: response.success ? "Success" : "Failed"
}
),
/* @__PURE__ */ jsxs("span", { className: "rounded-md border px-2 py-0.5 font-mono text-xs", children: [
"exit ",
response.exit_code
] }),
ct !== "application/json" && /* @__PURE__ */ jsx("span", { className: "rounded-md bg-secondary px-2 py-0.5 font-mono text-xs text-secondary-foreground", children: ct.split(";")[0] }),
response.error && /* @__PURE__ */ jsx("span", { className: "text-sm text-destructive", children: response.error })
] }),
response.cli && /* @__PURE__ */ jsxs("pre", { className: "overflow-x-auto rounded-md bg-muted p-3 font-mono text-xs", children: [
"$ ",
response.cli
] }),
output
] });
}
function OutputBody({
text,
parsed,
contentType,
blob,
bare,
onTableRowClick,
getTableRowHref,
isTableRowClickable
}) {
const ct = (contentType.split(";")[0] ?? "").trim();
if (ct === "application/pdf" && blob) {
return /* @__PURE__ */ jsx(PdfOutput, { blob });
}
if (ct === "application/clicky+json" || ct === "application/json+clicky") {
const clicky = /* @__PURE__ */ jsx(
Clicky,
{
data: parsed ?? text,
...onTableRowClick ? { onTableRowClick } : {},
...getTableRowHref ? { getTableRowHref } : {},
...isTableRowClickable ? { isTableRowClickable } : {}
}
);
const detailOutput = /* @__PURE__ */ jsx("div", { className: "detail-output", children: clicky });
if (bare) return detailOutput;
return /* @__PURE__ */ jsx(
Tabs,
{
defaultValue: "rendered",
tabs: [
{ value: "rendered", label: "Rendered", content: detailOutput },
{ value: "raw", label: "Raw", content: /* @__PURE__ */ jsx(TextOutput, { text }) }
]
}
);
}
if (ct === "text/html") {
const iframe = /* @__PURE__ */ jsx(
"iframe",
{
srcDoc: text,
className: "h-[600px] w-full rounded-md border bg-white",
sandbox: "allow-same-origin"
}
);
if (bare) return iframe;
return /* @__PURE__ */ jsx(
Tabs,
{
defaultValue: "preview",
tabs: [
{ value: "preview", label: "Preview", content: iframe },
{ value: "source", label: "Source", content: /* @__PURE__ */ jsx(TextOutput, { text }) }
]
}
);
}
if (parsed) {
const json = /* @__PURE__ */ jsx(JsonViewer, { data: parsed });
if (bare) return json;
return /* @__PURE__ */ jsx(
Tabs,
{
defaultValue: "output",
tabs: [
{ value: "output", label: "Output", content: json },
{ value: "raw", label: "Raw", content: /* @__PURE__ */ jsx(TextOutput, { text }) }
]
}
);
}
if (text) return /* @__PURE__ */ jsx(TextOutput, { text });
return /* @__PURE__ */ jsx("p", { className: "py-4 text-sm text-muted-foreground", children: "No output" });
}
function PdfOutput({ blob }) {
const [url, setURL] = useState("");
useEffect(() => {
const next = URL.createObjectURL(blob);
setURL(next);
return () => URL.revokeObjectURL(next);
}, [blob]);
if (!url) return null;
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
/* @__PURE__ */ jsx(
"a",
{
href: url,
download: "output.pdf",
className: "inline-block rounded-md border px-3 py-1.5 text-sm hover:bg-accent",
children: "Download PDF"
}
),
/* @__PURE__ */ jsx("iframe", { src: url, className: "h-[600px] w-full rounded-md border" })
] });
}
function JsonViewer({ data }) {
return /* @__PURE__ */ jsx("div", { className: "overflow-auto rounded-md bg-muted p-4 font-mono text-xs", children: /* @__PURE__ */ jsx(JsonView, { data, defaultOpenDepth: Number.MAX_SAFE_INTEGER }) });
}
function TextOutput({
text,
variant = "default"
}) {
return /* @__PURE__ */ jsx(
"pre",
{
className: `max-h-96 overflow-auto whitespace-pre-wrap rounded-md p-4 font-mono text-sm ${variant === "error" ? "bg-red-50 text-red-800 dark:bg-red-950 dark:text-red-200" : "bg-muted"}`,
children: text
}
);
}
function Tabs({
defaultValue,
tabs
}) {
const [value, setValue] = useState(defaultValue);
const active = tabs.find((tab) => tab.value === value) ?? tabs[0];
if (!active) return null;
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
/* @__PURE__ */ jsx("div", { className: "inline-flex rounded-md border bg-muted p-1", children: tabs.map((tab) => /* @__PURE__ */ jsx(
"button",
{
type: "button",
className: `rounded px-2 py-1 text-xs ${tab.value === active.value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground"}`,
onClick: () => setValue(tab.value),
children: tab.label
},
tab.value
)) }),
/* @__PURE__ */ jsx("div", { children: active.content })
] });
}
export {
CommandOutput
};
//# sourceMappingURL=CommandOutput.js.map