atelier settings: enter saves the api key

the key field was an Input and a Button side by side, outside a form, so Enter
did nothing. pasting a key and pressing enter is the strongest habit there is
in a password field, and when it silently does nothing it reads as "the key
did not save" — which is the one thing this screen must never be ambiguous
about.

TODO.md tracks nineteen panels with the same defect. this is not the twentieth.

everything else in the screen was already right and is left alone: type=password,
autoComplete=off, the server never returning a key, and the field starting
empty with a placeholder that says whether one is set.
This commit is contained in:
2026-08-20 16:39:51 +00:00
parent 1d1a4a6fa5
commit 7579620f81
@@ -195,7 +195,17 @@ export const AtelierProviders = () => {
<Label htmlFor={`${provider.id}-key`} className="text-xs text-duck-dark/70 dark:text-foreground/70">
API key
</Label>
<div className="flex gap-2">
{/* A form, so Enter saves. Pasting a key and pressing Enter is the strongest habit there
is in a password field, and outside a form it silently does nothing — which reads as
"the key did not save". TODO.md tracks nineteen panels with this same defect; this is
not the twentieth. */}
<form
className="flex gap-2"
onSubmit={(ev) => {
ev.preventDefault();
void saveKey(provider.id);
}}
>
<Input
id={`${provider.id}-key`}
type="password"
@@ -204,10 +214,10 @@ export const AtelierProviders = () => {
value={keyDrafts[provider.id] ?? ''}
onChange={(ev) => setKeyDrafts((current) => ({ ...current, [provider.id]: ev.target.value }))}
/>
<Button disabled={busyHere || !keyDrafts[provider.id]?.trim()} onClick={() => saveKey(provider.id)}>
<Button type="submit" disabled={busyHere || !keyDrafts[provider.id]?.trim()}>
Save
</Button>
</div>
</form>
<p className="text-xs text-duck-dark/40 dark:text-foreground/40">
Stored encrypted. The server never sends a key back, so this field always starts empty.
</p>