UNPKG

@flanksource/clicky-ui

Version:

Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.

251 lines (250 loc) 8.51 kB
import { useState, useEffect } from "react"; import { isPositionalParam } from "./types.js"; function titleCase(value) { return value.split(/[-_]/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" "); } function defaultValueForParameter(param, method) { var _a; if (method.toUpperCase() === "GET" && param.in === "query" && !param.required) { return ""; } const fallback = param.in === "path" ? "" : void 0; const value = ((_a = param.schema) == null ? void 0 : _a.default) ?? fallback; if (typeof value === "boolean") { return value ? "true" : "false"; } if (Array.isArray(value) || value != null && typeof value === "object") { return ""; } if (value == null) { return ""; } return String(value); } function buildInitialParameterValues(parameters, method, lockedValues = {}, initialValues = {}) { const values = Object.fromEntries( parameters.map((param) => [param.name, defaultValueForParameter(param, method)]) ); return { ...values, ...initialValues, ...lockedValues }; } function pruneParameterValues(values) { return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== "")); } function packParameterValues(values, parameters) { const positionalNames = new Set( parameters.filter((param) => param.in !== "path" && isPositionalParam(param)).map((p) => p.name) ); const params = {}; const args = []; for (const [key, value] of Object.entries(values)) { if (!value) continue; if (positionalNames.has(key)) { args.push(value); } else { params[key] = value; } } if (args.length > 0) { params.args = args.join(","); } return params; } function parametersToFormConfig(parameters, values, setValues, options = {}) { var _a, _b; const emitFilters = []; const lookupFilters = ((_a = options.lookup) == null ? void 0 : _a.filters) ?? {}; const includeLocations = new Set(options.includeLocations ?? ["path", "query", "header"]); const lockedValues = options.lockedValues ?? {}; const hideLocked = options.hideLocked ?? false; const rangeStart = parameters.find( (param) => { var _a2; return includeLocations.has(param.in) && param.in === "query" && ((_a2 = lookupFilters[param.name]) == null ? void 0 : _a2.type) === "from"; } ); const rangeEnd = parameters.find( (param) => { var _a2; return includeLocations.has(param.in) && param.in === "query" && ((_a2 = lookupFilters[param.name]) == null ? void 0 : _a2.type) === "to"; } ); const hasTimeRange = rangeStart != null && rangeEnd != null; for (const param of parameters) { if (!includeLocations.has(param.in)) continue; if (hasTimeRange && (param.name === (rangeStart == null ? void 0 : rangeStart.name) || param.name === (rangeEnd == null ? void 0 : rangeEnd.name))) { continue; } const disabled = Object.prototype.hasOwnProperty.call(lockedValues, param.name); if (disabled && hideLocked) continue; const value = disabled ? lockedValues[param.name] ?? "" : values[param.name] ?? ""; const label = ((_b = lookupFilters[param.name]) == null ? void 0 : _b.label) ?? titleCase(param.name); const onChange = (next) => { if (disabled) return; const stringValue = typeof next === "boolean" ? next ? "true" : "false" : next; setValues((current) => ({ ...current, [param.name]: stringValue })); }; const schema = param.schema; const lookupFilter = lookupFilters[param.name]; if ((lookupFilter == null ? void 0 : lookupFilter.type) === "multi-filter" && param.in === "query") { emitFilters.push({ key: param.name, kind: "multi", label, value: parseMultiFilterValue(value), disabled, options: lookupOptionsToFieldOptions(lookupFilter), onChange: (next) => setValues((current) => ({ ...current, [param.name]: serializeMultiFilterValue(next) })) }); continue; } if (schema == null ? void 0 : schema.enum) { emitFilters.push({ key: param.name, kind: "enum", label, value, disabled, options: schema.enum.map((item) => ({ value: String(item), label: String(item) })), onChange: (next) => onChange(next) }); continue; } if ((lookupFilter == null ? void 0 : lookupFilter.type) === "bool" || (schema == null ? void 0 : schema.type) === "boolean") { emitFilters.push({ key: param.name, kind: "boolean", label, value: value === "true", disabled, onChange: (next) => onChange(next) }); continue; } if (lookupFilter != null && param.in === "query") { if (lookupFilter.multi) { emitFilters.push({ key: param.name, kind: "lookup-multi", label, value: splitCommaValues(value), disabled, options: lookupOptionsToFieldOptions(lookupFilter), placeholder: param.description ?? "value-1, value-2", onChange: (next) => setValues((current) => ({ ...current, [param.name]: next.join(",") })) }); continue; } emitFilters.push({ key: param.name, kind: "lookup", label, value, disabled, options: lookupOptionsToFieldOptions(lookupFilter), placeholder: param.description ?? label, inputType: lookupFilter.type === "number" ? "number" : lookupFilter.type === "date" ? "date" : "text", onChange: (next) => onChange(next) }); continue; } emitFilters.push({ key: param.name, kind: "text", label, value, disabled, placeholder: param.description ?? label, onChange: (next) => onChange(next) }); } const config = { filters: emitFilters }; if (hasTimeRange && rangeStart != null && rangeEnd != null) { config.timeRange = { from: values[rangeStart.name] ?? "", to: values[rangeEnd.name] ?? "", onApply: (from, to) => setValues((current) => ({ ...current, [rangeStart.name]: from, [rangeEnd.name]: to })), ...rangeStart.description ? { fromPlaceholder: rangeStart.description } : {}, ...rangeEnd.description ? { toPlaceholder: rangeEnd.description } : {} }; } return config; } function useDebouncedRecord(value, delayMs) { const [debounced, setDebounced] = useState(value); useEffect(() => { const timeoutId = window.setTimeout(() => setDebounced(value), delayMs); return () => window.clearTimeout(timeoutId); }, [delayMs, value]); return debounced; } function parseMultiFilterValue(value) { const parsed = {}; for (const item of splitCommaValues(value)) { if (item.startsWith("!") && item.length > 1) { parsed[item.slice(1)] = "exclude"; } else { parsed[item] = "include"; } } return parsed; } function serializeMultiFilterValue(value) { return Object.entries(value).flatMap(([key, mode]) => { if (mode === "include") return [key]; if (mode === "exclude") return [`!${key}`]; return []; }).join(","); } function splitCommaValues(value) { return value.split(",").map((item) => item.trim()).filter(Boolean); } function lookupOptionsToFieldOptions(filter) { const merged = /* @__PURE__ */ new Map(); for (const [value, node] of Object.entries(filter.options ?? {})) { merged.set(value, { label: clickyNodeToPlainText(node) || value, title: clickyNodeToPlainText(node) || value }); } for (const [value, node] of Object.entries(filter.selected ?? {})) { if (!merged.has(value)) { merged.set(value, { label: clickyNodeToPlainText(node) || value, title: clickyNodeToPlainText(node) || value }); } } return Array.from(merged.entries()).map(([value, meta]) => ({ value, label: meta.label ?? value, title: meta.title ?? value })); } function clickyNodeToPlainText(node) { if (node == null) return ""; if (node.plain) return node.plain; if (node.text) return node.text; return (node.children ?? []).map((child) => clickyNodeToPlainText(child)).join(""); } export { buildInitialParameterValues, defaultValueForParameter, packParameterValues, parametersToFormConfig, parseMultiFilterValue, pruneParameterValues, serializeMultiFilterValue, titleCase, useDebouncedRecord }; //# sourceMappingURL=formMetadata.js.map