Skip to content

Conversation

Palanikannan1437
Copy link
Member

@Palanikannan1437 Palanikannan1437 commented Jul 30, 2025

Description

Fixes weird bugs that cause issues while multiple node views are rendered in the editor of the same type!

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Test Scenarios

References

Summary by CodeRabbit

  • Refactor
    • Added unique keys to various editor components to improve React rendering and reconciliation. Keys are now based on unique identifiers for callouts, code blocks, custom images, mentions, and embedded work items. No changes to component behavior or public interfaces.

Copy link
Contributor

coderabbitai bot commented Jul 30, 2025

Walkthrough

Unique and stable React key props have been added to several NodeViewWrapper components across different editor extensions. These keys are generated either from unique entity attributes or via UUIDs, ensuring each instance of these components can be reliably identified by React during rendering and reconciliation. No other logic or API changes were introduced.

Changes

Cohort / File(s) Change Summary
Callout Block: Add UUID-based key
packages/editor/src/core/extensions/callout/block.tsx
Adds a memoized UUID as a key prop to the NodeViewWrapper in CustomCalloutBlock.
Code Block: Add UUID-based key
packages/editor/src/core/extensions/code/code-block-node-view.tsx
Generates a memoized UUID and uses it as the key prop for the NodeViewWrapper in CodeBlockComponent.
Custom Image: Use entity id as key
packages/editor/src/core/extensions/custom-image/components/node-view.tsx
Extracts id from node attributes and assigns it as the key prop for NodeViewWrapper in CustomImageNodeView.
Mentions: Use entity_identifier as key
packages/editor/src/core/extensions/mentions/mention-node-view.tsx
Uses the node's entity_identifier attribute as the key prop for NodeViewWrapper in MentionNodeView.
Work Item Embed: Use entity_identifier as key
packages/editor/src/core/extensions/work-item-embed/extension.tsx
Sets the key prop on NodeViewWrapper using the embedded work item's entity_identifier in addNodeView.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇
A hop, a skip, a brand-new key,
Each node now shines uniquely!
With UUIDs and IDs in tow,
React will always surely know
Which block is which, from start to end—
No more confusion to amend!
Hooray for keys, your bunny friend!

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/node-view-rerenders

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

makeplane bot commented Jul 30, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

Copy link
Contributor

@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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1458c75 and 35c4d50.

📒 Files selected for processing (5)
  • packages/editor/src/core/extensions/callout/block.tsx (2 hunks)
  • packages/editor/src/core/extensions/code/code-block-node-view.tsx (3 hunks)
  • packages/editor/src/core/extensions/custom-image/components/node-view.tsx (2 hunks)
  • packages/editor/src/core/extensions/mentions/mention-node-view.tsx (1 hunks)
  • packages/editor/src/core/extensions/work-item-embed/extension.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
packages/editor/src/core/extensions/custom-image/components/node-view.tsx (1)

Learnt from: SatishGandham
PR: #5864
File: packages/editor/src/core/extensions/custom-image/read-only-custom-image.ts:60-60
Timestamp: 2024-10-22T08:03:04.373Z
Learning: In packages/editor/src/core/extensions/custom-image/read-only-custom-image.ts, the getImageSource command returns a string directly, not a function.

🔇 Additional comments (3)
packages/editor/src/core/extensions/code/code-block-node-view.tsx (1)

8-9: LGTM! Excellent implementation of stable unique keys.

The use of useMemo with uuidv4 ensures each code block instance gets a unique, stable key that persists across re-renders. This is the ideal approach for components that don't have natural unique identifiers.

Also applies to: 26-27, 41-41

packages/editor/src/core/extensions/callout/block.tsx (1)

2-3: LGTM! Consistent implementation with stable unique keys.

The implementation mirrors the approach used in the code block component, using useMemo with uuidv4 to generate stable, unique keys. This ensures proper React reconciliation for callout block instances.

Also applies to: 26-27, 33-33

packages/editor/src/core/extensions/custom-image/components/node-view.tsx (1)

25-25: Using imageEntityId as the React key is safe—no fallback needed

We verified that every CustomImage node is inserted via the extension’s insertImageComponent command, which always generates and assigns a UUID (uuidv4()) to node.attrs.id. This guarantees that:

  • id is never undefined or null when the node is rendered
  • IDs are universally unique thanks to UUID v4

The default null value in addAttributes() is only a placeholder until addCommands runs and sets a real UUID. You can continue using:

<NodeViewWrapper key={`custom-image-node-view-${imageEntityId}`}>

without additional fallback logic.

Comment on lines +20 to +23
<NodeViewWrapper
key={`mention-node-view-${attrs[EMentionComponentAttributeNames.ENTITY_IDENTIFIER]}`}
className="mention-component inline w-fit"
>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider handling empty entity_identifier to prevent key collisions.

The key generation uses entity_identifier directly, but if this value is undefined or empty (as suggested by the fallback on line 25), multiple mention nodes could end up with the same key mention-node-view-, causing React reconciliation issues.

Consider adding a fallback UUID or index-based key:

+ import { v4 as uuidv4 } from "uuid";
+ import { useMemo } from "react";

export const MentionNodeView: React.FC<MentionNodeViewProps> = (props) => {
  const {
    extension,
    node: { attrs },
  } = props;

+ const fallbackId = useMemo(() => uuidv4(), []);
+ const entityId = attrs[EMentionComponentAttributeNames.ENTITY_IDENTIFIER] || fallbackId;

  return (
    <NodeViewWrapper
-     key={`mention-node-view-${attrs[EMentionComponentAttributeNames.ENTITY_IDENTIFIER]}`}
+     key={`mention-node-view-${entityId}`}
      className="mention-component inline w-fit"
    >
🤖 Prompt for AI Agents
In packages/editor/src/core/extensions/mentions/mention-node-view.tsx around
lines 20 to 23, the key for NodeViewWrapper uses the entity_identifier directly,
which can be undefined or empty, leading to duplicate keys and React
reconciliation problems. To fix this, modify the key generation to include a
fallback value such as a UUID or a unique index when entity_identifier is
missing or empty, ensuring all keys are unique and stable.

@@ -18,7 +18,7 @@ export const WorkItemEmbedExtension = (props: Props) =>
WorkItemEmbedExtensionConfig.extend({
addNodeView() {
return ReactNodeViewRenderer((issueProps: any) => (
<NodeViewWrapper>
<NodeViewWrapper key={`work-item-embed-node-view-${issueProps.node.attrs.entity_identifier}`}>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider handling undefined entity_identifier to prevent key collisions.

Similar to the mentions component, if entity_identifier is undefined or empty, multiple work item embed nodes could end up with the same key, causing React reconciliation issues.

Consider adding a fallback mechanism:

export const WorkItemEmbedExtension = (props: Props) =>
  WorkItemEmbedExtensionConfig.extend({
    addNodeView() {
+     let nodeCounter = 0;
      return ReactNodeViewRenderer((issueProps: any) => {
+       const entityId = issueProps.node.attrs.entity_identifier || `fallback-${++nodeCounter}`;
        return (
-         <NodeViewWrapper key={`work-item-embed-node-view-${issueProps.node.attrs.entity_identifier}`}>
+         <NodeViewWrapper key={`work-item-embed-node-view-${entityId}`}>
            {props.widgetCallback({
              issueId: issueProps.node.attrs.entity_identifier,
              projectId: issueProps.node.attrs.project_identifier,
              workspaceSlug: issueProps.node.attrs.workspace_identifier,
            })}
          </NodeViewWrapper>
        );
      });
    },
  });
📝 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
<NodeViewWrapper key={`work-item-embed-node-view-${issueProps.node.attrs.entity_identifier}`}>
export const WorkItemEmbedExtension = (props: Props) =>
WorkItemEmbedExtensionConfig.extend({
addNodeView() {
let nodeCounter = 0;
return ReactNodeViewRenderer((issueProps: any) => {
const entityId =
issueProps.node.attrs.entity_identifier ||
`fallback-${++nodeCounter}`;
return (
<NodeViewWrapper
key={`work-item-embed-node-view-${entityId}`}
>
{props.widgetCallback({
issueId: issueProps.node.attrs.entity_identifier,
projectId: issueProps.node.attrs.project_identifier,
workspaceSlug: issueProps.node.attrs.workspace_identifier,
})}
</NodeViewWrapper>
);
});
},
});
🤖 Prompt for AI Agents
In packages/editor/src/core/extensions/work-item-embed/extension.tsx at line 21,
the key for NodeViewWrapper uses entity_identifier directly, which may be
undefined or empty, leading to key collisions in React. To fix this, add a
fallback value when entity_identifier is missing, such as a unique placeholder
string or a generated ID, ensuring each key remains unique and prevents
reconciliation issues.

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