import { useEffect, useState } from "react"; import { LuEye, LuEyeOff } from "react-icons/lu"; import { errorMessage } from "../api/client.js"; import { fetchHttpAuthLiterals, useHttpPages, useUpsertHttpAuth, } from "../api/hooks.js"; import { FormInput, FormSelect } from "./FormControls.jsx"; function emptyCred(source = "literal") { return { source, value: "", kv: "", namespace: "", secret: "" }; } function credFromPublic(field, literalValue) { if (!field || field.source === "missing") return emptyCred("literal"); if (field.source === "kv") { return { source: "kv", value: "", kv: field.kv ?? "", namespace: field.namespace ?? "", secret: "", }; } if (field.source === "secret") { return { source: "secret", value: "", kv: "", namespace: "", secret: field.secret ?? "", }; } if (typeof literalValue === "string") { return { source: "literal", value: literalValue, kv: "", namespace: "", secret: "", keep: true, }; } return { source: "literal", value: "", kv: "", namespace: "", secret: "", keep: field.set === true, }; } function toApiField(cred, { required = true } = {}) { if (cred.source === "kv") { const out = { kv: cred.kv }; if (cred.namespace) out.namespace = cred.namespace; return out; } if (cred.source === "secret") { return { secret: cred.secret }; } if (cred.value) return cred.value; if (cred.keep) return { keep: true }; if (!required) return ""; return null; } function emptyForm() { return { id: null, name: "", type: "bearer", token: emptyCred(), user: emptyCred(), password: emptyCred(), header: "", value: emptyCred(), unauthorized_status: "", unauthorized_response: "", }; } function formFromAuth(auth, literals = {}) { const cfg = auth.config ?? {}; return { id: auth.id, name: auth.name, type: auth.type, token: credFromPublic(cfg.token, literals.token), user: credFromPublic(cfg.user, literals.user), password: credFromPublic(cfg.password, literals.password), header: cfg.header ?? "", value: credFromPublic(cfg.value, literals.value), unauthorized_status: auth.unauthorized_status ?? "", unauthorized_response: auth.unauthorized_response ?? "", }; } function Field({ label, children, hint }) { return (
{label}
{children} {hint ? (
{hint}
) : null}
); } function CredentialFields({ label, cred, onChange, allowEmpty, masked }) { const [show, setShow] = useState(false); return (

{label}

onChange({ ...cred, source: e.target.value, keep: false })} > {cred.source === "literal" ? (
onChange({ ...cred, value: e.target.value, keep: false })} placeholder={ cred.keep && !cred.value ? "(unchanged — leave blank to keep)" : "" } required={!allowEmpty && !cred.keep && !cred.value} autoComplete="off" /> {masked ? ( ) : null}
) : null} {cred.source === "kv" ? ( <> onChange({ ...cred, namespace: e.target.value })} /> onChange({ ...cred, kv: e.target.value })} required /> ) : null} {cred.source === "secret" ? ( onChange({ ...cred, secret: e.target.value })} required pattern="[A-Za-z0-9._-]+" /> ) : null}
); } /** * Add / edit an HTTP trigger auth profile. * Reusable: mount when open; pass `auth` for edit (literals loaded inside). * * @param {"add" | "edit"} mode * @param {object} [auth] Public auth row when mode is "edit" * @param {() => void} onClose * @param {(saved: unknown) => void} [onSaved] */ export function AuthEditorModal({ mode, auth, onClose, onSaved }) { const { data: pages = [] } = useHttpPages(); const upsert = useUpsertHttpAuth(); const [form, setForm] = useState(emptyForm); const [loading, setLoading] = useState(mode === "edit"); useEffect(() => { if (mode !== "edit" || !auth?.id) { setForm(emptyForm()); setLoading(false); return; } let cancelled = false; setLoading(true); (async () => { /** @type {Record} */ let literals = {}; try { const data = await fetchHttpAuthLiterals(auth.id); literals = data.literals ?? {}; } catch { // Form still works with keep markers } if (cancelled) return; setForm(formFromAuth(auth, literals)); setLoading(false); })(); return () => { cancelled = true; }; }, [mode, auth]); function onSubmit(e) { e.preventDefault(); /** @type {Record} */ let config = {}; if (form.type === "bearer") { const token = toApiField(form.token); if (token == null) return; config = { token }; } else if (form.type === "basic") { const user = toApiField(form.user); if (user == null) return; const password = toApiField(form.password, { required: false }); config = { user, password: password ?? "" }; } else { const value = toApiField(form.value); if (value == null) return; config = { header: form.header, value }; } upsert.mutate( { id: form.id, name: form.name, type: form.type, config, unauthorized_status: form.unauthorized_status === "" ? null : Number(form.unauthorized_status), unauthorized_response: form.unauthorized_response || null, }, { onSuccess: (data) => { onSaved?.(data?.auth ?? data); onClose(); }, }, ); } const title = mode === "add" ? "New auth profile" : `Edit ${form.name || auth?.name || ""}`; return (

{title}

{loading ? (
) : (
setForm({ ...form, name: e.target.value })} required pattern="[A-Za-z0-9._-]+" autoComplete="off" /> setForm({ ...form, type: e.target.value })} > {form.type === "bearer" ? ( setForm({ ...form, token })} /> ) : null} {form.type === "basic" ? ( <> setForm({ ...form, user })} /> setForm({ ...form, password })} allowEmpty masked /> ) : null} {form.type === "header" ? ( <> setForm({ ...form, header: e.target.value })} required placeholder="X-Webhook-Secret" /> setForm({ ...form, value })} /> ) : null} setForm({ ...form, unauthorized_status: e.target.value })} min={100} max={599} placeholder="401" /> setForm({ ...form, unauthorized_response: e.target.value })} > {pages.map((p) => ( ))} {upsert.isError ? (

{errorMessage(upsert.error)}

) : null}
)} {loading ? (
) : null}
); }