From f913f9c56f1185df511258464124c817f94cfa61 Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Mon, 21 Jul 2025 14:01:49 -0300 Subject: [PATCH 1/8] fix: resolve save button activation in prompts settings (#5780) - Replace logical OR (||) with nullish coalescing (??) in onChange handlers - Fixes issue where empty strings were treated as falsy, preventing proper event handling - Applied fix to PromptsSettings.tsx and 5 similar instances in ModesView.tsx - Ensures Save button activates immediately when editing prompt text --- webview-ui/src/components/modes/ModesView.tsx | 10 +++++----- webview-ui/src/components/settings/PromptsSettings.tsx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 170d03b0e47..16cef65e1f4 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -833,7 +833,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { })()} onChange={(e) => { const value = - (e as unknown as CustomEvent)?.detail?.target?.value || + (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { @@ -888,7 +888,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { })()} onChange={(e) => { const value = - (e as unknown as CustomEvent)?.detail?.target?.value || + (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { @@ -943,7 +943,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { })()} onChange={(e) => { const value = - (e as unknown as CustomEvent)?.detail?.target?.value || + (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { @@ -1102,7 +1102,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { })()} onChange={(e) => { const value = - (e as unknown as CustomEvent)?.detail?.target?.value || + (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const customMode = findModeBySlug(visualMode, customModes) if (customMode) { @@ -1307,7 +1307,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { value={customInstructions || ""} onChange={(e) => { const value = - (e as unknown as CustomEvent)?.detail?.target?.value || + (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value setCustomInstructions(value || undefined) vscode.postMessage({ diff --git a/webview-ui/src/components/settings/PromptsSettings.tsx b/webview-ui/src/components/settings/PromptsSettings.tsx index a71132d62bb..3b2b5b2dfb2 100644 --- a/webview-ui/src/components/settings/PromptsSettings.tsx +++ b/webview-ui/src/components/settings/PromptsSettings.tsx @@ -147,7 +147,7 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom value={getSupportPromptValue(activeSupportOption)} onChange={(e) => { const value = - (e as unknown as CustomEvent)?.detail?.target?.value || + (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value const trimmedValue = value.trim() updateSupportPrompt(activeSupportOption, trimmedValue || undefined) From 7eae039367d4950a6dac793ceb7b1d9fc60c4d46 Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Mon, 21 Jul 2025 14:14:37 -0300 Subject: [PATCH 2/8] fix: ensure change detection triggers for all prompt types - Update CONDENSE prompt handling to also call setCustomSupportPrompts - This ensures the parent SettingsView component detects changes - Fixes issue where Save button remained disabled when editing prompts --- webview-ui/src/components/settings/PromptsSettings.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/webview-ui/src/components/settings/PromptsSettings.tsx b/webview-ui/src/components/settings/PromptsSettings.tsx index 3b2b5b2dfb2..5dd4e561ffe 100644 --- a/webview-ui/src/components/settings/PromptsSettings.tsx +++ b/webview-ui/src/components/settings/PromptsSettings.tsx @@ -62,6 +62,9 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom type: "updateCondensingPrompt", text: value || supportPrompt.default.CONDENSE, }) + // Also update the customSupportPrompts to trigger change detection + const updatedPrompts = { ...customSupportPrompts, [type]: value } + setCustomSupportPrompts(updatedPrompts) } else { const updatedPrompts = { ...customSupportPrompts, [type]: value } setCustomSupportPrompts(updatedPrompts) @@ -75,6 +78,10 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom type: "updateCondensingPrompt", text: supportPrompt.default.CONDENSE, }) + // Also update the customSupportPrompts to trigger change detection + const updatedPrompts = { ...customSupportPrompts } + delete updatedPrompts[type] + setCustomSupportPrompts(updatedPrompts) } else { const updatedPrompts = { ...customSupportPrompts } delete updatedPrompts[type] From 358a76be6c7bca705ba8c341a2faff3560a7ae44 Mon Sep 17 00:00:00 2001 From: MuriloFP Date: Mon, 21 Jul 2025 14:20:44 -0300 Subject: [PATCH 3/8] fix: remove immediate trim in onChange to ensure proper state updates - Move trimming logic into updateSupportPrompt function - This ensures the onChange event triggers immediately on any input - Empty strings are converted to undefined only when storing --- .../src/components/settings/PromptsSettings.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/webview-ui/src/components/settings/PromptsSettings.tsx b/webview-ui/src/components/settings/PromptsSettings.tsx index 5dd4e561ffe..c4b9e632d51 100644 --- a/webview-ui/src/components/settings/PromptsSettings.tsx +++ b/webview-ui/src/components/settings/PromptsSettings.tsx @@ -56,17 +56,21 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom }, []) const updateSupportPrompt = (type: SupportPromptType, value: string | undefined) => { + // Trim the value when storing, but keep empty strings + const trimmedValue = value?.trim() + const finalValue = trimmedValue === "" ? undefined : trimmedValue + if (type === "CONDENSE") { - setCustomCondensingPrompt(value || supportPrompt.default.CONDENSE) + setCustomCondensingPrompt(finalValue || supportPrompt.default.CONDENSE) vscode.postMessage({ type: "updateCondensingPrompt", - text: value || supportPrompt.default.CONDENSE, + text: finalValue || supportPrompt.default.CONDENSE, }) // Also update the customSupportPrompts to trigger change detection - const updatedPrompts = { ...customSupportPrompts, [type]: value } + const updatedPrompts = { ...customSupportPrompts, [type]: finalValue } setCustomSupportPrompts(updatedPrompts) } else { - const updatedPrompts = { ...customSupportPrompts, [type]: value } + const updatedPrompts = { ...customSupportPrompts, [type]: finalValue } setCustomSupportPrompts(updatedPrompts) } } @@ -156,8 +160,7 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value - const trimmedValue = value.trim() - updateSupportPrompt(activeSupportOption, trimmedValue || undefined) + updateSupportPrompt(activeSupportOption, value) }} rows={6} className="w-full" From 61aed256bba740e91c2d59be8f358a36902b7dd3 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 23 Sep 2025 22:38:33 +0000 Subject: [PATCH 4/8] fix: improve save button activation in prompts settings - Use nullish coalescing (??) instead of logical OR (||) to preserve empty strings - Remove trimming during editing to preserve intentional whitespace - Delete keys when undefined instead of setting them to undefined - Properly handle empty strings vs undefined values for better change detection Addresses review comments from PR #6026 --- webview-ui/src/components/modes/ModesView.tsx | 4 ++-- .../components/settings/PromptsSettings.tsx | 24 +++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 16cef65e1f4..ec44f2f9b06 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -1309,10 +1309,10 @@ const ModesView = ({ onDone }: ModesViewProps) => { const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value - setCustomInstructions(value || undefined) + setCustomInstructions(value ?? undefined) vscode.postMessage({ type: "customInstructions", - text: value.trim() || undefined, + text: value.trim() ?? undefined, }) }} rows={4} diff --git a/webview-ui/src/components/settings/PromptsSettings.tsx b/webview-ui/src/components/settings/PromptsSettings.tsx index c4b9e632d51..14b263715cc 100644 --- a/webview-ui/src/components/settings/PromptsSettings.tsx +++ b/webview-ui/src/components/settings/PromptsSettings.tsx @@ -56,21 +56,31 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom }, []) const updateSupportPrompt = (type: SupportPromptType, value: string | undefined) => { - // Trim the value when storing, but keep empty strings - const trimmedValue = value?.trim() - const finalValue = trimmedValue === "" ? undefined : trimmedValue + // Don't trim during editing to preserve intentional whitespace + // Use nullish coalescing to preserve empty strings + const finalValue = value ?? undefined if (type === "CONDENSE") { - setCustomCondensingPrompt(finalValue || supportPrompt.default.CONDENSE) + setCustomCondensingPrompt(finalValue ?? supportPrompt.default.CONDENSE) vscode.postMessage({ type: "updateCondensingPrompt", - text: finalValue || supportPrompt.default.CONDENSE, + text: finalValue ?? supportPrompt.default.CONDENSE, }) // Also update the customSupportPrompts to trigger change detection - const updatedPrompts = { ...customSupportPrompts, [type]: finalValue } + const updatedPrompts = { ...customSupportPrompts } + if (finalValue === undefined) { + delete updatedPrompts[type] + } else { + updatedPrompts[type] = finalValue + } setCustomSupportPrompts(updatedPrompts) } else { - const updatedPrompts = { ...customSupportPrompts, [type]: finalValue } + const updatedPrompts = { ...customSupportPrompts } + if (finalValue === undefined) { + delete updatedPrompts[type] + } else { + updatedPrompts[type] = finalValue + } setCustomSupportPrompts(updatedPrompts) } } From 93ea9e0aa9b1aff86b8a449b2060829b07d94c18 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 23 Sep 2025 22:42:21 +0000 Subject: [PATCH 5/8] test: update test expectations for nullish coalescing behavior - Update ModesView test to expect empty string preservation - Adjust expectations to match new ?? operator behavior vs || operator --- .../src/components/modes/__tests__/ModesView.spec.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx b/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx index e202114bbba..7e856166139 100644 --- a/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx +++ b/webview-ui/src/components/modes/__tests__/ModesView.spec.tsx @@ -223,12 +223,13 @@ describe("PromptsView", () => { const changeEvent = new Event("change", { bubbles: true }) fireEvent(textarea, changeEvent) - // The component calls setCustomInstructions with value || undefined - // Since empty string is falsy, it should be undefined - expect(setCustomInstructions).toHaveBeenCalledWith(undefined) + // The component calls setCustomInstructions with value ?? undefined + // With nullish coalescing, empty string is preserved (not treated as nullish) + expect(setCustomInstructions).toHaveBeenCalledWith("") + // The postMessage call will have multiple calls, we need to check the right one expect(vscode.postMessage).toHaveBeenCalledWith({ type: "customInstructions", - text: undefined, + text: "", // empty string is now preserved with ?? operator }) }) }) From bf3f2ff83d9e7f450d715fc0f641f73877856dbc Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 24 Sep 2025 22:05:46 +0000 Subject: [PATCH 6/8] fix(webview): preserve empty strings using nullish coalescing in prompts and modes --- tmp/Roo-Code | 1 + webview-ui/src/components/modes/ModesView.tsx | 3 ++- webview-ui/src/components/settings/PromptsSettings.tsx | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 160000 tmp/Roo-Code diff --git a/tmp/Roo-Code b/tmp/Roo-Code new file mode 160000 index 00000000000..b73680084ae --- /dev/null +++ b/tmp/Roo-Code @@ -0,0 +1 @@ +Subproject commit b73680084ae2f98ad6c741dcf28af8faa2e0599a diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index ec44f2f9b06..4cdbd1030f6 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -1109,7 +1109,8 @@ const ModesView = ({ onDone }: ModesViewProps) => { // For custom modes, update the JSON file updateCustomMode(visualMode, { ...customMode, - customInstructions: value.trim() || undefined, + // Preserve empty string; only treat null/undefined as unset + customInstructions: value.trim() ?? undefined, source: customMode.source || "global", }) } else { diff --git a/webview-ui/src/components/settings/PromptsSettings.tsx b/webview-ui/src/components/settings/PromptsSettings.tsx index 14b263715cc..9bad019c01b 100644 --- a/webview-ui/src/components/settings/PromptsSettings.tsx +++ b/webview-ui/src/components/settings/PromptsSettings.tsx @@ -105,7 +105,8 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom const getSupportPromptValue = (type: SupportPromptType): string => { if (type === "CONDENSE") { - return customCondensingPrompt || supportPrompt.default.CONDENSE + // Preserve empty string - only fall back to default when value is nullish + return customCondensingPrompt ?? supportPrompt.default.CONDENSE } return supportPrompt.get(customSupportPrompts, type) } From cc2622078f9f8df192492ce9e33bcb32d274b8de Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 24 Sep 2025 22:07:33 +0000 Subject: [PATCH 7/8] chore: remove stray nested gitlink tmp/Roo-Code --- tmp/Roo-Code | 1 - 1 file changed, 1 deletion(-) delete mode 160000 tmp/Roo-Code diff --git a/tmp/Roo-Code b/tmp/Roo-Code deleted file mode 160000 index b73680084ae..00000000000 --- a/tmp/Roo-Code +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b73680084ae2f98ad6c741dcf28af8faa2e0599a From cae23377087b1f588041193c0609d651e623ed9a Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Thu, 25 Sep 2025 17:57:26 -0500 Subject: [PATCH 8/8] fix(settings/prompts): enable Save on textarea input and preserve empty strings Use onInput to update custom support prompts per keystroke (no blur needed). In ModesView, avoid trimming during editing and send raw values to backend; preserve empty strings via ?? to ensure immediate dirty state. Closes #5780. --- webview-ui/src/components/modes/ModesView.tsx | 4 ++-- webview-ui/src/components/settings/PromptsSettings.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 4cdbd1030f6..cc8bd7389c8 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -1110,7 +1110,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { updateCustomMode(visualMode, { ...customMode, // Preserve empty string; only treat null/undefined as unset - customInstructions: value.trim() ?? undefined, + customInstructions: value ?? undefined, source: customMode.source || "global", }) } else { @@ -1313,7 +1313,7 @@ const ModesView = ({ onDone }: ModesViewProps) => { setCustomInstructions(value ?? undefined) vscode.postMessage({ type: "customInstructions", - text: value.trim() ?? undefined, + text: value ?? undefined, }) }} rows={4} diff --git a/webview-ui/src/components/settings/PromptsSettings.tsx b/webview-ui/src/components/settings/PromptsSettings.tsx index 9bad019c01b..e0f208f1e29 100644 --- a/webview-ui/src/components/settings/PromptsSettings.tsx +++ b/webview-ui/src/components/settings/PromptsSettings.tsx @@ -167,7 +167,7 @@ const PromptsSettings = ({ customSupportPrompts, setCustomSupportPrompts }: Prom { + onInput={(e) => { const value = (e as unknown as CustomEvent)?.detail?.target?.value ?? ((e as any).target as HTMLTextAreaElement).value