mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
🚜 refactor: added a common place for all LiteTextEditor and it's read only instances
This commit is contained in:
parent
ae9c729fc7
commit
ce987833b7
@ -1,3 +1,4 @@
|
|||||||
export { LiteTextEditor, LiteTextEditorWithRef } from "src/ui";
|
export { LiteTextEditor, LiteTextEditorWithRef } from "src/ui";
|
||||||
export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "src/ui/read-only";
|
export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "src/ui/read-only";
|
||||||
export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-core";
|
export type { LiteTextEditorProps, ILiteTextEditor } from "src/ui";
|
||||||
|
export type { LiteTextEditorReadOnlyProps, ILiteReadOnlyEditor } from "src/ui/read-only";
|
||||||
|
@ -12,12 +12,11 @@ import {
|
|||||||
import { FixedMenu } from "src/ui/menus/fixed-menu";
|
import { FixedMenu } from "src/ui/menus/fixed-menu";
|
||||||
import { LiteTextEditorExtensions } from "src/ui/extensions";
|
import { LiteTextEditorExtensions } from "src/ui/extensions";
|
||||||
|
|
||||||
interface ILiteTextEditor {
|
export type ILiteTextEditor = {
|
||||||
value: string;
|
value: string;
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
deleteFile: DeleteImage;
|
deleteFile: DeleteImage;
|
||||||
restoreFile: RestoreImage;
|
restoreFile: RestoreImage;
|
||||||
|
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
borderOnFocus?: boolean;
|
borderOnFocus?: boolean;
|
||||||
customClassName?: string;
|
customClassName?: string;
|
||||||
@ -42,9 +41,9 @@ interface ILiteTextEditor {
|
|||||||
mentionHighlights?: string[];
|
mentionHighlights?: string[];
|
||||||
mentionSuggestions?: IMentionSuggestion[];
|
mentionSuggestions?: IMentionSuggestion[];
|
||||||
submitButton?: React.ReactNode;
|
submitButton?: React.ReactNode;
|
||||||
}
|
};
|
||||||
|
|
||||||
interface LiteTextEditorProps extends ILiteTextEditor {
|
export interface LiteTextEditorProps extends ILiteTextEditor {
|
||||||
forwardedRef?: React.Ref<EditorHandle>;
|
forwardedRef?: React.Ref<EditorHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core";
|
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core";
|
||||||
|
|
||||||
interface ICoreReadOnlyEditor {
|
export type ILiteReadOnlyEditor = {
|
||||||
value: string;
|
value: string;
|
||||||
editorContentCustomClassNames?: string;
|
editorContentCustomClassNames?: string;
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
borderOnFocus?: boolean;
|
borderOnFocus?: boolean;
|
||||||
customClassName?: string;
|
customClassName?: string;
|
||||||
mentionHighlights: string[];
|
mentionHighlights: string[];
|
||||||
}
|
};
|
||||||
|
|
||||||
interface EditorCoreProps extends ICoreReadOnlyEditor {
|
export interface LiteTextEditorReadOnlyProps extends ILiteReadOnlyEditor {
|
||||||
forwardedRef?: React.Ref<EditorHandle>;
|
forwardedRef?: React.Ref<EditorHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ const LiteReadOnlyEditor = ({
|
|||||||
value,
|
value,
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
mentionHighlights,
|
mentionHighlights,
|
||||||
}: EditorCoreProps) => {
|
}: LiteTextEditorReadOnlyProps) => {
|
||||||
const editor = useReadOnlyEditor({
|
const editor = useReadOnlyEditor({
|
||||||
value,
|
value,
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
@ -51,7 +51,7 @@ const LiteReadOnlyEditor = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const LiteReadOnlyEditorWithRef = React.forwardRef<EditorHandle, ICoreReadOnlyEditor>((props, ref) => (
|
const LiteReadOnlyEditorWithRef = React.forwardRef<EditorHandle, ILiteReadOnlyEditor>((props, ref) => (
|
||||||
<LiteReadOnlyEditor {...props} forwardedRef={ref} />
|
<LiteReadOnlyEditor {...props} forwardedRef={ref} />
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
export { RichTextEditor, RichTextEditorWithRef } from "src/ui";
|
export { RichTextEditor, RichTextEditorWithRef } from "src/ui";
|
||||||
export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "src/ui/read-only";
|
export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "src/ui/read-only";
|
||||||
export type { RichTextEditorProps, IRichTextEditor } from "src/ui";
|
export type { RichTextEditorProps, IRichTextEditor } from "src/ui";
|
||||||
export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-core";
|
|
||||||
|
41
web/components/editor/lite-text-editor.tsx
Normal file
41
web/components/editor/lite-text-editor.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { LiteTextEditorWithRef, ILiteTextEditor } from "@plane/lite-text-editor";
|
||||||
|
|
||||||
|
import { useMention } from "hooks/store";
|
||||||
|
|
||||||
|
import { FileService } from "services/file.service";
|
||||||
|
|
||||||
|
interface EditorHandle {
|
||||||
|
clearEditor: () => void;
|
||||||
|
setEditorValue: (content: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LiteTextEditorWrapperProps
|
||||||
|
extends Omit<
|
||||||
|
ILiteTextEditor,
|
||||||
|
"uploadFile" | "deleteFile" | "restoreFile" | "mentionSuggestions" | "mentionHighlights"
|
||||||
|
> {
|
||||||
|
workspaceSlug: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileService = new FileService();
|
||||||
|
|
||||||
|
export const LiteTextEditor = React.forwardRef<EditorHandle, LiteTextEditorWrapperProps>(
|
||||||
|
({ workspaceSlug, ...props }, ref) => {
|
||||||
|
const editorSuggestions = useMention();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LiteTextEditorWithRef
|
||||||
|
ref={ref}
|
||||||
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||||
|
deleteFile={fileService.deleteImage}
|
||||||
|
restoreFile={fileService.restoreImage}
|
||||||
|
mentionSuggestions={editorSuggestions.mentionSuggestions}
|
||||||
|
mentionHighlights={editorSuggestions.mentionHighlights}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
LiteTextEditor.displayName = "LiteTextEditor";
|
21
web/components/editor/lite-text-read-only-editor.tsx
Normal file
21
web/components/editor/lite-text-read-only-editor.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { ILiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
||||||
|
|
||||||
|
import { useMention } from "hooks/store";
|
||||||
|
|
||||||
|
interface EditorHandle {
|
||||||
|
clearEditor: () => void;
|
||||||
|
setEditorValue: (content: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LiteTextReadOnlyEditorWrapperProps extends Omit<ILiteReadOnlyEditor, "mentionHighlights"> {}
|
||||||
|
|
||||||
|
export const LiteTextReadOnlyEditor = React.forwardRef<EditorHandle, LiteTextReadOnlyEditorWrapperProps>(
|
||||||
|
({ ...props }, ref) => {
|
||||||
|
const editorSuggestions = useMention();
|
||||||
|
|
||||||
|
return <LiteReadOnlyEditorWithRef ref={ref} mentionHighlights={editorSuggestions.mentionHighlights} {...props} />;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
LiteTextReadOnlyEditor.displayName = "LiteTextReadOnlyEditor";
|
41
web/components/editor/rich-text-read-only-editor.tsx
Normal file
41
web/components/editor/rich-text-read-only-editor.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { RichTextEditorWithRef, IRichTextEditor } from "@plane/rich-text-editor";
|
||||||
|
|
||||||
|
import { useMention } from "hooks/store";
|
||||||
|
|
||||||
|
import { FileService } from "services/file.service";
|
||||||
|
|
||||||
|
interface EditorHandle {
|
||||||
|
clearEditor: () => void;
|
||||||
|
setEditorValue: (content: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RichTextEditorWrapperProps
|
||||||
|
extends Omit<
|
||||||
|
IRichTextEditor,
|
||||||
|
"uploadFile" | "deleteFile" | "restoreFile" | "mentionSuggestions" | "mentionHighlights"
|
||||||
|
> {
|
||||||
|
workspaceSlug: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileService = new FileService();
|
||||||
|
|
||||||
|
export const RichTextEditor = React.forwardRef<EditorHandle, RichTextEditorWrapperProps>(
|
||||||
|
({ workspaceSlug, ...props }, ref) => {
|
||||||
|
const editorSuggestions = useMention();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RichTextEditorWithRef
|
||||||
|
ref={ref}
|
||||||
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||||
|
deleteFile={fileService.deleteImage}
|
||||||
|
restoreFile={fileService.restoreImage}
|
||||||
|
mentionSuggestions={editorSuggestions.mentionSuggestions}
|
||||||
|
mentionHighlights={editorSuggestions.mentionHighlights}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
RichTextEditor.displayName = "RichTextEditor";
|
@ -12,7 +12,7 @@ import { AIService } from "services/ai.service";
|
|||||||
// components
|
// components
|
||||||
import { GptAssistantPopover } from "components/core";
|
import { GptAssistantPopover } from "components/core";
|
||||||
import { PriorityDropdown } from "components/dropdowns";
|
import { PriorityDropdown } from "components/dropdowns";
|
||||||
import { RichTextEditor } from "components/editor/rich-text-wrapper";
|
import { RichTextEditor } from "components/editor/rich-text-editor";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input, ToggleSwitch } from "@plane/ui";
|
import { Button, Input, ToggleSwitch } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
// hooks
|
|
||||||
import { useMention } from "hooks/store";
|
|
||||||
// services
|
|
||||||
import { FileService } from "services/file.service";
|
|
||||||
// components
|
// components
|
||||||
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
import { LiteTextEditor } from "components/editor/lite-text-editor";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
import { Globe2, Lock } from "lucide-react";
|
import { Globe2, Lock } from "lucide-react";
|
||||||
@ -42,17 +38,12 @@ const commentAccess: commentAccessType[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// services
|
|
||||||
const fileService = new FileService();
|
|
||||||
|
|
||||||
export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAccessSpecifier = false }) => {
|
export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAccessSpecifier = false }) => {
|
||||||
// refs
|
// refs
|
||||||
const editorRef = React.useRef<any>(null);
|
const editorRef = React.useRef<any>(null);
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store hooks
|
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -82,25 +73,19 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAc
|
|||||||
name="comment_html"
|
name="comment_html"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
|
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
|
||||||
<LiteTextEditorWithRef
|
<LiteTextEditor
|
||||||
|
workspaceSlug={workspaceSlug as string}
|
||||||
onEnterKeyPress={handleSubmit(handleAddComment)}
|
onEnterKeyPress={handleSubmit(handleAddComment)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
|
||||||
deleteFile={fileService.deleteImage}
|
|
||||||
restoreFile={fileService.restoreImage}
|
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||||
customClassName="p-2 h-full"
|
customClassName="p-2 h-full"
|
||||||
editorContentCustomClassNames="min-h-[35px]"
|
editorContentCustomClassNames="min-h-[35px]"
|
||||||
debouncedUpdatesEnabled={false}
|
|
||||||
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
||||||
commentAccessSpecifier={
|
commentAccessSpecifier={
|
||||||
showAccessSpecifier
|
showAccessSpecifier
|
||||||
? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess }
|
? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess }
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
mentionSuggestions={mentionSuggestions}
|
|
||||||
mentionHighlights={mentionHighlights}
|
|
||||||
submitButton={
|
submitButton={
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
@ -2,23 +2,20 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useMention, useUser } from "hooks/store";
|
import { useUser } from "hooks/store";
|
||||||
// services
|
|
||||||
import { FileService } from "services/file.service";
|
|
||||||
// icons
|
// icons
|
||||||
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
|
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu } from "@plane/ui";
|
import { CustomMenu } from "@plane/ui";
|
||||||
import { CommentReaction } from "components/issues";
|
import { CommentReaction } from "components/issues";
|
||||||
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
// components
|
||||||
|
import { LiteTextEditor } from "components/editor/lite-text-editor";
|
||||||
|
import { LiteTextReadOnlyEditor } from "components/editor/lite-text-read-only-editor";
|
||||||
// helpers
|
// helpers
|
||||||
import { calculateTimeAgo } from "helpers/date-time.helper";
|
import { calculateTimeAgo } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import type { IIssueActivity } from "@plane/types";
|
import type { IIssueActivity } from "@plane/types";
|
||||||
|
|
||||||
// services
|
|
||||||
const fileService = new FileService();
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
comment: IIssueActivity;
|
comment: IIssueActivity;
|
||||||
handleCommentDeletion: (comment: string) => void;
|
handleCommentDeletion: (comment: string) => void;
|
||||||
@ -36,7 +33,6 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
|||||||
const showEditorRef = React.useRef<any>(null);
|
const showEditorRef = React.useRef<any>(null);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting },
|
||||||
@ -97,19 +93,14 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
|||||||
<div className="issue-comments-section p-0">
|
<div className="issue-comments-section p-0">
|
||||||
<form className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
|
<form className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
|
||||||
<div>
|
<div>
|
||||||
<LiteTextEditorWithRef
|
<LiteTextEditor
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
onEnterKeyPress={handleSubmit(onEnter)}
|
onEnterKeyPress={handleSubmit(onEnter)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
|
||||||
deleteFile={fileService.deleteImage}
|
|
||||||
restoreFile={fileService.restoreImage}
|
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={watch("comment_html") ?? ""}
|
value={watch("comment_html") ?? ""}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
customClassName="min-h-[50px] p-3 shadow-sm"
|
customClassName="min-h-[50px] p-3 shadow-sm"
|
||||||
onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)}
|
onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)}
|
||||||
mentionSuggestions={mentionSuggestions}
|
|
||||||
mentionHighlights={mentionHighlights}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-1 self-end">
|
<div className="flex gap-1 self-end">
|
||||||
@ -136,11 +127,10 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
|||||||
{comment.access === "INTERNAL" ? <Lock className="h-3 w-3" /> : <Globe2 className="h-3 w-3" />}
|
{comment.access === "INTERNAL" ? <Lock className="h-3 w-3" /> : <Globe2 className="h-3 w-3" />}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<LiteReadOnlyEditorWithRef
|
<LiteTextReadOnlyEditor
|
||||||
ref={showEditorRef}
|
ref={showEditorRef}
|
||||||
value={comment.comment_html ?? ""}
|
value={comment.comment_html ?? ""}
|
||||||
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
||||||
mentionHighlights={mentionHighlights}
|
|
||||||
/>
|
/>
|
||||||
<CommentReaction projectId={comment.project} commentId={comment.id} />
|
<CommentReaction projectId={comment.project} commentId={comment.id} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,7 +5,7 @@ import useReloadConfirmations from "hooks/use-reload-confirmation";
|
|||||||
import debounce from "lodash/debounce";
|
import debounce from "lodash/debounce";
|
||||||
// components
|
// components
|
||||||
import { TextArea } from "@plane/ui";
|
import { TextArea } from "@plane/ui";
|
||||||
import { RichTextEditor } from "components/editor/rich-text-wrapper";
|
import { RichTextEditor } from "components/editor/rich-text-editor";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { TIssueOperations } from "./issue-detail";
|
import { TIssueOperations } from "./issue-detail";
|
||||||
|
@ -25,7 +25,7 @@ import { ParentIssuesListModal } from "components/issues";
|
|||||||
import { IssueLabelSelect } from "components/issues/select";
|
import { IssueLabelSelect } from "components/issues/select";
|
||||||
import { CreateLabelModal } from "components/labels";
|
import { CreateLabelModal } from "components/labels";
|
||||||
import { CreateStateModal } from "components/states";
|
import { CreateStateModal } from "components/states";
|
||||||
import { RichTextEditor } from "components/editor/rich-text-wrapper";
|
import { RichTextEditor } from "components/editor/rich-text-editor";
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomMenu, Input, ToggleSwitch } from "@plane/ui";
|
import { Button, CustomMenu, Input, ToggleSwitch } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
|
@ -9,7 +9,7 @@ import useToast from "hooks/use-toast";
|
|||||||
// services
|
// services
|
||||||
import { AIService } from "services/ai.service";
|
import { AIService } from "services/ai.service";
|
||||||
// components
|
// components
|
||||||
import { RichTextEditor } from "components/editor/rich-text-wrapper";
|
import { RichTextEditor } from "components/editor/rich-text-editor";
|
||||||
import { GptAssistantPopover } from "components/core";
|
import { GptAssistantPopover } from "components/core";
|
||||||
import {
|
import {
|
||||||
CycleDropdown,
|
CycleDropdown,
|
||||||
|
@ -1,23 +1,17 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
|
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
|
||||||
// hooks
|
|
||||||
import { useMention } from "hooks/store";
|
|
||||||
// services
|
|
||||||
import { FileService } from "services/file.service";
|
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu } from "@plane/ui";
|
import { CustomMenu } from "@plane/ui";
|
||||||
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
|
||||||
// components
|
// components
|
||||||
import { IssueCommentReaction } from "./comment-reaction";
|
import { IssueCommentReaction } from "./comment-reaction";
|
||||||
|
import { LiteTextReadOnlyEditor } from "components/editor/lite-text-read-only-editor";
|
||||||
|
import { LiteTextEditor } from "components/editor/lite-text-editor";
|
||||||
// helpers
|
// helpers
|
||||||
import { calculateTimeAgo } from "helpers/date-time.helper";
|
import { calculateTimeAgo } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import type { IIssueActivity, IUser } from "@plane/types";
|
import type { IIssueActivity, IUser } from "@plane/types";
|
||||||
|
|
||||||
// services
|
|
||||||
const fileService = new FileService();
|
|
||||||
|
|
||||||
type IIssueCommentCard = {
|
type IIssueCommentCard = {
|
||||||
comment: IIssueActivity;
|
comment: IIssueActivity;
|
||||||
handleCommentDeletion: (comment: string) => void;
|
handleCommentDeletion: (comment: string) => void;
|
||||||
@ -49,8 +43,6 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||||||
// refs
|
// refs
|
||||||
const editorRef = React.useRef<any>(null);
|
const editorRef = React.useRef<any>(null);
|
||||||
const showEditorRef = React.useRef<any>(null);
|
const showEditorRef = React.useRef<any>(null);
|
||||||
// store hooks
|
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting },
|
||||||
@ -113,19 +105,14 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||||||
<div className="issue-comments-section p-0">
|
<div className="issue-comments-section p-0">
|
||||||
<div className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
|
<div className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
|
||||||
<div>
|
<div>
|
||||||
<LiteTextEditorWithRef
|
<LiteTextEditor
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
onEnterKeyPress={handleSubmit(formSubmit)}
|
onEnterKeyPress={handleSubmit(formSubmit)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
|
||||||
deleteFile={fileService.deleteImage}
|
|
||||||
restoreFile={fileService.restoreImage}
|
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={watch("comment_html") ?? ""}
|
value={watch("comment_html") ?? ""}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
customClassName="min-h-[50px] p-3 shadow-sm"
|
customClassName="min-h-[50px] p-3 shadow-sm"
|
||||||
onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)}
|
onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)}
|
||||||
mentionSuggestions={mentionSuggestions}
|
|
||||||
mentionHighlights={mentionHighlights}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-1 self-end">
|
<div className="flex gap-1 self-end">
|
||||||
@ -154,13 +141,11 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||||||
{comment.access === "INTERNAL" ? <Lock className="h-3 w-3" /> : <Globe2 className="h-3 w-3" />}
|
{comment.access === "INTERNAL" ? <Lock className="h-3 w-3" /> : <Globe2 className="h-3 w-3" />}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<LiteReadOnlyEditorWithRef
|
<LiteTextReadOnlyEditor
|
||||||
ref={showEditorRef}
|
ref={showEditorRef}
|
||||||
value={comment.comment_html ?? ""}
|
value={comment.comment_html ?? ""}
|
||||||
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
|
||||||
mentionHighlights={mentionHighlights}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
<IssueCommentReaction
|
<IssueCommentReaction
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
|
@ -2,12 +2,8 @@ import React from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { Globe2, Lock } from "lucide-react";
|
import { Globe2, Lock } from "lucide-react";
|
||||||
// hooks
|
|
||||||
import { useMention } from "hooks/store";
|
|
||||||
// services
|
|
||||||
import { FileService } from "services/file.service";
|
|
||||||
// components
|
// components
|
||||||
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
import { LiteTextEditor } from "components/editor/lite-text-editor";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
@ -42,9 +38,6 @@ const commentAccess: commentAccessType[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// services
|
|
||||||
const fileService = new FileService();
|
|
||||||
|
|
||||||
export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
||||||
const { disabled = false, onSubmit, showAccessSpecifier = false } = props;
|
const { disabled = false, onSubmit, showAccessSpecifier = false } = props;
|
||||||
// refs
|
// refs
|
||||||
@ -52,8 +45,6 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store hooks
|
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -83,19 +74,13 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
name="comment_html"
|
name="comment_html"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
|
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
|
||||||
<LiteTextEditorWithRef
|
<LiteTextEditor
|
||||||
|
workspaceSlug={workspaceSlug as string}
|
||||||
onEnterKeyPress={handleSubmit(handleAddComment)}
|
onEnterKeyPress={handleSubmit(handleAddComment)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
|
||||||
deleteFile={fileService.deleteImage}
|
|
||||||
restoreFile={fileService.restoreImage}
|
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||||
customClassName="p-2 h-full"
|
customClassName="p-2 h-full"
|
||||||
editorContentCustomClassNames="min-h-[35px]"
|
editorContentCustomClassNames="min-h-[35px]"
|
||||||
debouncedUpdatesEnabled={false}
|
|
||||||
mentionSuggestions={mentionSuggestions}
|
|
||||||
mentionHighlights={mentionHighlights}
|
|
||||||
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
||||||
commentAccessSpecifier={
|
commentAccessSpecifier={
|
||||||
showAccessSpecifier
|
showAccessSpecifier
|
||||||
|
@ -5,7 +5,7 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
import { useProject, useUser } from "hooks/store";
|
import { useProject, useUser } from "hooks/store";
|
||||||
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
||||||
// components
|
// components
|
||||||
import { RichTextEditor } from "components/editor/rich-text-wrapper";
|
import { RichTextEditor } from "components/editor/rich-text-editor";
|
||||||
import { IssuePeekOverviewReactions } from "components/issues";
|
import { IssuePeekOverviewReactions } from "components/issues";
|
||||||
// ui
|
// ui
|
||||||
import { TextArea } from "@plane/ui";
|
import { TextArea } from "@plane/ui";
|
||||||
|
Loading…
Reference in New Issue
Block a user