Dev#12
Conversation
Starting with code block, bold, italic, and strikethrough
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds code-block language selection and syntax highlighting to chat composer and renderer; introduces copy-to-clipboard for code blocks, slash-command & mention popup scaffolding, date-aware message grouping, reaction picker and message action bar components, tooltip provider wiring, and new date utilities. Two highlight deps added. Changes
Sequence DiagramsequenceDiagram
participant User
participant Editor as Message Input (TipTap)
participant Bubble as BubbleMenu
participant Composer as Composer Logic
participant Renderer as Markdown Renderer
participant Highlighter as rehype-highlight / highlight.js
participant Clipboard as Clipboard
User->>Editor: Type code block / select text
Editor->>Bubble: Detect code block -> show language selector
User->>Bubble: Choose language
Bubble->>Editor: Update codeBlock language attribute
User->>Composer: Send message
Composer->>Renderer: Render markdown with code block
Renderer->>Highlighter: Apply highlighting (language aware)
Renderer->>User: Display highlighted code + copy button
User->>Clipboard: Click copy
Clipboard->>User: Provide copied feedback
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/chat/composer/message-input.tsx`:
- Around line 221-347: The suggestion popup lifecycle (mounting the popup
element, positioning via positionPopup, adding resize/scroll listeners,
creating/destroying ReactRenderer, and cleanup) is duplicated between
createSlashCommandSuggestion and createMentionSuggestion; extract this into a
shared helper (e.g., createSuggestionPopupManager) that accepts params like
editor, initialProps, rendererComponent (SlashCommandList / MentionList), and a
callback to update props/handle key events, then replace the duplicated logic in
createSlashCommandSuggestion and createMentionSuggestion to call that helper and
use its returned API (onStart/onUpdate/onKeyDown/onExit), preserving existing
identifiers such as positionPopup, cleanup, ReactRenderer, currentProps, popup,
and reactRenderer to keep behavior identical.
- Around line 573-575: isSuggestionMenuOpen currently only checks for
"[data-mention-suggestion-open='true']" so Enter can still send when slash
suggestions are open; update isSuggestionMenuOpen (and the same guard used
around Enter-to-send checks) to query for a broader selector that includes slash
and any generic suggestion flags (e.g., add
"[data-slash-suggestion-open='true']" and/or "[data-suggestion-open='true']" to
the querySelector list) so it returns true whenever any suggestion menu is open.
In `@apps/web/src/components/chat/composer/slash-command-list.tsx`:
- Around line 53-58: The effect currently only watches items.length so selection
can persist incorrectly when the items array identity or content changes but
keeps the same length; update the useEffect that calls setSelectedIndex in
slash-command-list.tsx to depend on the full items array (or a derived stable
key like items.map(i => i.id)) instead of items.length, and reset the selection
to a safe default (e.g., setSelectedIndex(0) when items updates) so the selected
command is cleared on full list updates; reference the useEffect and
setSelectedIndex calls and replace the dependency array accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0a714673-1999-40e6-b88c-9b063f8092fb
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
apps/web/package.jsonapps/web/src/components/chat/composer/message-input.tsxapps/web/src/components/chat/composer/slash-command-list.tsxapps/web/src/components/chat/message-list.tsxapps/web/src/components/chat/message-markdown.tsx
divider grouping between messages sent on different dates, and floating action menu
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/chat/composer/message-input.tsx`:
- Around line 465-473: Replace the commented-out slash-command wiring with a
toggled, active code path: add a boolean feature flag (e.g., useSlashCommands)
near the top of the MessageInput component and conditionally initialize
slashCommandSuggestion via useMemo(() => createSlashCommandSuggestion(), []) and
slashCommandExtension via useMemo(() =>
createSlashCommandExtension(slashCommandSuggestion), [slashCommandSuggestion])
only when useSlashCommands is true; remove the commented blocks and ensure all
references to slashCommandSuggestion and slashCommandExtension are guarded by
the same flag (also update the second commented occurrence mentioned in the
review).
- Around line 700-710: The BubbleMenu shouldShow callback currently destructures
a non-existent element prop and calls element.contains(activeElement), causing a
runtime TypeError; update the callback signature to use the official props
(e.g., shouldShow={({ editor: tiptapEditor, view }) => { ... }}) and replace
element.contains(activeElement) with view.dom.contains(activeElement) (keeping
the existing document activeElement guard and the isEditable / isActive checks)
so containment is checked against the editor DOM provided by the view.
In `@apps/web/src/components/chat/message-item.tsx`:
- Around line 20-24: The handler handleCopyText currently calls
navigator.clipboard.writeText(message.content) without ensuring
navigator.clipboard exists, which can throw synchronously; update handleCopyText
to first check that message.content is present and that typeof navigator !==
'undefined' && navigator.clipboard is truthy before calling writeText, and only
then call navigator.clipboard.writeText(message.content). Keep the existing
Promise.catch to handle async rejections, and ensure the dependency array still
references message.content.
In `@apps/web/src/components/chat/message-markdown.tsx`:
- Around line 167-176: The user-mention replacement is running before
EVERYONE_MENTION_REGEX which lets " `@everyone`" inside a user label get rewritten
into nested/invalid markdown; swap the order so EVERYONE_MENTION_REGEX is
applied first on normalizedContent, then run the USER_MENTION_TOKEN_REGEX
replacement (the code that uses mentionById, getMentionLabel and
escapeMarkdownText) — i.e., change the return chain so EVERYONE_MENTION_REGEX
replacement happens before the USER_MENTION_TOKEN_REGEX replacement to prevent
altering text inside the generated [@...](mention:...) links.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3e53c451-ab7f-4923-b288-88edb5668983
📒 Files selected for processing (11)
apps/web/src/components/chat/composer/message-input.tsxapps/web/src/components/chat/composer/slash-command-list.tsxapps/web/src/components/chat/date-divider.tsxapps/web/src/components/chat/emoji-reaction-picker.tsxapps/web/src/components/chat/message-action-bar.tsxapps/web/src/components/chat/message-item.tsxapps/web/src/components/chat/message-list.tsxapps/web/src/components/chat/message-markdown.tsxapps/web/src/main.tsxapps/web/src/routes/_authenticated/$guildSlug/$channelId.tsxpackages/utils/src/date.ts
Process @everyone mentions before user mentions to prevent partial matches when user mention regex runs first.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
apps/web/src/components/chat/composer/message-input.tsx (2)
699-709:⚠️ Potential issue | 🔴 CriticalFix BubbleMenu
shouldShowprops usage (elementis invalid here).Line 699 destructures
element, and Line 708 callselement.contains(...). In Tiptap BubbleMenushouldShow, the documented props useview(notelement), so this can throw at runtime when that branch executes.🛠️ Proposed fix
- shouldShow={({ editor: tiptapEditor, element }) => { + shouldShow={({ editor: tiptapEditor, view }) => { const activeElement = typeof document !== "undefined" ? document.activeElement : null return ( tiptapEditor.isEditable && (tiptapEditor.isActive("codeBlock") || - (activeElement ? element.contains(activeElement) : false)) + (activeElement ? view.dom.contains(activeElement) : false)) ) }}For `@tiptap/react`@3.20.0 BubbleMenu (from "@tiptap/react/menus"), what is the `shouldShow` callback parameter shape, and does it include `element`?Reference: https://tiptap.dev/docs/editor/extensions/functionality/bubble-menu
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/chat/composer/message-input.tsx` around lines 699 - 709, The BubbleMenu shouldShow callback is using a non-existent element parameter; update the predicate to accept ({ editor: tiptapEditor, view }) instead of ({ editor: tiptapEditor, element }) and replace element.contains(activeElement) with view.dom.contains(activeElement) (keep the existing document.activeElement null-safe check and the tiptapEditor.isEditable / isActive("codeBlock") logic). Ensure you reference the shouldShow prop and tiptapEditor/view variables so the runtime uses the correct DOM node for containment checks.
464-472: 🧹 Nitpick | 🔵 TrivialAvoid shipping commented-out slash-command wiring.
Lines 464-472 and Line 491 keep disabled code paths as comments, which tends to drift. Prefer a small feature flag with live code paths (or remove until enabled).
♻️ Feature-flag pattern (hook-safe, no commented code)
- // Slash commands temporarily disabled. - // const slashCommandSuggestion = useMemo( - // () => createSlashCommandSuggestion(), - // [] - // ) - // const slashCommandExtension = useMemo( - // () => createSlashCommandExtension(slashCommandSuggestion), - // [slashCommandSuggestion] - // ) + const useSlashCommands = false + const slashCommandSuggestion = useMemo( + () => (useSlashCommands ? createSlashCommandSuggestion() : null), + [useSlashCommands] + ) + const slashCommandExtension = useMemo( + () => + slashCommandSuggestion + ? createSlashCommandExtension(slashCommandSuggestion) + : null, + [slashCommandSuggestion] + ) ... - // slashCommandExtension, + ...(slashCommandExtension ? [slashCommandExtension] : []),Also applies to: 491-492
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/web/src/components/chat/composer/message-input.tsx` around lines 464 - 472, Remove the commented-out slash-command wiring and either implement a small runtime feature flag or delete the code; specifically, replace the commented createSlashCommandSuggestion/createSlashCommandExtension lines with a feature-flagged implementation (e.g., const enableSlashCommands = useFeatureFlag('slashCommands') or a prop) and conditionally create the values: const slashCommandSuggestion = useMemo(() => enableSlashCommands ? createSlashCommandSuggestion() : null, [enableSlashCommands]) and const slashCommandExtension = useMemo(() => enableSlashCommands && slashCommandSuggestion ? createSlashCommandExtension(slashCommandSuggestion) : null, [enableSlashCommands, slashCommandSuggestion]); ensure hook rules are preserved (hooks not called conditionally) and remove the commented blocks at lines referencing slashCommandSuggestion/slashCommandExtension.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@apps/web/src/components/chat/composer/message-input.tsx`:
- Around line 699-709: The BubbleMenu shouldShow callback is using a
non-existent element parameter; update the predicate to accept ({ editor:
tiptapEditor, view }) instead of ({ editor: tiptapEditor, element }) and replace
element.contains(activeElement) with view.dom.contains(activeElement) (keep the
existing document.activeElement null-safe check and the tiptapEditor.isEditable
/ isActive("codeBlock") logic). Ensure you reference the shouldShow prop and
tiptapEditor/view variables so the runtime uses the correct DOM node for
containment checks.
- Around line 464-472: Remove the commented-out slash-command wiring and either
implement a small runtime feature flag or delete the code; specifically, replace
the commented createSlashCommandSuggestion/createSlashCommandExtension lines
with a feature-flagged implementation (e.g., const enableSlashCommands =
useFeatureFlag('slashCommands') or a prop) and conditionally create the values:
const slashCommandSuggestion = useMemo(() => enableSlashCommands ?
createSlashCommandSuggestion() : null, [enableSlashCommands]) and const
slashCommandExtension = useMemo(() => enableSlashCommands &&
slashCommandSuggestion ? createSlashCommandExtension(slashCommandSuggestion) :
null, [enableSlashCommands, slashCommandSuggestion]); ensure hook rules are
preserved (hooks not called conditionally) and remove the commented blocks at
lines referencing slashCommandSuggestion/slashCommandExtension.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c493c911-eaa2-4e4c-91d3-655c0f04acf2
📒 Files selected for processing (1)
apps/web/src/components/chat/composer/message-input.tsx
Pull Request Summary: Dev (PR #12)
Overview
This PR enhances chat UX across the web app by adding syntax-highlighted code blocks with copy support, editor code-block language selection and richer composer formatting (bubble menus), a scaffolded slash-command system, emoji reaction UI, a message action bar, date-aware message grouping with a date divider component, and new date utilities.
Changes
Dependencies
Editor / Composer
Slash Command List
Markdown Rendering / Code Blocks
Message List & Date Dividers
Message Item / Actions / Reactions
App-level
Mention Candidates
Observations / Notes
Suggested Reviews / Focus Areas
Confidence Score: 3/5
Rationale: The changes are substantial and generally follow existing patterns. The implementation appears well-scoped and integrates multiple UI improvements. However, the PR introduces many new components and behavior without tests, includes scaffolded but disabled features (slash commands) that may need documentation, and adds syntax-highlighting dependencies that should be assessed for bundle impact. These points suggest the PR is mostly solid but would benefit from follow-up fixes/tests.