@flanksource/clicky-ui
Version:
Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.
106 lines (105 loc) • 3.86 kB
JavaScript
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
import { useState } from "react";
import { Button } from "../components/button.js";
import { Icon } from "../data/Icon.js";
import { Modal } from "../overlay/Modal.js";
import { CommandForm } from "./CommandForm.js";
import { CommandOutput } from "./CommandOutput.js";
import { InlineError } from "./InlineError.js";
function OperationActionDialog({
operation,
client,
initialValues,
label,
defaultAccept = "application/clicky+json",
onNavigateAction
}) {
const [open, setOpen] = useState(false);
const [isExecuting, setIsExecuting] = useState(false);
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
async function handleExecute(params, headers) {
if (onNavigateAction) {
const href = hrefForOperationAction(operation.path, params);
if (!href) return;
const separator = href.includes("?") ? "&" : "?";
onNavigateAction(`${href}${separator}autoRun=1`);
return;
}
setIsExecuting(true);
setError(null);
setResponse(null);
try {
const result = await client.executeCommand(operation.path, operation.method, params, headers);
setResponse(result);
} catch (err) {
setError(err);
} finally {
setIsExecuting(false);
}
}
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setOpen(true), children: [
/* @__PURE__ */ jsx(Icon, { name: "codicon:play" }),
label
] }),
/* @__PURE__ */ jsx(Modal, { open, onClose: () => setOpen(false), title: label, size: "lg", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
/* @__PURE__ */ jsx(
CommandForm,
{
parameters: operation.operation.parameters ?? [],
onExecute: handleExecute,
isPending: isExecuting,
method: operation.method,
path: operation.path,
accept: defaultAccept,
initialValues
}
),
error ? /* @__PURE__ */ jsx(InlineError, { title: `Failed to execute ${operation.path}`, error }) : response ? /* @__PURE__ */ jsx(CommandOutput, { response }) : null
] }) })
] });
}
function hrefForOperationAction(path, params) {
const nextParams = { ...params };
const args = parseArgsParam(params.args);
let route = apiPathToRoutePath(path);
for (const [index, name] of pathParamNames(path).entries()) {
const value = nextParams[name] || args[index];
if (!value) return void 0;
route = route.replace(`:${name}`, encodeURIComponent(value));
delete nextParams[name];
if (!nextParams[name] && value === args[index]) {
delete nextParams.args;
}
}
const search = new URLSearchParams();
for (const [key, value] of Object.entries(nextParams)) {
if (value && key !== "autoRun") search.set(key, value);
}
const query = search.toString();
return query ? `${route}?${query}` : route;
}
function apiPathToRoutePath(path) {
const cliPath = path.trim().replace(/^\/api\/v1\/?/, "").replace(/^\/+/, "").replace(/\/+$/, "");
if (!cliPath) return "/";
return `/${cliPath.replace(/\{([^}]+)\}/g, ":$1")}`;
}
function pathParamNames(path) {
return [...path.matchAll(/\{([^}]+)\}/g)].map((match) => match[1]).filter((name) => Boolean(name));
}
function parseArgsParam(value) {
if (!value) return [];
const trimmed = value.trim();
if (!trimmed || trimmed === "[]" || trimmed.toLowerCase() === "null") return [];
try {
const parsed = JSON.parse(trimmed);
if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);
} catch {
}
return trimmed.split(",").map((part) => part.trim()).filter(Boolean);
}
export {
OperationActionDialog
};
//# sourceMappingURL=OperationActionDialog.js.map