mentions loading state part done

This commit is contained in:
Palanikannan1437 2024-02-21 18:26:49 +05:30
parent 875eb054a2
commit a3033203af
14 changed files with 375 additions and 171 deletions

View File

@ -1,3 +1,4 @@
import { Editor, Range } from "@tiptap/react";
export type IMentionSuggestion = { export type IMentionSuggestion = {
id: string; id: string;
type: string; type: string;
@ -7,4 +8,9 @@ export type IMentionSuggestion = {
redirect_uri: string; redirect_uri: string;
}; };
export type CommandProps = {
editor: Editor;
range: Range;
};
export type IMentionHighlight = string; export type IMentionHighlight = string;

View File

@ -35,79 +35,81 @@ export const CoreEditorExtensions = (
deleteFile: DeleteImage, deleteFile: DeleteImage,
restoreFile: RestoreImage, restoreFile: RestoreImage,
cancelUploadImage?: () => any cancelUploadImage?: () => any
) => [ ) => {
StarterKit.configure({ return [
bulletList: { StarterKit.configure({
HTMLAttributes: { bulletList: {
class: "list-disc list-outside leading-3 -mt-2", HTMLAttributes: {
class: "list-disc list-outside leading-3 -mt-2",
},
}, },
}, orderedList: {
orderedList: { HTMLAttributes: {
HTMLAttributes: { class: "list-decimal list-outside leading-3 -mt-2",
class: "list-decimal list-outside leading-3 -mt-2", },
}, },
}, listItem: {
listItem: { HTMLAttributes: {
HTMLAttributes: { class: "leading-normal -mb-2",
class: "leading-normal -mb-2", },
}, },
}, code: false,
code: false, codeBlock: false,
codeBlock: false, horizontalRule: {
horizontalRule: { HTMLAttributes: { class: "mt-4 mb-4" },
HTMLAttributes: { class: "mt-4 mb-4" }, },
}, blockquote: false,
blockquote: false, dropcursor: {
dropcursor: { color: "rgba(var(--color-text-100))",
color: "rgba(var(--color-text-100))", width: 2,
width: 2, },
}, }),
}), CustomQuoteExtension.configure({
CustomQuoteExtension.configure({ HTMLAttributes: { className: "border-l-4 border-custom-border-300" },
HTMLAttributes: { className: "border-l-4 border-custom-border-300" }, }),
}), CustomKeymap,
CustomKeymap, ListKeymap,
ListKeymap, CustomLinkExtension.configure({
CustomLinkExtension.configure({ openOnClick: true,
openOnClick: true, autolink: true,
autolink: true, linkOnPaste: true,
linkOnPaste: true, protocols: ["http", "https"],
protocols: ["http", "https"], validate: (url: string) => isValidHttpUrl(url),
validate: (url: string) => isValidHttpUrl(url), HTMLAttributes: {
HTMLAttributes: { class:
class: "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", },
}, }),
}), ImageExtension(deleteFile, restoreFile, cancelUploadImage).configure({
ImageExtension(deleteFile, restoreFile, cancelUploadImage).configure({ HTMLAttributes: {
HTMLAttributes: { class: "rounded-lg border border-custom-border-300",
class: "rounded-lg border border-custom-border-300", },
}, }),
}), TiptapUnderline,
TiptapUnderline, TextStyle,
TextStyle, Color,
Color, TaskList.configure({
TaskList.configure({ HTMLAttributes: {
HTMLAttributes: { class: "not-prose pl-2",
class: "not-prose pl-2", },
}, }),
}), TaskItem.configure({
TaskItem.configure({ HTMLAttributes: {
HTMLAttributes: { class: "flex items-start my-4",
class: "flex items-start my-4", },
}, nested: true,
nested: true, }),
}), CustomCodeBlockExtension,
CustomCodeBlockExtension, CustomCodeInlineExtension,
CustomCodeInlineExtension, Markdown.configure({
Markdown.configure({ html: true,
html: true, transformCopiedText: true,
transformCopiedText: true, transformPastedText: true,
transformPastedText: true, }),
}), Table,
Table, TableHeader,
TableHeader, TableCell,
TableCell, TableRow,
TableRow, Mentions(mentionConfig.mentionSuggestions, mentionConfig.mentionHighlights, false),
Mentions(mentionConfig.mentionSuggestions, mentionConfig.mentionHighlights, false), ];
]; };

View File

@ -32,6 +32,12 @@ export const CustomMention = Mention.extend<CustomMentionOptions>({
redirect_uri: { redirect_uri: {
default: "/", default: "/",
}, },
entity_identifier: {
default: null,
},
entity_name: {
default: null,
},
}; };
}, },
@ -43,17 +49,6 @@ export const CustomMention = Mention.extend<CustomMentionOptions>({
return [ return [
{ {
tag: "mention-component", tag: "mention-component",
getAttrs: (node: string | HTMLElement) => {
if (typeof node === "string") {
return null;
}
return {
id: node.getAttribute("data-mention-id") || "",
target: node.getAttribute("data-mention-target") || "",
label: node.innerText.slice(1) || "",
redirect_uri: node.getAttribute("redirect_uri"),
};
},
}, },
]; ];
}, },

View File

@ -1,15 +1,115 @@
// @ts-nocheck
import { Suggestion } from "src/ui/mentions/suggestion";
import { CustomMention } from "src/ui/mentions/custom"; import { CustomMention } from "src/ui/mentions/custom";
import { IMentionHighlight } from "src/types/mention-suggestion"; import { IMentionHighlight, IMentionSuggestion } from "src/types/mention-suggestion";
import { ReactRenderer } from "@tiptap/react";
import { Editor } from "@tiptap/core";
import tippy from "tippy.js";
export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighlights: IMentionHighlight[], readonly) => import { v4 as uuidv4 } from "uuid";
import { MentionList } from "src/ui/mentions/mention-list";
export const getSuggestionItems =
(getSuggestions: () => Promise<IMentionSuggestion[]>) =>
async ({ query }: { query: string }) => {
console.log("yaa");
const suggestions = await getSuggestions();
const mappedSuggestions: IMentionSuggestion[] = suggestions.map((suggestion): IMentionSuggestion => {
const transactionId = uuidv4();
return {
...suggestion,
id: transactionId,
};
});
const filteredSuggestions = mappedSuggestions
.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5);
console.log("yoo", filteredSuggestions);
return filteredSuggestions;
};
export const Mentions = (
mentionSuggestions: () => Promise<IMentionSuggestion[]>,
mentionHighlights: IMentionHighlight[],
readonly: boolean
) =>
CustomMention.configure({ CustomMention.configure({
HTMLAttributes: { HTMLAttributes: {
class: "mention", class: "mention",
}, },
readonly: readonly, readonly: readonly,
mentionHighlights: mentionHighlights, mentionHighlights: mentionHighlights,
suggestion: Suggestion(mentionSuggestions), suggestion: {
items: ({ query }) => {
const suggestions = mentionSuggestions();
const mappedSuggestions: IMentionSuggestion[] = suggestions.map((suggestion): IMentionSuggestion => {
const transactionId = uuidv4();
return {
...suggestion,
id: transactionId,
};
});
const filteredSuggestions = mappedSuggestions
.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5);
console.log("yoo", filteredSuggestions);
return filteredSuggestions;
},
// @ts-ignore
render: () => {
let reactRenderer: ReactRenderer | null = null;
let popup: any | null = null;
return {
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
props.editor.storage.mentionsOpen = true;
reactRenderer = new ReactRenderer(MentionList, {
props,
editor: props.editor,
});
// @ts-ignore
popup = tippy("body", {
getReferenceClientRect: props.clientRect,
appendTo: () => document.querySelector("#editor-container"),
content: reactRenderer.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => {
reactRenderer?.updateProps(props);
popup &&
popup[0].setProps({
getReferenceClientRect: props.clientRect,
});
},
onKeyDown: (props: { event: KeyboardEvent }) => {
if (props.event.key === "Escape") {
popup?.[0].hide();
return true;
}
const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"];
if (navigationKeys.includes(props.event.key)) {
// @ts-ignore
reactRenderer?.ref?.onKeyDown(props);
event?.stopPropagation();
return true;
}
return false;
},
onExit: (props: { editor: Editor; event: KeyboardEvent }) => {
props.editor.storage.mentionsOpen = false;
popup?.[0].destroy();
reactRenderer?.destroy();
},
};
},
},
}); });

View File

@ -19,6 +19,8 @@ export const MentionList = forwardRef((props: MentionListProps, ref) => {
props.command({ props.command({
id: item.id, id: item.id,
label: item.title, label: item.title,
entity_identifier: item.entity_identifier,
entity_name: item.entity_name,
target: "users", target: "users",
redirect_uri: item.redirect_uri, redirect_uri: item.redirect_uri,
}); });

View File

@ -20,13 +20,13 @@ export const MentionNodeView = (props) => {
<NodeViewWrapper className="mention-component inline w-fit"> <NodeViewWrapper className="mention-component inline w-fit">
<span <span
className={cn("mention rounded bg-custom-primary-100/20 px-1 py-0.5 font-medium text-custom-primary-100", { className={cn("mention rounded bg-custom-primary-100/20 px-1 py-0.5 font-medium text-custom-primary-100", {
"bg-yellow-500/20 text-yellow-500": highlights ? highlights.includes(props.node.attrs.id) : false, "bg-yellow-500/20 text-yellow-500": highlights
? highlights.includes(props.node.attrs.entity_identifier)
: false,
"cursor-pointer": !props.extension.options.readonly, "cursor-pointer": !props.extension.options.readonly,
// "hover:bg-custom-primary-300" : !props.extension.options.readonly && !highlights.includes(props.node.attrs.id) // "hover:bg-custom-primary-300" : !props.extension.options.readonly && !highlights.includes(props.node.attrs.id)
})} })}
onClick={handleClick} onClick={handleClick}
data-mention-target={props.node.attrs.target}
data-mention-id={props.node.attrs.id}
> >
@{props.node.attrs.label} @{props.node.attrs.label}
</span> </span>

View File

@ -2,65 +2,80 @@ import { ReactRenderer } from "@tiptap/react";
import { Editor } from "@tiptap/core"; import { Editor } from "@tiptap/core";
import tippy from "tippy.js"; import tippy from "tippy.js";
import { MentionList } from "src/ui/mentions/mention-list"; import { v4 as uuidv4 } from "uuid";
import { IMentionSuggestion } from "src/types/mention-suggestion"; import { IMentionSuggestion } from "src/types/mention-suggestion";
import { MentionList } from "src/ui/mentions/mention-list";
export const Suggestion = (suggestions: IMentionSuggestion[]) => ({ export const getSuggestionItems = (suggestions: IMentionSuggestion[]) => {
items: ({ query }: { query: string }) => return ({ query }: { query: string }) => {
suggestions.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5), const mappedSuggestions: IMentionSuggestion[] = suggestions.map((suggestion): IMentionSuggestion => {
render: () => { const transactionId = uuidv4();
let reactRenderer: ReactRenderer | null = null; return {
let popup: any | null = null; ...suggestion,
id: transactionId,
};
});
return mappedSuggestions
.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5);
};
};
return { // export const Suggestion = (suggestions: IMentionSuggestion[]) => ({
onStart: (props: { editor: Editor; clientRect: DOMRect }) => { // items: getSuggestionItems(suggestions),
props.editor.storage.mentionsOpen = true; // render: () => {
reactRenderer = new ReactRenderer(MentionList, { // let reactRenderer: ReactRenderer | null = null;
props, // let popup: any | null = null;
editor: props.editor, //
}); // return {
// @ts-ignore // onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
popup = tippy("body", { // props.editor.storage.mentionsOpen = true;
getReferenceClientRect: props.clientRect, // reactRenderer = new ReactRenderer(MentionList, {
appendTo: () => document.querySelector("#editor-container"), // props,
content: reactRenderer.element, // editor: props.editor,
showOnCreate: true, // });
interactive: true, // // @ts-ignore
trigger: "manual", // popup = tippy("body", {
placement: "bottom-start", // getReferenceClientRect: props.clientRect,
}); // appendTo: () => document.querySelector("#editor-container"),
}, // content: reactRenderer.element,
// showOnCreate: true,
onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => { // interactive: true,
reactRenderer?.updateProps(props); // trigger: "manual",
// placement: "bottom-start",
popup && // });
popup[0].setProps({ // },
getReferenceClientRect: props.clientRect, //
}); // onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => {
}, // reactRenderer?.updateProps(props);
onKeyDown: (props: { event: KeyboardEvent }) => { //
if (props.event.key === "Escape") { // popup &&
popup?.[0].hide(); // popup[0].setProps({
// getReferenceClientRect: props.clientRect,
return true; // });
} // },
// onKeyDown: (props: { event: KeyboardEvent }) => {
const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"]; // if (props.event.key === "Escape") {
// popup?.[0].hide();
if (navigationKeys.includes(props.event.key)) { //
// @ts-ignore // return true;
reactRenderer?.ref?.onKeyDown(props); // }
event?.stopPropagation(); //
return true; // const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"];
} //
return false; // if (navigationKeys.includes(props.event.key)) {
}, // // @ts-ignore
onExit: (props: { editor: Editor; event: KeyboardEvent }) => { // reactRenderer?.ref?.onKeyDown(props);
props.editor.storage.mentionsOpen = false; // event?.stopPropagation();
popup?.[0].destroy(); // return true;
reactRenderer?.destroy(); // }
}, // return false;
}; // },
}, // onExit: (props: { editor: Editor; event: KeyboardEvent }) => {
}); // props.editor.storage.mentionsOpen = false;
// popup?.[0].destroy();
// reactRenderer?.destroy();
// },
// };
// },
// });

View File

@ -1,6 +1,13 @@
"use client"; "use client";
import React, { useState } from "react"; import React, { useState } from "react";
import { UploadImage, DeleteImage, RestoreImage, getEditorClassNames, useEditor } from "@plane/editor-core"; import {
UploadImage,
DeleteImage,
RestoreImage,
getEditorClassNames,
useEditor,
IMentionSuggestion,
} from "@plane/editor-core";
import { DocumentEditorExtensions } from "src/ui/extensions"; import { DocumentEditorExtensions } from "src/ui/extensions";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions"; import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions";
import { EditorHeader } from "src/ui/components/editor-header"; import { EditorHeader } from "src/ui/components/editor-header";
@ -43,6 +50,9 @@ interface IDocumentEditor {
debouncedUpdatesEnabled?: boolean; debouncedUpdatesEnabled?: boolean;
isSubmitting: "submitting" | "submitted" | "saved"; isSubmitting: "submitting" | "submitted" | "saved";
mentionHighlights?: string[];
mentionSuggestions?: IMentionSuggestion[];
// embed configuration // embed configuration
duplicationConfig?: IDuplicationConfig; duplicationConfig?: IDuplicationConfig;
pageLockConfig?: IPageLockConfig; pageLockConfig?: IPageLockConfig;
@ -66,6 +76,8 @@ const DocumentEditor = ({
editorContentCustomClassNames, editorContentCustomClassNames,
value, value,
uploadFile, uploadFile,
mentionHighlights,
mentionSuggestions,
deleteFile, deleteFile,
restoreFile, restoreFile,
isSubmitting, isSubmitting,
@ -109,6 +121,8 @@ const DocumentEditor = ({
cancelUploadImage, cancelUploadImage,
rerenderOnPropsChange, rerenderOnPropsChange,
forwardedRef, forwardedRef,
mentionSuggestions,
mentionHighlights,
extensions: DocumentEditorExtensions(uploadFile, setHideDragHandleFunction, setIsSubmitting), extensions: DocumentEditorExtensions(uploadFile, setHideDragHandleFunction, setIsSubmitting),
}); });

View File

@ -22,6 +22,8 @@ interface IDocumentReadOnlyEditor {
documentDetails: DocumentDetails; documentDetails: DocumentDetails;
pageLockConfig?: IPageLockConfig; pageLockConfig?: IPageLockConfig;
pageArchiveConfig?: IPageArchiveConfig; pageArchiveConfig?: IPageArchiveConfig;
mentionHighlights?: string[];
pageDuplicationConfig?: IDuplicationConfig; pageDuplicationConfig?: IDuplicationConfig;
onActionCompleteHandler: (action: { onActionCompleteHandler: (action: {
title: string; title: string;
@ -44,6 +46,7 @@ const DocumentReadOnlyEditor = ({
borderOnFocus, borderOnFocus,
customClassName, customClassName,
value, value,
mentionHighlights,
documentDetails, documentDetails,
forwardedRef, forwardedRef,
pageDuplicationConfig, pageDuplicationConfig,
@ -58,6 +61,7 @@ const DocumentReadOnlyEditor = ({
const editor = useReadOnlyEditor({ const editor = useReadOnlyEditor({
value, value,
mentionHighlights,
forwardedRef, forwardedRef,
rerenderOnPropsChange, rerenderOnPropsChange,
extensions: [IssueWidgetPlaceholder()], extensions: [IssueWidgetPlaceholder()],

View File

@ -81,7 +81,6 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
render={({ field: { value, onChange } }) => ( render={({ field: { value, onChange } }) => (
<LiteTextEditorWithRef <LiteTextEditorWithRef
onEnterKeyPress={(e) => { onEnterKeyPress={(e) => {
console.log("yo");
handleSubmit(onSubmit)(e); handleSubmit(onSubmit)(e);
}} }}
cancelUploadImage={fileService.cancelUpload} cancelUploadImage={fileService.cancelUpload}

View File

@ -1,11 +1,50 @@
import { useContext } from "react"; import useSWR from "swr";
// mobx store
import { StoreContext } from "contexts/store-context";
// types
import { IMentionStore } from "store/mention.store";
export const useMention = (): IMentionStore => { import { ProjectMemberService } from "services/project";
const context = useContext(StoreContext); import { IProjectMember } from "@plane/types";
if (context === undefined) throw new Error("useMention must be used within StoreProvider"); import { UserService } from "services/user.service";
return context.mention; import { useRef, useEffect } from "react";
export const useMention = ({ workspaceSlug, projectId }: { workspaceSlug: string; projectId: string }) => {
const userService = new UserService();
const projectMemberService = new ProjectMemberService();
const { data: projectMembers } = useSWR(["projectMembers", workspaceSlug, projectId], async () => {
const members = await projectMemberService.fetchProjectMembers(workspaceSlug, projectId);
const detailedMembers = await Promise.all(
members.map(async (member) => projectMemberService.getProjectMember(workspaceSlug, projectId, member.id))
);
return detailedMembers;
});
const projectMembersRef = useRef<IProjectMember[] | undefined>();
useEffect(() => {
if (projectMembers) {
projectMembersRef.current = projectMembers;
}
}, [projectMembers]);
const { data: user } = useSWR("currentUser", async () => userService.currentUser());
const mentionHighlights = user ? [user.id] : [];
const getMentionSuggestions = () => () => {
const mentionSuggestions =
projectMembersRef.current?.map((memberDetails) => ({
entity_name: "user_mention",
entity_identifier: `${memberDetails?.member?.id}`,
type: "User",
title: `${memberDetails?.member?.display_name}`,
subtitle: memberDetails?.member?.email ?? "",
avatar: `${memberDetails?.member?.avatar}`,
redirect_uri: `/${workspaceSlug}/profile/${memberDetails?.member?.id}`,
})) || [];
return mentionSuggestions;
};
return {
getMentionSuggestions,
mentionHighlights,
};
}; };

View File

@ -6,7 +6,7 @@ import { ReactElement, useEffect, useRef, useState } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
// hooks // hooks
import { useApplication, usePage, useUser, useWorkspace } from "hooks/store"; import { useApplication, useMention, usePage, useUser, useWorkspace } from "hooks/store";
import useReloadConfirmations from "hooks/use-reload-confirmation"; import useReloadConfirmations from "hooks/use-reload-confirmation";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// services // services
@ -29,6 +29,8 @@ import { NextPageWithLayout } from "lib/types";
import { EUserProjectRoles } from "constants/project"; import { EUserProjectRoles } from "constants/project";
import { useProjectPages } from "hooks/store/use-project-specific-pages"; import { useProjectPages } from "hooks/store/use-project-specific-pages";
import { IssuePeekOverview } from "components/issues"; import { IssuePeekOverview } from "components/issues";
import { ProjectMemberService } from "services/project";
import { UserService } from "services/user.service";
// services // services
const fileService = new FileService(); const fileService = new FileService();
@ -84,8 +86,22 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
: null : null
); );
const projectMemberService = new ProjectMemberService();
const { data: projectMembers } = useSWR(["projectMembers", workspaceSlug, projectId], async () => {
const members = await projectMemberService.fetchProjectMembers(workspaceSlug, projectId);
const detailedMembers = await Promise.all(
members.map(async (member) => projectMemberService.getProjectMember(workspaceSlug, projectId, member.id))
);
console.log("ye toh chal", detailedMembers);
return detailedMembers;
});
const pageStore = usePage(pageId as string); const pageStore = usePage(pageId as string);
// store hooks
const { getMentionSuggestions, mentionHighlights, mentionSuggestions } = useMention({ workspaceSlug, projectId });
const { setShowAlert } = useReloadConfirmations(pageStore?.isSubmitting === "submitting"); const { setShowAlert } = useReloadConfirmations(pageStore?.isSubmitting === "submitting");
useEffect( useEffect(
@ -273,6 +289,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
last_updated_at: updated_at, last_updated_at: updated_at,
last_updated_by: updated_by, last_updated_by: updated_by,
}} }}
mentionHighlights={mentionHighlights}
pageLockConfig={userCanLock && !archived_at ? { action: unlockPage, is_locked: is_locked } : undefined} pageLockConfig={userCanLock && !archived_at ? { action: unlockPage, is_locked: is_locked } : undefined}
pageDuplicationConfig={userCanDuplicate && !archived_at ? { action: duplicate_page } : undefined} pageDuplicationConfig={userCanDuplicate && !archived_at ? { action: duplicate_page } : undefined}
pageArchiveConfig={ pageArchiveConfig={
@ -300,6 +317,8 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
last_updated_at: updated_at, last_updated_at: updated_at,
last_updated_by: updated_by, last_updated_by: updated_by,
}} }}
mentionSuggestions={getMentionSuggestions(projectMembers)}
mentionHighlights={mentionHighlights}
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)} uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
deleteFile={fileService.getDeleteImageFunction(workspaceId)} deleteFile={fileService.getDeleteImageFunction(workspaceId)}
restoreFile={fileService.getRestoreImageFunction(workspaceId)} restoreFile={fileService.getRestoreImageFunction(workspaceId)}

View File

@ -33,9 +33,12 @@ export class MentionStore implements IMentionStore {
const suggestions = (projectMemberIds ?? [])?.map((memberId) => { const suggestions = (projectMemberIds ?? [])?.map((memberId) => {
const memberDetails = this.rootStore.memberRoot.project.getProjectMemberDetails(memberId); const memberDetails = this.rootStore.memberRoot.project.getProjectMemberDetails(memberId);
// __AUTO_GENERATED_PRINT_VAR_START__
console.log("MentionStore#mentionSuggestions#(anon) memberDetails are: %s", memberDetails?.member.id); // __AUTO_GENERATED_PRINT_VAR_END__
return { return {
id: `${memberDetails?.member?.id}`, entity_name: "user_mention",
entity_identifier: `${memberDetails?.member?.id}`,
type: "User", type: "User",
title: `${memberDetails?.member?.display_name}`, title: `${memberDetails?.member?.display_name}`,
subtitle: memberDetails?.member?.email ?? "", subtitle: memberDetails?.member?.email ?? "",

View File

@ -5012,7 +5012,7 @@ fault@^2.0.0:
dependencies: dependencies:
format "^0.2.0" format "^0.2.0"
fflate@^0.4.1: fflate@^0.4.8:
version "0.4.8" version "0.4.8"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
@ -7171,12 +7171,18 @@ postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29:
picocolors "^1.0.0" picocolors "^1.0.0"
source-map-js "^1.0.2" source-map-js "^1.0.2"
posthog-js@^1.88.4: posthog-js@^1.105.0:
version "1.96.1" version "1.108.3"
resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.96.1.tgz#4f9719a24e4e14037b0e72d430194d7cdb576447" resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.108.3.tgz#774353d7ad594b68e6f5e6cce0fe8b583562f455"
integrity sha512-kv1vQqYMt2BV3YHS+wxsbGuP+tz+M3y1AzNhz8TfkpY1HT8W/ONT0i0eQpeRr9Y+d4x/fZ6M4cXG5GMvi9lRCA== integrity sha512-Vi9lX/MhovsKIEdj2aJ5ioku9U/eMGY8/DzKf4EpyrElxPPdabAdCDRUa81eAqxC6npkOpkHskawUPLg20le4Q==
dependencies: dependencies:
fflate "^0.4.1" fflate "^0.4.8"
preact "^10.19.3"
preact@^10.19.3:
version "10.19.6"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.19.6.tgz#66007b67aad4d11899f583df1b0116d94a89b8f5"
integrity sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==
prebuild-install@^7.1.1: prebuild-install@^7.1.1:
version "7.1.1" version "7.1.1"