fix(settings): buffer Save-managed settings in cachedState until Save#872
fix(settings): buffer Save-managed settings in cachedState until Save#872JunyongParkDev wants to merge 2 commits into
Conversation
Several controls inside SettingsView wrote their changes to the extension host immediately via `updateSettings`, instead of buffering them in local `cachedState` and waiting for the user to click Save. Because Discard reverts edits by resetting `cachedState` to the persisted state, any control that already posted `updateSettings` poisoned that source of truth — so Discard could no longer undo the change, silently breaking the Save/Discard contract. Route all five Save-managed values exclusively through `cachedState` / `setCachedStateField` while SettingsView is open: - allowedCommands / deniedCommands (AutoApproveSettings): drop the immediate updateSettings on add/remove. - profileThresholds (ContextManagementSettings): drop the immediate updateSettings on the non-default profile branch; remove the now-unused vscode import. - includeTaskHistoryInEnhance (PromptsSettings): drop the immediate updateSettings on toggle. - mcpEnabled (McpEnabledToggle / McpView): adopt the existing "props first, fall back to context" pattern so SettingsView can pass the buffered value and a cachedState-backed setter; uncontrolled usage keeps the original immediate behavior. Genuinely-immediate actions (autoApprovalEnabled, per-server MCP toggle/delete/restart/timeout) are not in the Save payload and are left unchanged. The extension host side is correct and untouched. Add/update tests at the webview-ui component layer: buffering assertions for each control, a McpEnabledToggle controlled/uncontrolled regression, and a SettingsView Discard regression. Signed-off-by: JunyongParkDev <jun94.park@samsung.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughSettings-managed controls now update cached state without immediate persistence. MCP enablement supports controlled state in ChangesSettings buffering and MCP integration
Estimated code review effort: 3 (Moderate) | ~25 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Related GitHub Issue
Closes: #862
Description
Several controls inside
SettingsViewwrote their changes to the extension host immediately viaupdateSettings, instead of buffering them in the localcachedStateand waiting for the user to click Save. Because Discard reverts edits by resettingcachedStateback to the persisted state (setCachedState(extensionState)), any control that had already postedupdateSettingspoisoned that source of truth — so Discard could no longer undo the change, silently breaking the Save/Discard contract.This PR routes all five Save-managed values exclusively through
cachedState/setCachedStateFieldwhileSettingsViewis open:allowedCommands/deniedCommands(AutoApproveSettings) — drop the immediateupdateSettingson command add/remove.profileThresholds(ContextManagementSettings) — drop the immediateupdateSettingson the non-default profile branch; remove the now-unusedvscodeimport.includeTaskHistoryInEnhance(PromptsSettings) — drop the immediateupdateSettingson toggle.mcpEnabled(McpEnabledToggle/McpView) — adopt the existing "props first, fall back to context" pattern soSettingsViewcan pass the buffered value and acachedState-backed setter. BecausemcpEnabledis also read byMcpViewto gate the server list, the prop is threaded throughMcpViewdown to the toggle.Design choices / trade-offs:
webviewMessageHandler.ts) is correct and left untouched — persisting on receipt ofupdateSettingsis expected. The fix belongs on the webview side: stop sending it before Save.McpEnabledToggleandMcpViewstay backward compatible: when used uncontrolled (no props), they fall back to live extension state and keep the original immediate-persist behavior. Only theSettingsView(controlled) path buffers.autoApprovalEnabledand the per-server MCP actions (toggleMcpServer,deleteMcpServer,restartMcpServer,updateMcpTimeout).Test Procedure
Automated (webview-ui component/unit layer — the lowest layer that would have failed):
cd webview-ui npx vitest run \ src/components/settings/__tests__/AutoApproveSettings.spec.tsx \ src/components/settings/__tests__/ContextManagementSettings.spec.tsx \ src/components/settings/__tests__/PromptsSettings.spec.tsx \ src/components/mcp/__tests__/McpEnabledToggle.spec.tsx \ src/components/settings/__tests__/SettingsView.spec.tsxAdded / updated tests:
AutoApproveSettings— adding/removing allowed & denied commands buffers viasetCachedStateFieldand posts noupdateSettings.ContextManagementSettings— changing a non-default profile threshold buffers and posts noupdateSettings.PromptsSettings— toggling include-task-history calls the setter and posts noupdateSettings.McpEnabledToggle— controlled usage buffers via the setter prop and posts nothing; uncontrolled usage keeps the original immediate behavior.SettingsView— existing allowed-command tests updated to assert no pre-Save persistence, plus a new Discard regression test.Manual (reproduces the original bug; using Allowed Commands as the example):
npm testin the allowed-commands input and click Add.npm testis still there. After this PR: it is gone.The same flow reproduces for denied commands, non-default profile thresholds,
Prompts → Enhance → include task history, and MCP → Enable MCP.
Pre-Submission Checklist
Screenshots / Videos
Documentation Updates
Additional Notes
The behavior now matches the repository's Settings View Pattern: Save-managed values bind to local
cachedState,Saveposts them once viahandleSubmit, andDiscardfully reverts. No changes to the extension host or message protocol.Get in Touch
Summary by CodeRabbit