🔼 refactor: Improve UX for Command Popovers - #12677
Conversation
* Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched. * Refactored onFocus logic to clear the textarea and set the search value based on command character input. * Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries. * Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions.
|
@codex review |
There was a problem hiding this comment.
Pull request overview
Refactors command popover UX to better handle fast typing and loading states, while adding test coverage for command triggering behavior.
Changes:
- Added aggregated
isLoadingstate touseMentionsto drive consistent loading indicators. - Updated command-trigger detection logic in
useHandleKeyUpto support fast typists via a short-length fallback. - Added Jest unit tests for
useHandleKeyUpand updated popover components to show spinners and improve focus behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| client/src/hooks/Input/useMentions.ts | Exposes an aggregated isLoading flag across multiple mention-related queries. |
| client/src/hooks/Input/useHandleKeyUp.ts | Adjusts command trigger heuristics (adds short-length fallback). |
| client/src/hooks/Input/useHandleKeyUp.spec.ts | Adds unit tests covering command triggering, toggles, and permission gating. |
| client/src/components/Chat/Input/PromptsCommand.tsx | Improves focus behavior and renders a loading spinner when opening with no matches during load. |
| client/src/components/Chat/Input/Mention.tsx | Adds loading spinner rendering and refines focus behavior; wires in useMentions().isLoading. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const startPos = textAreaRef.current?.selectionStart; | ||
| if (typeof startPos !== 'number') { | ||
| return false; | ||
| } | ||
|
|
||
| return startPos === 1; | ||
| return startPos === 1 || text.length <= MAX_COMMAND_TRIGGER_LENGTH; | ||
| }; |
There was a problem hiding this comment.
shouldTriggerCommand now returns true whenever the textarea starts with the command char and the text is short, regardless of which key was pressed or where the cursor is. This means non-text/navigation keys (e.g. ArrowLeft/ArrowRight/Home/End) can inadvertently open a command popover as long as the message begins with '/', '@', or '+' and is <= 5 chars. Consider additionally gating on the key event (e.g., only trigger on printable character keys) and/or requiring selectionStart to be at the end of the text for the length-based fallback; also add a unit test that verifies arrow/navigation keys do not trigger popovers.
| onFocus={() => { | ||
| setOpen(true); | ||
| const textarea = textAreaRef.current; | ||
| if (!textarea) { | ||
| return; |
There was a problem hiding this comment.
The new onFocus handler contains fairly involved logic (reading/clearing the textarea, extracting the command search text, dispatching an input event) that is now duplicated in multiple popover components (e.g., here and in PromptsCommand). Consider extracting this into a shared helper (or small hook) so future tweaks to the command-focus behavior don’t drift between components.
| onFocus={() => { | ||
| setOpen(true); | ||
| const textarea = textAreaRef.current; | ||
| if (!textarea) { | ||
| return; |
There was a problem hiding this comment.
The textarea-syncing logic inside this onFocus handler is duplicated with the similar block in Mention. Consider extracting a shared helper/hook for the command-popover focus behavior to reduce duplication and ensure fixes (e.g. search extraction / textarea clearing) stay consistent across popovers.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee3c10585b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
* Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete. * Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position. * Improved agent query handling in useMentions hook for better performance and clarity.
* Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling. * Simplified onFocus logic to enhance user experience when interacting with command inputs. * Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input. * Improved performance by memoizing popover state and reducing unnecessary re-renders.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a4d9b4bf87
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d338571a01
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
d338571 to
ddc08f1
Compare
GitNexus: ❌ deploy failedThe deploy failed — the previous index (if any) continues to be served. |
- Fix endpointType regression: add effectiveEndpointByIndex selector that returns endpointType ?? endpoint, matching the original ChatForm guard for custom endpoints proxying assistants - Extract duplicated initInputRef callback into shared useInitPopoverInput hook, used by both Mention and PromptsCommand - Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End, Delete) to invalidKeys to prevent false popover triggers - Add endpoint gating tests for assistants/azureAssistants blocking the + command - Remove unused _index param from MentionContent
ddc08f1 to
7a2c136
Compare
GitNexus: ❌ deploy failedThe deploy failed — the previous index (if any) continues to be served. |
* refactor: Improve UX for Command Popovers * Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched. * Refactored onFocus logic to clear the textarea and set the search value based on command character input. * Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries. * Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions. * ci: useHandleKeyUp tests for command navigation * Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete. * Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position. * Improved agent query handling in useMentions hook for better performance and clarity. * refactor: Optimize Mention and PromptsCommand Components * Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling. * Simplified onFocus logic to enhance user experience when interacting with command inputs. * Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input. * Improved performance by memoizing popover state and reducing unnecessary re-renders. * fix: Address review findings for command popover refactor - Fix endpointType regression: add effectiveEndpointByIndex selector that returns endpointType ?? endpoint, matching the original ChatForm guard for custom endpoints proxying assistants - Extract duplicated initInputRef callback into shared useInitPopoverInput hook, used by both Mention and PromptsCommand - Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End, Delete) to invalidKeys to prevent false popover triggers - Add endpoint gating tests for assistants/azureAssistants blocking the + command - Remove unused _index param from MentionContent
* refactor: Improve UX for Command Popovers * Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched. * Refactored onFocus logic to clear the textarea and set the search value based on command character input. * Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries. * Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions. * ci: useHandleKeyUp tests for command navigation * Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete. * Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position. * Improved agent query handling in useMentions hook for better performance and clarity. * refactor: Optimize Mention and PromptsCommand Components * Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling. * Simplified onFocus logic to enhance user experience when interacting with command inputs. * Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input. * Improved performance by memoizing popover state and reducing unnecessary re-renders. * fix: Address review findings for command popover refactor - Fix endpointType regression: add effectiveEndpointByIndex selector that returns endpointType ?? endpoint, matching the original ChatForm guard for custom endpoints proxying assistants - Extract duplicated initInputRef callback into shared useInitPopoverInput hook, used by both Mention and PromptsCommand - Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End, Delete) to invalidKeys to prevent false popover triggers - Add endpoint gating tests for assistants/azureAssistants blocking the + command - Remove unused _index param from MentionContent
Resolves conflicts from: - Sidebar Icon Toggle (LibreChat-AI#12642) - kept our branding logo, took upstream's setActive prop change on NewChatButton - Command Popover UX (LibreChat-AI#12677) - adopted upstream's popoverAtom pattern in ChatForm/Mention, kept Jotai in useHandleKeyUp - Preserve Selected Artifact (LibreChat-AI#12601) - accepted upstream's fix - Entra ID Group Sync (LibreChat-AI#12606) - accepted upstream's expanded logic - families.ts - kept our Jotai atomFamily definitions, added effectiveEndpointByIndex as Jotai selector Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: Improve UX for Command Popovers * Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched. * Refactored onFocus logic to clear the textarea and set the search value based on command character input. * Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries. * Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions. * ci: useHandleKeyUp tests for command navigation * Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete. * Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position. * Improved agent query handling in useMentions hook for better performance and clarity. * refactor: Optimize Mention and PromptsCommand Components * Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling. * Simplified onFocus logic to enhance user experience when interacting with command inputs. * Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input. * Improved performance by memoizing popover state and reducing unnecessary re-renders. * fix: Address review findings for command popover refactor - Fix endpointType regression: add effectiveEndpointByIndex selector that returns endpointType ?? endpoint, matching the original ChatForm guard for custom endpoints proxying assistants - Extract duplicated initInputRef callback into shared useInitPopoverInput hook, used by both Mention and PromptsCommand - Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End, Delete) to invalidKeys to prevent false popover triggers - Add endpoint gating tests for assistants/azureAssistants blocking the + command - Remove unused _index param from MentionContent
* refactor: Improve UX for Command Popovers * Added loading state handling in Mention and PromptsCommand components to display a spinner when data is being fetched. * Refactored onFocus logic to clear the textarea and set the search value based on command character input. * Introduced a new `isLoading` state in the useMentions hook to manage loading indicators across multiple data queries. * Added unit tests for the useHandleKeyUp hook to ensure command triggering works correctly under various conditions. * ci: useHandleKeyUp tests for command navigation * Added tests to ensure that the command popovers do not trigger when the cursor is mid-text after pressing ArrowLeft or Delete. * Updated the shouldTriggerCommand function to refine the conditions under which commands are triggered based on cursor position. * Improved agent query handling in useMentions hook for better performance and clarity. * refactor: Optimize Mention and PromptsCommand Components * Refactored Mention and PromptsCommand components to utilize Recoil state for popover visibility, improving state management and reducing prop drilling. * Simplified onFocus logic to enhance user experience when interacting with command inputs. * Added unit tests for useHandleKeyUp to ensure proper command handling and popover visibility based on user input. * Improved performance by memoizing popover state and reducing unnecessary re-renders. * fix: Address review findings for command popover refactor - Fix endpointType regression: add effectiveEndpointByIndex selector that returns endpointType ?? endpoint, matching the original ChatForm guard for custom endpoints proxying assistants - Extract duplicated initInputRef callback into shared useInitPopoverInput hook, used by both Mention and PromptsCommand - Add navigation keys (ArrowLeft, ArrowRight, ArrowDown, Home, End, Delete) to invalidKeys to prevent false popover triggers - Add endpoint gating tests for assistants/azureAssistants blocking the + command - Remove unused _index param from MentionContent
Summary
Fixes several UX issues with the
@,+, and/command popovers in the chat input:@/+command text not clearing from textarea — When the mention popover opened, the command character stayed visible in the textarea (unlike/which cleared correctly). Root cause:ChatFormsubscribed to the mention popover atoms viauseRecoilState, causing it to re-render when the popover opened, which interfered with the textarea clearing logic. The/command avoided this becausePromptsCommandmanaged its popover state internally.Perpetual loading spinner for mentions —
useMentionsincludedisLoadingAgentsunconditionally in its aggregateisLoadingflag, but the agents query is often disabled (no agent access / model select off). With React Query v4, disabled queries without cache stay in loading status, causing a permanent spinner.Overly broad command trigger fallback — The fast-typing fallback in
shouldTriggerCommandwould re-trigger the popover on navigation keys (ArrowLeft, Delete) within short command text, since it only checked text length without verifying cursor position.Changes
Architecture: Align Mention with PromptsCommand pattern
Mention.tsx— Wrapped in aMentionPopoverContainer(memoized) that reads its popover atom internally viauseRecoilValueand conditionally renders the content. UsesuseSetRecoilState(write-only) to close itself. Replaces the oldsetShowMentionPopoverprop withpopoverAtom.ChatForm.tsx— RemoveduseRecoilStatesubscriptions forshowMentionPopoverFamilyandshowPlusPopoverFamily. ChatForm no longer re-renders when these popover states change. Both<Mention>components are rendered unconditionally — they manage their own visibility internally.useHandleKeyUp.ts— All three popover setters (@,+,/) now useuseSetRecoilStateinternally. Removed setter props from the hook parameters, fully decoupling it from ChatForm. Moved theisAssistantsEndpointguard (previously in ChatForm's render) into the+command handler.Bug fixes
useMentions.ts— Exposed aggregateisLoadingfrom all data queries. GatedisLoadingAgentsbehindagentQueryEnabledso a disabled query can't cause perpetual loading.useHandleKeyUp.ts—shouldTriggerCommandfallback now requiresstartPos === text.length(cursor at end) in addition to the length cap, preventing spurious triggers during text navigation.UX improvements
Mention.tsx/PromptsCommand.tsx— ReplacedautoFocuswith a callback ref (initInputRef) that focuses the input, transfers command text as a search prefix, and clears the textarea in one synchronous pass. Shows a loading spinner when data is still fetching and no matches exist yet.Test plan
useHandleKeyUpunit tests (37 tests) — covers command triggering, fast typing, navigation keys, paste protection, toggles, permission gating, and endpoint gating@→ popover opens, textarea clears, command char is gone+→ same behavior (not on assistants endpoints)/→ same behavior (unchanged)