[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:
Aaryan Khandelwal
2024-09-02 14:00:41 +05:30
committed by GitHub
parent 03c28a11e8
commit bac5b53ffb
7 changed files with 46 additions and 27 deletions

View File

@@ -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">

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) => {

View File

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

View File

@@ -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;
});

View File

@@ -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"]);
};