diff --git a/src/components/AgentModelsDialog.tsx b/src/components/AgentModelsDialog.tsx index 95ae4397c..0f88396b4 100644 --- a/src/components/AgentModelsDialog.tsx +++ b/src/components/AgentModelsDialog.tsx @@ -22,7 +22,12 @@ import { serializeAgentConfig, } from "../lib/models/agent-config-serialization"; import { formatCompactModelId, formatModelDisplay } from "../lib/models/display"; -import { type ModelOverrideMap, type ModelOverrideTarget } from "../lib/models/overrides"; +import type { ModelOverrideMap, ModelOverrideTarget } from "../lib/models/overrides"; +import { + DismissGuardNotice, + handleRovingFocusKeyDown, + useAccessibleDialog, +} from "./accessibility/AccessibleDialog"; import type { ComposerModelOption } from "./ChatComposer"; import { CopyRawButton } from "./chat/CopyRawButton"; import type { @@ -161,18 +166,13 @@ export function AgentModelsDialog({ } }, [open]); - useEffect(() => { - if (!open) { - return; - } - const handler = (event: KeyboardEvent) => { - if (event.key === "Escape") { - onClose(); - } - }; - window.addEventListener("keydown", handler); - return () => window.removeEventListener("keydown", handler); - }, [open, onClose]); + const accessibleDialog = useAccessibleDialog({ + open, + onClose, + hasUnsavedChanges: Boolean( + pasteValue.trim() || profileName.trim() || profileDescription.trim(), + ), + }); const serialized = useMemo( () => @@ -329,13 +329,17 @@ export function AgentModelsDialog({ ); return ( -
+
event.stopPropagation()} + aria-describedby={ + accessibleDialog.showDismissGuard ? "agent-models-dismiss-warning" : undefined + } + tabIndex={-1} >
- +
+ +
+ +
{tab === "agents" ? ( <> diff --git a/src/components/AppConfigDialog.tsx b/src/components/AppConfigDialog.tsx index 6584473a2..f12423e02 100644 --- a/src/components/AppConfigDialog.tsx +++ b/src/components/AppConfigDialog.tsx @@ -21,6 +21,11 @@ import { } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; +import { + DismissGuardNotice, + handleRovingFocusKeyDown, + useAccessibleDialog, +} from "./accessibility/AccessibleDialog"; import { readJson } from "./chat/messageUtils"; type TargetKind = "storage" | "vector" | "llm" | "observability" | "compute"; @@ -163,6 +168,15 @@ export function AppConfigDialog({ return draft.observability.targets; }, [draft, tab]); + const configDirty = + Boolean(importText.trim()) || + (draft !== null && view !== null && JSON.stringify(draft) !== JSON.stringify(view.config)); + const accessibleDialog = useAccessibleDialog({ + open, + onClose, + hasUnsavedChanges: configDirty, + }); + if (!open) return null; const updateTarget = (targetId: string, patch: Partial) => { @@ -402,13 +416,17 @@ export function AppConfigDialog({ const registry = view?.registry[tab] ?? []; return ( -
+
event.stopPropagation()} + aria-describedby={ + accessibleDialog.showDismissGuard ? "app-config-dismiss-warning" : undefined + } + tabIndex={-1} >
@@ -425,7 +443,8 @@ export function AppConfigDialog({ className="icon-button" type="button" aria-label="Close app configuration" - onClick={onClose} + data-dialog-initial-focus + onClick={accessibleDialog.requestClose} > @@ -453,7 +472,7 @@ export function AppConfigDialog({
) : null} - +
+ +
+ +