import { useState } from "react"; import { emptyPlacement, type AuthMethod, type Placement } from "../lib/auth-placements"; import { Button } from "./button"; import { DialogFooter } from "./dialog"; import { Input } from "./input"; import { Label } from "./label"; import { PlacementEditor } from "./placement-editor"; // --------------------------------------------------------------------------- // Add custom auth method — apiKey-only, plugin-agnostic. // // A custom method is reusable: any account on this integration can pick it. The // user names it and declares one or more PLACEMENTS (where the credential goes). // This component owns the UI; the plugin-specific persistence (mapping generic // placements to its wire template + the configure mutation) is INJECTED via // `onCreate`, so `packages/react` never imports a plugin package (the dependency // runs the other way). OAuth is never offered here — custom methods are // apiKey-only (decided). // --------------------------------------------------------------------------- /** Persist a custom method built from the user's placements. Returns the * created `AuthMethod` (so the caller can select it) or `null` on failure. The * plugin binds this to its own template converter + configure mutation. */ export type CreateCustomMethod = (input: { readonly label: string; readonly placements: readonly Placement[]; }) => Promise; export function AddCustomMethodForm(props: { readonly onCreate: CreateCustomMethod; readonly onCreated: (method: AuthMethod) => void; readonly onCancel: () => void; }) { const { onCreate, onCreated, onCancel } = props; const [label, setLabel] = useState(""); const [placements, setPlacements] = useState([emptyPlacement()]); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const namedPlacements = placements.filter((p: Placement) => p.name.trim().length > 0); const canSubmit = !submitting && namedPlacements.length > 0; const handleSubmit = async () => { if (!canSubmit) return; setSubmitting(true); setError(null); const created = await onCreate({ label: label.trim(), placements: namedPlacements, }); if (created === null) { setSubmitting(false); setError("Failed to add method. Please try again."); return; } onCreated(created); }; return ( <>

Optional; shown in the connection picker.

) => setLabel(e.target.value)} />

Bearer-token APIs usually use an Authorization header with a Bearer prefix.

{error ?

{error}

: null}
); }