Skip to content

feat: add mention in editor - #59

Merged
Ali1raz merged 14 commits into
mainfrom
feat/mention
Oct 29, 2026
Merged

Ali1raz merged 14 commits into
mainfrom
feat/mention

Conversation

@Ali1raz

@Ali1raz Ali1raz commented Jul 9, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added @mention suggestions to message editors and thread replies.
    • Suggestions search team members by name or email and support keyboard navigation.
    • Added styled mention pills within message content.
  • Improvements

    • Improved message content spacing and readability.
    • Adjusted editor sizing for smaller layouts.

@vercel

vercel Bot commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
team-flow Ready Ready Preview Oct 29, 2026 1:08pm UTC

@coderabbitai

coderabbitai Bot commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b313a1d1-42be-48a3-ab39-85975f94f53f
Walkthrough

TipTap mention dependencies, editor extensions, suggestion rendering, member queries, message composer wiring, mention styling, and message content layout are updated to support team-member mentions.

Changes: User mentions

Layer / File(s) Summary
Mention extension foundation
package.json, components/editor/mentions.tsx, components/editor/extensions.ts, skills-lock.json
Mention dependencies, the MentionUser shape, the configured TipTap mention extension, and skill metadata are added.
Suggestion dropdown lifecycle
components/editor/mentions.tsx, app/globals.css
Mention suggestions render member rows with keyboard navigation, popup positioning, dismissal handling, cleanup, and themed mention styling.
Dynamic editor integration
components/editor/editor.tsx, components/editor/extensions.ts, app/(organization)/organizations/[organizationId]/_components/message-item.tsx
Editor conditionally configures mention suggestions from mentionsQuery; editor sizing and rendered message layout classes are adjusted.
Member lookup and composer wiring
app/(organization)/organizations/[organizationId]/_components/edit-message-form.tsx, app/(organization)/organizations/[organizationId]/_components/messaeg-input.tsx, app/(organization)/organizations/[organizationId]/_components/message-omposer.tsx, components/thread-sidebar/threads-form.tsx
Message forms query team members, normalize member records, filter up to eight name/email matches, and pass mention data into composers and editors.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MessageInput
  participant TeamMembersQuery
  participant Messagecomponser
  participant Editor
  participant MentionSuggestions
  MessageInput->>TeamMembersQuery: fetch members for teamId
  TeamMembersQuery-->>MessageInput: return member records
  MessageInput->>Messagecomponser: pass members
  Messagecomponser->>Editor: pass mentionsQuery
  Editor->>MentionSuggestions: configure @ suggestions
  MentionSuggestions->>Messagecomponser: request matching members
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding mention support to the editor.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 feat/mention
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 3

🧹 Nitpick comments (7)
app/(organization)/organizations/[organizationId]/_components/message-omposer.tsx (1)

6-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add explanatory comments to the new mentionsQuery logic.

The new callback (filter/limit logic, empty-members guard) has no comments explaining the reasoning, e.g. why results are capped at 8.

As per coding guidelines, **/*.{ts,tsx,js,jsx}: "Add comments to any new code you add, explaining the reason for the code or the non-obvious decision it implements."

💬 Suggested comment
   const mentionsQuery = useCallback(
     async (query: string) => {
       if (!members?.length) {
         return [];
       }

       const normalizedQuery = query.toLowerCase();
+      // Cap suggestions to 8 rows to keep the dropdown compact and avoid
+      // rendering excessively long member lists.
       return members
         .filter(
           (member) =>
             member.name.toLowerCase().includes(normalizedQuery) ||
             (member.email?.toLowerCase().includes(normalizedQuery) ?? false)
         )
         .slice(0, 8);
     },
     [members]
   );

Also applies to: 20-20, 31-54

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/`(organization)/organizations/[organizationId]/_components/message-omposer.tsx
around lines 6 - 7, Add explanatory comments to the new mentionsQuery callback
in the message composer, including the empty-members guard, filtering behavior,
and the reason results are capped at 8; keep comments focused on the non-obvious
decisions and use the MentionUser-related logic to locate the implementation.

Source: Coding guidelines

app/(organization)/organizations/[organizationId]/_components/messaeg-input.tsx (1)

61-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate members-fetch logic across composer forms.

The suspense query + member-array mapping here is identical to the block added in components/thread-sidebar/threads-form.tsx (lines 60-70). Consider extracting a shared useTeamMembers(teamId) hook to avoid drift between the two copies as the member shape evolves.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/`(organization)/organizations/[organizationId]/_components/messaeg-input.tsx
around lines 61 - 71, Extract the duplicated members query and mapping into a
shared useTeamMembers(teamId) hook, then replace the inline logic in the message
input component and components/thread-sidebar/threads-form.tsx with that hook.
Preserve the existing returned member shape and suspense-query behavior.
components/editor/mentions.tsx (3)

24-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fragile plugin lookup for closeSuggestion.

The heuristic finds "the" suggestion plugin by duck-typing its state shape (active/decorationId keys). This works today because Mention is the only suggestion-based extension, but if a second suggestion extension (emoji, slash-commands, etc.) is added later, find() will grab whichever plugin appears first and may close/dismiss the wrong one.

Consider configuring the Mention extension with an explicit suggestion.pluginKey and storing/exporting that key so closeSuggestion can look it up directly instead of scanning by shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/editor/mentions.tsx` around lines 24 - 36, Replace the duck-typed
plugin search in closeSuggestion with an explicit Mention suggestion plugin key.
Configure the Mention extension’s suggestion option with a named pluginKey,
export or otherwise share that key with closeSuggestion, and retrieve the plugin
directly from view.state using the key before dispatching the exit metadata.

188-211: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Popup position isn't updated on scroll/resize.

position() is only invoked from onStart and onUpdate (i.e., when the query text changes). If the page or a scrollable ancestor scrolls while the dropdown is open, the fixed-positioned popup stays anchored to the last computed rect and visually drifts away from the caret until the next keystroke.

Consider adding a scroll/resize listener (removed in onExit) that re-runs position(props).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/editor/mentions.tsx` around lines 188 - 211, Add scroll and resize
listeners when the mention popup opens, reusing the current SuggestionProps to
call position(props) whenever the viewport or scrollable content changes; remove
both listeners in onExit to prevent leaks, and ensure listener setup/cleanup is
coordinated with the existing popup lifecycle and position function.

49-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Typo in comment.

"Refences" should be "References".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/editor/mentions.tsx` around lines 49 - 54, Correct the typo in the
documentation comment above the mention editor extension: change “Refences and
Thanks to” to “References and Thanks to”.
app/(organization)/organizations/[organizationId]/_components/edit-message-form.tsx (1)

63-86: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing comment for the magic 8-result cap.

The .slice(0, 8) limit and the filter rules are new, non-obvious logic with no explanation of why 8 was chosen (e.g., UI/perf constraint for the dropdown).
As per coding guidelines, add a short comment for new code that isn't self-evident.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/`(organization)/organizations/[organizationId]/_components/edit-message-form.tsx
around lines 63 - 86, The mentionsQuery result cap and matching logic lack
context. Add a brief comment before the filtering or slicing in mentionsQuery
explaining that results are limited to 8 to keep the mention dropdown concise
and performant.

Source: Coding guidelines

components/editor/editor.tsx (1)

31-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate Mention.configure({HTMLAttributes:{class:"mention"}}) between this file and extensions.ts.

The same HTMLAttributes config is repeated in components/editor/extensions.ts (Lines 57-61) and here. If the class name or attributes ever change, both call sites must be kept in sync manually.

Consider extracting a small factory (e.g., createMentionExtension(suggestion?)) shared by both files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/editor/editor.tsx` around lines 31 - 39, Remove the duplicated
Mention configuration by introducing a shared factory such as
createMentionExtension(suggestion?) in the editor extension utilities,
centralizing the HTMLAttributes class setting and optional suggestion setup.
Update both the editor extension construction and extensions.ts to use this
factory while preserving their existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/`(organization)/organizations/[organizationId]/_components/edit-message-form.tsx:
- Around line 63-86: Extract the shared case-insensitive member filtering,
eight-result limit, and MentionUser mapping from mentionsQuery into a reusable
filterMembersForMentions helper with an optional limit defaulting to 8; update
this component’s mentionsQuery and the corresponding composer implementations,
including message-omposer.tsx, to call the helper.

In `@components/editor/editor.tsx`:
- Around line 26-40: Add a brief comment above the `baseExtensions.filter` and
configured `Mention` replacement in `editorExtensions`, explaining that the
default mention extension is removed and replaced with a suggestion-configured
instance when `mentionsQuery` is available.

In `@package.json`:
- Around line 43-52: Update the `@tiptap/extension-code-block-lowlight` dependency
to version ^3.27.3 in package.json, matching the other Tiptap packages and
avoiding peer dependency conflicts with `@tiptap/core` and `@tiptap/pm`.

---

Nitpick comments:
In
`@app/`(organization)/organizations/[organizationId]/_components/edit-message-form.tsx:
- Around line 63-86: The mentionsQuery result cap and matching logic lack
context. Add a brief comment before the filtering or slicing in mentionsQuery
explaining that results are limited to 8 to keep the mention dropdown concise
and performant.

In
`@app/`(organization)/organizations/[organizationId]/_components/messaeg-input.tsx:
- Around line 61-71: Extract the duplicated members query and mapping into a
shared useTeamMembers(teamId) hook, then replace the inline logic in the message
input component and components/thread-sidebar/threads-form.tsx with that hook.
Preserve the existing returned member shape and suspense-query behavior.

In
`@app/`(organization)/organizations/[organizationId]/_components/message-omposer.tsx:
- Around line 6-7: Add explanatory comments to the new mentionsQuery callback in
the message composer, including the empty-members guard, filtering behavior, and
the reason results are capped at 8; keep comments focused on the non-obvious
decisions and use the MentionUser-related logic to locate the implementation.

In `@components/editor/editor.tsx`:
- Around line 31-39: Remove the duplicated Mention configuration by introducing
a shared factory such as createMentionExtension(suggestion?) in the editor
extension utilities, centralizing the HTMLAttributes class setting and optional
suggestion setup. Update both the editor extension construction and
extensions.ts to use this factory while preserving their existing behavior.

In `@components/editor/mentions.tsx`:
- Around line 24-36: Replace the duck-typed plugin search in closeSuggestion
with an explicit Mention suggestion plugin key. Configure the Mention
extension’s suggestion option with a named pluginKey, export or otherwise share
that key with closeSuggestion, and retrieve the plugin directly from view.state
using the key before dispatching the exit metadata.
- Around line 188-211: Add scroll and resize listeners when the mention popup
opens, reusing the current SuggestionProps to call position(props) whenever the
viewport or scrollable content changes; remove both listeners in onExit to
prevent leaks, and ensure listener setup/cleanup is coordinated with the
existing popup lifecycle and position function.
- Around line 49-54: Correct the typo in the documentation comment above the
mention editor extension: change “Refences and Thanks to” to “References and
Thanks to”.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c84f2a00-c5d4-41f2-86aa-d5e7dc10aa09

📥 Commits

Reviewing files that changed from the base of the PR and between af63a0d and 4cc0d35.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • app/(organization)/organizations/[organizationId]/_components/edit-message-form.tsx
  • app/(organization)/organizations/[organizationId]/_components/messaeg-input.tsx
  • app/(organization)/organizations/[organizationId]/_components/message-item.tsx
  • app/(organization)/organizations/[organizationId]/_components/message-omposer.tsx
  • app/globals.css
  • components/editor/editor.tsx
  • components/editor/extensions.ts
  • components/editor/mentions.tsx
  • components/thread-sidebar/threads-form.tsx
  • package.json
  • skills-lock.json

Comment thread components/editor/editor.tsx Resolved
Comment thread package.json Resolved
ali-raza-fa22 and others added 2 commits October 27, 2026 09:54
Resolve conflicts combining mention feature from feat/mention with
main's updates: newer Tiptap (3.30.1), details extension, react-table,
conversationKey, expandable content, and editor onSubmit/keyboard
handling. Regenerate pnpm-lock.yaml from merged package.json.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Add Mention model to Prisma schema with relations on Message and User.
Create lib/mentions.ts with analyzeContent() and server-side
validMentionIds() that re-validates membership (team or org scope)
and excludes the author.

Update createMessage and updateMessage handlers to parse Tiptap
content, validate mentions, and persist Mention rows in a single
transaction. Output now includes computed mentionedUserIds.

Add mentionedUserIds to messageListItemSchema and include it in the
message:created realtime payload so PartyKit can notify mentioned users.

Also wire up the user.mention RPC endpoint, useMentionUsers hook, and
mention picker imports used by the editor.
@Ali1raz
Ali1raz requested a review from ali-raza-fa22 October 27, 2026 10:26
@ali-raza-fa22
ali-raza-fa22 requested a balanced review from Copilot October 27, 2026 10:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Use Inngest to queue mention emails on message creation and edits, with
recipient validation, retries, and HTML escaping. Add the Inngest API
route and development tooling. closes #105
- Fix TS2353 in createMessage: narrow teamId from the discriminated
  union scope before passing to inngest.send
- Add mentionedUserIds to RealtimeMessageSchema so the message:created
  payload carries server-validated mention IDs
- Map mentionedUserIds from raw realtime payload into MessageListItemType
  in the conversation realtime provider

@Ali1raz Ali1raz left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ok

@Ali1raz Ali1raz left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ok

@ali-raza-fa22 ali-raza-fa22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

use shadcn command command component for mention.tsx

Comment thread components/editor/mentions.tsx Resolved
@Ali1raz
Ali1raz merged commit 73dd0c7 into main Oct 29, 2026
3 of 4 checks passed
@Ali1raz
Ali1raz deleted the feat/mention branch October 30, 2026 06:50

This branch was successfully deployed

1 active deployment
Preview — 8f6bae52 Deployed Oct 29, 2026 by vercel[bot]
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.

3 participants