mirror of
https://github.com/makeplane/plane.git
synced 2026-01-25 07:38:46 -06:00
[WEB-2348] fix: allow updating comments with just mentions in them (#5471)
* fix: accept mentions while updating comments * chore: remove console log * chore: update empty string helper function
This commit is contained in:
committed by
GitHub
parent
03c28a11e8
commit
bac5b53ffb
@@ -5,7 +5,7 @@ import { EditorRefApi, ILiteTextEditor, LiteTextEditorWithRef } from "@plane/edi
|
||||
import { IssueCommentToolbar } from "@/components/editor";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { isEmptyHtmlString } from "@/helpers/string.helper";
|
||||
import { isCommentEmpty } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useMention } from "@/hooks/use-mention";
|
||||
// services
|
||||
@@ -33,10 +33,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
|
||||
function isMutableRefObject<T>(ref: React.ForwardedRef<T>): ref is React.MutableRefObject<T | null> {
|
||||
return !!ref && typeof ref === "object" && "current" in ref;
|
||||
}
|
||||
const isEmpty =
|
||||
props.initialValue?.trim() === "" ||
|
||||
props.initialValue === "<p></p>" ||
|
||||
(isEmptyHtmlString(props.initialValue ?? "") && !props.initialValue?.includes("mention-component"));
|
||||
const isEmpty = isCommentEmpty(props.initialValue);
|
||||
|
||||
return (
|
||||
<div className="border border-custom-border-200 rounded p-3 space-y-3">
|
||||
|
||||
@@ -50,13 +50,29 @@ export const checkEmailValidity = (email: string): boolean => {
|
||||
return isEmailValid;
|
||||
};
|
||||
|
||||
export const isEmptyHtmlString = (htmlString: string) => {
|
||||
export const isEmptyHtmlString = (htmlString: string, allowedHTMLTags: string[] = []) => {
|
||||
// Remove HTML tags using regex
|
||||
const cleanText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: ["img"] });
|
||||
const cleanText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: allowedHTMLTags });
|
||||
// Trim the string and check if it's empty
|
||||
return cleanText.trim() === "";
|
||||
};
|
||||
|
||||
/**
|
||||
* @description this function returns whether a comment is empty or not by checking for the following conditions-
|
||||
* 1. If comment is undefined
|
||||
* 2. If comment is an empty string
|
||||
* 3. If comment is "<p></p>"
|
||||
* @param {string | undefined} comment
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isCommentEmpty = (comment: string | undefined): boolean => {
|
||||
// return true if comment is undefined
|
||||
if (!comment) return true;
|
||||
return (
|
||||
comment?.trim() === "" || comment === "<p></p>" || isEmptyHtmlString(comment ?? "", ["img", "mention-component"])
|
||||
);
|
||||
};
|
||||
|
||||
export const replaceUnderscoreIfSnakeCase = (str: string) => str.replace(/_/g, " ");
|
||||
|
||||
export const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||
export const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IssueCommentToolbar } from "@/components/editor";
|
||||
import { EIssueCommentAccessSpecifier } from "@/constants/issue";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { isEmptyHtmlString } from "@/helpers/string.helper";
|
||||
import { isCommentEmpty } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useMember, useMention, useUser } from "@/hooks/store";
|
||||
// services
|
||||
@@ -59,10 +59,7 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
|
||||
user: currentUser ?? undefined,
|
||||
});
|
||||
|
||||
const isEmpty =
|
||||
props.initialValue?.trim() === "" ||
|
||||
props.initialValue === "<p></p>" ||
|
||||
(isEmptyHtmlString(props.initialValue ?? "") && !props.initialValue?.includes("mention-component"));
|
||||
const isEmpty = isCommentEmpty(props.initialValue);
|
||||
|
||||
function isMutableRefObject<T>(ref: React.ForwardedRef<T>): ref is React.MutableRefObject<T | null> {
|
||||
return !!ref && typeof ref === "object" && "current" in ref;
|
||||
|
||||
@@ -13,7 +13,7 @@ import { LiteTextEditor, LiteTextReadOnlyEditor } from "@/components/editor";
|
||||
// constants
|
||||
import { EIssueCommentAccessSpecifier } from "@/constants/issue";
|
||||
// helpers
|
||||
import { isEmptyHtmlString } from "@/helpers/string.helper";
|
||||
import { isCommentEmpty } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useIssueDetail, useUser, useWorkspace } from "@/hooks/store";
|
||||
// components
|
||||
@@ -80,10 +80,8 @@ export const IssueCommentCard: FC<TIssueCommentCard> = observer((props) => {
|
||||
isEditing && setFocus("comment_html");
|
||||
}, [isEditing, setFocus]);
|
||||
|
||||
const isEmpty =
|
||||
watch("comment_html")?.trim() === "" ||
|
||||
watch("comment_html") === "<p></p>" ||
|
||||
isEmptyHtmlString(watch("comment_html") ?? "");
|
||||
const commentHTML = watch("comment_html");
|
||||
const isEmpty = isCommentEmpty(commentHTML);
|
||||
|
||||
if (!comment || !currentUser) return <></>;
|
||||
return (
|
||||
@@ -148,7 +146,7 @@ export const IssueCommentCard: FC<TIssueCommentCard> = observer((props) => {
|
||||
workspaceSlug={workspaceSlug}
|
||||
ref={editorRef}
|
||||
id={comment.id}
|
||||
initialValue={watch("comment_html") ?? ""}
|
||||
initialValue={commentHTML ?? ""}
|
||||
value={null}
|
||||
onChange={(comment_json, comment_html) => setValue("comment_html", comment_html)}
|
||||
onEnterKeyPress={(e) => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { LiteTextEditor } from "@/components/editor/lite-text-editor/lite-text-e
|
||||
import { EIssueCommentAccessSpecifier } from "@/constants/issue";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { isEmptyHtmlString } from "@/helpers/string.helper";
|
||||
import { isCommentEmpty } from "@/helpers/string.helper";
|
||||
// hooks
|
||||
import { useIssueDetail, useWorkspace } from "@/hooks/store";
|
||||
// editor
|
||||
@@ -53,10 +53,7 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
||||
});
|
||||
|
||||
const commentHTML = watch("comment_html");
|
||||
const isEmpty =
|
||||
commentHTML?.trim() === "" ||
|
||||
commentHTML === "<p></p>" ||
|
||||
(isEmptyHtmlString(commentHTML ?? "") && !commentHTML?.includes("mention-component"));
|
||||
const isEmpty = isCommentEmpty(commentHTML);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -74,7 +74,7 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
|
||||
if (
|
||||
issueKey === "description_html" &&
|
||||
changesMade.description_html &&
|
||||
isEmptyHtmlString(changesMade.description_html)
|
||||
isEmptyHtmlString(changesMade.description_html, ["img"])
|
||||
)
|
||||
delete changesMade.description_html;
|
||||
});
|
||||
|
||||
@@ -230,9 +230,23 @@ export const checkEmailValidity = (email: string): boolean => {
|
||||
return isEmailValid;
|
||||
};
|
||||
|
||||
export const isEmptyHtmlString = (htmlString: string) => {
|
||||
export const isEmptyHtmlString = (htmlString: string, allowedHTMLTags: string[] = []) => {
|
||||
// Remove HTML tags using regex
|
||||
const cleanText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: ["img"] });
|
||||
const cleanText = DOMPurify.sanitize(htmlString, { ALLOWED_TAGS: allowedHTMLTags });
|
||||
// Trim the string and check if it's empty
|
||||
return cleanText.trim() === "";
|
||||
};
|
||||
|
||||
/**
|
||||
* @description this function returns whether a comment is empty or not by checking for the following conditions-
|
||||
* 1. If comment is undefined
|
||||
* 2. If comment is an empty string
|
||||
* 3. If comment is "<p></p>"
|
||||
* @param {string | undefined} comment
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isCommentEmpty = (comment: string | undefined): boolean => {
|
||||
// return true if comment is undefined
|
||||
if (!comment) return true;
|
||||
return comment?.trim() === "" || comment === "<p></p>" || isEmptyHtmlString(comment ?? "", ["mention-component"]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user