fix(web): keep focus in place after removing a media API key (#148)
Remove unmounts itself once clicked, so focus fell to the body and the settings dialog pulled it back to its popup a frame later. Whatever field the user (or a test) focused in that frame lost focus again; in CI the cleared transcription URL was still sent on the next save. Remove now moves focus to the key field before it disappears. Claude-Session: https://claude.ai/code/session_01UfVneQG6488JGLiHYAc9RZ Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
ca57ebda85
commit
f3fb07e41f
@ -105,6 +105,7 @@ test("the deployment owner points media at their own servers", async ({ page },
|
|||||||
await expect(comfyKey).toHaveAttribute("placeholder", "Saved");
|
await expect(comfyKey).toHaveAttribute("placeholder", "Saved");
|
||||||
|
|
||||||
await comfy.getByRole("button", { name: "Remove", exact: true }).click();
|
await comfy.getByRole("button", { name: "Remove", exact: true }).click();
|
||||||
|
await expect(comfyKey).toBeFocused();
|
||||||
await transcription.getByLabel("Server URL", { exact: true }).fill("");
|
await transcription.getByLabel("Server URL", { exact: true }).fill("");
|
||||||
await panel.getByRole("button", { name: "Save", exact: true }).click();
|
await panel.getByRole("button", { name: "Save", exact: true }).click();
|
||||||
await expect.poll(() => saved.length).toBe(2);
|
await expect.poll(() => saved.length).toBe(2);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Trans, useLingui } from "@lingui/react/macro";
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
import type { MediaSettingsUpdate, MediaSettingsView } from "@rakazo/contracts";
|
import type { MediaSettingsUpdate, MediaSettingsView } from "@rakazo/contracts";
|
||||||
import { Button, Field, FieldLabel, Input, Textarea } from "@rakazo/ui-web";
|
import { Button, Field, FieldLabel, Input, Textarea } from "@rakazo/ui-web";
|
||||||
import { useEffect, useId, useState } from "react";
|
import { useEffect, useId, useRef, useState } from "react";
|
||||||
import { rpc } from "../lib/rpc";
|
import { rpc } from "../lib/rpc";
|
||||||
import { SuccessPop } from "./ai/primitives";
|
import { SuccessPop } from "./ai/primitives";
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ function ApiKeyField({
|
|||||||
}) {
|
}) {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const id = useId();
|
const id = useId();
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const showSaved = saved && !draft.remove;
|
const showSaved = saved && !draft.remove;
|
||||||
return (
|
return (
|
||||||
<Field className="mt-4">
|
<Field className="mt-4">
|
||||||
@ -41,13 +42,19 @@ function ApiKeyField({
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="xs"
|
size="xs"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={() => onChange({ value: "", remove: true })}
|
onClick={() => {
|
||||||
|
// The button unmounts once clicked; hand focus to the field so the dialog
|
||||||
|
// does not pull it back to its popup a frame later.
|
||||||
|
inputRef.current?.focus();
|
||||||
|
onChange({ value: "", remove: true });
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Trans>Remove</Trans>
|
<Trans>Remove</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
|
ref={inputRef}
|
||||||
id={id}
|
id={id}
|
||||||
type="password"
|
type="password"
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user