@flanksource/clicky-ui 0.3.57 → 0.3.58

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.
@@ -14,9 +14,9 @@ function detectMode() {
14
14
  /** Resolve build + runtime version metadata. */
15
15
  function getVersionInfo() {
16
16
  return {
17
- commit: read(() => "4ccb2b26b", ""),
18
- tag: read(() => "clicky-ui@0.3.56", ""),
19
- date: read(() => "2026-11-02T18:28:00.772Z", ""),
17
+ commit: read(() => "88d37e993", ""),
18
+ tag: read(() => "clicky-ui@0.3.57", ""),
19
+ date: read(() => "2026-11-03T05:17:56.556Z", ""),
20
20
  dirty: read(() => true, false),
21
21
  mode: detectMode()
22
22
  };
@@ -14,9 +14,9 @@ function detectMode() {
14
14
  /** Resolve build + runtime version metadata. */
15
15
  function getVersionInfo() {
16
16
  return {
17
- commit: read(() => "4ccb2b26b", ""),
18
- tag: read(() => "clicky-ui@0.3.56", ""),
19
- date: read(() => "2026-11-02T18:27:24.592Z", ""),
17
+ commit: read(() => "88d37e993", ""),
18
+ tag: read(() => "clicky-ui@0.3.57", ""),
19
+ date: read(() => "2026-11-03T05:17:16.360Z", ""),
20
20
  dirty: read(() => true, false),
21
21
  mode: detectMode()
22
22
  };
@@ -51,7 +51,7 @@ function CommandForm({ parameters, onExecute, isPending, method: _method, path,
51
51
  })
52
52
  }, param.name))
53
53
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
54
- className: inlineLayout ? "sticky bottom-0 z-10 -mx-2 flex justify-end border-t border-border bg-background/95 px-2 py-3 backdrop-blur-sm" : "flex justify-end",
54
+ className: inlineLayout ? "sticky bottom-0 z-10 flex justify-end border-t border-border bg-background/95 py-3 backdrop-blur-sm" : "flex justify-end",
55
55
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_button.Button, {
56
56
  type: "submit",
57
57
  disabled: isPending,
@@ -1 +1 @@
1
- {"version":3,"file":"CommandForm.cjs","names":["useReducer","normalizeParameters","submitValue","packParameterValues","Button","parameterPlaceholder","Icon","UiClose","pathParamNames"],"sources":["../../src/rpc/CommandForm.tsx"],"sourcesContent":["import { useReducer, type FormEvent, type KeyboardEvent, type ReactNode } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiClose } from \"../icons\";\nimport { parameterPlaceholder, type OpenAPIParameter, type OperationRequestValues } from \"./types\";\nimport { normalizeParameters, pathParamNames, submitValue } from \"./command-form-utils\";\nimport { packParameterValues, type ParameterValues } from \"./formMetadata\";\n\nexport type CommandFormSubmission = {\n values: ParameterValues;\n request: OperationRequestValues;\n headers: Record<string, string>;\n};\n\nexport type CommandFormProps = {\n parameters: OpenAPIParameter[];\n onExecute: (submission: CommandFormSubmission) => void;\n isPending: boolean;\n method: string;\n path: string;\n accept: string;\n initialValues?: Record<string, string>;\n};\n\ntype FormState = Record<string, string>;\ntype FormAction = { name: string; value: string };\n\nfunction formReducer(state: FormState, action: FormAction): FormState {\n return { ...state, [action.name]: action.value };\n}\n\nexport function CommandForm({\n parameters,\n onExecute,\n isPending,\n method: _method,\n path,\n accept,\n initialValues,\n}: CommandFormProps) {\n const [values, dispatch] = useReducer(\n formReducer,\n { parameters, path, initialValues },\n ({ parameters: params, path: formPath, initialValues: overrides }) =>\n buildInitialState(normalizeParameters(params, formPath), formPath, overrides),\n );\n\n const formParameters = normalizeParameters(parameters, path);\n const visibleParams = formParameters.filter((p) => !(p.in === \"path\" && initialValues?.[p.name]));\n const inlineLayout = visibleParams.length >= INLINE_LAYOUT_THRESHOLD;\n\n function handleSubmit(event: FormEvent) {\n event.preventDefault();\n const submittedValues: ParameterValues = {};\n for (const param of formParameters) {\n const value = submitValue(param, values[param.name]);\n if (value == null) continue;\n submittedValues[param.name] = value;\n }\n onExecute({\n values: submittedValues,\n request: packParameterValues(submittedValues, formParameters),\n headers: { Accept: accept },\n });\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {visibleParams.length > 0 && (\n <div className={inlineLayout ? \"grid gap-2\" : \"grid gap-4\"}>\n {visibleParams.map((param) => (\n <ParameterField\n key={param.name}\n param={param}\n value={values[param.name] || \"\"}\n inline={inlineLayout}\n onChange={(value) => dispatch({ name: param.name, value })}\n />\n ))}\n </div>\n )}\n\n <div\n className={\n inlineLayout\n ? \"sticky bottom-0 z-10 -mx-2 flex justify-end border-t border-border bg-background/95 px-2 py-3 backdrop-blur-sm\"\n : \"flex justify-end\"\n }\n >\n <Button type=\"submit\" disabled={isPending}>\n {isPending ? \"Executing...\" : \"Execute\"}\n </Button>\n </div>\n </form>\n );\n}\n\nconst INLINE_LAYOUT_THRESHOLD = 6;\n\nfunction ParameterField({\n param,\n value,\n inline,\n onChange,\n}: {\n param: OpenAPIParameter;\n value: string;\n inline: boolean;\n onChange: (value: string) => void;\n}) {\n const schema = param.schema;\n const fieldId = `param-${param.name}`;\n\n if (isMultiValueParam(param)) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <TagInput\n id={fieldId}\n value={value}\n placeholder={parameterPlaceholder(param) || param.name}\n onChange={onChange}\n />\n </FieldWrapper>\n );\n }\n\n if (schema?.enum) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <select\n id={fieldId}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n >\n <option value=\"\">Select {param.name}</option>\n {schema.enum.map((v) => (\n <option key={String(v)} value={String(v)}>\n {String(v)}\n </option>\n ))}\n </select>\n </FieldWrapper>\n );\n }\n\n if (schema?.type === \"boolean\") {\n const checkbox = (\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={value === \"true\"}\n onChange={(event) => onChange(event.target.checked ? \"true\" : \"false\")}\n />\n );\n if (inline) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline>\n <div className=\"flex h-9 items-center\">{checkbox}</div>\n </FieldWrapper>\n );\n }\n return (\n <div className=\"flex items-center gap-2\">\n {checkbox}\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n {param.description && (\n <span className=\"text-xs text-muted-foreground\">{param.description}</span>\n )}\n </div>\n );\n }\n\n if (isDateParam(param)) {\n const dateTime = schema?.format === \"date-time\";\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <div className=\"flex gap-2\">\n <input\n id={fieldId}\n type={dateTime ? \"datetime-local\" : \"date\"}\n value={dateInputValue(value, dateTime)}\n className={inputClassName}\n onChange={(event) => onChange(dateOutputValue(event.target.value, dateTime))}\n />\n {value && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={`Clear ${param.name}`}\n onClick={() => onChange(\"\")}\n >\n <Icon icon={UiClose} />\n </Button>\n )}\n </div>\n </FieldWrapper>\n );\n }\n\n const inputType = schema?.type === \"integer\" || schema?.type === \"number\" ? \"number\" : \"text\";\n\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <input\n id={fieldId}\n type={inputType}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n placeholder={\n schema?.default != null\n ? String(schema.default)\n : parameterPlaceholder(param) || param.name\n }\n />\n </FieldWrapper>\n );\n}\n\nfunction TagInput({\n id,\n value,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string;\n placeholder: string;\n onChange: (value: string) => void;\n}) {\n const tags = parseTags(value);\n\n function commit(raw: string, input: HTMLInputElement) {\n const next = raw\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n if (next.length === 0) return;\n onChange(serializeTags([...tags, ...next]));\n input.value = \"\";\n }\n\n function remove(index: number) {\n onChange(serializeTags(tags.filter((_, i) => i !== index)));\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n if (event.key === \"Enter\" || event.key === \",\") {\n event.preventDefault();\n commit(input.value, input);\n return;\n }\n if (event.key === \"Backspace\" && input.value === \"\" && tags.length > 0) {\n remove(tags.length - 1);\n }\n }\n\n return (\n <div className=\"flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent px-2 py-1 shadow-sm\">\n {tags.map((tag, index) => (\n <span\n key={`${tag}-${index}`}\n className=\"inline-flex h-6 max-w-full items-center gap-1 rounded-md bg-muted px-2 text-xs\"\n >\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-foreground\"\n aria-label={`Remove ${tag}`}\n onClick={() => remove(index)}\n >\n <Icon icon={UiClose} />\n </button>\n </span>\n ))}\n <input\n id={id}\n className=\"min-w-0 flex-1 basis-32 bg-transparent px-1 py-1 text-sm outline-none\"\n placeholder={tags.length === 0 ? placeholder : \"\"}\n onKeyDown={handleKeyDown}\n onBlur={(event) => commit(event.currentTarget.value, event.currentTarget)}\n />\n </div>\n );\n}\n\nfunction FieldWrapper({\n param,\n fieldId,\n inline,\n children,\n}: {\n param: OpenAPIParameter;\n fieldId: string;\n inline?: boolean;\n children: ReactNode;\n}) {\n const label = (\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n );\n\n if (inline) {\n return (\n <div className=\"grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5\">\n <div className=\"flex h-9 items-center\">{label}</div>\n <div className=\"min-w-0\">{children}</div>\n {param.description && (\n <p className=\"col-start-2 text-xs text-muted-foreground\">{param.description}</p>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"space-y-1.5\">\n {label}\n {children}\n {param.description && <p className=\"text-xs text-muted-foreground\">{param.description}</p>}\n </div>\n );\n}\n\nfunction buildInitialState(\n parameters: OpenAPIParameter[],\n path: string,\n overrides?: Record<string, string>,\n): FormState {\n const state: FormState = {};\n for (const p of parameters) {\n state[p.name] = initialParamValue(p, overrides?.[p.name]);\n }\n for (const name of pathParamNames(path)) {\n if (state[name] == null) {\n state[name] = overrides?.[name] ?? \"\";\n }\n }\n return state;\n}\n\nfunction initialParamValue(param: OpenAPIParameter, override: string | undefined): string {\n if (override != null) return sanitizeInitialValue(param, override);\n const value = param.schema?.default;\n if (value == null) return \"\";\n return sanitizeInitialValue(param, String(value));\n}\n\nfunction sanitizeInitialValue(param: OpenAPIParameter, value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"[]\" || trimmed === \"null\") return \"\";\n if (isDateParam(param) && isZeroDate(trimmed)) return \"\";\n return value;\n}\n\nfunction isMultiValueParam(param: OpenAPIParameter): boolean {\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return (\n param.schema?.type === \"array\" ||\n String(param.schema?.default ?? \"\") === \"[]\" ||\n text.includes(\"repeatable\")\n );\n}\n\nfunction parseTags(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited tags below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nfunction serializeTags(tags: string[]): string {\n return tags.join(\",\");\n}\n\nfunction isDateParam(param: OpenAPIParameter): boolean {\n const format = param.schema?.format?.toLowerCase();\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return format === \"date\" || format === \"date-time\" || text.includes(\"date\");\n}\n\nfunction isZeroDate(value: string): boolean {\n return value.startsWith(\"0001-01-01\") || value === \"0001-01-01\";\n}\n\nfunction dateInputValue(value: string, dateTime: boolean): string {\n if (!value || value.startsWith(\"0001-01-01\")) return \"\";\n if (!dateTime) return value.slice(0, 10);\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value.slice(0, 16);\n const offset = parsed.getTimezoneOffset() * 60_000;\n return new Date(parsed.getTime() - offset).toISOString().slice(0, 16);\n}\n\nfunction dateOutputValue(value: string, dateTime: boolean): string {\n if (!value) return \"\";\n if (!dateTime) return value;\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value;\n return parsed.toISOString();\n}\n\nconst inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"CommandForm.cjs","names":["useReducer","normalizeParameters","submitValue","packParameterValues","Button","parameterPlaceholder","Icon","UiClose","pathParamNames"],"sources":["../../src/rpc/CommandForm.tsx"],"sourcesContent":["import { useReducer, type FormEvent, type KeyboardEvent, type ReactNode } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiClose } from \"../icons\";\nimport { parameterPlaceholder, type OpenAPIParameter, type OperationRequestValues } from \"./types\";\nimport { normalizeParameters, pathParamNames, submitValue } from \"./command-form-utils\";\nimport { packParameterValues, type ParameterValues } from \"./formMetadata\";\n\nexport type CommandFormSubmission = {\n values: ParameterValues;\n request: OperationRequestValues;\n headers: Record<string, string>;\n};\n\nexport type CommandFormProps = {\n parameters: OpenAPIParameter[];\n onExecute: (submission: CommandFormSubmission) => void;\n isPending: boolean;\n method: string;\n path: string;\n accept: string;\n initialValues?: Record<string, string>;\n};\n\ntype FormState = Record<string, string>;\ntype FormAction = { name: string; value: string };\n\nfunction formReducer(state: FormState, action: FormAction): FormState {\n return { ...state, [action.name]: action.value };\n}\n\nexport function CommandForm({\n parameters,\n onExecute,\n isPending,\n method: _method,\n path,\n accept,\n initialValues,\n}: CommandFormProps) {\n const [values, dispatch] = useReducer(\n formReducer,\n { parameters, path, initialValues },\n ({ parameters: params, path: formPath, initialValues: overrides }) =>\n buildInitialState(normalizeParameters(params, formPath), formPath, overrides),\n );\n\n const formParameters = normalizeParameters(parameters, path);\n const visibleParams = formParameters.filter((p) => !(p.in === \"path\" && initialValues?.[p.name]));\n const inlineLayout = visibleParams.length >= INLINE_LAYOUT_THRESHOLD;\n\n function handleSubmit(event: FormEvent) {\n event.preventDefault();\n const submittedValues: ParameterValues = {};\n for (const param of formParameters) {\n const value = submitValue(param, values[param.name]);\n if (value == null) continue;\n submittedValues[param.name] = value;\n }\n onExecute({\n values: submittedValues,\n request: packParameterValues(submittedValues, formParameters),\n headers: { Accept: accept },\n });\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {visibleParams.length > 0 && (\n <div className={inlineLayout ? \"grid gap-2\" : \"grid gap-4\"}>\n {visibleParams.map((param) => (\n <ParameterField\n key={param.name}\n param={param}\n value={values[param.name] || \"\"}\n inline={inlineLayout}\n onChange={(value) => dispatch({ name: param.name, value })}\n />\n ))}\n </div>\n )}\n\n <div\n className={\n inlineLayout\n ? \"sticky bottom-0 z-10 flex justify-end border-t border-border bg-background/95 py-3 backdrop-blur-sm\"\n : \"flex justify-end\"\n }\n >\n <Button type=\"submit\" disabled={isPending}>\n {isPending ? \"Executing...\" : \"Execute\"}\n </Button>\n </div>\n </form>\n );\n}\n\nconst INLINE_LAYOUT_THRESHOLD = 6;\n\nfunction ParameterField({\n param,\n value,\n inline,\n onChange,\n}: {\n param: OpenAPIParameter;\n value: string;\n inline: boolean;\n onChange: (value: string) => void;\n}) {\n const schema = param.schema;\n const fieldId = `param-${param.name}`;\n\n if (isMultiValueParam(param)) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <TagInput\n id={fieldId}\n value={value}\n placeholder={parameterPlaceholder(param) || param.name}\n onChange={onChange}\n />\n </FieldWrapper>\n );\n }\n\n if (schema?.enum) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <select\n id={fieldId}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n >\n <option value=\"\">Select {param.name}</option>\n {schema.enum.map((v) => (\n <option key={String(v)} value={String(v)}>\n {String(v)}\n </option>\n ))}\n </select>\n </FieldWrapper>\n );\n }\n\n if (schema?.type === \"boolean\") {\n const checkbox = (\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={value === \"true\"}\n onChange={(event) => onChange(event.target.checked ? \"true\" : \"false\")}\n />\n );\n if (inline) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline>\n <div className=\"flex h-9 items-center\">{checkbox}</div>\n </FieldWrapper>\n );\n }\n return (\n <div className=\"flex items-center gap-2\">\n {checkbox}\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n {param.description && (\n <span className=\"text-xs text-muted-foreground\">{param.description}</span>\n )}\n </div>\n );\n }\n\n if (isDateParam(param)) {\n const dateTime = schema?.format === \"date-time\";\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <div className=\"flex gap-2\">\n <input\n id={fieldId}\n type={dateTime ? \"datetime-local\" : \"date\"}\n value={dateInputValue(value, dateTime)}\n className={inputClassName}\n onChange={(event) => onChange(dateOutputValue(event.target.value, dateTime))}\n />\n {value && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={`Clear ${param.name}`}\n onClick={() => onChange(\"\")}\n >\n <Icon icon={UiClose} />\n </Button>\n )}\n </div>\n </FieldWrapper>\n );\n }\n\n const inputType = schema?.type === \"integer\" || schema?.type === \"number\" ? \"number\" : \"text\";\n\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <input\n id={fieldId}\n type={inputType}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n placeholder={\n schema?.default != null\n ? String(schema.default)\n : parameterPlaceholder(param) || param.name\n }\n />\n </FieldWrapper>\n );\n}\n\nfunction TagInput({\n id,\n value,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string;\n placeholder: string;\n onChange: (value: string) => void;\n}) {\n const tags = parseTags(value);\n\n function commit(raw: string, input: HTMLInputElement) {\n const next = raw\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n if (next.length === 0) return;\n onChange(serializeTags([...tags, ...next]));\n input.value = \"\";\n }\n\n function remove(index: number) {\n onChange(serializeTags(tags.filter((_, i) => i !== index)));\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n if (event.key === \"Enter\" || event.key === \",\") {\n event.preventDefault();\n commit(input.value, input);\n return;\n }\n if (event.key === \"Backspace\" && input.value === \"\" && tags.length > 0) {\n remove(tags.length - 1);\n }\n }\n\n return (\n <div className=\"flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent px-2 py-1 shadow-sm\">\n {tags.map((tag, index) => (\n <span\n key={`${tag}-${index}`}\n className=\"inline-flex h-6 max-w-full items-center gap-1 rounded-md bg-muted px-2 text-xs\"\n >\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-foreground\"\n aria-label={`Remove ${tag}`}\n onClick={() => remove(index)}\n >\n <Icon icon={UiClose} />\n </button>\n </span>\n ))}\n <input\n id={id}\n className=\"min-w-0 flex-1 basis-32 bg-transparent px-1 py-1 text-sm outline-none\"\n placeholder={tags.length === 0 ? placeholder : \"\"}\n onKeyDown={handleKeyDown}\n onBlur={(event) => commit(event.currentTarget.value, event.currentTarget)}\n />\n </div>\n );\n}\n\nfunction FieldWrapper({\n param,\n fieldId,\n inline,\n children,\n}: {\n param: OpenAPIParameter;\n fieldId: string;\n inline?: boolean;\n children: ReactNode;\n}) {\n const label = (\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n );\n\n if (inline) {\n return (\n <div className=\"grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5\">\n <div className=\"flex h-9 items-center\">{label}</div>\n <div className=\"min-w-0\">{children}</div>\n {param.description && (\n <p className=\"col-start-2 text-xs text-muted-foreground\">{param.description}</p>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"space-y-1.5\">\n {label}\n {children}\n {param.description && <p className=\"text-xs text-muted-foreground\">{param.description}</p>}\n </div>\n );\n}\n\nfunction buildInitialState(\n parameters: OpenAPIParameter[],\n path: string,\n overrides?: Record<string, string>,\n): FormState {\n const state: FormState = {};\n for (const p of parameters) {\n state[p.name] = initialParamValue(p, overrides?.[p.name]);\n }\n for (const name of pathParamNames(path)) {\n if (state[name] == null) {\n state[name] = overrides?.[name] ?? \"\";\n }\n }\n return state;\n}\n\nfunction initialParamValue(param: OpenAPIParameter, override: string | undefined): string {\n if (override != null) return sanitizeInitialValue(param, override);\n const value = param.schema?.default;\n if (value == null) return \"\";\n return sanitizeInitialValue(param, String(value));\n}\n\nfunction sanitizeInitialValue(param: OpenAPIParameter, value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"[]\" || trimmed === \"null\") return \"\";\n if (isDateParam(param) && isZeroDate(trimmed)) return \"\";\n return value;\n}\n\nfunction isMultiValueParam(param: OpenAPIParameter): boolean {\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return (\n param.schema?.type === \"array\" ||\n String(param.schema?.default ?? \"\") === \"[]\" ||\n text.includes(\"repeatable\")\n );\n}\n\nfunction parseTags(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited tags below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nfunction serializeTags(tags: string[]): string {\n return tags.join(\",\");\n}\n\nfunction isDateParam(param: OpenAPIParameter): boolean {\n const format = param.schema?.format?.toLowerCase();\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return format === \"date\" || format === \"date-time\" || text.includes(\"date\");\n}\n\nfunction isZeroDate(value: string): boolean {\n return value.startsWith(\"0001-01-01\") || value === \"0001-01-01\";\n}\n\nfunction dateInputValue(value: string, dateTime: boolean): string {\n if (!value || value.startsWith(\"0001-01-01\")) return \"\";\n if (!dateTime) return value.slice(0, 10);\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value.slice(0, 16);\n const offset = parsed.getTimezoneOffset() * 60_000;\n return new Date(parsed.getTime() - offset).toISOString().slice(0, 16);\n}\n\nfunction dateOutputValue(value: string, dateTime: boolean): string {\n if (!value) return \"\";\n if (!dateTime) return value;\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value;\n return parsed.toISOString();\n}\n\nconst inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n"],"mappings":"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"}
@@ -51,7 +51,7 @@ function CommandForm({ parameters, onExecute, isPending, method: _method, path,
51
51
  })
52
52
  }, param.name))
53
53
  }), /* @__PURE__ */ jsx("div", {
54
- className: inlineLayout ? "sticky bottom-0 z-10 -mx-2 flex justify-end border-t border-border bg-background/95 px-2 py-3 backdrop-blur-sm" : "flex justify-end",
54
+ className: inlineLayout ? "sticky bottom-0 z-10 flex justify-end border-t border-border bg-background/95 py-3 backdrop-blur-sm" : "flex justify-end",
55
55
  children: /* @__PURE__ */ jsx(Button, {
56
56
  type: "submit",
57
57
  disabled: isPending,
@@ -1 +1 @@
1
- {"version":3,"file":"CommandForm.js","names":[],"sources":["../../src/rpc/CommandForm.tsx"],"sourcesContent":["import { useReducer, type FormEvent, type KeyboardEvent, type ReactNode } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiClose } from \"../icons\";\nimport { parameterPlaceholder, type OpenAPIParameter, type OperationRequestValues } from \"./types\";\nimport { normalizeParameters, pathParamNames, submitValue } from \"./command-form-utils\";\nimport { packParameterValues, type ParameterValues } from \"./formMetadata\";\n\nexport type CommandFormSubmission = {\n values: ParameterValues;\n request: OperationRequestValues;\n headers: Record<string, string>;\n};\n\nexport type CommandFormProps = {\n parameters: OpenAPIParameter[];\n onExecute: (submission: CommandFormSubmission) => void;\n isPending: boolean;\n method: string;\n path: string;\n accept: string;\n initialValues?: Record<string, string>;\n};\n\ntype FormState = Record<string, string>;\ntype FormAction = { name: string; value: string };\n\nfunction formReducer(state: FormState, action: FormAction): FormState {\n return { ...state, [action.name]: action.value };\n}\n\nexport function CommandForm({\n parameters,\n onExecute,\n isPending,\n method: _method,\n path,\n accept,\n initialValues,\n}: CommandFormProps) {\n const [values, dispatch] = useReducer(\n formReducer,\n { parameters, path, initialValues },\n ({ parameters: params, path: formPath, initialValues: overrides }) =>\n buildInitialState(normalizeParameters(params, formPath), formPath, overrides),\n );\n\n const formParameters = normalizeParameters(parameters, path);\n const visibleParams = formParameters.filter((p) => !(p.in === \"path\" && initialValues?.[p.name]));\n const inlineLayout = visibleParams.length >= INLINE_LAYOUT_THRESHOLD;\n\n function handleSubmit(event: FormEvent) {\n event.preventDefault();\n const submittedValues: ParameterValues = {};\n for (const param of formParameters) {\n const value = submitValue(param, values[param.name]);\n if (value == null) continue;\n submittedValues[param.name] = value;\n }\n onExecute({\n values: submittedValues,\n request: packParameterValues(submittedValues, formParameters),\n headers: { Accept: accept },\n });\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {visibleParams.length > 0 && (\n <div className={inlineLayout ? \"grid gap-2\" : \"grid gap-4\"}>\n {visibleParams.map((param) => (\n <ParameterField\n key={param.name}\n param={param}\n value={values[param.name] || \"\"}\n inline={inlineLayout}\n onChange={(value) => dispatch({ name: param.name, value })}\n />\n ))}\n </div>\n )}\n\n <div\n className={\n inlineLayout\n ? \"sticky bottom-0 z-10 -mx-2 flex justify-end border-t border-border bg-background/95 px-2 py-3 backdrop-blur-sm\"\n : \"flex justify-end\"\n }\n >\n <Button type=\"submit\" disabled={isPending}>\n {isPending ? \"Executing...\" : \"Execute\"}\n </Button>\n </div>\n </form>\n );\n}\n\nconst INLINE_LAYOUT_THRESHOLD = 6;\n\nfunction ParameterField({\n param,\n value,\n inline,\n onChange,\n}: {\n param: OpenAPIParameter;\n value: string;\n inline: boolean;\n onChange: (value: string) => void;\n}) {\n const schema = param.schema;\n const fieldId = `param-${param.name}`;\n\n if (isMultiValueParam(param)) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <TagInput\n id={fieldId}\n value={value}\n placeholder={parameterPlaceholder(param) || param.name}\n onChange={onChange}\n />\n </FieldWrapper>\n );\n }\n\n if (schema?.enum) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <select\n id={fieldId}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n >\n <option value=\"\">Select {param.name}</option>\n {schema.enum.map((v) => (\n <option key={String(v)} value={String(v)}>\n {String(v)}\n </option>\n ))}\n </select>\n </FieldWrapper>\n );\n }\n\n if (schema?.type === \"boolean\") {\n const checkbox = (\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={value === \"true\"}\n onChange={(event) => onChange(event.target.checked ? \"true\" : \"false\")}\n />\n );\n if (inline) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline>\n <div className=\"flex h-9 items-center\">{checkbox}</div>\n </FieldWrapper>\n );\n }\n return (\n <div className=\"flex items-center gap-2\">\n {checkbox}\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n {param.description && (\n <span className=\"text-xs text-muted-foreground\">{param.description}</span>\n )}\n </div>\n );\n }\n\n if (isDateParam(param)) {\n const dateTime = schema?.format === \"date-time\";\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <div className=\"flex gap-2\">\n <input\n id={fieldId}\n type={dateTime ? \"datetime-local\" : \"date\"}\n value={dateInputValue(value, dateTime)}\n className={inputClassName}\n onChange={(event) => onChange(dateOutputValue(event.target.value, dateTime))}\n />\n {value && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={`Clear ${param.name}`}\n onClick={() => onChange(\"\")}\n >\n <Icon icon={UiClose} />\n </Button>\n )}\n </div>\n </FieldWrapper>\n );\n }\n\n const inputType = schema?.type === \"integer\" || schema?.type === \"number\" ? \"number\" : \"text\";\n\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <input\n id={fieldId}\n type={inputType}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n placeholder={\n schema?.default != null\n ? String(schema.default)\n : parameterPlaceholder(param) || param.name\n }\n />\n </FieldWrapper>\n );\n}\n\nfunction TagInput({\n id,\n value,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string;\n placeholder: string;\n onChange: (value: string) => void;\n}) {\n const tags = parseTags(value);\n\n function commit(raw: string, input: HTMLInputElement) {\n const next = raw\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n if (next.length === 0) return;\n onChange(serializeTags([...tags, ...next]));\n input.value = \"\";\n }\n\n function remove(index: number) {\n onChange(serializeTags(tags.filter((_, i) => i !== index)));\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n if (event.key === \"Enter\" || event.key === \",\") {\n event.preventDefault();\n commit(input.value, input);\n return;\n }\n if (event.key === \"Backspace\" && input.value === \"\" && tags.length > 0) {\n remove(tags.length - 1);\n }\n }\n\n return (\n <div className=\"flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent px-2 py-1 shadow-sm\">\n {tags.map((tag, index) => (\n <span\n key={`${tag}-${index}`}\n className=\"inline-flex h-6 max-w-full items-center gap-1 rounded-md bg-muted px-2 text-xs\"\n >\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-foreground\"\n aria-label={`Remove ${tag}`}\n onClick={() => remove(index)}\n >\n <Icon icon={UiClose} />\n </button>\n </span>\n ))}\n <input\n id={id}\n className=\"min-w-0 flex-1 basis-32 bg-transparent px-1 py-1 text-sm outline-none\"\n placeholder={tags.length === 0 ? placeholder : \"\"}\n onKeyDown={handleKeyDown}\n onBlur={(event) => commit(event.currentTarget.value, event.currentTarget)}\n />\n </div>\n );\n}\n\nfunction FieldWrapper({\n param,\n fieldId,\n inline,\n children,\n}: {\n param: OpenAPIParameter;\n fieldId: string;\n inline?: boolean;\n children: ReactNode;\n}) {\n const label = (\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n );\n\n if (inline) {\n return (\n <div className=\"grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5\">\n <div className=\"flex h-9 items-center\">{label}</div>\n <div className=\"min-w-0\">{children}</div>\n {param.description && (\n <p className=\"col-start-2 text-xs text-muted-foreground\">{param.description}</p>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"space-y-1.5\">\n {label}\n {children}\n {param.description && <p className=\"text-xs text-muted-foreground\">{param.description}</p>}\n </div>\n );\n}\n\nfunction buildInitialState(\n parameters: OpenAPIParameter[],\n path: string,\n overrides?: Record<string, string>,\n): FormState {\n const state: FormState = {};\n for (const p of parameters) {\n state[p.name] = initialParamValue(p, overrides?.[p.name]);\n }\n for (const name of pathParamNames(path)) {\n if (state[name] == null) {\n state[name] = overrides?.[name] ?? \"\";\n }\n }\n return state;\n}\n\nfunction initialParamValue(param: OpenAPIParameter, override: string | undefined): string {\n if (override != null) return sanitizeInitialValue(param, override);\n const value = param.schema?.default;\n if (value == null) return \"\";\n return sanitizeInitialValue(param, String(value));\n}\n\nfunction sanitizeInitialValue(param: OpenAPIParameter, value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"[]\" || trimmed === \"null\") return \"\";\n if (isDateParam(param) && isZeroDate(trimmed)) return \"\";\n return value;\n}\n\nfunction isMultiValueParam(param: OpenAPIParameter): boolean {\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return (\n param.schema?.type === \"array\" ||\n String(param.schema?.default ?? \"\") === \"[]\" ||\n text.includes(\"repeatable\")\n );\n}\n\nfunction parseTags(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited tags below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nfunction serializeTags(tags: string[]): string {\n return tags.join(\",\");\n}\n\nfunction isDateParam(param: OpenAPIParameter): boolean {\n const format = param.schema?.format?.toLowerCase();\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return format === \"date\" || format === \"date-time\" || text.includes(\"date\");\n}\n\nfunction isZeroDate(value: string): boolean {\n return value.startsWith(\"0001-01-01\") || value === \"0001-01-01\";\n}\n\nfunction dateInputValue(value: string, dateTime: boolean): string {\n if (!value || value.startsWith(\"0001-01-01\")) return \"\";\n if (!dateTime) return value.slice(0, 10);\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value.slice(0, 16);\n const offset = parsed.getTimezoneOffset() * 60_000;\n return new Date(parsed.getTime() - offset).toISOString().slice(0, 16);\n}\n\nfunction dateOutputValue(value: string, dateTime: boolean): string {\n if (!value) return \"\";\n if (!dateTime) return value;\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value;\n return parsed.toISOString();\n}\n\nconst inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"CommandForm.js","names":[],"sources":["../../src/rpc/CommandForm.tsx"],"sourcesContent":["import { useReducer, type FormEvent, type KeyboardEvent, type ReactNode } from \"react\";\nimport { Button } from \"../components/button\";\nimport { Icon } from \"../data/Icon\";\nimport { UiClose } from \"../icons\";\nimport { parameterPlaceholder, type OpenAPIParameter, type OperationRequestValues } from \"./types\";\nimport { normalizeParameters, pathParamNames, submitValue } from \"./command-form-utils\";\nimport { packParameterValues, type ParameterValues } from \"./formMetadata\";\n\nexport type CommandFormSubmission = {\n values: ParameterValues;\n request: OperationRequestValues;\n headers: Record<string, string>;\n};\n\nexport type CommandFormProps = {\n parameters: OpenAPIParameter[];\n onExecute: (submission: CommandFormSubmission) => void;\n isPending: boolean;\n method: string;\n path: string;\n accept: string;\n initialValues?: Record<string, string>;\n};\n\ntype FormState = Record<string, string>;\ntype FormAction = { name: string; value: string };\n\nfunction formReducer(state: FormState, action: FormAction): FormState {\n return { ...state, [action.name]: action.value };\n}\n\nexport function CommandForm({\n parameters,\n onExecute,\n isPending,\n method: _method,\n path,\n accept,\n initialValues,\n}: CommandFormProps) {\n const [values, dispatch] = useReducer(\n formReducer,\n { parameters, path, initialValues },\n ({ parameters: params, path: formPath, initialValues: overrides }) =>\n buildInitialState(normalizeParameters(params, formPath), formPath, overrides),\n );\n\n const formParameters = normalizeParameters(parameters, path);\n const visibleParams = formParameters.filter((p) => !(p.in === \"path\" && initialValues?.[p.name]));\n const inlineLayout = visibleParams.length >= INLINE_LAYOUT_THRESHOLD;\n\n function handleSubmit(event: FormEvent) {\n event.preventDefault();\n const submittedValues: ParameterValues = {};\n for (const param of formParameters) {\n const value = submitValue(param, values[param.name]);\n if (value == null) continue;\n submittedValues[param.name] = value;\n }\n onExecute({\n values: submittedValues,\n request: packParameterValues(submittedValues, formParameters),\n headers: { Accept: accept },\n });\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {visibleParams.length > 0 && (\n <div className={inlineLayout ? \"grid gap-2\" : \"grid gap-4\"}>\n {visibleParams.map((param) => (\n <ParameterField\n key={param.name}\n param={param}\n value={values[param.name] || \"\"}\n inline={inlineLayout}\n onChange={(value) => dispatch({ name: param.name, value })}\n />\n ))}\n </div>\n )}\n\n <div\n className={\n inlineLayout\n ? \"sticky bottom-0 z-10 flex justify-end border-t border-border bg-background/95 py-3 backdrop-blur-sm\"\n : \"flex justify-end\"\n }\n >\n <Button type=\"submit\" disabled={isPending}>\n {isPending ? \"Executing...\" : \"Execute\"}\n </Button>\n </div>\n </form>\n );\n}\n\nconst INLINE_LAYOUT_THRESHOLD = 6;\n\nfunction ParameterField({\n param,\n value,\n inline,\n onChange,\n}: {\n param: OpenAPIParameter;\n value: string;\n inline: boolean;\n onChange: (value: string) => void;\n}) {\n const schema = param.schema;\n const fieldId = `param-${param.name}`;\n\n if (isMultiValueParam(param)) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <TagInput\n id={fieldId}\n value={value}\n placeholder={parameterPlaceholder(param) || param.name}\n onChange={onChange}\n />\n </FieldWrapper>\n );\n }\n\n if (schema?.enum) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <select\n id={fieldId}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n >\n <option value=\"\">Select {param.name}</option>\n {schema.enum.map((v) => (\n <option key={String(v)} value={String(v)}>\n {String(v)}\n </option>\n ))}\n </select>\n </FieldWrapper>\n );\n }\n\n if (schema?.type === \"boolean\") {\n const checkbox = (\n <input\n id={fieldId}\n type=\"checkbox\"\n className=\"h-4 w-4 accent-primary\"\n checked={value === \"true\"}\n onChange={(event) => onChange(event.target.checked ? \"true\" : \"false\")}\n />\n );\n if (inline) {\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline>\n <div className=\"flex h-9 items-center\">{checkbox}</div>\n </FieldWrapper>\n );\n }\n return (\n <div className=\"flex items-center gap-2\">\n {checkbox}\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n {param.description && (\n <span className=\"text-xs text-muted-foreground\">{param.description}</span>\n )}\n </div>\n );\n }\n\n if (isDateParam(param)) {\n const dateTime = schema?.format === \"date-time\";\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <div className=\"flex gap-2\">\n <input\n id={fieldId}\n type={dateTime ? \"datetime-local\" : \"date\"}\n value={dateInputValue(value, dateTime)}\n className={inputClassName}\n onChange={(event) => onChange(dateOutputValue(event.target.value, dateTime))}\n />\n {value && (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={`Clear ${param.name}`}\n onClick={() => onChange(\"\")}\n >\n <Icon icon={UiClose} />\n </Button>\n )}\n </div>\n </FieldWrapper>\n );\n }\n\n const inputType = schema?.type === \"integer\" || schema?.type === \"number\" ? \"number\" : \"text\";\n\n return (\n <FieldWrapper param={param} fieldId={fieldId} inline={inline}>\n <input\n id={fieldId}\n type={inputType}\n value={value}\n className={inputClassName}\n onChange={(event) => onChange(event.target.value)}\n placeholder={\n schema?.default != null\n ? String(schema.default)\n : parameterPlaceholder(param) || param.name\n }\n />\n </FieldWrapper>\n );\n}\n\nfunction TagInput({\n id,\n value,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string;\n placeholder: string;\n onChange: (value: string) => void;\n}) {\n const tags = parseTags(value);\n\n function commit(raw: string, input: HTMLInputElement) {\n const next = raw\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n if (next.length === 0) return;\n onChange(serializeTags([...tags, ...next]));\n input.value = \"\";\n }\n\n function remove(index: number) {\n onChange(serializeTags(tags.filter((_, i) => i !== index)));\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n const input = event.currentTarget;\n if (event.key === \"Enter\" || event.key === \",\") {\n event.preventDefault();\n commit(input.value, input);\n return;\n }\n if (event.key === \"Backspace\" && input.value === \"\" && tags.length > 0) {\n remove(tags.length - 1);\n }\n }\n\n return (\n <div className=\"flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent px-2 py-1 shadow-sm\">\n {tags.map((tag, index) => (\n <span\n key={`${tag}-${index}`}\n className=\"inline-flex h-6 max-w-full items-center gap-1 rounded-md bg-muted px-2 text-xs\"\n >\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"text-muted-foreground hover:text-foreground\"\n aria-label={`Remove ${tag}`}\n onClick={() => remove(index)}\n >\n <Icon icon={UiClose} />\n </button>\n </span>\n ))}\n <input\n id={id}\n className=\"min-w-0 flex-1 basis-32 bg-transparent px-1 py-1 text-sm outline-none\"\n placeholder={tags.length === 0 ? placeholder : \"\"}\n onKeyDown={handleKeyDown}\n onBlur={(event) => commit(event.currentTarget.value, event.currentTarget)}\n />\n </div>\n );\n}\n\nfunction FieldWrapper({\n param,\n fieldId,\n inline,\n children,\n}: {\n param: OpenAPIParameter;\n fieldId: string;\n inline?: boolean;\n children: ReactNode;\n}) {\n const label = (\n <label htmlFor={fieldId} className=\"text-sm font-medium\">\n {param.name}\n {param.required && <span className=\"text-destructive\"> *</span>}\n </label>\n );\n\n if (inline) {\n return (\n <div className=\"grid grid-cols-[10rem_1fr] items-start gap-x-3 gap-y-0.5\">\n <div className=\"flex h-9 items-center\">{label}</div>\n <div className=\"min-w-0\">{children}</div>\n {param.description && (\n <p className=\"col-start-2 text-xs text-muted-foreground\">{param.description}</p>\n )}\n </div>\n );\n }\n\n return (\n <div className=\"space-y-1.5\">\n {label}\n {children}\n {param.description && <p className=\"text-xs text-muted-foreground\">{param.description}</p>}\n </div>\n );\n}\n\nfunction buildInitialState(\n parameters: OpenAPIParameter[],\n path: string,\n overrides?: Record<string, string>,\n): FormState {\n const state: FormState = {};\n for (const p of parameters) {\n state[p.name] = initialParamValue(p, overrides?.[p.name]);\n }\n for (const name of pathParamNames(path)) {\n if (state[name] == null) {\n state[name] = overrides?.[name] ?? \"\";\n }\n }\n return state;\n}\n\nfunction initialParamValue(param: OpenAPIParameter, override: string | undefined): string {\n if (override != null) return sanitizeInitialValue(param, override);\n const value = param.schema?.default;\n if (value == null) return \"\";\n return sanitizeInitialValue(param, String(value));\n}\n\nfunction sanitizeInitialValue(param: OpenAPIParameter, value: string): string {\n const trimmed = value.trim();\n if (trimmed === \"[]\" || trimmed === \"null\") return \"\";\n if (isDateParam(param) && isZeroDate(trimmed)) return \"\";\n return value;\n}\n\nfunction isMultiValueParam(param: OpenAPIParameter): boolean {\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return (\n param.schema?.type === \"array\" ||\n String(param.schema?.default ?? \"\") === \"[]\" ||\n text.includes(\"repeatable\")\n );\n}\n\nfunction parseTags(value: string): string[] {\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"[]\" || trimmed === \"null\") return [];\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed.map(String).filter(Boolean);\n } catch {\n // Fall back to comma-delimited tags below.\n }\n return trimmed\n .split(\",\")\n .map((part) => part.trim())\n .filter(Boolean);\n}\n\nfunction serializeTags(tags: string[]): string {\n return tags.join(\",\");\n}\n\nfunction isDateParam(param: OpenAPIParameter): boolean {\n const format = param.schema?.format?.toLowerCase();\n const text = `${param.name} ${param.description ?? \"\"}`.toLowerCase();\n return format === \"date\" || format === \"date-time\" || text.includes(\"date\");\n}\n\nfunction isZeroDate(value: string): boolean {\n return value.startsWith(\"0001-01-01\") || value === \"0001-01-01\";\n}\n\nfunction dateInputValue(value: string, dateTime: boolean): string {\n if (!value || value.startsWith(\"0001-01-01\")) return \"\";\n if (!dateTime) return value.slice(0, 10);\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value.slice(0, 16);\n const offset = parsed.getTimezoneOffset() * 60_000;\n return new Date(parsed.getTime() - offset).toISOString().slice(0, 16);\n}\n\nfunction dateOutputValue(value: string, dateTime: boolean): string {\n if (!value) return \"\";\n if (!dateTime) return value;\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) return value;\n return parsed.toISOString();\n}\n\nconst inputClassName =\n \"h-9 w-full min-w-0 rounded-md border border-input bg-background px-2 text-sm text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:bg-muted/40 focus-visible:ring-2 focus-visible:ring-ring\";\n"],"mappings":"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"}