refactor(cli): Reactive useSettingsStore hook#14915
refactor(cli): Reactive useSettingsStore hook#14915jacob314 merged 7 commits intogoogle-gemini:mainfrom
Conversation
Summary of ChangesHello @psinha40898, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request undertakes a substantial refactor of the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This is an excellent refactoring of the SettingsDialog component. The introduction of useReducer to manage the component's complex state and the extraction of inline editing logic into the useInlineEdit custom hook have significantly improved the code's structure, readability, and maintainability. Deriving state where possible, like for showRestartPrompt and effectiveFocusSection, is a great application of React best practices. The addition of comprehensive tests for the new reducer and hook is also a major plus, ensuring the new logic is robust.
I found one logic issue in how default values for restart-required settings are handled, which I've detailed in a specific comment. Besides that, this is a very strong pull request that greatly enhances the quality of the codebase.
|
The PR successfully refactors Code Quality & Patterns
Tests
Logic Issue (Reset to Default)I confirmed the potential issue with resetting to default values for restart-required settings:
// Example fix for the PendingValue type
export type PendingValue = boolean | number | string | undefined; // undefined represents 'unset'RecommendationThis is a high-quality refactor. Please address the |
1605c8c to
5aaf2bb
Compare
I can push a defect test a long with a fix but will note it for now and wait for a reviewer to decide whether this refactor PR should modify any
Same here because the Because the focus of the PR is on React usage |
|
Thanks for the significant refactor! This cleans up the state management in I've reviewed the changes and the discussion. Here are the items to address before merging:
Verification: Great work on simplifying this component! |
6d69a2e to
6b11a74
Compare
jacob314
left a comment
There was a problem hiding this comment.
think this is generally on the right track. need to go a bit further to make sure we don't have any odd patterns forcing updates left. commented on the couple remaining cases where I see us forcing updates in a somewhat hacky way. if possible would be nice to remove as well.
|
let me know when this is ready fore view. there are a few merge conflicts. |
358fadd to
6cf9ba8
Compare
|
Instead of refactoring settings to be a store it is probably better to use the event bus architecture in place |
|
Hi @psinha40898, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this. We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: Improving Our Contribution Process & Introducing New Guidelines. Key Update: Starting January 26, 2026, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed. Thank you for your understanding and for being a part of our community! |
…ve updates Implemented the external store pattern in LoadedSettings to support reactive companion updates via useSyncExternalStore. - Added subscribe and getSnapshot methods to LoadedSettings - Implemented immutable snapshotting using structuredClone - Wrapped the existing event bus for store subscriptions - Added useSettingsStore reactive hook to SettingsContext
6cf9ba8 to
e6d3c6c
Compare
|
Hi there! Thank you for your contribution to Gemini CLI. To improve our contribution process and better track changes, we now require all pull requests to be associated with an existing issue, as announced in our recent discussion and as detailed in our CONTRIBUTING.md. This pull request is being closed because it is not currently linked to an issue. You can easily reopen this PR once you have linked it to an issue. How to link an issue: Thank you for your understanding and for being a part of our community! |
Pull Request Review: refactor(cli): Reactive useSettingsStore hookOverall, this is a very high-quality refactor that effectively addresses the reactive settings anti-pattern. The introduction of Highlights:
Suggested Improvement:
// packages/cli/src/ui/contexts/SettingsContext.tsx
default:
return checkExhaustive(scope);Great work on this! |
b800869
…ini/gemini-cli (#37) * fix(cli): resolve double rendering in shpool and address vscode lint warnings (google-gemini#18704) * feat(plan): document and validate Plan Mode policy overrides (google-gemini#18825) * Fix pressing any key to exit select mode. (google-gemini#18421) * fix(cli): update F12 behavior to only open drawer if browser fails (google-gemini#18829) * feat(plan): allow skills to be enabled in plan mode (google-gemini#18817) Co-authored-by: Jerop Kipruto <jerop@google.com> * docs(plan): add documentation for plan mode tools (google-gemini#18827) * Remove experimental note in extension settings docs (google-gemini#18822) * Update prompt and grep tool definition to limit context size (google-gemini#18780) * docs(plan): add `ask_user` tool documentation (google-gemini#18830) * Revert unintended credentials exposure (google-gemini#18840) * feat(core): update internal utility models to Gemini 3 (google-gemini#18773) * feat(a2a): add value-resolver for auth credential resolution (google-gemini#18653) * Removed getPlainTextLength (google-gemini#18848) * More grep prompt tweaks (google-gemini#18846) * refactor(cli): Reactive useSettingsStore hook (google-gemini#14915) * fix(mcp): Ensure that stdio MCP server execution has the `GEMINI_CLI=1` env variable populated. (google-gemini#18832) * fix(core): improve headless mode detection for flags and query args (google-gemini#18855) * refactor(cli): simplify UI and remove legacy inline tool confirmation logic (google-gemini#18566) * feat(cli): deprecate --allowed-tools and excludeTools in favor of policy engine (google-gemini#18508) * fix(workflows): improve maintainer detection for automated PR actions (google-gemini#18869) * refactor(cli): consolidate useToolScheduler and delete legacy implementation (google-gemini#18567) * Update changelog for v0.28.0 and v0.29.0-preview0 (google-gemini#18819) * fix(core): ensure sub-agents are registered regardless of tools.allowed (google-gemini#18870) --------- Co-authored-by: Brad Dux <959674+braddux@users.noreply.github.com> Co-authored-by: Jerop Kipruto <jerop@google.com> Co-authored-by: Jacob Richman <jacob314@gmail.com> Co-authored-by: Sandy Tao <sandytao520@icloud.com> Co-authored-by: Adib234 <30782825+Adib234@users.noreply.github.com> Co-authored-by: christine betts <chrstn@uw.edu> Co-authored-by: Christian Gunderman <gundermanc@gmail.com> Co-authored-by: Adam Weidman <65992621+adamfweidman@users.noreply.github.com> Co-authored-by: Dev Randalpura <devrandalpura@google.com> Co-authored-by: Pyush Sinha <pyushsinha20@gmail.com> Co-authored-by: Richie Foreman <richie.foreman@gmail.com> Co-authored-by: Gal Zahavi <38544478+galz10@users.noreply.github.com> Co-authored-by: Abhi <43648792+abhipatel12@users.noreply.github.com> Co-authored-by: Abhijit Balaji <abhijitbalaji@google.com> Co-authored-by: Bryan Morgan <bryanmorgan@google.com> Co-authored-by: g-samroberts <158088236+g-samroberts@users.noreply.github.com> Co-authored-by: matt korwel <matt.korwel@gmail.com>

Summary
The
SettingsDialogis bloated through excessive use of React State, Effect, unnecessary redundant states, and the use of React Anti Patterns to sync the UI with theLoadedSettings.Anti Pattern:
SettingsContextis a thin DI for a mutable object, forcing a React anti-pattern inSettingsDialog: updating state manually after mutation instead of one idiomatic update.Before the simple refactors, it makes sense to incrementally merge the requirements to remove this Anti Pattern from UI that is Reactive with Settings.
Details
PR1: Convert LoadedSettings to a store and create a second hook in SettingsContext that re-renders when a settings changed event is emitted
Problem: Components needing to re-render on settings changes (like SettingsDialog) currently use an anti-pattern: mutate
LoadedSettings, then manually callsetStateto trigger re-render.Solution:
Convert LoadedSettings to a store
useSyncExternalStoreto subscribe to the event bus. Whenever a settings-changed event is emitted, React checks if the snapshot has changed in object identity. If it has, it triggers the re-render we need.Why a second hook: Exposing this as a new hook (useSettingsStore) rather than changing useSettings means:
Files changed:
Next Steps:
PR2: Refactor SettingsDialog business logic to use the reactive store
This PR will ship with one small UX change - if a user toggles all restart required settings back to the value they initially were, the restart required prompt will also toggle off (b/c it's not required to apply those settings at that state). This was just a natural extension of removing complicated logic such as synchronizing many React states and batching mutations.
Replaces the imperative state-syncing model in SettingsDialog with the reactive useSettingsStore() from PR1.
pendingSettings,modifiedSettings,globalPendingChanges,_restartRequiredSettings,showRestartPrompt) and 5 obsolete utility functions from settingsUtils.tssettingsprop from SettingsDialog (reads from context instead)https://react.dev/reference/react/useState
Files changed:
PR 2 against PR 1 (outdated post-merge):
psinha40898/gemini-cli@pyush/refactor/settings-4...psinha40898:gemini-cli:pyush/refactor/settings-dialog-business
204 additions and 686 deletions.
PR3: Extract hooks from BaseSettingsDialog
Pure React cleanup — no business logic changes, no external API changes.
https://react.dev/learn/extracting-state-logic-into-a-reducer
useInlineEditor) in BaseSettingsDialoghttps://react.dev/learn/reusing-logic-with-custom-hooks#when-to-use-custom-hooks
https://react.dev/learn/you-might-not-need-an-effect
Files changed:
PR 3 against PR 2: (outdated post-merge):
psinha40898/gemini-cli@pyush/refactor/settings-dialog-business...psinha40898:gemini-cli:pyush/refactor/settings-dialog-base-hooks
392 additions and 183 deletions.
Future Work:
Related Issues
RELATED TO #15840
How to Validate
Pre-Merge Checklist