-
Notifications
You must be signed in to change notification settings - Fork 10.6k
feat: Show tip on first request and refactor phrases #12952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Show tip on first request and refactor phrases #12952
Conversation
- Shows an informative tip on the first request to help new users. - Refactors witty phrases and tips into separate constant files for better organization. - Updates tests to reflect the new behavior and improve robustness.
Summary of ChangesHello @JayadityaGit, 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 refines the CLI's loading experience by introducing a dedicated informative tip for the user's first interaction, making the onboarding process more guided. Concurrently, it significantly improves code structure by externalizing loading phrases and tips into separate constant files, which enhances modularity and simplifies future updates. The changes are supported by updated and expanded test coverage to ensure the new behavior is correctly implemented. 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This PR does a great job of refactoring the loading phrases and tips into separate constants, which significantly improves code organization and maintainability. The new feature to display a tip on the first request is a nice enhancement to the user experience. My main feedback is a critical architectural concern regarding the use of a module-level variable to manage the 'first request' state. This introduces global state outside of React's control, which is an anti-pattern. I've left specific comments detailing the issue and suggesting a more idiomatic solution using React's Context API. Addressing this will make the implementation much more robust and aligned with React best practices.
| ]; | ||
|
|
||
| // Track if it's the very first activation globally across the app | ||
| let hasShownFirstRequestTip = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a module-level mutable variable (hasShownFirstRequestTip) to manage state across hook instances is an architectural anti-pattern in React. It introduces global state outside of React's control, which can lead to unpredictable behavior and makes testing more complex (as evidenced by the need for __resetFirstRequestFlagForTesting).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To my eye the best solution is having a ref inside of the usePhraseCycler hook.
Having a React context is complete overkill b/c we already have uiState
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed
| let phraseList; | ||
| // Show a tip on the first request after startup, then continue with 1/6 chance | ||
| if (!hasShownFirstRequestTip) { | ||
| // Show a tip during the first request | ||
| phraseList = INFORMATIVE_TIPS; | ||
| hasShownFirstRequestTip = true; // Mark that we've shown the first request tip | ||
| } else { | ||
| // Roughly 1 in 6 chance to show a tip after the first request | ||
| const showTip = Math.random() < 1 / 6; | ||
| phraseList = showTip ? INFORMATIVE_TIPS : WITTY_LOADING_PHRASES; | ||
| } | ||
| const randomIndex = Math.floor(Math.random() * phraseList.length); | ||
| setCurrentLoadingPhrase(phraseList[randomIndex]); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic relies on the module-level hasShownFirstRequestTip variable. A more robust and idiomatic React solution would be to manage this application-wide state using a React Context. This would keep the state management within React's lifecycle, making it more predictable and maintainable.
I recommend creating a FirstRequestTipContext to provide and update this state, and then consuming it within this hook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gemini is correct that this module level variable is a React anti pattern
I'm surprised that it recommended creating a new React context as the solution.
A ref works fine here to my eye
The difference is when you declare a module level variable React has no idea about its existence.
With useRef(false) that means when the hook is called by a component the flag is set to False and then modified within that component's lifecycle.
So when it mounts the flag is set to false by default, and the flag is modified within the component's (that calls the hook) lifecycle.
uiState already stores and exposes this to any component in the tree that would need it.
the tldr is that:
with useRef React has full knowledge of this flag or ref and before it did not even know that it existed.
| ]; | ||
|
|
||
| // Track if it's the very first activation globally across the app | ||
| let hasShownFirstRequestTip = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To my eye the best solution is having a ref inside of the usePhraseCycler hook.
Having a React context is complete overkill b/c we already have uiState
| describe('usePhraseCycler', () => { | ||
| beforeEach(() => { | ||
| vi.useFakeTimers(); | ||
| __resetFirstRequestFlagForTesting(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with useRef inside of usePhraseCycler you would be able to safely remove this from your PR
| describe('useLoadingIndicator', () => { | ||
| beforeEach(() => { | ||
| vi.useFakeTimers(); | ||
| __resetFirstRequestFlagForTesting(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with useRef inside of usePhraseCycler you would be able to safely remove this from your PR
| loadingPhrases[0], | ||
| ); | ||
| const phraseIntervalRef = useRef<NodeJS.Timeout | null>(null); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here add const hasShownFirstTipRef = useRef(false);
| const showTip = Math.random() < 1 / 6; | ||
| const phraseList = showTip ? INFORMATIVE_TIPS : WITTY_LOADING_PHRASES; | ||
| let phraseList; | ||
| // Show a tip on the first request after startup, then continue with 1/6 chance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove unnecessary llm generated comments
Fun fact: LLMs generate better code when leaving these types of comments, but neither LLMs nor humans need them to understand clear code such as this so they become quite unnecessary
Thank you @psinha40898 ! |
jacob314
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Jacob Richman <jacob314@gmail.com>
…2952) Co-authored-by: Jacob Richman <jacob314@gmail.com>

Summary
This PR enhances the onboarding experience by displaying an informative tip during the first request in the CLI. It also refactors the witty loading phrases and informative tips into dedicated constant files, improving code organization, readability, and maintainability.
Details
Updated the
usePhraseCyclerhook to differentiate between first and subsequent requests:On the first request, a tip is always displayed.
On subsequent requests, the existing behavior is preserved — showing either a witty phrase or a tip (with a 1/6 probability).
Extracted
WITTY_LOADING_PHRASESandINFORMATIVE_TIPSfromusePhraseCycler.tsinto separate files located underpackages/cli/src/ui/constants/.Updated and expanded test coverage:
Adjusted test suites for
usePhraseCycleranduseLoadingIndicatorto align with the new logic.Added a dedicated test case to verify that a tip is shown on the first activation.
Related Issues
None.
How to Validate
Run the CLI application.
Trigger an action that shows a loading spinner (e.g., sending a prompt).
Expected: The first spinner displays an informative tip.
Trigger another spinner.
Expected: Subsequent spinners show either a witty phrase or a tip (with 1/6 probability).
Run the test suite to confirm all checks pass:
Pre-Merge Checklist
Updated relevant documentation and README (if applicable)
Added/updated tests
Noted breaking changes (if any)
Validated on required platforms:
#12953