Skip to content

feat: Implement file mention feature for assistant#2977

Open
paultranvan wants to merge 1 commit intomasterfrom
feature/file-mention-feature
Open

feat: Implement file mention feature for assistant#2977
paultranvan wants to merge 1 commit intomasterfrom
feature/file-mention-feature

Conversation

@paultranvan
Copy link
Copy Markdown
Contributor

@paultranvan paultranvan commented Mar 26, 2026

Add possibility to search on files from assistant prompt, to ask question on the selected files only
image

Summary by CodeRabbit

  • New Features

    • File-mention in conversations: type "@" to search, insert, and manage files; removable file chips shown under composer.
    • Keyboard-friendly mention menu with debounced search and selection.
    • Sent messages now include attached file references and display attachments inline.
  • Chores

    • Added .worktrees to VCS ignore.
    • Allowed *.spec.jsx tests and added i18n strings for mention UI.
    • Introduced shared tool/type interfaces.

@paultranvan paultranvan force-pushed the feature/file-mention-feature branch from 99ec9da to da4e4a3 Compare March 26, 2026 16:56
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Walkthrough

This PR adds file-mention support to the conversation UI. It introduces FileMentionContext, FileMentionMenu, and FileChipsList; extends ConversationBar and ConversationComposer to handle mentions and pass attachment IDs into the realtime chat adapter; updates the adapter to include attachmentIDs; adds mention regex/constants; introduces UserMessageAttachments and query adjustments for file-by-id caching; adds i18n strings; adds tool type definitions; tweaks fetch/result mapping and Jest config; and updates .gitignore.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main feature being implemented: file mention functionality for the assistant component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/file-mention-feature

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@paultranvan paultranvan force-pushed the feature/file-mention-feature branch 6 times, most recently from dbd01ba to 8715747 Compare April 2, 2026 09:08
@paultranvan paultranvan marked this pull request as ready for review April 2, 2026 09:24
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cozy-search/src/components/Conversations/ConversationComposer.jsx`:
- Around line 31-34: handleSend currently always calls resetFileMention after
composerRuntime.send(), which clears selected files even when send was ignored;
modify handleSend to only clear file mentions when a send actually occurred by
checking the send outcome. Update handleSend to either: 1) call const sent =
composerRuntime.send(); if sent is truthy (or await it if it returns a Promise)
then call resetFileMention(); or 2) if a capability flag exists, check
composerRuntime.canSend() before calling send and only call resetFileMention()
when canSend() is true and send() succeeds. Ensure you reference handleSend,
composerRuntime.send, composerRuntime.canSend (if present) and resetFileMention
in the change.

In `@packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx`:
- Around line 108-110: Replace the hard-coded user-facing strings in
FileMentionMenu.jsx (the Loading... and No files found ListItem texts rendered
when isLoading or fileResults.length === 0) with localized messages using the
project’s i18n/localization helper (e.g., the translation hook or intl formatter
used elsewhere in the repo); import the localization utility at the top of the
component and call it inside the FileMentionMenu render to return translated
strings for both the loading and empty states so the menu text is localized
across locales.
- Around line 65-70: The handler handleKeyDown currently calls
e.preventDefault() on Tab even when nothing is selectable; change it so you
first check whether fileResults[selectedIndex] exists and only then call
e.preventDefault() and invoke handleSelect(fileResults[selectedIndex]). In other
words, guard the preventDefault() and handleSelect() behind the truthy check of
fileResults[selectedIndex] (using the existing variables fileResults and
selectedIndex) so Tab is only consumed when there is an actual selection.
- Around line 91-93: The effect that sets menuKeyDownRef.current = handleKeyDown
should clear the ref on unmount and be controlled by dependencies so stale
closures (with old fileResults/selectedIndex) are not kept; update the useEffect
around menuKeyDownRef/handleKeyDown to include a dependency array (e.g.,
[handleKeyDown]) and return a cleanup that sets menuKeyDownRef.current = null
(or undefined), referencing menuKeyDownRef, handleKeyDown, fileResults,
selectedIndex and keeping ConversationBar's hasMention guard working as before.

In `@packages/cozy-search/src/components/Conversations/mentionConstants.js`:
- Around line 3-4: The mention regexes MENTION_MATCH_REGEX and
MENTION_REPLACE_REGEX are too restrictive (currently use [\w. ]), rejecting
valid filename characters like hyphens; update both constants to widen the
allowed character class (e.g., include -, parentheses, and other common filename
chars) or switch to a safer pattern like "any non-space, non-@" (e.g., [^@\s]+)
so mentions match real filenames while preserving the existing (^|\s)@...
anchors; change both MENTION_MATCH_REGEX and MENTION_REPLACE_REGEX accordingly.

In `@packages/cozy-search/src/components/Conversations/Sources/URLSourceItem.jsx`:
- Around line 12-25: The component reads source.FileURL into url and uses it
directly as the href on the ListItem (rendered as an anchor); validate the URL
protocol before rendering to avoid javascript: payloads by parsing the url
(e.g., new URL(url) in try/catch) and only allow protocols 'http:' and 'https:';
if the URL is invalid or not allowed, avoid rendering an anchor (return null or
render a non-clickable item) so ListItem with component="a" and href={url} is
only used when the protocol check passes.

In `@packages/cozy-search/src/components/Search/useFetchResult.jsx`:
- Around line 100-103: The effect in useFetchResult.jsx currently omits
searchOptions from the dependency array causing stale filters when
SearchProvider passes dynamic searchOptions; either add searchOptions to the
effect deps in the useEffect that references
dataProxy/searchValue/state.searchValue so the effect re-runs when filters
change, or ensure the caller (e.g., SearchProvider/FileMentionMenu) provides a
stable memoized searchOptions (wrap it with useMemo) so the omitted dependency
is safe—update the effect dependency list or memoize the searchOptions prop
accordingly to fix stale search behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 77bfc8ae-9af7-4f8d-8476-7dde1943a2b5

📥 Commits

Reviewing files that changed from the base of the PR and between b098564 and 8715747.

📒 Files selected for processing (13)
  • .gitignore
  • packages/cozy-search/src/components/Conversations/ConversationBar.jsx
  • packages/cozy-search/src/components/Conversations/ConversationComposer.jsx
  • packages/cozy-search/src/components/Conversations/FileChipsList.jsx
  • packages/cozy-search/src/components/Conversations/FileMentionContext.jsx
  • packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx
  • packages/cozy-search/src/components/Conversations/Sources/URLSourceItem.jsx
  • packages/cozy-search/src/components/Conversations/mentionConstants.js
  • packages/cozy-search/src/components/CozyAssistantRuntimeProvider.tsx
  • packages/cozy-search/src/components/Search/useFetchResult.jsx
  • packages/cozy-search/src/components/adapters/CozyRealtimeChatAdapter.ts
  • packages/cozy-search/src/tools/types.ts
  • packages/cozy-search/tests/jest.config.js

Comment on lines +91 to +93
useEffect(() => {
menuKeyDownRef.current = handleKeyDown
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "FileMentionMenu.jsx" -type f

Repository: linagora/cozy-libs

Length of output: 133


🏁 Script executed:

cat -n ./packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx | head -120

Repository: linagora/cozy-libs

Length of output: 4601


🏁 Script executed:

grep -r "menuKeyDownRef" ./packages/cozy-search/src/components/Conversations/ -n

Repository: linagora/cozy-libs

Length of output: 929


🏁 Script executed:

cat -n ./packages/cozy-search/src/components/Conversations/ConversationBar.jsx | sed -n '30,75p'

Repository: linagora/cozy-libs

Length of output: 1572


🏁 Script executed:

cat -n ./packages/cozy-search/src/components/Conversations/FileMentionContext.jsx

Repository: linagora/cozy-libs

Length of output: 2845


Add cleanup to clear the stale key handler on unmount.

The effect updates menuKeyDownRef.current without a cleanup function or dependency array. When the mention is closed and reopened, the ref may briefly hold a stale handleKeyDown closure with outdated fileResults and selectedIndex. Although ConversationBar guards the call with hasMention, adding cleanup prevents the stale handler from being invoked during the unmount/remount window.

🔧 Suggested fix
   useEffect(() => {
     menuKeyDownRef.current = handleKeyDown
+    return () => {
+      menuKeyDownRef.current = null
+    }
+  }, [handleKeyDown, menuKeyDownRef])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
menuKeyDownRef.current = handleKeyDown
})
useEffect(() => {
menuKeyDownRef.current = handleKeyDown
return () => {
menuKeyDownRef.current = null
}
}, [handleKeyDown, menuKeyDownRef])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx` around
lines 91 - 93, The effect that sets menuKeyDownRef.current = handleKeyDown
should clear the ref on unmount and be controlled by dependencies so stale
closures (with old fileResults/selectedIndex) are not kept; update the useEffect
around menuKeyDownRef/handleKeyDown to include a dependency array (e.g.,
[handleKeyDown]) and return a cleanup that sets menuKeyDownRef.current = null
(or undefined), referencing menuKeyDownRef, handleKeyDown, fileResults,
selectedIndex and keeping ConversationBar's hasMention guard working as before.

@paultranvan paultranvan force-pushed the feature/file-mention-feature branch from 8715747 to 6324c15 Compare April 2, 2026 09:58
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/cozy-search/src/components/Conversations/ConversationBar.jsx (1)

42-48: Consider potential state synchronization drift.

The handleChange updates FileMentionContext.inputValue alongside the parent's state (via onChange). Since ComposerPrimitive.Input manages its own state through the composer runtime, the context's inputValue mirrors this for mention detection.

If the composer text is ever updated programmatically without going through this handler (e.g., composerRuntime.setText() called elsewhere), the context's inputValue could become stale. Ensure that all code paths that modify the composer text also call handleInputChange to keep them synchronized—the FileMentionMenu.clearMention function already does this correctly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/ConversationBar.jsx` around
lines 42 - 48, The FileMentionContext's inputValue can drift if the composer
text is updated outside handleChange; ensure every code path that
programmatically updates the composer text (e.g., calls to
composerRuntime.setText or other places that mutate the ComposerPrimitive.Input)
also invokes handleInputChange to keep context in sync—review and update any
callers that set text programmatically to call handleInputChange(newText)
(FileMentionMenu.clearMention already does this); specifically audit usages of
composerRuntime.setText and any prop callbacks that mutate the input and add
calls to handleInputChange so FileMentionContext.inputValue stays consistent
with the composer.
packages/cozy-search/src/components/Conversations/FileMentionContext.jsx (1)

52-78: Intentional omission of menuKeyDownRef from dependencies is correct but may benefit from a comment.

The menuKeyDownRef is included in the context value but excluded from useMemo dependencies. This is correct because useRef returns a stable object across renders—only .current mutates. Consider adding a brief comment to clarify this is intentional for future maintainers.

📝 Suggested clarifying comment
   const value = useMemo(
     () => ({
       selectedFiles,
       inputValue,
       addFile,
       removeFile,
       reset,
       removeMentionText,
       handleInputChange,
       hasMention,
       mentionSearchTerm,
       getAttachmentsIDs,
-      menuKeyDownRef
+      menuKeyDownRef // Ref is stable; .current is mutated by FileMentionMenu
     }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/FileMentionContext.jsx`
around lines 52 - 78, The useMemo callback builds the context value including
menuKeyDownRef but the dependencies array intentionally omits menuKeyDownRef;
add a brief inline comment next to the dependencies array (or above the useMemo)
explaining that menuKeyDownRef is a stable ref returned by useRef so its object
identity does not change and only .current mutates, therefore it is
intentionally excluded from the dependency list—refer to the value constant,
useMemo call, and menuKeyDownRef to locate where to add the comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/cozy-search/src/components/Conversations/ConversationBar.jsx`:
- Around line 42-48: The FileMentionContext's inputValue can drift if the
composer text is updated outside handleChange; ensure every code path that
programmatically updates the composer text (e.g., calls to
composerRuntime.setText or other places that mutate the ComposerPrimitive.Input)
also invokes handleInputChange to keep context in sync—review and update any
callers that set text programmatically to call handleInputChange(newText)
(FileMentionMenu.clearMention already does this); specifically audit usages of
composerRuntime.setText and any prop callbacks that mutate the input and add
calls to handleInputChange so FileMentionContext.inputValue stays consistent
with the composer.

In `@packages/cozy-search/src/components/Conversations/FileMentionContext.jsx`:
- Around line 52-78: The useMemo callback builds the context value including
menuKeyDownRef but the dependencies array intentionally omits menuKeyDownRef;
add a brief inline comment next to the dependencies array (or above the useMemo)
explaining that menuKeyDownRef is a stable ref returned by useRef so its object
identity does not change and only .current mutates, therefore it is
intentionally excluded from the dependency list—refer to the value constant,
useMemo call, and menuKeyDownRef to locate where to add the comment.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d46c1329-e096-4f9d-9859-80a5cf4f7288

📥 Commits

Reviewing files that changed from the base of the PR and between 8715747 and 6324c15.

📒 Files selected for processing (16)
  • .gitignore
  • packages/cozy-search/src/components/Conversations/ConversationBar.jsx
  • packages/cozy-search/src/components/Conversations/ConversationComposer.jsx
  • packages/cozy-search/src/components/Conversations/FileChipsList.jsx
  • packages/cozy-search/src/components/Conversations/FileMentionContext.jsx
  • packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx
  • packages/cozy-search/src/components/Conversations/mentionConstants.js
  • packages/cozy-search/src/components/CozyAssistantRuntimeProvider.tsx
  • packages/cozy-search/src/components/Search/useFetchResult.jsx
  • packages/cozy-search/src/components/adapters/CozyRealtimeChatAdapter.ts
  • packages/cozy-search/src/locales/en.json
  • packages/cozy-search/src/locales/fr.json
  • packages/cozy-search/src/locales/ru.json
  • packages/cozy-search/src/locales/vi.json
  • packages/cozy-search/src/tools/types.ts
  • packages/cozy-search/tests/jest.config.js
✅ Files skipped from review due to trivial changes (9)
  • .gitignore
  • packages/cozy-search/tests/jest.config.js
  • packages/cozy-search/src/locales/en.json
  • packages/cozy-search/src/locales/vi.json
  • packages/cozy-search/src/locales/ru.json
  • packages/cozy-search/src/locales/fr.json
  • packages/cozy-search/src/components/Conversations/FileChipsList.jsx
  • packages/cozy-search/src/components/Conversations/mentionConstants.js
  • packages/cozy-search/src/tools/types.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/cozy-search/src/components/Conversations/ConversationComposer.jsx
  • packages/cozy-search/src/components/Search/useFetchResult.jsx
  • packages/cozy-search/src/components/adapters/CozyRealtimeChatAdapter.ts
  • packages/cozy-search/src/components/CozyAssistantRuntimeProvider.tsx
  • packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx

@paultranvan paultranvan force-pushed the feature/file-mention-feature branch from 6324c15 to 509f68c Compare April 3, 2026 14:53
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (5)
packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx (2)

142-148: Icon rendering assumes specific structure.

The icon rendering logic checks for icon.type === 'component' but falls back to rendering file.icon directly otherwise. This works if file.icon is already a React element, but could fail silently if it's an unexpected type. Consider adding a null check or default icon fallback.

🔧 Optional: Add defensive fallback
               <ListItemIcon>
-                {file.icon && file.icon.type === 'component' ? (
+                {file.icon?.type === 'component' ? (
                   <Icon icon={file.icon.component} size={32} />
-                ) : (
+                ) : file.icon ? (
                   file.icon
+                ) : (
+                  <Icon icon={FileIcon} size={32} />
                 )}
               </ListItemIcon>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx` around
lines 142 - 148, The icon rendering in FileMentionMenu.jsx inside the
ListItemIcon block assumes file.icon exists and is either a component descriptor
or a React element; add defensive checks and a fallback: ensure you null-check
file.icon before accessing file.icon.type, render <Icon
icon={file.icon.component} /> only when file.icon && file.icon.type ===
'component', treat other truthy values as valid React elements, and if file.icon
is missing or an unexpected type render a default/icon placeholder so the UI
won't fail silently (refer to ListItemIcon, Icon, and the file.icon usage).

109-115: Consider adding a dependency array to the useLayoutEffect.

The effect currently runs on every render because it lacks a dependency array. While this ensures the latest handleKeyDown closure is always used, it's slightly inefficient. Adding [handleKeyDown] as deps (after wrapping handleKeyDown in useCallback) would be more optimal.

However, since handleKeyDown depends on multiple values (fileResults, selectedIndex, composerRuntime, etc.), the current approach is a pragmatic trade-off that avoids complex dependency management.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx` around
lines 109 - 115, The effect currently rebinds menuKeyDownRef on every render;
wrap handleKeyDown in useCallback (including its actual dependencies such as
fileResults, selectedIndex, composerRuntime, etc.) so it is stable, then change
the useLayoutEffect to include [handleKeyDown] as its dependency and keep the
same setup/teardown (menuKeyDownRef.current = handleKeyDown and cleanup setting
it to null). This ensures the latest closure is used without running the effect
every render; reference useLayoutEffect, menuKeyDownRef, and handleKeyDown when
making the change.
packages/cozy-search/src/components/Conversations/ConversationBar.jsx (1)

38-40: anchorEl state could potentially be simplified.

The useEffect to set anchorEl based on hasMention ensures the ref is populated after mount. An alternative would be to pass containerRef.current directly to FileMentionMenu since it's only rendered when hasMention is true. However, the current approach is safe and explicit.

🔧 Optional simplification
-  const [anchorEl, setAnchorEl] = useState(null)
-
-  useEffect(() => {
-    setAnchorEl(hasMention ? containerRef.current : null)
-  }, [hasMention])
...
       {hasMention && (
         <FileMentionMenu
-          anchorEl={anchorEl}
+          anchorEl={containerRef.current}
           searchTerm={mentionSearchTerm}

This works because FileMentionMenu is only rendered when hasMention is true, and by that point containerRef.current is guaranteed to be populated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/ConversationBar.jsx` around
lines 38 - 40, The anchorEl state and its useEffect can be removed and
simplified: delete the anchorEl state declaration and the useEffect that calls
setAnchorEl(hasMention ? containerRef.current : null), and instead pass
containerRef.current directly as the anchorEl prop to FileMentionMenu when
rendering (only when hasMention is true); update any references to anchorEl to
use containerRef.current and keep identifiers containerRef, hasMention,
FileMentionMenu, and setAnchorEl removed accordingly.
packages/cozy-search/src/components/Messages/UserMessageAttachments.jsx (1)

13-18: Consider handling query error state.

The component handles loading and empty states but doesn't handle potential query errors. If the file fetch fails, users won't see any indication of the problem. Consider adding error handling.

🔧 Add error handling
-  const { data: files, ...queryResult } = useQuery(
+  const { data: files, fetchStatus, ...queryResult } = useQuery(
     filesByIds.definition,
     filesByIds.options
   )

-  if (!enabled || isQueryLoading(queryResult) || !files?.length) return null
+  if (!enabled || isQueryLoading(queryResult)) return null
+  if (fetchStatus === 'failed' || !files?.length) return null

Alternatively, you could render a fallback UI indicating the error, but silently returning null is acceptable for a non-critical display feature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Messages/UserMessageAttachments.jsx`
around lines 13 - 18, The component currently ignores query errors when calling
useQuery (filesByIds.definition / filesByIds.options) and only checks
isQueryLoading and files length; update the logic to handle errors from
queryResult (e.g., queryResult.error or an isQueryError flag) by either
rendering a simple fallback/error UI or logging the error and returning null for
non-critical displays; specifically, locate the useQuery call and the early
return that uses isQueryLoading and files, add an error check on queryResult and
implement the chosen fallback behavior.
packages/cozy-search/src/components/Conversations/FileMentionContext.jsx (1)

59-86: menuKeyDownRef in value but not in dependency array.

menuKeyDownRef is included in the context value object (line 72) but omitted from the useMemo dependency array. While this works correctly because refs are referentially stable, including it in the deps would be more explicit and consistent.

🔧 Optional fix for consistency
     [
       selectedFiles,
       inputValue,
       addFile,
       removeFile,
       reset,
       removeMentionText,
       handleInputChange,
       hasMention,
       mentionSearchTerm,
       snapshotAttachmentsIDs,
-      getAttachmentsIDs
+      getAttachmentsIDs,
+      menuKeyDownRef
     ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cozy-search/src/components/Conversations/FileMentionContext.jsx`
around lines 59 - 86, The context value returned from useMemo in the
FileMentionContext component includes menuKeyDownRef but the dependency array
omits it; update the useMemo dependency array to include menuKeyDownRef so the
memoization is explicit and consistent with the value object (locate the useMemo
that builds value, the value object itself, and the dependency array).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/cozy-search/src/components/Conversations/ConversationBar.jsx`:
- Around line 38-40: The anchorEl state and its useEffect can be removed and
simplified: delete the anchorEl state declaration and the useEffect that calls
setAnchorEl(hasMention ? containerRef.current : null), and instead pass
containerRef.current directly as the anchorEl prop to FileMentionMenu when
rendering (only when hasMention is true); update any references to anchorEl to
use containerRef.current and keep identifiers containerRef, hasMention,
FileMentionMenu, and setAnchorEl removed accordingly.

In `@packages/cozy-search/src/components/Conversations/FileMentionContext.jsx`:
- Around line 59-86: The context value returned from useMemo in the
FileMentionContext component includes menuKeyDownRef but the dependency array
omits it; update the useMemo dependency array to include menuKeyDownRef so the
memoization is explicit and consistent with the value object (locate the useMemo
that builds value, the value object itself, and the dependency array).

In `@packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx`:
- Around line 142-148: The icon rendering in FileMentionMenu.jsx inside the
ListItemIcon block assumes file.icon exists and is either a component descriptor
or a React element; add defensive checks and a fallback: ensure you null-check
file.icon before accessing file.icon.type, render <Icon
icon={file.icon.component} /> only when file.icon && file.icon.type ===
'component', treat other truthy values as valid React elements, and if file.icon
is missing or an unexpected type render a default/icon placeholder so the UI
won't fail silently (refer to ListItemIcon, Icon, and the file.icon usage).
- Around line 109-115: The effect currently rebinds menuKeyDownRef on every
render; wrap handleKeyDown in useCallback (including its actual dependencies
such as fileResults, selectedIndex, composerRuntime, etc.) so it is stable, then
change the useLayoutEffect to include [handleKeyDown] as its dependency and keep
the same setup/teardown (menuKeyDownRef.current = handleKeyDown and cleanup
setting it to null). This ensures the latest closure is used without running the
effect every render; reference useLayoutEffect, menuKeyDownRef, and
handleKeyDown when making the change.

In `@packages/cozy-search/src/components/Messages/UserMessageAttachments.jsx`:
- Around line 13-18: The component currently ignores query errors when calling
useQuery (filesByIds.definition / filesByIds.options) and only checks
isQueryLoading and files length; update the logic to handle errors from
queryResult (e.g., queryResult.error or an isQueryError flag) by either
rendering a simple fallback/error UI or logging the error and returning null for
non-critical displays; specifically, locate the useQuery call and the early
return that uses isQueryLoading and files, add an error check on queryResult and
implement the chosen fallback behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b8b4e29-0962-4799-aa24-9738da0ec1e2

📥 Commits

Reviewing files that changed from the base of the PR and between 6324c15 and 509f68c.

📒 Files selected for processing (19)
  • .gitignore
  • packages/cozy-search/src/components/Conversations/ConversationBar.jsx
  • packages/cozy-search/src/components/Conversations/ConversationComposer.jsx
  • packages/cozy-search/src/components/Conversations/FileChipsList.jsx
  • packages/cozy-search/src/components/Conversations/FileMentionContext.jsx
  • packages/cozy-search/src/components/Conversations/FileMentionMenu.jsx
  • packages/cozy-search/src/components/Conversations/mentionConstants.js
  • packages/cozy-search/src/components/CozyAssistantRuntimeProvider.tsx
  • packages/cozy-search/src/components/Messages/UserMessage.jsx
  • packages/cozy-search/src/components/Messages/UserMessageAttachments.jsx
  • packages/cozy-search/src/components/Search/useFetchResult.jsx
  • packages/cozy-search/src/components/adapters/CozyRealtimeChatAdapter.ts
  • packages/cozy-search/src/components/queries.js
  • packages/cozy-search/src/locales/en.json
  • packages/cozy-search/src/locales/fr.json
  • packages/cozy-search/src/locales/ru.json
  • packages/cozy-search/src/locales/vi.json
  • packages/cozy-search/src/tools/types.ts
  • packages/cozy-search/tests/jest.config.js
✅ Files skipped from review due to trivial changes (9)
  • packages/cozy-search/src/locales/fr.json
  • packages/cozy-search/tests/jest.config.js
  • packages/cozy-search/src/locales/en.json
  • packages/cozy-search/src/locales/vi.json
  • packages/cozy-search/src/locales/ru.json
  • packages/cozy-search/src/components/Conversations/FileChipsList.jsx
  • packages/cozy-search/src/components/Conversations/mentionConstants.js
  • .gitignore
  • packages/cozy-search/src/tools/types.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cozy-search/src/components/Search/useFetchResult.jsx
  • packages/cozy-search/src/components/Conversations/ConversationComposer.jsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant