Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PE-93] refactor: editor mentions extension #6178

Open
wants to merge 15 commits into
base: preview
Choose a base branch
from

Conversation

aaryan610
Copy link
Collaborator

@aaryan610 aaryan610 commented Dec 10, 2024

Description

Frontend-

This PR refactors the editor mentions extension. The search callback function and the render component are now passed by the web app instead of handling all the logic inside the editor itself.

It also refactors the logic for arrow key navigation for the mentions component and slash commands menu by extracting the common logic into a separate file.

Backend-

Added a new search endpoint which returns an object with the requested entities based on the search query

Type of Change

  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring

Test Scenarios

  • Mentions across all the editors(issue descriptions, comments and pages)
  • Slash commands menu across all the editors.

Summary by CodeRabbit

  • New Features

    • Introduced a new search API endpoint for enhanced searching capabilities.
    • Added new components for user mentions and additional mentions rendering.
    • Implemented a custom hook for managing editor mentions.
  • Improvements

    • Streamlined mention handling by replacing highlights with component-based rendering.
    • Enhanced type definitions for better clarity and maintainability.
    • Improved markdown content handling by integrating a new parsing mechanism.
  • Bug Fixes

    • Improved error handling during mention fetching processes.
    • Enhanced error logging for export processes.
  • Chores

    • Updated various import statements for consistency and clarity.
    • Removed deprecated hooks and types related to mentions.

Copy link
Contributor

coderabbitai bot commented Dec 10, 2024

Walkthrough

The pull request introduces a series of changes primarily focused on enhancing the search and mention functionalities within the editor components. A new SearchEndpoint is added to handle search queries, while existing mention handling is refactored to streamline the process using a new EditorMentionsRoot component. Various components and hooks are updated to utilize this new structure, improving the integration of mentions and search capabilities across the application.

Changes

File Path Change Summary
apiserver/plane/app/urls/search.py Added a new URL pattern for SearchEndpoint and updated urlpatterns.
apiserver/plane/app/views/__init__.py Updated imports to include SearchEndpoint.
apiserver/plane/app/views/search/base.py Introduced SearchEndpoint class with a get method for processing search queries.
packages/editor/package.json Added dependency @plane/types.
packages/editor/src/core/components/editors/document/read-only-editor.tsx Updated mentionHandler property type in IDocumentReadOnlyEditor interface.
packages/editor/src/core/components/editors/editor-wrapper.tsx Updated extensions property type in Props.
packages/editor/src/core/extensions/core-without-props.ts Modified imports and updated exported constants for mentions.
packages/editor/src/core/extensions/extensions.tsx Renamed CustomMention to CustomMentionExtension and updated mention handling.
packages/editor/src/core/extensions/mentions/extension-config.ts Introduced CustomMentionExtensionConfig for mentions.
packages/editor/src/core/extensions/mentions/mention-node-view.tsx Updated props and removed internal state management for highlights.
packages/editor/src/core/extensions/mentions/mentions-list-dropdown.tsx Added MentionsListDropdown for displaying mention suggestions.
packages/editor/src/core/extensions/mentions/types.ts Defined types related to mentions.
packages/editor/src/core/hooks/use-editor.ts Enhanced type definitions in CustomEditorProps.
packages/editor/src/core/hooks/use-read-only-editor.ts Updated mention handling in CustomReadOnlyEditorProps.
web/core/hooks/use-editor-mention.tsx Introduced useEditorMention hook for fetching mentions.
web/core/services/project/project.service.ts Added searchEntity method for searching entities.
web/core/components/pages/editor/editor-body.tsx Updated mention handling logic in PageEditorBody.
web/core/components/pages/version/editor.tsx Simplified mention handling by removing hooks and updating mentionHandler.
web/ee/components/editor/index.ts Re-exported all entities from ce/components/editor.
web/ee/constants/editor.ts Re-exported constants from ce/constants/editor.

Suggested labels

✍️editor, 🐛bug

Suggested reviewers

  • Palanikannan1437
  • SatishGandham

Poem

In the meadow where bunnies play,
New features hop in, brightening the day.
With mentions and searches, oh what a delight,
Our editor's spruced up, everything feels right!
So let’s celebrate with a joyful cheer,
For the changes that bring us all near! 🐇✨

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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.

@aaryan610 aaryan610 changed the title refactor: editor mentions refactor: editor mentions extension Dec 10, 2024
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: 12

🧹 Outside diff range and nitpick comments (25)
space/core/components/editor/index.ts (1)

Line range hint 1-6: Consider adding JSDoc documentation for the exported modules.

Since this is a key entry point for editor components, adding documentation about the purpose and contents of each module would improve maintainability.

Add documentation like this:

+/**
+ * @module editor
+ * @description Core editor components and utilities
+ * 
+ * - embeds: Editor mention and embed components
+ * - lite-text-editor: Lightweight text editor implementation
+ * - lite-text-read-only-editor: Read-only version of lite editor
+ * - rich-text-read-only-editor: Read-only rich text editor
+ * - toolbar: Editor toolbar components
+ */
 export * from "./embeds";
 export * from "./lite-text-editor";
 export * from "./lite-text-read-only-editor";
 export * from "./rich-text-read-only-editor";
 export * from "./toolbar";
space/core/components/editor/lite-text-read-only-editor.tsx (1)

26-26: Consider adding explicit typing for EditorMentionsRoot props

To improve type safety, consider explicitly typing the props passed to EditorMentionsRoot.

-      renderComponent: (props) => <EditorMentionsRoot {...props} />,
+      renderComponent: (props: EditorMentionsRootProps) => <EditorMentionsRoot {...props} />,
space/core/components/editor/rich-text-read-only-editor.tsx (1)

18-32: Consider adding JSDoc documentation

The component would benefit from JSDoc comments explaining the mention handling behavior and EditorMentionsRoot integration.

+/**
+ * A read-only rich text editor component that supports mentions.
+ * @param props - Component props excluding disabledExtensions, fileHandler, and mentionHandler
+ * @param ref - Reference to access editor API
+ */
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
web/core/hooks/use-editor-mention.tsx (1)

40-62: Use forEach Instead of map for Side Effects

In the loop over Object.keys(res), the returned array from map is not utilized. Since the purpose is side effects (i.e., building suggestionSections), it's more appropriate to use forEach.

Suggested Change:

Replace map with forEach:

- Object.keys(res).map((key) => {
+ Object.keys(res).forEach((key) => {

This clarifies the intent and avoids any confusion regarding unused return values.

packages/editor/src/core/extensions/slash-commands/command-menu.tsx (1)

Line range hint 28-74: Consider Consolidating Keyboard Event Handling

With the addition of the onKeyDown handler via useImperativeHandle, there may be redundancy with the existing useEffect that adds a keydown listener to document. Consolidating these may prevent potential conflicts and simplify the component.

Suggestion:

Evaluate if both keyboard event handlers are necessary. If external components handle keyboard events via the ref, you might remove the useEffect to avoid duplicate event listeners:

- useEffect(() => {
-   const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"];
-   const onKeyDown = (e: KeyboardEvent) => {
-     // existing key handling logic
-   };
-   document.addEventListener("keydown", onKeyDown);
-   return () => {
-     document.removeEventListener("keydown", onKeyDown);
-   };
- }, [sections, selectedIndex, setSelectedIndex, selectItem]);

Ensure that all necessary keyboard interactions are still effectively managed after consolidation.

apiserver/plane/app/views/search/base.py (2)

258-258: Enforce a maximum limit on the count parameter

To prevent potential performance issues or abuse, consider enforcing a maximum limit on the count parameter. This ensures that clients cannot request an excessive number of results.

Apply this diff to set a maximum limit:

 try:
     count = int(request.query_params.get("count", 5))
+    max_count = 100  # Define a sensible maximum limit
+    if count > max_count:
+        count = max_count
 except ValueError:
     return Response({"error": "Invalid 'count' parameter"}, status=status.HTTP_400_BAD_REQUEST)

263-449: Refactor to reduce code duplication

The repetitive patterns in handling different query_type cases can be refactored to enhance maintainability and adhere to the DRY (Don't Repeat Yourself) principle. Consider abstracting common logic into helper functions.

packages/editor/src/core/types/mention.ts (1)

13-17: Consider adding JSDoc comments for better documentation.

While the types are well-structured, adding JSDoc comments would improve code documentation and IDE support.

+/** Represents a section of mention suggestions */
 export type TMentionSection = {
   key: string;
   title?: string;
   items: TMentionSuggestion[];
 };

+/** Props passed to the mention component renderer */
 export type TMentionComponentProps = Pick<TMentionSuggestion, "entity_identifier" | "entity_name">;

+/** Handler for read-only mention functionality */
 export type TReadOnlyMentionHandler = {
   renderComponent: (props: TMentionComponentProps) => React.ReactNode;
 };

+/** Full mention handler with search capability */
 export type TMentionHandler = TReadOnlyMentionHandler & {
   searchCallback?: (query: string) => Promise<TMentionSection[]>;
 };

Also applies to: 19-19, 21-27

packages/editor/src/core/extensions/mentions/mention-node-view.tsx (1)

19-23: Consider using more specific CSS class names.

The class name 'mention-component' could potentially conflict with other components. Consider using a more specific naming convention.

-    <NodeViewWrapper className="mention-component inline w-fit">
+    <NodeViewWrapper className="editor-mention-component inline w-fit">
space/core/components/editor/embeds/mentions/user.tsx (2)

24-32: Extract link construction to a helper function.

Consider moving the profile link construction to a helper function for better reusability and maintainability.

+const getUserProfileLink = (workspaceSlug: string, userId: string) => 
+  `/${workspaceSlug}/profile/${userId}`;

 export const EditorUserMention: React.FC<Props> = observer((props) => {
   // ...
-  const profileLink = `/${workspaceSlug}/profile/${id}`;
+  const profileLink = getUserProfileLink(workspaceSlug, id);
   // ...
 });

26-28: Consider extracting styles to a constant or utility function.

The conditional class names could be extracted to improve readability and reusability.

+const getMentionStyles = (isCurrentUser: boolean) => cn(
+  "not-prose inline px-1 py-0.5 rounded bg-yellow-500/20 text-yellow-500 no-underline",
+  { "bg-custom-primary-100/20 text-custom-primary-100": isCurrentUser }
+);

 export const EditorUserMention: React.FC<Props> = observer((props) => {
   // ...
   return (
     <div
-      className={cn("not-prose inline px-1 py-0.5 rounded bg-yellow-500/20 text-yellow-500 no-underline", {
-        "bg-custom-primary-100/20 text-custom-primary-100": id === currentUser?.id,
-      })}
+      className={getMentionStyles(id === currentUser?.id)}
     >
packages/editor/src/core/helpers/tippy.ts (1)

33-55: Consider extracting navigation logic into separate functions

The navigation logic for up/down directions contains similar patterns. Consider extracting these into separate functions for better maintainability.

+const moveUp = (section: number, item: number, sections: any[]) => {
+  item--;
+  if (item < 0) {
+    section--;
+    if (section < 0) section = sections.length - 1;
+    item = sections[section]?.items?.length - 1;
+  }
+  return { section, item };
+};

+const moveDown = (section: number, item: number, sections: any[]) => {
+  item++;
+  if (item >= sections[section]?.items?.length) {
+    section++;
+    if (section >= sections.length) section = 0;
+    item = 0;
+  }
+  return { section, item };
+};

 if (direction === "up") {
-  // current implementation
+  const result = moveUp(nextSection, nextItem, sections);
+  nextSection = result.section;
+  nextItem = result.item;
 } else {
-  // current implementation
+  const result = moveDown(nextSection, nextItem, sections);
+  nextSection = result.section;
+  nextItem = result.item;
 }
web/core/components/editor/rich-text-editor/rich-text-editor.tsx (1)

28-31: Consider adding loading state handling

The useEditorMention hook might benefit from exposing a loading state to show feedback during mention searches.

-const { fetchMentions } = useEditorMention({
+const { fetchMentions, isLoading } = useEditorMention({
   projectId: projectId?.toString() ?? "",
   workspaceSlug: workspaceSlug?.toString() ?? "",
 });
packages/types/src/search.d.ts (1)

11-69: Consider enhancing type safety with strict null checks.

The response types are well-structured, but consider adding explicit null checks for optional fields. This would help prevent potential runtime errors when handling search results.

Example enhancement:

export type TSearchResponse = {
-  cycle?: TCycleSearchResponse[];
+  cycle?: TCycleSearchResponse[] | null;
-  issue?: TIssueSearchResponse[];
+  issue?: TIssueSearchResponse[] | null;
  // Apply similar changes to other optional arrays
};
packages/editor/src/core/extensions/mentions/utils.ts (1)

21-43: Enhance error handling in dropdown initialization.

The onStart method could benefit from more robust error handling:

  1. Add error logging for failed initialization
  2. Handle edge cases when component creation fails

Example enhancement:

 onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
   if (!searchCallback) return;
   if (!props.clientRect) return;
+  try {
     component = new ReactRenderer<CommandListInstance, MentionsListDropdownProps>(
       // ... existing code
     );
+  } catch (error) {
+    console.error('Failed to initialize mentions dropdown:', error);
+    return;
+  }
   // ... rest of the code
 },
packages/editor/package.json (1)

40-40: LGTM! Consider version constraints for better stability.

While using "*" is common in monorepos for internal packages, consider using a more specific version range (e.g., "^1.0.0") if the types package starts following semantic versioning.

web/core/components/editor/embeds/mentions/user.tsx (4)

16-18: Consider extending Props interface for better flexibility.

The Props interface could benefit from optional properties for customization, such as className for styling overrides.

 type Props = {
   id: string;
+  className?: string;
+  showTooltip?: boolean;
 };

23-24: Consider using a custom hook for popper logic.

The popper-related state and configuration could be extracted into a reusable hook for better maintainability.

// usePopper.ts
export const useUserMentionPopper = () => {
  const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
  const [referenceElement, setReferenceElement] = useState<HTMLAnchorElement | null>(null);
  const popper = usePopper(referenceElement, popperElement, {
    placement: "bottom-start",
    modifiers: [{ name: "preventOverflow", options: { padding: 12 } }],
  });
  
  return { popperElement, setPopperElement, referenceElement, setReferenceElement, ...popper };
};

69-77: Add loading state for avatar.

Consider adding a loading state for the avatar while the image is being fetched.

 <Avatar
   src={getFileURL(userDetails?.avatar_url ?? "")}
   name={userDetails?.display_name}
   size={40}
   className="text-xl"
   showTooltip={false}
+  fallback={<div className="animate-pulse bg-custom-background-80 rounded-full size-10" />}
 />

79-82: Add title attribute for better UX.

Consider adding a title attribute to the link for better user experience when hovering.

 <Link 
   href={profileLink} 
+  title={`${userDetails?.first_name} ${userDetails?.last_name}`}
   className="not-prose font-medium text-custom-text-100 text-base hover:underline"
 >
web/core/components/editor/lite-text-editor/lite-text-editor.tsx (1)

75-80: Enhance error handling in searchCallback

While the error handling is good, consider providing more specific error information to help with debugging.

 searchCallback: async (query) => {
   const res = await fetchMentions(query);
-  if (!res) throw new Error("Failed in fetching mentions");
+  if (!res) throw new Error(`Failed to fetch mentions for query: ${query}`);
   return res;
 },
web/core/services/project/project.service.ts (1)

166-185: Consider improving query_type parameter handling.

While the implementation is correct, consider moving the query_type array joining logic to a separate utility function for better maintainability and reusability.

Here's a suggested refactor:

+const formatQueryTypes = (types: TSearchEntities[]): string => types.join(",");
+
 async searchEntity(
   workspaceSlug: string,
   projectId: string,
   params: {
     query_type: TSearchEntities[];
     count?: number;
     query: string;
   }
 ): Promise<TSearchResponse> {
   return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/search/`, {
     params: {
       ...params,
-      query_type: params.query_type.join(","),
+      query_type: formatQueryTypes(params.query_type),
     },
   })
web/core/components/pages/editor/editor-body.tsx (1)

211-216: Improve error message in searchCallback.

The error message "Failed in fetching mentions" could be more descriptive to aid in debugging.

 searchCallback: async (query) => {
   const res = await fetchMentions(query);
-  if (!res) throw new Error("Failed in fetching mentions");
+  if (!res) throw new Error("Failed to fetch mentions: No response received from the server");
   return res;
 },
packages/editor/src/core/hooks/use-editor.ts (2)

33-33: Consider adding JSDoc comments for better documentation.

The type improvements look good! To further enhance maintainability, consider adding JSDoc comments to document the purpose and expected shape of these props:

+/** Additional extensions to be included in the editor */
 extensions?: Extensions;
+/** Handler for mention functionality including search and suggestions */
 mentionHandler: TMentionHandler;

Also applies to: 39-39


Line range hint 48-90: Consider enhancing error handling during editor initialization.

While the changes look good, consider adding more robust error handling during editor initialization. This could help catch and handle potential issues with the new mention handler implementation.

 const editor = useTiptapEditor({
+  onError: (error) => {
+    console.error('Editor initialization failed:', error);
+    handleEditorReady?.(false);
+  },
   autofocus,
   editorProps: {
     ...CoreEditorProps({
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 205395e and 760d415.

📒 Files selected for processing (71)
  • apiserver/plane/app/urls/search.py (2 hunks)
  • apiserver/plane/app/views/__init__.py (1 hunks)
  • apiserver/plane/app/views/search/base.py (3 hunks)
  • packages/editor/package.json (1 hunks)
  • packages/editor/src/core/components/editors/document/read-only-editor.tsx (2 hunks)
  • packages/editor/src/core/components/editors/editor-wrapper.tsx (2 hunks)
  • packages/editor/src/core/extensions/core-without-props.ts (2 hunks)
  • packages/editor/src/core/extensions/extensions.tsx (3 hunks)
  • packages/editor/src/core/extensions/mentions/extension-config.ts (1 hunks)
  • packages/editor/src/core/extensions/mentions/extension.tsx (1 hunks)
  • packages/editor/src/core/extensions/mentions/index.ts (1 hunks)
  • packages/editor/src/core/extensions/mentions/mention-node-view.tsx (1 hunks)
  • packages/editor/src/core/extensions/mentions/mentions-list-dropdown.tsx (1 hunks)
  • packages/editor/src/core/extensions/mentions/mentions-list.tsx (0 hunks)
  • packages/editor/src/core/extensions/mentions/mentions-without-props.tsx (0 hunks)
  • packages/editor/src/core/extensions/mentions/types.ts (1 hunks)
  • packages/editor/src/core/extensions/mentions/utils.ts (1 hunks)
  • packages/editor/src/core/extensions/read-only-extensions.tsx (3 hunks)
  • packages/editor/src/core/extensions/slash-commands/command-menu.tsx (5 hunks)
  • packages/editor/src/core/extensions/slash-commands/root.tsx (2 hunks)
  • packages/editor/src/core/helpers/tippy.ts (1 hunks)
  • packages/editor/src/core/hooks/use-editor.ts (3 hunks)
  • packages/editor/src/core/hooks/use-read-only-editor.ts (3 hunks)
  • packages/editor/src/core/types/collaboration.ts (2 hunks)
  • packages/editor/src/core/types/editor.ts (4 hunks)
  • packages/editor/src/core/types/index.ts (1 hunks)
  • packages/editor/src/core/types/mention-suggestion.ts (0 hunks)
  • packages/editor/src/core/types/mention.ts (1 hunks)
  • packages/types/.prettierrc (1 hunks)
  • packages/types/src/index.d.ts (1 hunks)
  • packages/types/src/search.d.ts (1 hunks)
  • space/ce/components/editor/embeds/index.ts (1 hunks)
  • space/ce/components/editor/embeds/mentions/index.ts (1 hunks)
  • space/ce/components/editor/embeds/mentions/root.tsx (1 hunks)
  • space/ce/components/editor/index.ts (1 hunks)
  • space/core/components/editor/embeds/index.ts (1 hunks)
  • space/core/components/editor/embeds/mentions/index.ts (1 hunks)
  • space/core/components/editor/embeds/mentions/root.tsx (1 hunks)
  • space/core/components/editor/embeds/mentions/user.tsx (1 hunks)
  • space/core/components/editor/index.ts (1 hunks)
  • space/core/components/editor/lite-text-editor.tsx (2 hunks)
  • space/core/components/editor/lite-text-read-only-editor.tsx (2 hunks)
  • space/core/components/editor/rich-text-editor.tsx (2 hunks)
  • space/core/components/editor/rich-text-read-only-editor.tsx (2 hunks)
  • space/core/store/mentions.store.ts (0 hunks)
  • space/core/store/root.store.ts (0 hunks)
  • space/ee/components/editor/index.ts (1 hunks)
  • web/ce/components/editor/embeds/index.ts (1 hunks)
  • web/ce/components/editor/embeds/mentions/index.ts (1 hunks)
  • web/ce/components/editor/embeds/mentions/root.tsx (1 hunks)
  • web/ce/components/editor/index.ts (1 hunks)
  • web/ce/constants/editor.ts (1 hunks)
  • web/ce/hooks/use-additional-editor-mention.tsx (1 hunks)
  • web/core/components/editor/embeds/index.ts (1 hunks)
  • web/core/components/editor/embeds/mentions/index.ts (1 hunks)
  • web/core/components/editor/embeds/mentions/root.tsx (1 hunks)
  • web/core/components/editor/embeds/mentions/user.tsx (1 hunks)
  • web/core/components/editor/index.ts (1 hunks)
  • web/core/components/editor/lite-text-editor/lite-text-editor.tsx (3 hunks)
  • web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx (2 hunks)
  • web/core/components/editor/rich-text-editor/rich-text-editor.tsx (3 hunks)
  • web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx (2 hunks)
  • web/core/components/pages/editor/editor-body.tsx (4 hunks)
  • web/core/components/pages/version/editor.tsx (2 hunks)
  • web/core/hooks/store/index.ts (0 hunks)
  • web/core/hooks/store/use-mention.ts (0 hunks)
  • web/core/hooks/use-editor-mention.tsx (1 hunks)
  • web/core/services/project/project.service.ts (2 hunks)
  • web/ee/components/editor/index.ts (1 hunks)
  • web/ee/constants/editor.ts (1 hunks)
  • web/ee/hooks/use-additional-editor-mention.tsx (1 hunks)
💤 Files with no reviewable changes (7)
  • web/core/hooks/store/index.ts
  • space/core/store/root.store.ts
  • packages/editor/src/core/types/mention-suggestion.ts
  • space/core/store/mentions.store.ts
  • packages/editor/src/core/extensions/mentions/mentions-list.tsx
  • packages/editor/src/core/extensions/mentions/mentions-without-props.tsx
  • web/core/hooks/store/use-mention.ts
✅ Files skipped from review due to trivial changes (21)
  • web/core/components/editor/index.ts
  • web/core/components/editor/embeds/mentions/index.ts
  • space/ce/components/editor/embeds/mentions/index.ts
  • web/core/components/editor/embeds/index.ts
  • web/ce/components/editor/embeds/index.ts
  • space/ce/components/editor/embeds/index.ts
  • web/ce/components/editor/index.ts
  • space/ce/components/editor/index.ts
  • space/core/components/editor/embeds/mentions/index.ts
  • web/ee/hooks/use-additional-editor-mention.tsx
  • packages/editor/src/core/types/index.ts
  • web/ce/components/editor/embeds/mentions/index.ts
  • web/ee/components/editor/index.ts
  • space/core/components/editor/embeds/index.ts
  • web/ee/constants/editor.ts
  • space/ce/components/editor/embeds/mentions/root.tsx
  • packages/editor/src/core/extensions/mentions/index.ts
  • packages/types/.prettierrc
  • web/ce/components/editor/embeds/mentions/root.tsx
  • packages/editor/src/core/extensions/mentions/types.ts
  • space/ee/components/editor/index.ts
🧰 Additional context used
🪛 Biome (1.9.4)
web/ce/hooks/use-additional-editor-mention.tsx

[error] 14-14: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🔇 Additional comments (54)
space/core/components/editor/index.ts (1)

1-1: LGTM! Let's verify the embeds module.

The addition of the embeds export aligns with the PR's objective to refactor editor mentions.

Let's verify the embeds module and its exports:

✅ Verification successful

Export structure verified and working as expected

The embeds module is properly structured with:

  • A clean export chain: index.ts -> mentions/index.ts -> components
  • Two main components: EditorMentionsRoot and EditorUserMention
  • No naming conflicts with other editor exports
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the embeds module exists and check its exports

# Check if the embeds directory exists
fd --type f "^.*\.(ts|tsx)$" space/core/components/editor/embeds

# Look for exported mention-related components
rg -t ts -t tsx "export.*(?:EditorMentionsRoot|EditorUserMention)" space/core/components/editor/embeds

Length of output: 406


Script:

#!/bin/bash
# Let's check the exports in these files directly
echo "=== Content of embeds/index.ts ==="
cat space/core/components/editor/embeds/index.ts

echo -e "\n=== Content of embeds/mentions/index.ts ==="
cat space/core/components/editor/embeds/mentions/index.ts

echo -e "\n=== Content of embeds/mentions/root.tsx ==="
cat space/core/components/editor/embeds/mentions/root.tsx

echo -e "\n=== Content of embeds/mentions/user.tsx ==="
cat space/core/components/editor/embeds/mentions/user.tsx

# Also check for any potential naming conflicts in other editor exports
echo -e "\n=== Checking for potential naming conflicts ==="
rg -t ts "^export" space/core/components/editor/ --glob '!**/embeds/**'

Length of output: 3506

web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx (2)

2-5: LGTM! Clean import organization

The import structure properly separates core editor functionality from the mentions feature, aligning with the PR's refactoring objectives.


33-35: Implementation aligns with refactoring goals

The new mention handler implementation using EditorMentionsRoot follows a more modular approach, improving code organization.

Let's verify consistent mention handling across different editors:

✅ Verification successful

Let me try a different approach to verify the mention handling implementation.


Mention handling implementation is consistent across editors

The search results confirm that:

  • The EditorMentionsRoot component is consistently used across all editor variants (lite-text, rich-text) in both read-only and editable modes
  • The implementation follows the same pattern using renderComponent: (props) => <EditorMentionsRoot {...props} /> in all instances
  • The mention handling is properly integrated into both web and space applications
  • The types in the editor package properly define the mention handler interface

The new implementation maintains consistency across the codebase and aligns with the modular approach.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent mention handling implementation across editors

# Search for other editor components using EditorMentionsRoot
echo "Checking mention handling implementation across editors..."
rg -l "EditorMentionsRoot" --type typescript

# Verify the mention handler structure
echo "\nVerifying mention handler structure..."
ast-grep --pattern 'mentionHandler = {
  renderComponent: $_
}'

Length of output: 363


Script:

#!/bin/bash
# Search for files containing EditorMentionsRoot
echo "Searching for EditorMentionsRoot usage..."
rg "EditorMentionsRoot"

# Search for mentionHandler implementations
echo -e "\nSearching for mentionHandler implementations..."
rg "mentionHandler" -A 2

# Look for editor-related files
echo -e "\nLooking for editor files..."
fd "editor" --type f

Length of output: 19019

web/core/components/pages/version/editor.tsx (2)

6-6: LGTM! Import changes align with mention handling refactor.

The removal of user-related types and addition of EditorMentionsRoot aligns with the PR's objective of centralizing mention handling logic.

Also applies to: 9-10


100-100: Verify read-only mention rendering.

The mention handling has been simplified by delegating to EditorMentionsRoot. Please ensure that:

  1. Mentions are properly rendered in read-only mode
  2. Existing mentions in version history remain intact
✅ Verification successful

EditorMentionsRoot is properly integrated for read-only rendering

The verification shows that:

  1. EditorMentionsRoot is consistently used across both editable and read-only editors (rich-text-read-only-editor.tsx, lite-text-read-only-editor.tsx)
  2. The component handles mentions through a simple entity-based approach that works identically in both read and write modes
  3. The implementation in web/core/components/pages/version/editor.tsx follows the same pattern as other read-only editors in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for EditorMentionsRoot usage in read-only contexts
ast-grep --pattern 'DocumentReadOnlyEditorWithRef {
  $$$
  mentionHandler={{
    renderComponent: $_
  }}
  $$$
}'

# Check if there are any special handling for read-only mentions
rg -A 5 'EditorMentionsRoot.*read.*only' 

Length of output: 160


Script:

#!/bin/bash
# Let's try a broader search for EditorMentionsRoot implementation and usage
ast-grep --pattern 'const EditorMentionsRoot = $_'

# Search for any read-only related props or handling in EditorMentionsRoot
rg -A 5 'EditorMentionsRoot.*props'

# Check DocumentReadOnlyEditorWithRef implementation
ast-grep --pattern 'const DocumentReadOnlyEditorWithRef = $_'

# Look for any mention-related props in read-only contexts
rg -A 5 'readOnly.*mention|mention.*readOnly'

Length of output: 8173

space/core/components/editor/lite-text-editor.tsx (2)

5-5: LGTM: Clean import organization

The addition of EditorMentionsRoot is properly grouped with related editor components.


48-48: Verify mention functionality and improve type safety

While the simplified mention handler using component composition is a good approach, please ensure:

  1. The removal of previous mention logic (hooks, highlights) doesn't break existing functionality
  2. The props being spread to EditorMentionsRoot are properly typed

Let's verify the component implementation and its usage:

Consider adding explicit type information:

-          renderComponent: (props) => <EditorMentionsRoot {...props} />,
+          renderComponent: (props: EditorMentionsProps) => <EditorMentionsRoot {...props} />,
✅ Verification successful

Let me gather more information about the types and implementation details.


Based on the results, I can now provide the final response:

Mention functionality is properly typed and implemented

The changes are safe because:

  • EditorMentionsRoot is properly typed with TMentionComponentProps
  • The component has a clean implementation that handles both user mentions and additional mentions
  • The props type is well-defined in the editor package as Pick<TMentionSuggestion, "entity_identifier" | "entity_name">

The suggestion to add explicit type annotation is unnecessary since the types are already properly inferred from the renderComponent prop type in TReadOnlyMentionHandler.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check EditorMentionsRoot implementation and its usage
echo "Checking EditorMentionsRoot implementation:"
ast-grep --pattern 'export const EditorMentionsRoot = $_'

echo "\nChecking other usages of EditorMentionsRoot:"
rg "EditorMentionsRoot" -A 3

echo "\nChecking removed mention-related code:"
git log -S "useMention" --patch

Length of output: 9731


Script:

#!/bin/bash
# Check TMentionComponentProps type definition
echo "Checking TMentionComponentProps type definition:"
rg "type TMentionComponentProps" -A 5

# Check implementation of EditorMentionsRoot
echo "\nChecking EditorMentionsRoot implementation details:"
rg -A 15 "export const EditorMentionsRoot"

# Check for any mention-related hooks that might have been removed
echo "\nChecking for mention hooks:"
rg "useMention" --type ts --type tsx

Length of output: 2615

space/core/components/editor/lite-text-read-only-editor.tsx (2)

4-5: LGTM: Clean import organization

The addition of EditorMentionsRoot import is well-organized and aligns with the mention refactoring objectives.


25-27: Clean implementation of mentionHandler

The new implementation using EditorMentionsRoot is concise and follows good practices by properly spreading props.

Let's verify consistent usage across other editor components:

✅ Verification successful

EditorMentionsRoot implementation is consistent across editor components

The verification shows that the mentionHandler implementation using EditorMentionsRoot is consistently used across all read-only editor components in the codebase:

  • space/core/components/editor/lite-text-read-only-editor.tsx
  • space/core/components/editor/rich-text-read-only-editor.tsx
  • web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx
  • web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx

All these components use the same pattern:

mentionHandler={{
  renderComponent: (props) => <EditorMentionsRoot {...props} />,
}}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent EditorMentionsRoot usage across editor components
# Expected: All editor components should use similar mentionHandler implementation

# Search for mentionHandler implementations
rg -A 3 'mentionHandler[=:]' --type typescript

# Search for EditorMentionsRoot usage
ast-grep --pattern 'renderComponent: $_props => <EditorMentionsRoot {...$_props} />'

Length of output: 170


Script:

#!/bin/bash
# Let's try different approaches to find mentionHandler and EditorMentionsRoot usage

# Search for mentionHandler with .tsx extension
rg -A 3 'mentionHandler[=:]' --type tsx

# Search for EditorMentionsRoot imports and usage
rg 'EditorMentionsRoot' --type tsx

# Find all editor-related files to analyze the component usage pattern
fd -e tsx editor

Length of output: 1789


Script:

#!/bin/bash
# Let's try with explicit file extensions and content search

# Search for mentionHandler in all editor files
for file in $(fd -e tsx editor); do
  echo "=== $file ==="
  grep -A 3 "mentionHandler" "$file" 2>/dev/null
done

# Search for EditorMentionsRoot in all editor files
for file in $(fd -e tsx editor); do
  echo "=== $file ==="
  grep "EditorMentionsRoot" "$file" 2>/dev/null
done

Length of output: 19306

space/core/components/editor/rich-text-editor.tsx (3)

3-5: Verify EditorMentionsRoot implementation

The switch from IMentionHighlight to EditorMentionsRoot represents a significant architectural change in how mentions are handled. Let's ensure the new component is properly implemented.

✅ Verification successful

EditorMentionsRoot implementation verified and properly used

The switch from IMentionHighlight to EditorMentionsRoot is a valid architectural change. The component is:

  • Properly implemented in components/editor/embeds/mentions/root.tsx as a React functional component
  • Handles mention rendering through a type-switch pattern for different entity types (e.g., user mentions)
  • Consistently imported and used across multiple editor components in both web and space packages
  • Part of a unified mentions handling approach across different editor variants (rich text, lite text, read-only)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify EditorMentionsRoot implementation and its usage
# Expected: EditorMentionsRoot should handle mention rendering and interactions

# Check EditorMentionsRoot implementation
ast-grep --pattern 'export const EditorMentionsRoot = $_'

# Check for any existing tests
fd -e test.tsx -e spec.tsx -e test.ts -e spec.ts | grep -i "editormentions"

Length of output: 135


Script:

#!/bin/bash
# Let's try a broader search to locate the EditorMentionsRoot component
# First, search for the file containing EditorMentionsRoot
rg -l "EditorMentionsRoot"

# Then, let's look for any exports containing EditorMentionsRoot
rg "export.*EditorMentionsRoot" -A 5

# Also search for any imports of EditorMentionsRoot to understand its usage
rg "import.*EditorMentionsRoot"

# Check the components directory structure
fd -t f . components/editor/

Length of output: 3277


19-21: ⚠️ Potential issue

Breaking Change: mentionHandler interface has been modified

The mentionHandler interface has changed from using highlights/suggestions to renderComponent. This is a breaking change that could affect existing implementations.


20-20: Verify EditorMentionsRoot props

The component spreads all props directly to EditorMentionsRoot. We should verify the prop types for type safety.

✅ Verification successful

Based on the search results, I can now generate the final response since we have found the type definitions. The TMentionComponentProps type is defined in the @plane/editor package and is properly typed with entity_identifier and entity_name properties, which are being correctly passed through the spread operator. Here's my final response:

Props are properly typed and safe to spread

The EditorMentionsRoot component is properly typed with TMentionComponentProps from @plane/editor, which includes only the essential props (entity_identifier and entity_name). The spread operator usage is safe here as it's passing through a well-defined interface.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check EditorMentionsRoot prop types
# Expected: Props should match what's being passed from mentionHandler

# Find EditorMentionsRoot prop interface
ast-grep --pattern 'interface $_ {
  $$$
}'  | grep -A 10 "EditorMentions"

Length of output: 73


Script:

#!/bin/bash
# Let's try different approaches to find EditorMentionsRoot component and its type definitions

# Search for EditorMentionsRoot in TypeScript/TSX files
rg "EditorMentionsRoot" -t typescript -t tsx -A 5 -B 5

# Also search for type/interface definitions specifically
rg "type.*EditorMentions|interface.*EditorMentions" -t typescript -t tsx

Length of output: 199


Script:

#!/bin/bash
# Let's try without file type filters since they're not recognized
# First find the file containing EditorMentionsRoot
fd -e tsx -e ts | xargs rg "EditorMentionsRoot" -l

# Then get the content around EditorMentionsRoot usage and definition
rg "EditorMentionsRoot" -A 5 -B 5

Length of output: 24463


Script:

#!/bin/bash
# Let's check the type definition of TMentionComponentProps and related types
rg "type.*TMentionComponentProps|interface.*TMentionComponentProps" -A 5

# Also check for any imports from @plane/editor that might contain the type definitions
rg "from.*@plane/editor.*" -A 1

Length of output: 14794

space/core/components/editor/rich-text-read-only-editor.tsx (2)

4-5: LGTM: Import aligns with mention refactoring

The addition of EditorMentionsRoot import supports the new component-based approach for handling mentions.


25-27: Verify EditorMentionsRoot integration

The new mention handling implementation looks good, but let's verify that EditorMentionsRoot receives all necessary props for existing functionality.

✅ Verification successful

Let me gather more information about the MentionComponentProps type to ensure all necessary props are being passed correctly.


Let me check the TMentionSuggestion type since TMentionComponentProps is derived from it.


EditorMentionsRoot integration is properly implemented

The implementation is correct and complete. The verification shows that:

  • TMentionComponentProps correctly picks the required props (entity_identifier and entity_name) from TMentionSuggestion
  • These props are properly spread to EditorMentionsRoot in all editor variants
  • EditorMentionsRoot correctly destructures and uses these props to render the appropriate mention component
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check EditorMentionsRoot props and usage
# Look for EditorMentionsRoot prop definitions and other usages

# Check component props
ast-grep --pattern 'interface $PROPS {
  $$$
}

export const EditorMentionsRoot = ($props: $PROPS)'

# Check other usages for consistency
rg -A 3 'EditorMentionsRoot.*props'

Length of output: 5258


Script:

#!/bin/bash
# Check the TMentionComponentProps type definition
ast-grep --pattern 'type TMentionComponentProps = {
  $$$
}'

# Also check for interface definition
ast-grep --pattern 'interface TMentionComponentProps {
  $$$
}'

# Look for any imports of TMentionComponentProps
rg 'TMentionComponentProps'

Length of output: 1393


Script:

#!/bin/bash
# Check TMentionSuggestion type definition
ast-grep --pattern 'type TMentionSuggestion = {
  $$$
}'

# Also check interface definition
ast-grep --pattern 'interface TMentionSuggestion {
  $$$
}'

# Look at the implementation to see how these props are used
rg -A 5 'entity_identifier.*entity_name' 'space/core/components/editor/embeds/mentions/root.tsx'

Length of output: 922

packages/editor/src/core/extensions/mentions/extension.tsx (3)

11-13: Refactored Extension Enhances Modularity

Renaming to CustomMentionExtension and restructuring to accept props improves modularity and configurability of the mentions extension. This enhances the extension's flexibility and reusability.


14-20: Proper Extension of Parent Options and Inclusion of Render Component

The addOptions method correctly extends parent options using ...this.parent?.() and includes the renderComponent, ensuring that custom rendering capabilities are integrated seamlessly.


26-28: Suggestion Render Function Configured Appropriately

The suggestion render function is properly configured using renderMentionsDropdown with the provided searchCallback, which should ensure accurate mention suggestions within the editor.

web/core/hooks/use-editor-mention.tsx (1)

23-78: Efficient Implementation of useEditorMention Hook

The useEditorMention hook is well-implemented. The use of useCallback for fetchMentions optimizes performance by memoizing the function, and the integration with ProjectService and useAdditionalEditorMention effectively manages mention suggestions.

packages/editor/src/core/extensions/slash-commands/command-menu.tsx (1)

91-108: Efficient Keyboard Event Handling with useImperativeHandle

The use of useImperativeHandle to expose the onKeyDown handler is a good approach for managing keyboard interactions from parent components. This enhances the component's reusability and control over keyboard navigation.

packages/editor/src/core/extensions/mentions/mentions-list-dropdown.tsx (1)

1-162: Well-implemented MentionsListDropdown component

The component is well-structured and follows React best practices. State management with hooks like useState, useEffect, and useCallback is effectively utilized. The keyboard navigation and item selection logic are clean and efficient.

web/ce/constants/editor.ts (1)

1-4: Correct addition of EDITOR_MENTION_TYPES constant

The EDITOR_MENTION_TYPES constant is properly defined and typed, enhancing clarity and maintainability.

apiserver/plane/app/urls/search.py (1)

18-22: LGTM! Verify endpoint integration

The new search endpoint URL pattern follows consistent naming and hierarchy conventions.

Let's verify the endpoint integration:

✅ Verification successful

URL pattern properly integrated and endpoint implementation verified

The search endpoint is correctly integrated with:

  • Proper view implementation in apiserver/plane/app/views/search/base.py
  • No conflicting URL patterns in the URL configuration
  • Consistent URL hierarchy following RESTful conventions
  • Complete search functionality for multiple entity types (users, projects, issues, cycles, modules, pages)
  • Proper access control checks through project membership
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any conflicting URL patterns and verify the view is properly imported
rg -A 1 "path\(['\"]workspaces/<str:slug>/projects/<uuid:project_id>/search" 

Length of output: 80


Script:

#!/bin/bash
# Let's try a broader search to verify the endpoint integration

# Check for SearchEndpoint view definition and imports
rg -l "class SearchEndpoint"

# Check URL patterns with broader context
rg -B 2 -A 2 "search" apiserver/plane/app/urls/

# Check imports in the search.py file
cat apiserver/plane/app/urls/search.py

Length of output: 2475


Script:

#!/bin/bash
# Let's verify the SearchEndpoint view implementation
cat apiserver/plane/app/views/search/base.py

# Check if there are any other similar search endpoints to ensure no conflicts
rg -l "class.*SearchEndpoint" apiserver/plane/app/views/

Length of output: 15929

space/core/components/editor/embeds/mentions/root.tsx (1)

1-17: ⚠️ Potential issue

Consolidate duplicate MentionsRoot implementation

This is an exact duplicate of the implementation in web/core. To improve maintainability:

  1. Extract this component to a shared location
  2. Update imports in both web and space packages

Let's verify all current usages to ensure safe refactoring:

packages/editor/src/core/types/mention.ts (1)

4-11: LGTM! Well-structured mention suggestion type.

The TMentionSuggestion type provides a comprehensive structure for mention suggestions with all necessary fields.

packages/editor/src/core/extensions/mentions/mention-node-view.tsx (1)

7-11: LGTM! Well-typed props definition.

The Props type correctly extends NodeViewProps and properly types the node attributes.

packages/types/src/index.d.ts (1)

31-31: LGTM! Verify search types usage.

The addition of search types export aligns with the PR objectives for implementing the new search endpoint.

✅ Verification successful

The previous command may have failed because the import path alias "@/types" might not be the actual import path. Let's verify the actual exports and their usage patterns in the codebase.


Export of search types is appropriate and well-defined

The search types are properly defined in packages/types/src/search.d.ts with comprehensive type definitions for search functionality including:

  • Clear entity type definitions (TSearchEntities)
  • Well-structured response types for different entities (users, projects, issues, cycles, modules, pages)
  • Proper type inheritance from existing entity interfaces
  • Complete search response type (TSearchResponse)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify the usage of search types across the codebase
ast-grep --pattern 'import { $_ } from "@/types"' | grep -B 2 -A 2 'search'

Length of output: 75


Script:

#!/bin/bash
# Let's first check what's in the search types file
cat packages/types/src/search.ts

# Also check for any imports using relative paths
rg -g '*.{ts,tsx,js,jsx}' 'from.*["\'].*search["\']' -B 2 -A 2

# And check for potential type usage with ast-grep
ast-grep --pattern 'import { $_ } from "@coderabbit/types"'

Length of output: 212


Script:

#!/bin/bash
# Let's check if the file exists with .d.ts extension since it's a type definition
cat packages/types/src/search.d.ts

# Search for any files containing 'search' in the types directory
fd . packages/types/src --type f

# Look for any imports of search types across the codebase
rg -g '*.{ts,tsx,js,jsx}' -i 'from.*["\'].*/(types|search)["\']'

Length of output: 4759

packages/editor/src/core/types/collaboration.ts (2)

39-39: Ensure consistent implementation of mention handlers.

The clear separation between TMentionHandler and TReadOnlyMentionHandler improves type safety, but requires verification of correct implementation across all editor variants.

Also applies to: 47-47

✅ Verification successful

Consistent implementation of mention handlers verified

The codebase shows a clear and consistent implementation pattern:

  • TMentionHandler is correctly used in editable components and hooks (editor.ts, use-editor.ts, extensions.tsx)
  • TReadOnlyMentionHandler is properly used in read-only variants (read-only-editor.tsx, use-read-only-editor.ts, read-only-extensions.tsx)
  • The type hierarchy is well-defined with TMentionHandler extending TReadOnlyMentionHandler with additional search capabilities
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify correct handler type usage in editor components
ast-grep --pattern 'class $_ implements $_ {
  $$$
  mentionHandler: $_
  $$$
}'

Length of output: 82


Script:

#!/bin/bash
# Search for mentionHandler type declarations and usages
rg "mentionHandler.*:" -A 2

# Search for TMentionHandler and TReadOnlyMentionHandler definitions and usages
rg "T(ReadOnly)?MentionHandler" -A 2

Length of output: 9506


11-12: Verify the impact of mention handler type changes.

The shift from highlight/suggestion based types to component-based handler types represents a significant architectural change.

✅ Verification successful

Type changes have been properly implemented across the codebase

Based on the verification results:

  1. The old types (IMentionHighlight and IMentionSuggestion) have been completely removed with no remaining references.
  2. The new types (TMentionHandler and TReadOnlyMentionHandler) are consistently used across all relevant interfaces and components.
  3. All editor-related components and interfaces have been updated to use the new mention handler types, maintaining type safety.
  4. The changes follow a clear separation between read-only and editable mention handlers, as evidenced by their usage in respective components.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any remaining uses of old mention types
rg "IMentionHighlight|IMentionSuggestion" --type ts

# Verify all editor components have been updated to use new types
ast-grep --pattern 'mentionHandler: $_MentionHandler'

Length of output: 109


Script:

#!/bin/bash
# Search for any files importing or using mention-related types
rg "import.*Mention" --type ts -A 3

# Search for mentionHandler property usage in interfaces and types
ast-grep --pattern 'interface $_ {
  $$$
  mentionHandler$_
  $$$
}'

# Search for mentionHandler property usage in component props
ast-grep --pattern 'type $_ = {
  $$$
  mentionHandler$_
  $$$
}'

Length of output: 14446


Script:

#!/bin/bash
# Search for interfaces and types with mentionHandler property
rg "mentionHandler.*:" --type ts -B 2 -A 2

# Search for old type references in type definitions
rg "type.*=.*Mention" --type ts -B 2 -A 2

# Search for any mention-related props in components
ast-grep --pattern 'mentionHandler={$_}'

Length of output: 5090

web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx (2)

34-34: Confirm consistent mention rendering implementation.

The mentionHandler implementation using renderComponent aligns with the new architecture. However, we should verify this pattern across all editor variants.

✅ Verification successful

The previous pattern might have been too specific. Let's try these alternative approaches to find mention rendering implementations across editor variants.


Mention rendering implementation is consistent across all editor variants

The verification shows that all editor variants consistently use EditorMentionsRoot component with the same rendering pattern:

  • rich-text-editor
  • rich-text-read-only-editor
  • lite-text-editor
  • lite-text-read-only-editor
  • version editor
  • editor-body

Each implementation follows the same pattern of renderComponent: (props) => <EditorMentionsRoot {...props} /> for the mentionHandler prop.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent mention handler implementation
ast-grep --pattern 'mentionHandler={{
  renderComponent: $_
}}'

Length of output: 65


Script:

#!/bin/bash
# Let's try a different pattern to search for mention rendering implementations
ast-grep --pattern 'renderComponent: ($$$) => <EditorMentionsRoot'

# Also search for any EditorMentionsRoot usage
rg "EditorMentionsRoot" -A 2

# And search for mentionHandler prop usage
rg "mentionHandler" -A 2

Length of output: 20458


4-5: Verify EditorMentionsRoot component implementation.

The addition of EditorMentionsRoot component import supports the new component-based mention rendering approach.

✅ Verification successful

EditorMentionsRoot component implementation is properly structured and functional

The component is correctly implemented as a router for different types of mentions:

  • It handles user mentions through EditorUserMention component
  • Falls back to EditorAdditionalMentionsRoot for other mention types
  • Properly accepts and forwards the required TMentionComponentProps from the editor
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify EditorMentionsRoot component implementation
ast-grep --pattern 'export const EditorMentionsRoot = $_ => {
  $$$
}'

Length of output: 72


Script:

#!/bin/bash
# Let's try different approaches to locate EditorMentionsRoot component

# Search for EditorMentionsRoot in all files
rg "EditorMentionsRoot" -A 5

# Find files that might contain the component
fd "editor-mentions-root" --type f

# Look for exports containing EditorMentionsRoot
ast-grep --pattern 'export { $$ EditorMentionsRoot $$ }'

# Check barrel files for re-exports
fd "index.ts" --type f --exec rg "EditorMentionsRoot" {}

Length of output: 14007


Script:

#!/bin/bash
# Let's examine the EditorMentionsRoot component implementation and its dependencies
cat web/core/components/editor/embeds/mentions/root.tsx

# Also check for the user mention component it renders
ast-grep --pattern 'const EditorUserMention = $_ => {
  $$$
}'

Length of output: 682

packages/editor/src/core/helpers/tippy.ts (1)

28-28: Verify the default index behavior

When there are no sections, returning { section: 0, item: 0 } might lead to undefined behavior since we're trying to access an empty array.

Consider throwing an error or returning undefined instead:

-  if (!sections.length) return { section: 0, item: 0 };
+  if (!sections.length) return undefined;
packages/editor/src/core/components/editors/editor-wrapper.tsx (1)

1-1: Verify type compatibility with existing extensions

The change from Extension<any, any>[] to Extensions type might affect existing extension implementations.

Also applies to: 15-15

✅ Verification successful

Type change from Extension to Extensions is safe to use

The change from Extension<any, any>[] to Extensions type is a safe refactor as:

  1. Extensions is the official type from @tiptap/core used consistently throughout the codebase
  2. The file only changes the type in the Props interface, which is locally scoped
  3. All extension implementations in the codebase already follow the pattern compatible with the Extensions type
  4. The change aligns with the type usage in other editor components and hooks (useEditor, useReadOnlyEditor, etc.)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any custom extensions that might be affected by the type change
rg "extends Extension" --type typescript

Length of output: 77


Script:

#!/bin/bash
# Search for any custom extensions or Extension type usage
rg "Extension[<\s]|extends Extension" -t ts -t tsx

# Also search for Extensions type usage to understand the impact
rg "Extensions[<\s]|type.*Extensions" -t ts -t tsx

Length of output: 161


Script:

#!/bin/bash
# Search for Extension and Extensions usage without file type flags
rg "Extension[<\s]|extends Extension"

# Also check for Props interface that uses these types
rg "interface.*Props.*Extension"

Length of output: 5407


Script:

#!/bin/bash
# Let's check the specific file for the type change and its usage
cat packages/editor/src/core/components/editors/editor-wrapper.tsx

# Also check the Extensions type usage in the codebase
rg -B2 -A2 "Extensions(\s|[<>])" 

Length of output: 16304

web/core/components/editor/rich-text-editor/rich-text-editor.tsx (1)

52-52: Verify EditorMentionsRoot props type safety

Ensure that all required props are properly typed and passed to EditorMentionsRoot component.

✅ Verification successful

Props are properly typed and safely passed to EditorMentionsRoot component

The verification shows that:

  1. EditorMentionsRoot component is properly typed with TMentionComponentProps from @plane/editor
  2. TMentionComponentProps is well-defined with required props: entity_identifier and entity_name
  3. The component correctly handles these props and renders appropriate components based on the entity_name
  4. Props spreading in the parent components is type-safe as it's using the same interface
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for EditorMentionsRoot component definition and its props
rg "EditorMentionsRoot" --type typescript -A 10

Length of output: 82


Script:

#!/bin/bash
# Search for EditorMentionsRoot component definition and its props using ripgrep without file type filter
rg "EditorMentionsRoot" -A 10

Length of output: 23315


Script:

#!/bin/bash
# Search for TMentionComponentProps type definition
rg "TMentionComponentProps" -A 5

# Search for EditorAdditionalMentionsRoot component
rg "EditorAdditionalMentionsRoot" -A 5

Length of output: 5541

packages/types/src/search.d.ts (1)

9-9: LGTM! Well-defined search entity types.

The TSearchEntities type clearly defines all searchable entities, aligning with the PR's objectives for mentions functionality.

packages/editor/src/core/extensions/mentions/utils.ts (1)

14-15: Address TypeScript type issues.

Multiple @ts-expect-error comments indicate type mismatches with Tiptap and Tippy. Consider:

  1. Opening issues in respective repositories
  2. Creating local type declarations to bridge the gaps

Let's check if these issues are already reported:

Also applies to: 32-33

✅ Verification successful

Let me check the specific type issues in the codebase to provide a more accurate assessment.


Let me check the imports and type definitions to better understand the context.


Let me check the specific implementation to understand the type issues better.


Let me check the actual implementation of the suggestion options type to understand the mismatch.


Based on the code analysis, I can now provide a final response:

Type suppression is valid in this case

The @ts-expect-error comments are addressing known type mismatches between Tiptap's type definitions and their actual implementation:

  1. The first suppression is for the render function's signature mismatch with Tiptap's SuggestionOptions["render"] type
  2. The second suppression is for Tippy.js's incomplete type definitions for its instance methods

These are external dependency type issues that can't be fixed locally. The suppressions are well-documented and necessary until the upstream libraries fix their type definitions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related issues in Tiptap and Tippy.js repositories
gh issue list -R ueberdosis/tiptap -S "typescript suggestion types" --json number,title,state
gh issue list -R atomiks/tippyjs -S "typescript types incorrect" --json number,title,state

Length of output: 400


Script:

#!/bin/bash
# Search for ts-expect-error comments and their context
rg "@ts-expect-error" packages/editor/src/core/extensions/mentions/ -B 2 -A 2

# Search for type-related imports from tiptap
rg "from '@tiptap" packages/editor/src/core/extensions/mentions/utils.ts -B 1 -A 1

Length of output: 1130


Script:

#!/bin/bash
# Check imports and type definitions
rg "import.*from.*tiptap" packages/editor/src/core/extensions/mentions/utils.ts
rg "type.*from.*tiptap" packages/editor/src/core/extensions/mentions/utils.ts

# Check the interface/type definitions
ast-grep --pattern 'type $_ = $_'
ast-grep --pattern 'interface $_ $_'

# Check how TMentionHandler is defined
rg "TMentionHandler" packages/editor/src/core/extensions/mentions/ -A 3

Length of output: 65972


Script:

#!/bin/bash
# Check the implementation where ts-expect-error is used
rg -B 5 -A 5 "@ts-expect-error" packages/editor/src/core/extensions/mentions/utils.ts

# Check the related Tiptap types
rg "SuggestionOptions" packages/editor/src/core/extensions/mentions/utils.ts -B 2 -A 2

Length of output: 1444


Script:

#!/bin/bash
# Check the SuggestionOptions type definition
ast-grep --pattern 'interface SuggestionOptions {
  $$$
}'

# Check how the render function is used in other places
rg "SuggestionOptions.*render" -A 5

Length of output: 734

packages/editor/src/core/components/editors/document/read-only-editor.tsx (1)

13-13: LGTM! Clean type transition for mention handler.

The change from the specific mention handler interface to TReadOnlyMentionHandler improves type consistency across the codebase while maintaining clear component contracts.

Also applies to: 26-26

packages/editor/src/core/extensions/core-without-props.ts (2)

16-16: LGTM! Import change aligns with mention refactoring.

The switch from CustomMentionWithoutProps to CustomMentionExtensionConfig reflects the architectural shift in handling mentions.


Line range hint 100-104: Verify extension configuration changes.

The removal of function invocation syntax suggests a change in how the mention extension is configured. Please ensure all consumers of this extension are updated accordingly.

✅ Verification successful

No breaking changes in mention extension configuration

The verification shows that CustomMentionWithoutProps is not used anywhere in the codebase, and the new CustomMentionExtensionConfig is properly defined in extension-config.ts and consistently used across the codebase. The change appears to be part of a clean implementation rather than a breaking change, as there are no remnants of old configuration patterns that need updating.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining usage of old CustomMentionWithoutProps
rg "CustomMentionWithoutProps" --type ts --type tsx

# Search for usage of new CustomMentionExtensionConfig
rg "CustomMentionExtensionConfig" --type ts --type tsx

Length of output: 162


Script:

#!/bin/bash
# Search for any remaining usage of old CustomMentionWithoutProps
rg "CustomMentionWithoutProps"

# Search for usage of new CustomMentionExtensionConfig
rg "CustomMentionExtensionConfig"

# Search for any mention-related configuration patterns
rg -A 3 "mention.*config" -i

Length of output: 3140

packages/editor/src/core/extensions/slash-commands/root.tsx (2)

5-6: LGTM: Type safety improvement with CommandListInstance

Good move extracting the CommandListInstance type to a separate helper file, improving type organization and reusability.


Line range hint 65-69: Verify the editor prop usage in ReactRenderer

The ReactRenderer instantiation now includes an additional editor prop. Ensure this prop is properly utilized in the SlashCommandsMenu component.

✅ Verification successful

The editor prop is properly defined and used in the SlashCommandsMenu component

The verification shows that:

  • The SlashCommandsMenuProps interface explicitly includes editor: Editor as a prop
  • The component is defined with these props and receives them via forwardRef
  • The ReactRenderer instantiation correctly passes the editor prop
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if SlashCommandsMenu uses the editor prop
ast-grep --pattern 'interface SlashCommandsMenuProps {
  $$$
  editor: $_
  $$$
}'

Length of output: 84


Script:

#!/bin/bash
# Let's try to find the SlashCommandsMenu component and its props definition
rg -A 5 "SlashCommandsMenu.*Props" --type typescript

# Also search for the component definition
ast-grep --pattern 'const SlashCommandsMenu = ({ $$$, editor, $$$ }: $_) => {
  $$$
}'

# And check the ReactRenderer implementation
rg -A 5 "class ReactRenderer" --type typescript

Length of output: 263


Script:

#!/bin/bash
# Let's try without typescript file type specification
rg -A 5 "SlashCommandsMenu.*Props"

# Search for the component definition
rg -A 5 "const SlashCommandsMenu"

# Check ReactRenderer implementation
rg -A 5 "class ReactRenderer"

Length of output: 3437

web/core/components/editor/lite-text-editor/lite-text-editor.tsx (1)

48-52: LGTM: Improved mention handling with dedicated hook

Good refactoring to use a dedicated useEditorMention hook with proper type safety for projectId and workspaceSlug.

packages/editor/src/core/extensions/read-only-extensions.tsx (2)

22-22: LGTM: Consistent mention handling across extensions

Good improvements:

  1. Consistent naming with CustomMentionExtension
  2. Strong typing with TReadOnlyMentionHandler
  3. Simplified Props interface

Also applies to: 32-32, 39-39


134-134: Verify mention handler integration

Ensure the CustomMentionExtension properly handles the mentionHandler configuration.

✅ Verification successful

Let me verify the CustomMentionExtensionConfig implementation to ensure it properly supports the mentionHandler properties.


Let me check the type definitions and the mention handler interface.


Let me check the TReadOnlyMentionHandler type to complete the verification.


CustomMentionExtension properly integrates mentionHandler

The implementation correctly handles both required components of TMentionHandler:

  • The renderComponent prop is properly passed through the extension options and used in MentionNodeView
  • The searchCallback is correctly utilized in the mentions dropdown configuration
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check CustomMentionExtension implementation
ast-grep --pattern 'export const CustomMentionExtension = ($_) => {
  $$$
}'

Length of output: 1860


Script:

#!/bin/bash
# Check CustomMentionExtensionConfig implementation
ast-grep --pattern 'export const CustomMentionExtensionConfig = $_'

# Check TMentionHandler type definition
ast-grep --pattern 'type TMentionHandler = {
  $$$
}'

Length of output: 4517


Script:

#!/bin/bash
# Search for TMentionHandler interface/type definition
rg "type TMentionHandler" -A 5

# Check renderMentionsDropdown implementation
ast-grep --pattern 'const renderMentionsDropdown = ($_) => {
  $$$
}'

Length of output: 357


Script:

#!/bin/bash
# Check TReadOnlyMentionHandler definition
rg "type TReadOnlyMentionHandler" -A 5

# Check renderComponent usage in MentionNodeView
ast-grep --pattern 'const MentionNodeView = ($_) => {
  $$$
}'

Length of output: 2052

packages/editor/src/core/hooks/use-read-only-editor.ts (2)

4-4: Type safety improvements look good!

The changes enhance type safety by:

  • Replacing any with Extensions type for better type checking
  • Using TReadOnlyMentionHandler for mentions handling

Also applies to: 19-19, 26-26, 31-31


64-64: Verify mentionHandler integration

The mentionHandler is now passed directly to CoreReadOnlyEditorExtensions. Let's verify its usage across the codebase.

✅ Verification successful

Let me check how mentionHandler is used within the CoreReadOnlyEditorExtensions to verify its integration.


Let me check the implementation of CustomMentionExtension to verify how it uses the mentionHandler.


Let me check the implementation details of the CustomMentionExtension in the mentions/extension.tsx file.


mentionHandler integration is properly implemented

The verification shows that mentionHandler is correctly integrated:

  • It's properly passed from use-read-only-editor to CoreReadOnlyEditorExtensions
  • CoreReadOnlyEditorExtensions correctly forwards it to CustomMentionExtension
  • CustomMentionExtension properly utilizes the mentionHandler props (searchCallback and renderComponent) in its implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CoreReadOnlyEditorExtensions usage to verify mentionHandler integration
rg -A 3 "CoreReadOnlyEditorExtensions" 

Length of output: 1192


Script:

#!/bin/bash
# Search for mentionHandler usage within CoreReadOnlyEditorExtensions
ast-grep --pattern 'mentionHandler'

Length of output: 243


Script:

#!/bin/bash
# Search for CustomMentionExtension implementation
ast-grep --pattern 'CustomMentionExtension'

Length of output: 551


Script:

#!/bin/bash
# Get the implementation of CustomMentionExtension
cat packages/editor/src/core/extensions/mentions/extension.tsx

Length of output: 866

packages/editor/src/core/extensions/extensions.tsx (2)

21-21: Good architectural improvements!

The changes improve the codebase by:

  • Using consistent naming with CustomMentionExtension
  • Consolidating mention handling into a single handler
  • Using proper TypeScript types

Also applies to: 36-36, 44-44


144-144: Verify mention extension initialization

The mention extension is now initialized with a single handler. Let's verify its implementation.

✅ Verification successful

Let me gather more information about the mention extension configuration and its dependencies.


Let me check one final piece to verify the mention handler type and interface.


Mention extension implementation is properly configured

The mention extension is correctly initialized with the required handler. The implementation shows:

  • Proper extension configuration with required attributes and storage
  • Correct rendering setup with both node view and dropdown components
  • Expected handler interface with searchCallback for mention suggestions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CustomMentionExtension implementation
ast-grep --pattern 'export const CustomMentionExtension = ($_) => {
  $$$
}'

Length of output: 1860


Script:

#!/bin/bash
# Search for CustomMentionExtensionConfig implementation
ast-grep --pattern 'export const CustomMentionExtensionConfig = $_'

# Search for MentionNodeView implementation
ast-grep --pattern 'export const MentionNodeView = $_'

# Search for renderMentionsDropdown implementation
ast-grep --pattern 'export const renderMentionsDropdown = $_'

Length of output: 11116


Script:

#!/bin/bash
# Search for TMentionHandler type definition
rg "type TMentionHandler" -A 5

Length of output: 285

apiserver/plane/app/views/__init__.py (1)

161-161: Verify SearchEndpoint implementation

The SearchEndpoint has been added to imports. Let's verify its implementation and usage.

✅ Verification successful

SearchEndpoint is properly implemented and integrated

The SearchEndpoint is correctly implemented in views/search/base.py and properly integrated into the URL routing at urls/search.py. It's registered at the endpoint /workspaces/<str:slug>/projects/<uuid:project_id>/search/ and handles project-specific search functionality with query parameters for type and count. The implementation aligns with the codebase's search endpoint hierarchy alongside GlobalSearchEndpoint and IssueSearchEndpoint.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for SearchEndpoint implementation and its URL routing
rg -A 5 "class SearchEndpoint"

# Search for URL patterns using SearchEndpoint
rg "path.*SearchEndpoint.*as_view"

Length of output: 656


Script:

#!/bin/bash
# Let's check the URL patterns in urls.py files that might use SearchEndpoint
fd urls.py | xargs rg "SearchEndpoint"

# Let's also check for any references to SearchEndpoint in the codebase
rg "SearchEndpoint" -B 2 -A 2

# Check if there are any tests for SearchEndpoint
fd test | xargs rg "SearchEndpoint"

Length of output: 2792

packages/editor/src/core/types/editor.ts (2)

1-1: LGTM! Improved type imports and organization.

The addition of Extensions from @tiptap/core and the new mention handler types (TMentionHandler, TReadOnlyMentionHandler) improves type organization and maintainability.

Also applies to: 14-15


117-117: Improved type safety for extensions.

The change from any[] to Extensions type provides better type safety and IDE support.

Also applies to: 128-128, 131-131

web/core/components/pages/editor/editor-body.tsx (2)

74-78: LGTM! Clean implementation of editor mentions.

The use of a dedicated hook useEditorMention improves code organization and reusability.


243-243: LGTM! Consistent mention handling.

The read-only editor's mentionHandler implementation is consistent with the editable version.

packages/editor/src/core/hooks/use-editor.ts (2)

6-6: LGTM! Type imports enhance type safety.

The addition of proper type imports (Extensions and TMentionHandler) improves type safety by replacing any types and providing better type definitions for mention handling.

Also applies to: 25-25


91-94: Verify CoreEditorExtensions integration with new TMentionHandler type.

The change looks correct, but let's verify the integration with CoreEditorExtensions.

✅ Verification successful

Based on the comprehensive search results, I can now provide a final response:

CoreEditorExtensions properly integrates with new TMentionHandler type

The verification confirms proper integration:

  • TMentionHandler is correctly defined and used throughout the codebase
  • CoreEditorExtensions correctly passes the mentionHandler to CustomMentionExtension
  • No legacy mention structure (highlights/suggestions) found in the codebase, except for a console error log
  • The type is consistently used across all editor variants (rich text, lite text, read-only)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify CoreEditorExtensions properly handles TMentionHandler

# Check CoreEditorExtensions implementation
ast-grep --pattern 'function CoreEditorExtensions($_) {
  $$$
  mentionHandler: $_
  $$$
}'

# Check for any direct usage of the old mention structure
rg -l 'highlights.*suggestions' --type ts

Length of output: 137


Script:

#!/bin/bash
# Let's try a different approach to verify the integration

# Find files containing CoreEditorExtensions
rg -l "CoreEditorExtensions" --type ts

# Search for mentionHandler usage in the codebase
rg "mentionHandler" -A 5 -B 5 --type ts

# Look for TMentionHandler type definition and usage
rg "TMentionHandler" -A 3 -B 3 --type ts

# Search for any mention-related types and interfaces
ast-grep --pattern 'interface $_ {
  $$$
  mention
  $$$
}'

Length of output: 57587


Script:

#!/bin/bash
# Let's check the CoreEditorExtensions implementation and CustomMentionExtension usage

# Find CoreEditorExtensions implementation
ast-grep --pattern 'export const CoreEditorExtensions = ($_) => {
  $$$
}'

# Check CustomMentionExtension implementation
ast-grep --pattern 'CustomMentionExtension($_)'

# Look for the old mention structure in the codebase
rg "highlights|suggestions" -A 3 -B 3 --type ts

Length of output: 1653

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: 1

🧹 Outside diff range and nitpick comments (4)
apiserver/plane/app/views/search/base.py (4)

284-299: Move avatar URL construction to User model

The avatar URL construction logic should be moved to the User model as a property to maintain DRY principles and ensure consistent URL generation across the application.

Create a property in the User model:

@property
def avatar_url(self):
    if self.avatar_asset:
        return f"/api/assets/v2/static/{self.avatar_asset}/"
    return self.avatar

Then simplify the query:

-    .annotate(
-        member__avatar_url=Case(
-            When(
-                member__avatar_asset__isnull=False,
-                then=Concat(
-                    Value("/api/assets/v2/static/"),
-                    "member__avatar_asset",
-                    Value("/"),
-                ),
-            ),
-            When(
-                member__avatar_asset__isnull=True, then="member__avatar"
-            ),
-            default=Value(None),
-            output_field=models.CharField(),
-        )
-    )
+    .annotate(
+        member__avatar_url=F('member__avatar_url')
+    )

317-318: Replace magic number with a named constant

The network=2 condition should use a named constant for better maintainability and clarity.

Define the constant at the module level:

+# Project visibility constants
+PROJECT_VISIBILITY_PUBLIC = 2
+
 # ... rest of the code ...
-        | Q(network=2),
+        | Q(network=PROJECT_VISIBILITY_PUBLIC),

335-340: Optimize sequence_id parsing logic

The sequence ID parsing could be optimized by compiling the regex pattern once and handling the parsing more efficiently.

Apply this optimization:

+# Compile regex pattern once at module level
+SEQUENCE_ID_PATTERN = re.compile(r"\b\d+\b")
+
 # ... in the method ...
-    sequences = re.findall(r"\b\d+\b", query)
-    for sequence_id in sequences:
-        q |= Q(**{"sequence_id": sequence_id})
+    if sequences := SEQUENCE_ID_PATTERN.findall(query):
+        q |= Q(sequence_id__in=sequences)

275-304: Extract common query patterns

Multiple search implementations share similar patterns for filtering and ordering. Consider extracting these into reusable methods.

Create utility methods:

def _apply_base_filters(self, queryset, slug):
    return queryset.filter(
        project__project_projectmember__member=self.request.user,
        project__project_projectmember__is_active=True,
        workspace__slug=slug,
    )

def _apply_search_filter(self, queryset, query, fields):
    if not query:
        return queryset
    q = Q()
    for field in fields:
        q |= Q(**{f"{field}__icontains": query})
    return queryset.filter(q)

This would simplify each search implementation and reduce code duplication.

Also applies to: 342-362, 373-407, 418-435, 446-460

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 760d415 and 223822b.

📒 Files selected for processing (1)
  • apiserver/plane/app/views/search/base.py (3 hunks)
🔇 Additional comments (2)
apiserver/plane/app/views/search/base.py (2)

5-15: LGTM: Import statements are well-organized and necessary

The new imports are properly categorized and required for the new search functionality.

Also applies to: 35-36


259-259: ⚠️ Potential issue

Add exception handling for count parameter conversion

The count parameter is converted to an integer without exception handling, which may raise a ValueError if an invalid value is provided.

Apply this diff to handle exceptions:

-count = int(request.query_params.get("count", 5))
+try:
+    count = int(request.query_params.get("count", 5))
+except ValueError:
+    return Response({"error": "Invalid 'count' parameter"}, status=status.HTTP_400_BAD_REQUEST)

apiserver/plane/app/views/search/base.py Show resolved Hide resolved
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: 0

🔭 Outside diff range comments (2)
web/core/components/issues/description-input.tsx (2)

Line range hint 89-93: Address the exhaustive-deps warning properly

The TODO comment acknowledges an ESLint warning about missing dependencies. This should be properly addressed rather than suppressed.

Consider refactoring the debounced save functionality to properly handle all dependencies:

- const debouncedFormSave = useCallback(
-   debounce(async () => {
-     handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
-   }, 1500),
-   [handleSubmit, issueId]
- );
+ const debouncedFormSave = useMemo(
+   () =>
+     debounce(async () => {
+       handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted"));
+     }, 1500),
+   [handleSubmit, handleDescriptionFormSubmit, setIsSubmitting]
+ );

Line range hint 127-137: Enhance error handling for file uploads

The current error handling for file uploads only logs the error to console. Consider providing better error feedback to users.

   } catch (error) {
-    console.log("Error in uploading issue asset:", error);
-    throw new Error("Asset upload failed. Please try again later.");
+    console.error("Error uploading issue asset:", error);
+    const errorMessage = error instanceof Error ? error.message : "Asset upload failed";
+    throw new Error(`Failed to upload file: ${errorMessage}. Please try again later.`);
   }
🧹 Nitpick comments (1)
web/core/components/issues/description-input.tsx (1)

Line range hint 36-165: Consider improving component architecture

The component could benefit from better separation of concerns:

  1. Extract file upload logic into a custom hook (e.g., useFileUpload)
  2. Consider splitting the form handling into a separate component
  3. Move the debounced save logic into a custom hook

This would improve maintainability and testability of the code.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 223822b and 48959da.

📒 Files selected for processing (5)
  • packages/editor/package.json (1 hunks)
  • packages/types/src/index.d.ts (1 hunks)
  • web/core/components/editor/rich-text-editor/rich-text-editor.tsx (3 hunks)
  • web/core/components/issues/description-input.tsx (1 hunks)
  • web/core/hooks/use-editor-mention.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/editor/package.json
  • packages/types/src/index.d.ts
  • web/core/components/editor/rich-text-editor/rich-text-editor.tsx
  • web/core/hooks/use-editor-mention.tsx
🔇 Additional comments (2)
web/core/components/issues/description-input.tsx (2)

Line range hint 22-34: LGTM! Props interface is well-defined

The interface provides a comprehensive set of props for handling issue descriptions, including proper TypeScript types and essential operations.


18-18: Verify mention functionality after removing useMember hook

The removal of useMember hook aligns with the PR's objective to refactor the editor mentions extension. However, let's verify that mention functionality is properly handled by the new architecture.

✅ Verification successful

Mention functionality is properly handled by the new architecture

The removal of useMember hook is safe as the codebase has been refactored to use a centralized mention handling system through EditorMentionsRoot. This component is consistently integrated across all editor variants:

  • Rich text editor
  • Lite text editor
  • Read-only editors
  • Page editors

The EditorMentionsRoot component (web/core/components/editor/embeds/mentions/root.tsx) handles user mentions through a dedicated EditorUserMention component, ensuring consistent mention functionality throughout the application.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that mention handling is properly implemented in the new architecture

# Check if RichTextEditor component is using the new mention handling
ast-grep --pattern 'RichTextEditor {
  $$$
  mentionHighlights={$_}
  $$$
}'

# Check for the new EditorMentionsRoot component usage
rg -A 5 "EditorMentionsRoot"

Length of output: 13935

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

🧹 Nitpick comments (2)
web/core/components/pages/editor/header/options-dropdown.tsx (1)

78-82: Add error handling for the parsing function

While integrating replaceCustomComponentsFromMarkdownContent, consider adding error handling to catch any potential exceptions that might occur during the parsing process. This ensures the application remains robust in case of unexpected input or errors.

Apply this diff to include error handling:

            if (!editorRef) return;
            const markdownContent = editorRef.getMarkDown();
+           let parsedMarkdownContent = "";
+           try {
                parsedMarkdownContent = replaceCustomComponentsFromMarkdownContent({
                  markdownContent,
                });
+           } catch (error) {
+             console.error("Error parsing markdown content:", error);
+             setToast({
+               type: TOAST_TYPE.ERROR,
+               title: "Error!",
+               message: "Failed to parse markdown content.",
+             });
+             return;
+           }
web/core/components/pages/modals/export-page-modal.tsx (1)

182-182: Consider improving error logging

Using console.error for error logging is acceptable, but consider implementing a centralized error handling mechanism or using an error tracking service for better monitoring and debugging in production environments.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 48959da and b9940f9.

📒 Files selected for processing (5)
  • packages/editor/src/core/extensions/mentions/extension-config.ts (1 hunks)
  • web/core/components/pages/editor/header/options-dropdown.tsx (3 hunks)
  • web/core/components/pages/modals/export-page-modal.tsx (3 hunks)
  • web/core/hooks/use-parse-editor-content.ts (1 hunks)
  • web/helpers/editor.helper.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/editor/src/core/extensions/mentions/extension-config.ts
🧰 Additional context used
🪛 Biome (1.9.4)
web/core/hooks/use-parse-editor-content.ts

[error] 167-167: The regular expression includes this negated empty character class.

Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.

(lint/correctness/noEmptyCharacterClassInRegex)


[error] 180-180: The regular expression includes this negated empty character class.

Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.

(lint/correctness/noEmptyCharacterClassInRegex)

🔇 Additional comments (4)
web/helpers/editor.helper.ts (1)

Line range hint 1-60: LGTM!

The refactoring correctly removes the parsing functions, and the remaining code is clean and well-structured.

web/core/components/pages/editor/header/options-dropdown.tsx (2)

28-28: LGTM!

The import of useParseEditorContent is correctly added.


64-64: LGTM!

The hook useParseEditorContent is properly utilized to enhance the markdown copy functionality.

web/core/components/pages/modals/export-page-modal.tsx (1)

104-106: LGTM!

The integration of the useParseEditorContent hook properly replaces direct imports, enhancing modularity and code reuse.

web/core/hooks/use-parse-editor-content.ts Show resolved Hide resolved
web/core/hooks/use-parse-editor-content.ts Show resolved Hide resolved
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: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b9940f9 and 1837cc0.

📒 Files selected for processing (2)
  • apiserver/plane/app/urls/search.py (2 hunks)
  • web/core/services/project/project.service.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apiserver/plane/app/urls/search.py
🔇 Additional comments (2)
web/core/services/project/project.service.ts (2)

5-6: LGTM! Type imports are well-organized.

The new type imports follow the existing pattern and are correctly imported from the shared types package.


175-184: Verify error handling consistency across the service.

The error handling follows the service pattern, but let's verify it's consistent with other endpoints and handles all error cases properly.

✅ Verification successful

Error handling is consistent with service patterns

The error handling in the entity-search endpoint follows the predominant pattern across the codebase, where most services use throw error?.response?.data. This is consistent with other endpoints in the project service and aligns with the general error handling approach throughout the application's services.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check error handling consistency across the service

# Check if other methods in the service use the same error handling pattern
rg "throw error\?\.response(\?\.data)?" "web/core/services/project/project.service.ts"

# Look for any error handling variations in similar search endpoints
rg "catch.*error.*throw" "web/core/services/**/*search*.ts"

Length of output: 770


Script:

#!/bin/bash
# Let's check error handling patterns in all service files to get a comprehensive view
rg "\.catch\(\s*\(error\)" "web/core/services/" -A 2

# Also check for any other error handling patterns in the project service
rg "catch.*{" "web/core/services/project/project.service.ts" -A 3

Length of output: 59665

web/core/services/project/project.service.ts Outdated Show resolved Hide resolved
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: 3

♻️ Duplicate comments (2)
web/core/hooks/use-parse-editor-content.ts (1)

189-189: ⚠️ Potential issue

Fix the regular expressions to avoid using negated empty character classes

The regular expressions include negated empty character classes [^]*, which matches any character, potentially leading to unintended matches.

Apply these fixes:

-const imageComponentRegex = /<image-component[^>]*src="([^"]+)"[^>]*>[^]*<\/image-component>/g;
+const imageComponentRegex = /<image-component[^>]*src="([^"]+)"[^>]*>[\s\S]*?<\/image-component>/g;

-const issueEmbedRegex = /<issue-embed-component[^>]*>[^]*<\/issue-embed-component>/g;
+const issueEmbedRegex = /<issue-embed-component[^>]*>[\s\S]*?<\/issue-embed-component>/g;

Also applies to: 202-202

🧰 Tools
🪛 Biome (1.9.4)

[error] 189-189: The regular expression includes this negated empty character class.

Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.

(lint/correctness/noEmptyCharacterClassInRegex)

web/ce/hooks/use-additional-editor-mention.tsx (1)

25-27: ⚠️ Potential issue

Remove empty destructuring and implement the section update logic.

The function currently has an empty destructuring and no implementation, despite receiving typed arguments for response and sections.

 const updateAdditionalSections = useCallback((args: TAdditionalEditorMentionHandlerArgs) => {
-  const {} = args;
+  const { response, sections } = args;
+  // TODO: Implement section update logic using response and sections
 }, []);
🧰 Tools
🪛 Biome (1.9.4)

[error] 26-26: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🧹 Nitpick comments (3)
web/core/hooks/use-parse-editor-content.ts (2)

204-205: Remove or improve performance logging

Performance logging should not be in production code. Consider using performance monitoring tools instead.

-console.log("Exec time:", end - start);
+if (process.env.NODE_ENV === 'development') {
+  console.debug("Editor content parse time:", end - start, "ms");
+}

167-167: Improve origin URL handling

The current origin URL handling could be more robust by providing a fallback.

-const originUrl = typeof window !== "undefined" && (window.location.origin ?? "");
+const originUrl = typeof window !== "undefined" 
+  ? window.location.origin 
+  : process.env.NEXT_PUBLIC_APP_URL ?? "";
web/ce/hooks/use-additional-editor-mention.tsx (1)

17-22: Add JSDoc comments to clarify the return type behavior.

The TAdditionalParseEditorContentReturnType type allows undefined as a return value, but it's not clear under what conditions this occurs. Consider adding documentation to explain the scenarios.

+/**
+ * Return type for parsing editor content
+ * @returns An object with redirectionPath and textContent when the entity is found
+ * @returns undefined when the entity is not found or cannot be parsed
+ */
 export type TAdditionalParseEditorContentReturnType =
   | {
       redirectionPath: string;
       textContent: string;
     }
   | undefined;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3f96129 and 906cc05.

📒 Files selected for processing (2)
  • web/ce/hooks/use-additional-editor-mention.tsx (1 hunks)
  • web/core/hooks/use-parse-editor-content.ts (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
web/ce/hooks/use-additional-editor-mention.tsx

[error] 26-26: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 31-31: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

web/core/hooks/use-parse-editor-content.ts

[error] 189-189: The regular expression includes this negated empty character class.

Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.

(lint/correctness/noEmptyCharacterClassInRegex)


[error] 202-202: The regular expression includes this negated empty character class.

Negated empty character classes match anything.
If you want to match against [, escape it [.
Otherwise, remove the character class or fill it.

(lint/correctness/noEmptyCharacterClassInRegex)

🔇 Additional comments (2)
web/core/hooks/use-parse-editor-content.ts (2)

1-18: LGTM: Hook setup and dependencies are well-structured

The hook follows React conventions and includes all necessary dependencies for the functionality.


211-215: LGTM: Clean and well-structured exports

The hook exports are clean and follow React conventions.

Comment on lines +113 to +128
const imgElements = doc.querySelectorAll("img");
await Promise.all(
Array.from(imgElements).map(async (img) => {
// get the image src from the img element
const src = img.getAttribute("src");
if (src) {
try {
const base64Image = await getBase64Image(src);
img.src = base64Image;
} catch (error) {
// log the error if the image conversion fails
console.error("Failed to convert image to base64:", error);
}
}
})
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add proper error handling and timeout for image conversion

The current implementation has two potential issues:

  1. Failed image conversions are only logged to console, which might lead to silent failures in production
  2. No timeout handling for image conversion, which could cause the function to hang indefinitely

Consider implementing this improvement:

 const imgElements = doc.querySelectorAll("img");
-await Promise.all(
-  Array.from(imgElements).map(async (img) => {
+const timeout = (ms: number) => new Promise((_, reject) => 
+  setTimeout(() => reject(new Error('Timeout')), ms));
+await Promise.all(
+  Array.from(imgElements).map(async (img) => {
     const src = img.getAttribute("src");
     if (src) {
       try {
-        const base64Image = await getBase64Image(src);
+        const base64Image = await Promise.race([
+          getBase64Image(src),
+          timeout(5000) // 5 second timeout
+        ]);
         img.src = base64Image;
       } catch (error) {
-        console.error("Failed to convert image to base64:", error);
+        // Remove the image if conversion fails
+        img.remove();
+        // Log error with context for monitoring
+        console.error("Image conversion failed:", {
+          error,
+          src: src.substring(0, 100), // truncate for logging
+          timestamp: new Date().toISOString()
+        });
       }
     }
   })
 );
📝 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
const imgElements = doc.querySelectorAll("img");
await Promise.all(
Array.from(imgElements).map(async (img) => {
// get the image src from the img element
const src = img.getAttribute("src");
if (src) {
try {
const base64Image = await getBase64Image(src);
img.src = base64Image;
} catch (error) {
// log the error if the image conversion fails
console.error("Failed to convert image to base64:", error);
}
}
})
);
const imgElements = doc.querySelectorAll("img");
const timeout = (ms: number) => new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms));
await Promise.all(
Array.from(imgElements).map(async (img) => {
// get the image src from the img element
const src = img.getAttribute("src");
if (src) {
try {
const base64Image = await Promise.race([
getBase64Image(src),
timeout(5000) // 5 second timeout
]);
img.src = base64Image;
} catch (error) {
// Remove the image if conversion fails
img.remove();
// Log error with context for monitoring
console.error("Image conversion failed:", {
error,
src: src.substring(0, 100), // truncate for logging
timestamp: new Date().toISOString()
});
}
}
})
);

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: 1

🧹 Nitpick comments (1)
space/core/components/editor/embeds/mentions/user.tsx (1)

32-41: Enhance render logic with a11y improvements and remove redundant optional chaining.

  1. The optional chaining on userDetails is redundant since we already check for its existence in the earlier condition.
  2. Add ARIA attributes to improve accessibility for screen readers.
 return (
   <div
     className={cn("not-prose inline px-1 py-0.5 rounded bg-yellow-500/20 text-yellow-500 no-underline", {
       "bg-custom-primary-100/20 text-custom-primary-100": id === currentUser?.id,
     })}
+    role="button"
+    aria-label={`Mention ${userDetails.member__display_name}`}
   >
-    <Link href={profileLink}>@{userDetails?.member__display_name}</Link>
+    <Link href={profileLink}>@{userDetails.member__display_name}</Link>
   </div>
 );
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 906cc05 and 4094755.

📒 Files selected for processing (2)
  • space/core/components/editor/embeds/mentions/user.tsx (1 hunks)
  • web/core/components/editor/embeds/mentions/user.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/core/components/editor/embeds/mentions/user.tsx
🔇 Additional comments (2)
space/core/components/editor/embeds/mentions/user.tsx (2)

1-11: LGTM! Well-organized imports and clean type definition.

The imports are properly organized with clear grouping comments, and the Props type is concise and well-defined.


21-30: LGTM! Proper error handling implemented.

The component correctly handles the case of missing user details by showing a fallback UI.

@aaryan610 aaryan610 marked this pull request as draft December 17, 2024 10:52
@aaryan610 aaryan610 changed the title refactor: editor mentions extension [PE-93] refactor: editor mentions extension Dec 17, 2024
@aaryan610 aaryan610 marked this pull request as ready for review December 17, 2024 12:22
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: 1

🧹 Nitpick comments (9)
packages/editor/src/core/extensions/mentions/utils.ts (3)

12-19: Consider improving type safety for the popup variable.

While the component is well-typed, the popup variable uses any. Consider creating a proper type for the Tippy instance to improve type safety.

-    let popup: any | null = null;
+    let popup: ReturnType<typeof tippy> | null = null;

50-65: Improve return value documentation for keyboard handling.

The keyboard event handler's return values could be more explicit about their meaning:

  • true: event was handled
  • false: event should be processed by other handlers

Add JSDoc comments to clarify the return values:

+    /**
+     * Handles keyboard events for the mentions dropdown
+     * @returns true if the event was handled, false otherwise
+     */
     onKeyDown: (props: { event: KeyboardEvent }) => {

12-72: Well-structured implementation aligning with refactoring goals.

The implementation successfully separates concerns by:

  1. Accepting the search callback as a prop instead of handling it internally
  2. Providing a clean interface for the web application
  3. Maintaining a clear separation between rendering and data fetching

Consider adding error boundaries around the ReactRenderer to handle potential rendering errors gracefully.

packages/types/src/search.d.ts (3)

68-75: Improve type safety of TSearchResponse

Consider making the response type more strictly typed by using TSearchEntities as keys.

-export type TSearchResponse = {
-  cycle_mention?: TCycleSearchResponse[];
-  issue_mention?: TIssueSearchResponse[];
-  module_mention?: TModuleSearchResponse[];
-  page_mention?: TPageSearchResponse[];
-  project_mention?: TProjectSearchResponse[];
-  user_mention?: TUserSearchResponse[];
-};
+export type TSearchResponse = {
+  [K in TSearchEntities]?: {
+    'user_mention': TUserSearchResponse;
+    'issue_mention': TIssueSearchResponse;
+    'project_mention': TProjectSearchResponse;
+    'cycle_mention': TCycleSearchResponse;
+    'module_mention': TModuleSearchResponse;
+    'page_mention': TPageSearchResponse;
+  }[K][];
+};

47-47: Add strict typing for status fields

The status fields in TCycleSearchResponse and TModuleSearchResponse could benefit from more specific typing.

-  status: ICycle["status"];
+  status: "draft" | "started" | "completed" | "cancelled";

-  status: IModule["status"];
+  status: "planned" | "in-progress" | "completed" | "cancelled";

Also applies to: 56-56


9-15: Add JSDoc comments for better documentation

Consider adding JSDoc comments to describe the purpose and usage of each search entity type.

+/**
+ * Represents the different types of entities that can be mentioned in the editor.
+ * Used for filtering search results and determining the type of mention being created.
+ */
 export type TSearchEntities =
   | "user_mention"
   | "issue_mention"
   | "project_mention"
   | "cycle_mention"
   | "module_mention"
   | "page_mention";
web/core/components/editor/lite-text-editor/lite-text-editor.tsx (1)

91-91: Consider memoizing the EditorMentionsRoot render function

The renderComponent function could benefit from memoization to prevent unnecessary re-renders.

+const renderMentionsRoot = React.useCallback((props) => <EditorMentionsRoot {...props} />, []);
 mentionHandler={{
   searchCallback: async (query) => {
     const res = await fetchMentions(query);
     if (!res) throw new Error("Failed in fetching mentions");
     return res;
   },
-  renderComponent: (props) => <EditorMentionsRoot {...props} />,
+  renderComponent: renderMentionsRoot,
 }}

Also applies to: 92-92

web/core/components/pages/editor/editor-body.tsx (1)

212-217: Add error message localization.

The error message should be localized for better user experience.

 searchCallback: async (query) => {
   const res = await fetchMentions(query);
   if (!res) throw new Error("Failed in fetching mentions");
   return res;
 },
apiserver/plane/app/views/search/base.py (1)

254-469: Consider implementing caching and pagination.

The search endpoint could benefit from:

  1. Caching frequently accessed data to improve performance
  2. Implementing proper pagination for large result sets

Consider implementing Redis caching for search results and using Django's pagination:

from django.core.cache import cache
from django.core.paginator import Paginator

# Add cache key generation
def get_cache_key(self, query_type, query, project_id):
    return f"search:{query_type}:{project_id}:{query}"

# Add cache wrapper
def get_cached_results(self, cache_key, queryset, count):
    cached_data = cache.get(cache_key)
    if cached_data is not None:
        return cached_data
    
    results = list(queryset[:count])
    cache.set(cache_key, results, timeout=300)  # Cache for 5 minutes
    return results
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4094755 and f29c789.

📒 Files selected for processing (8)
  • apiserver/plane/app/views/search/base.py (3 hunks)
  • packages/editor/src/core/extensions/mentions/utils.ts (1 hunks)
  • packages/types/src/search.d.ts (1 hunks)
  • web/core/components/editor/lite-text-editor/lite-text-editor.tsx (3 hunks)
  • web/core/components/editor/rich-text-editor/rich-text-editor.tsx (2 hunks)
  • web/core/components/pages/editor/editor-body.tsx (5 hunks)
  • web/core/hooks/use-editor-mention.tsx (1 hunks)
  • web/core/services/project/project.service.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/core/hooks/use-editor-mention.tsx
🔇 Additional comments (14)
packages/editor/src/core/extensions/mentions/utils.ts (3)

1-11: LGTM! Well-organized imports.

The imports are properly organized and grouped with clear comments.


35-36: Fragile DOM query for editor container.

The current DOM query using querySelector is fragile.


66-70: LGTM! Proper cleanup in onExit.

The cleanup logic properly handles both the popup and component instances, and updates the editor state.

web/core/components/editor/rich-text-editor/rich-text-editor.tsx (2)

50-54: Improve error handling in search callback

The current error handling could be more informative and might swallow useful error details.


31-34: Verify searchEntity implementation across workspace contexts

The searchEntity implementation assumes both workspaceSlug and projectId are available. Consider handling cases where projectId is undefined.

web/core/components/editor/lite-text-editor/lite-text-editor.tsx (2)

86-91: Improve error handling in search callback

The error handling pattern is repeated here and could be more informative.


55-59: LGTM: Consistent mention handling implementation

The implementation of useEditorMention and searchEntity is consistent with the rich-text-editor component, which helps maintain code consistency across different editor variants.

web/core/services/project/project.service.ts (2)

1-7: LGTM!

The import statements are correctly updated to include the new types required for the search functionality.


174-189: 🛠️ Refactor suggestion

Add input validation and error handling.

The method should validate required parameters and handle potential errors more gracefully.

Apply this diff to improve the implementation:

 async searchEntity(
   workspaceSlug: string,
   projectId: string,
   params: TSearchEntityRequestPayload
 ): Promise<TSearchResponse> {
+  if (!workspaceSlug || !projectId || !params?.query_type?.length) {
+    throw new Error("Missing required parameters");
+  }
+
   return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/entity-search/`, {
     params: {
       ...params,
       query_type: params.query_type.join(","),
     },
   })
     .then((response) => response?.data)
     .catch((error) => {
-      throw error?.response?.data;
+      throw error?.response?.data || new Error("Failed to search entities");
     });
 }

Likely invalid or redundant comment.

web/core/components/pages/editor/editor-body.tsx (3)

19-19: LGTM!

The imports are correctly updated to support the new mention handling mechanism.

Also applies to: 26-27, 37-37, 42-42


75-79: LGTM!

The useEditorMention hook is properly configured with the searchEntity callback.


244-244: LGTM!

The read-only editor's mentionHandler is correctly configured with the EditorMentionsRoot component.

apiserver/plane/app/views/search/base.py (2)

5-19: LGTM!

The imports are correctly updated to include necessary Django model utilities.


257-259: Previous review comments still apply.

The validation for query_types and exception handling for the count parameter should be addressed as mentioned in previous review comments.

Comment on lines +21 to +43
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
if (!searchCallback) return;
if (!props.clientRect) return;
component = new ReactRenderer<CommandListInstance, MentionsListDropdownProps>(MentionsListDropdown, {
props: {
...props,
searchCallback,
},
editor: props.editor,
});
props.editor.storage.mentionsOpen = true;
// @ts-expect-error - Tippy types are incorrect
popup = tippy("body", {
getReferenceClientRect: props.clientRect,
appendTo: () =>
document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'),
content: component.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
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

Add cleanup in early return cases.

When searchCallback or clientRect is not provided, the function returns early without cleaning up any existing instances.

   onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
-    if (!searchCallback) return;
-    if (!props.clientRect) return;
+    if (!searchCallback || !props.clientRect) {
+      popup?.[0]?.destroy();
+      component?.destroy();
+      return;
+    }
📝 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
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
if (!searchCallback) return;
if (!props.clientRect) return;
component = new ReactRenderer<CommandListInstance, MentionsListDropdownProps>(MentionsListDropdown, {
props: {
...props,
searchCallback,
},
editor: props.editor,
});
props.editor.storage.mentionsOpen = true;
// @ts-expect-error - Tippy types are incorrect
popup = tippy("body", {
getReferenceClientRect: props.clientRect,
appendTo: () =>
document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'),
content: component.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
if (!searchCallback || !props.clientRect) {
popup?.[0]?.destroy();
component?.destroy();
return;
}
component = new ReactRenderer<CommandListInstance, MentionsListDropdownProps>(MentionsListDropdown, {
props: {
...props,
searchCallback,
},
editor: props.editor,
});
props.editor.storage.mentionsOpen = true;
// @ts-expect-error - Tippy types are incorrect
popup = tippy("body", {
getReferenceClientRect: props.clientRect,
appendTo: () =>
document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'),
content: component.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},

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

Successfully merging this pull request may close these issues.

3 participants