Skip to content

feat(ui): Introduce useUI Hook and UIContext#5488

Merged
jacob314 merged 1 commit intogoogle-gemini:mainfrom
Lyonk71:feat/5446-create-useUI
Sep 6, 2025
Merged

feat(ui): Introduce useUI Hook and UIContext#5488
jacob314 merged 1 commit intogoogle-gemini:mainfrom
Lyonk71:feat/5446-create-useUI

Conversation

@Lyonk71
Copy link
Copy Markdown
Contributor

@Lyonk71 Lyonk71 commented Aug 4, 2025

This commit introduces the foundational UIContext and useUI hook.

This is the first step in decoupling the UI's state management from its presentation. It creates a centralized context for providing UI-related actions, like opening dialogs, to the entire component tree.

This change addresses issue #5446.

This PR has been expanded to include the whole of phase 1 described in #5399

This commit introduces a major architectural refactor to the CLI's React UI. It establishes a clear separation between state management and presentational components by centralizing application logic and state into a new AppContainer component.

Key Changes

AppContainer as State Hub

  • A new AppContainer.tsx component now wraps the App component.
  • It is responsible for initializing all major UI hooks (useHistory, useSlashCommandProcessor, useGeminiStream, useConsoleMessages, etc.) and managing the entire lifecycle of the UI state.

Centralized State via React Contexts

  • UIStateContext: Provides a single, comprehensive UIState object containing all dynamic data for the UI (e.g., history, dialog visibility, streaming status, input buffer).
  • UIActionsContext: Exposes a stable set of UIActions (e.g., handleFinalSubmit, handleThemeSelect, handleClearScreen) for components to dispatch events and trigger state changes.
  • AppContext, ConfigContext, SettingsContext: These contexts provide global, relatively static data (version, config, settings) to the component tree, avoiding the need for prop drilling.

Presentational App.tsx

  • The App.tsx component has been significantly simplified. It is now a purely presentational component that consumes state and actions from the new contexts via the useUIState and useUIActions hooks. Its role is to structure the layout of the main UI components.

Simplified Hooks and Components

  • Hooks like useAuthCommand and useThemeCommand no longer manage their own dialog visibility state. This state is lifted into the central UIState, and the hooks now focus purely on the logic of their respective commands.
  • Components like Composer.tsx now pull data directly from context instead of receiving a large number of props, simplifying their API and improving readability.

Pre-React Initialization

  • A new initializeApp function (packages/cli/src/core/initializer.ts) handles critical startup tasks (auth, theme validation) before the React UI is rendered, ensuring a cleaner separation of concerns.

@Lyonk71 Lyonk71 requested a review from a team as a code owner August 4, 2025 02:36
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @Lyonk71, 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!

I've introduced the foundational UIContext and useUI hook. This is a crucial first step towards decoupling UI state management from its presentation, providing a centralized context for UI-related actions across the component tree. This change addresses issue #5446.

Highlights

  • New UI Context and Hook: I've added packages/cli/src/ui/hooks/useUI.ts, which defines the UIContext using React's createContext and the useUI hook. This hook provides access to a set of UIContextActions such as openHelp, openAuthDialog, toggleCorgiMode, and quit, enabling centralized UI state management.
Using Gemini Code Assist

The 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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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 or fill out our survey to provide feedback.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the foundational UIContext and useUI hook to start decoupling UI state management from presentation components. The implementation is solid, following standard React patterns for context creation and consumption. The useUI hook correctly ensures it's used within a provider wrapper, which is a good practice. This change sets a good foundation for the planned refactoring and I have no concerns with the code as written.

@Lyonk71
Copy link
Copy Markdown
Contributor Author

Lyonk71 commented Aug 4, 2025

@jacob314, this is the first step on the roadmap we discussed to decouple layout from rendering: #5399

Copy link
Copy Markdown
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks reasonable. Can you include more of the functionality using in the pr to help judge how it works out in practice_

@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch from a63ded7 to 2bc6359 Compare August 12, 2025 02:14
@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch from 2bc6359 to 23f4413 Compare August 20, 2025 04:25
Comment thread packages/cli/src/ui/types.ts Outdated
Comment thread packages/cli/src/ui/components/MainContent.tsx Outdated
Comment thread packages/cli/src/ui/components/Footer.tsx Outdated
Comment thread packages/cli/src/ui/components/InputArea.tsx Outdated
Comment thread packages/cli/src/ui/components/InputArea.tsx Outdated
Copy link
Copy Markdown
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we stick with having this context as a follow up it would be nice to structure this more. it has core chat history data, a bunch of things that are generally just plumbed through from settings, some history stuff, a bunch of prop-drill input state that would be good to group together.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Definitely intended to be a part 2 for this refactor - I kept this as simple as possible for now for ease of implementation/merge conflicts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UIStateContext worries me a bit. This is a ton of info to be promoting to a context. Is this really needed? Would be better to explicitly pass these around where needed with prop drilling unless there are reasons we really need to do this to achieve this refactor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point - I intentionally overused context here as an expediency. It was faster to implement and easier to handle the merge-conflict load. But now that the brunt of the refactor work is done, we'll be able to re-introduce prop usage over time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a case where we should pass the version in directly rather than using appContext just to get the version. That will keep the app efficient and explicit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, change has been implemented.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a case where the uiState generally makes sense. I would suggest we pass it in as a property instead of using Context.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good callout - I figured this is the sort of thing that could be in a followup refactor, refactor-then-optimize?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest making these properties explicit or having a DialogState sub object on uiState.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment - definitely agree. I lean towards breaking this up in a follow up refactor?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good. lets land this and then worry about that.

Comment thread packages/cli/src/ui/hooks/slashCommandProcessor.ts Outdated
Comment thread packages/cli/src/ui/App.tsx Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this a helper method and separate all the dialog specific state a seperate interface under uiState just for the dialogState.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to what i mentioned above - this will be a good candidate for a follow up PR to break up UIStateContext

@gemini-cli gemini-cli bot added kind/bug priority/p2 Important but can be addressed in a future release. area/platform Issues related to Build infra, Release mgmt, Testing, Eval infra, Capacity, Quota mgmt labels Aug 22, 2025
@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch 12 times, most recently from f937287 to cec6f7c Compare September 1, 2025 05:37
Comment thread packages/cli/src/ui/App.tsx Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have missed it, but where was this logic moved to?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spot on, Abhi. Looks like I must've borked a merge conflict somewhere along the way. I'll follow up when I get this resolved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reintroduced the fallback handler into the new architecture + tested it out locally. Thanks for spotting this!

@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch 2 times, most recently from 73aede4 to 463cfba Compare September 3, 2025 21:52
Comment thread packages/a2a-server/package.json Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: are these changes needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, these were left over from local testing. I just removed them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did this output change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't intend to push changes to this - I was just doing some local testing. reverted.

@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch 7 times, most recently from 36c3eb8 to 96c1fcb Compare September 6, 2025 02:39
Copy link
Copy Markdown
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a major and impressive architectural refactor. It does an excellent job of separating state management from the UI presentation, which will significantly improve maintainability. The introduction of AppContainer as a central state hub and the decomposition of the old App.tsx into smaller, focused components is a huge step forward.

Here is a summary of my review based on the steps you provided.

I've reviewed the diff with a focus on ensuring no functionality was lost during the refactor.

1. Functionality Preservation:
The refactor appears to be complete and correct. All the state, effects, and UI logic from the monolithic App.tsx have been successfully relocated to the new architecture:

  • State and business logic hooks have been moved to AppContainer.tsx.
  • State is exposed globally through UIStateContext and AppContext.
  • Actions are exposed via UIActionsContext.
  • The UI has been cleanly decomposed into new components: MainContent, DialogManager, Composer, Notifications, and AppHeader.

I did not find any features or logic that were dropped. The implementation seems to have been moved, not removed.

3. Code Quality and Consistency:

  • The code quality is very high. The new structure is clean, modular, and aligns with modern React best practices.
  • The inclusion of Mermaid diagrams (/docs/mermaid/) to document the new architecture is an excellent practice and very helpful for understanding the changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed? if so can you switch to the standard wrap with providers from the test helpers? suspect this isn't needed as this change was briefly in main but backed out as I recall.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. At least for the moment, yes because the standard renderWithProviders helpers doesn't give the ConfigContext that the component needs for testing. But probably something that can be cleaned up at some point?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good to cleanup later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good. lets land this and then worry about that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert this change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert this change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this change. No need to make this async

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread packages/core/src/config/config.ts Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert this one the code is not async.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems like a fine change but unrelated. can you revert it from here and land it separately.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we revert "skipLibCheck"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes/Done.

Comment thread appcontainer-refactor.txt Outdated
@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch from 96c1fcb to f353fdc Compare September 6, 2025 04:46
@Lyonk71 Lyonk71 force-pushed the feat/5446-create-useUI branch from f353fdc to 04e4047 Compare September 6, 2025 04:59
@jacob314 jacob314 enabled auto-merge September 6, 2025 05:29
Copy link
Copy Markdown
Contributor

@jacob314 jacob314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@jacob314 jacob314 added this pull request to the merge queue Sep 6, 2025
Merged via the queue into google-gemini:main with commit 885af07 Sep 6, 2025
20 checks passed
@Lyonk71 Lyonk71 deleted the feat/5446-create-useUI branch September 7, 2025 15:52
}

trustedFolders.setValue(cwd, trustLevel);
const newIsTrusted =
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this restart logic removed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge conflict. please send a per to add this back.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sharing @shrutip90. Tracking the issue here: #8031 I'll be free to get a PR up to fix this in a couple of hours.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update, @Lyank71. Confirming that re-introducing the restart logic for folder trust changes is the correct approach. Let me know if you encounter any issues when creating the PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, sent out #8038.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update, @shrutip90! Appreciate you getting a PR up so quickly to address this.

giraffe-tree pushed a commit to giraffe-tree/gemini-cli that referenced this pull request Oct 10, 2025
Co-authored-by: Jacob Richman <jacob314@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/platform Issues related to Build infra, Release mgmt, Testing, Eval infra, Capacity, Quota mgmt priority/p2 Important but can be addressed in a future release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants