From 2caa320face244728530229f4a4a58b2e66f5493 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 10 Feb 2025 00:08:52 -0500 Subject: [PATCH] Make sure to blur fields when user hits Done in settings --- .changeset/fair-boxes-smile.md | 5 ++ .../src/components/settings/SettingsView.tsx | 8 ++- .../settings/__tests__/SettingsView.test.tsx | 56 +++++++++---------- 3 files changed, 39 insertions(+), 30 deletions(-) create mode 100644 .changeset/fair-boxes-smile.md diff --git a/.changeset/fair-boxes-smile.md b/.changeset/fair-boxes-smile.md new file mode 100644 index 0000000000..d4b770b683 --- /dev/null +++ b/.changeset/fair-boxes-smile.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Make sure that we fire the onBlur for edited fields when the user hits Done in settings diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index bd2a244afb..307ac250da 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -68,7 +68,13 @@ const SettingsView = ({ onDone }: SettingsViewProps) => { const [modelIdErrorMessage, setModelIdErrorMessage] = useState(undefined) const [commandInput, setCommandInput] = useState("") - const handleSubmit = () => { + const handleSubmit = async () => { + // Focus the active element's parent to trigger blur + document.activeElement?.parentElement?.focus() + + // Small delay to let blur events complete + await new Promise((resolve) => setTimeout(resolve, 50)) + const apiValidationResult = validateApiConfiguration(apiConfiguration) const modelIdValidationResult = validateModelId(apiConfiguration, glamaModels, openRouterModels) diff --git a/webview-ui/src/components/settings/__tests__/SettingsView.test.tsx b/webview-ui/src/components/settings/__tests__/SettingsView.test.tsx index 4beb30dd1c..e9242f7be6 100644 --- a/webview-ui/src/components/settings/__tests__/SettingsView.test.tsx +++ b/webview-ui/src/components/settings/__tests__/SettingsView.test.tsx @@ -1,5 +1,4 @@ -import React from "react" -import { render, screen, fireEvent } from "@testing-library/react" +import { render, screen, fireEvent, waitFor } from "@testing-library/react" import SettingsView from "../SettingsView" import { ExtensionStateContextProvider } from "../../../context/ExtensionStateContext" import { vscode } from "../../../utils/vscode" @@ -14,14 +13,7 @@ jest.mock("../../../utils/vscode", () => ({ // Mock ApiConfigManager component jest.mock("../ApiConfigManager", () => ({ __esModule: true, - default: ({ - currentApiConfigName, - listApiConfigMeta, - onSelectConfig, - onDeleteConfig, - onRenameConfig, - onUpsertConfig, - }: any) => ( + default: ({ currentApiConfigName }: any) => (
Current config: {currentApiConfigName}
@@ -134,7 +126,7 @@ describe("SettingsView - Sound Settings", () => { expect(screen.queryByRole("slider", { name: /volume/i })).not.toBeInTheDocument() }) - it("toggles sound setting and sends message to VSCode", () => { + it("toggles sound setting and sends message to VSCode", async () => { renderSettingsView() const soundCheckbox = screen.getByRole("checkbox", { @@ -149,12 +141,14 @@ describe("SettingsView - Sound Settings", () => { const doneButton = screen.getByText("Done") fireEvent.click(doneButton) - expect(vscode.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - type: "soundEnabled", - bool: true, - }), - ) + await waitFor(() => { + expect(vscode.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: "soundEnabled", + bool: true, + }), + ) + }) }) it("shows volume slider when sound is enabled", () => { @@ -172,7 +166,7 @@ describe("SettingsView - Sound Settings", () => { expect(volumeSlider).toHaveValue("0.5") }) - it("updates volume and sends message to VSCode when slider changes", () => { + it("updates volume and sends message to VSCode when slider changes", async () => { renderSettingsView() // Enable sound @@ -190,9 +184,11 @@ describe("SettingsView - Sound Settings", () => { fireEvent.click(doneButton) // Verify message sent to VSCode - expect(vscode.postMessage).toHaveBeenCalledWith({ - type: "soundVolume", - value: 0.75, + await waitFor(() => { + expect(vscode.postMessage).toHaveBeenCalledWith({ + type: "soundVolume", + value: 0.75, + }) }) }) }) @@ -309,7 +305,7 @@ describe("SettingsView - Allowed Commands", () => { expect(commands).toHaveLength(1) }) - it("saves allowed commands when clicking Done", () => { + it("saves allowed commands when clicking Done", async () => { const { onDone } = renderSettingsView() // Enable always allow execute @@ -329,12 +325,14 @@ describe("SettingsView - Allowed Commands", () => { fireEvent.click(doneButton) // Verify VSCode messages were sent - expect(vscode.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - type: "allowedCommands", - commands: ["npm test"], - }), - ) - expect(onDone).toHaveBeenCalled() + await waitFor(() => { + expect(vscode.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: "allowedCommands", + commands: ["npm test"], + }), + ) + expect(onDone).toHaveBeenCalled() + }) }) })