diff --git a/packages/web/src/components/AuthEditorModal.jsx b/packages/web/src/components/AuthEditorModal.jsx index 8b01e7d..67977c0 100644 --- a/packages/web/src/components/AuthEditorModal.jsx +++ b/packages/web/src/components/AuthEditorModal.jsx @@ -6,6 +6,7 @@ import { useHttpPages, useUpsertHttpAuth, } from "../api/hooks.js"; +import { FormInput, FormSelect } from "./FormControls.jsx"; function emptyCred(source = "literal") { return { source, value: "", kv: "", namespace: "", secret: "" }; @@ -120,15 +121,15 @@ function CredentialFields({ label, cred, onChange, allowEmpty, masked }) {

{label}

- + {cred.source === "literal" ? (
- onChange({ ...cred, value: e.target.value, keep: false })} placeholder={ @@ -168,16 +169,16 @@ function CredentialFields({ label, cred, onChange, allowEmpty, masked }) { {cred.source === "kv" ? ( <> - onChange({ ...cred, namespace: e.target.value })} /> - onChange({ ...cred, kv: e.target.value })} @@ -191,8 +192,8 @@ function CredentialFields({ label, cred, onChange, allowEmpty, masked }) { label="Secret name" hint="Encrypted secret — value is never shown here. Manage it on the Secrets page." > - onChange({ ...cred, secret: e.target.value })} @@ -297,8 +298,8 @@ export function AuthEditorModal({ mode, auth, onClose, onSaved }) { ) : (
- setForm({ ...form, name: e.target.value })} required @@ -308,15 +309,15 @@ export function AuthEditorModal({ mode, auth, onClose, onSaved }) { - + {form.type === "bearer" ? ( @@ -345,8 +346,8 @@ export function AuthEditorModal({ mode, auth, onClose, onSaved }) { {form.type === "header" ? ( <> - setForm({ ...form, header: e.target.value })} required @@ -362,9 +363,9 @@ export function AuthEditorModal({ mode, auth, onClose, onSaved }) { ) : null} - setForm({ ...form, unauthorized_status: e.target.value })} min={100} @@ -374,8 +375,8 @@ export function AuthEditorModal({ mode, auth, onClose, onSaved }) { - + {upsert.isError ? ( diff --git a/packages/web/src/components/ConfirmDialog.jsx b/packages/web/src/components/ConfirmDialog.jsx new file mode 100644 index 0000000..6a24543 --- /dev/null +++ b/packages/web/src/components/ConfirmDialog.jsx @@ -0,0 +1,55 @@ +import { Modal } from "./Modal.jsx"; + +/** + * Shared confirm / delete dialog. + * + * @param {object} props + * @param {boolean} props.open + * @param {string} props.title + * @param {import("react").ReactNode} [props.message] + * @param {string} [props.confirmLabel] + * @param {string} [props.confirmClass] + * @param {boolean} [props.loading] + * @param {boolean} [props.pending] alias for loading + * @param {boolean} [props.confirmDisabled] + * @param {import("react").ReactNode} [props.error] + * @param {() => void} props.onCancel + * @param {() => void} props.onConfirm + */ +export function ConfirmDialog({ + open, + title, + message, + confirmLabel = "Delete", + confirmClass = "btn-error", + loading, + pending, + confirmDisabled = false, + error, + onCancel, + onConfirm, +}) { + const busy = Boolean(loading ?? pending); + + return ( + +

{title}

+ {message ?
{message}
: null} + {error ?

{error}

: null} +
+ + +
+
+ ); +} diff --git a/packages/web/src/components/FormControls.jsx b/packages/web/src/components/FormControls.jsx new file mode 100644 index 0000000..d971e8e --- /dev/null +++ b/packages/web/src/components/FormControls.jsx @@ -0,0 +1,27 @@ +/** + * Shared DaisyUI form controls — always bordered + sm. + */ + +import { forwardRef } from "react"; + +export const FormInput = forwardRef(function FormInput({ className = "", ...props }, ref) { + return ; +}); + +export const FormSelect = forwardRef(function FormSelect({ className = "", children, ...props }, ref) { + return ( + + ); +}); + +export const FormTextarea = forwardRef(function FormTextarea({ className = "", ...props }, ref) { + return ( +