✨ feat(SanitizedDiv): add a new component to sanitize and render HTML content safely
🔨 refactor(chatMessage): replace the usage of DOMPurify with SanitizedHTMLWrapper component in chatMessage component 🔨 refactor(formModal): replace the usage of DOMPurify with SanitizedHTMLWrapper component in formModal component 🔨 refactor(genericModal): replace the usage of DOMPurify with SanitizedHTMLWrapper component in genericModal component
This commit is contained in:
parent
3896f894ac
commit
9a3e0d2891
4 changed files with 38 additions and 20 deletions
21
src/frontend/src/components/SanitizedDiv/index.tsx
Normal file
21
src/frontend/src/components/SanitizedDiv/index.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import DOMPurify from "dompurify";
|
||||||
|
|
||||||
|
const SanitizedHTMLWrapper = ({
|
||||||
|
className,
|
||||||
|
content,
|
||||||
|
onClick,
|
||||||
|
suppressWarning = false,
|
||||||
|
}) => {
|
||||||
|
const sanitizedHTML = DOMPurify.sanitize(content);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={className}
|
||||||
|
dangerouslySetInnerHTML={{ __html: sanitizedHTML }}
|
||||||
|
suppressContentEditableWarning={suppressWarning}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SanitizedHTMLWrapper;
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import Convert from "ansi-to-html";
|
import Convert from "ansi-to-html";
|
||||||
import DOMPurify from "dompurify";
|
|
||||||
import { MessageCircle, User2 } from "lucide-react";
|
import { MessageCircle, User2 } from "lucide-react";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
@ -8,6 +7,7 @@ import remarkGfm from "remark-gfm";
|
||||||
import remarkMath from "remark-math";
|
import remarkMath from "remark-math";
|
||||||
import AiIcon from "../../../assets/Gooey Ring-5s-271px.svg";
|
import AiIcon from "../../../assets/Gooey Ring-5s-271px.svg";
|
||||||
import AiIconStill from "../../../assets/froze-flow.png";
|
import AiIconStill from "../../../assets/froze-flow.png";
|
||||||
|
import SanitizedHTMLWrapper from "../../../components/SanitizedDiv";
|
||||||
import { ChatMessageType } from "../../../types/chat";
|
import { ChatMessageType } from "../../../types/chat";
|
||||||
import { classNames } from "../../../utils";
|
import { classNames } from "../../../utils";
|
||||||
import { CodeBlock } from "../../formModal/chatMessage/codeBlock";
|
import { CodeBlock } from "../../formModal/chatMessage/codeBlock";
|
||||||
|
|
@ -68,13 +68,12 @@ export default function ChatMessage({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{chat.thought && chat.thought !== "" && !hidden && (
|
{chat.thought && chat.thought !== "" && !hidden && (
|
||||||
<div
|
<SanitizedHTMLWrapper
|
||||||
onClick={() => setHidden((prev) => !prev)}
|
|
||||||
className=" chat-message-modal-thought"
|
className=" chat-message-modal-thought"
|
||||||
dangerouslySetInnerHTML={{
|
content={convert.toHtml(chat.thought)}
|
||||||
__html: DOMPurify.sanitize(convert.toHtml(chat.thought)),
|
suppressWarning={false}
|
||||||
}}
|
onClick={() => setHidden((prev) => !prev)}
|
||||||
></div>
|
/>
|
||||||
)}
|
)}
|
||||||
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
|
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
|
||||||
<div className="chat-message-modal-markdown">
|
<div className="chat-message-modal-markdown">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import Convert from "ansi-to-html";
|
import Convert from "ansi-to-html";
|
||||||
import DOMPurify from "dompurify";
|
|
||||||
import { ChevronDown } from "lucide-react";
|
import { ChevronDown } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
@ -8,6 +7,7 @@ import remarkGfm from "remark-gfm";
|
||||||
import remarkMath from "remark-math";
|
import remarkMath from "remark-math";
|
||||||
import MaleTechnology from "../../../assets/male-technologist.png";
|
import MaleTechnology from "../../../assets/male-technologist.png";
|
||||||
import Robot from "../../../assets/robot.png";
|
import Robot from "../../../assets/robot.png";
|
||||||
|
import SanitizedHTMLWrapper from "../../../components/SanitizedDiv";
|
||||||
import { THOUGHTS_ICON } from "../../../constants";
|
import { THOUGHTS_ICON } from "../../../constants";
|
||||||
import { ChatMessageType } from "../../../types/chat";
|
import { ChatMessageType } from "../../../types/chat";
|
||||||
import { classNames } from "../../../utils";
|
import { classNames } from "../../../utils";
|
||||||
|
|
@ -57,13 +57,11 @@ export default function ChatMessage({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{chat.thought && chat.thought !== "" && !hidden && (
|
{chat.thought && chat.thought !== "" && !hidden && (
|
||||||
<div
|
<SanitizedHTMLWrapper
|
||||||
|
className=" form-modal-chat-thought"
|
||||||
|
content={convert.toHtml(chat.thought)}
|
||||||
onClick={() => setHidden((prev) => !prev)}
|
onClick={() => setHidden((prev) => !prev)}
|
||||||
className=" form-modal-chat-thought "
|
/>
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: DOMPurify.sanitize(convert.toHtml(chat.thought)),
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
)}
|
)}
|
||||||
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
|
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import DOMPurify from "dompurify";
|
|
||||||
import { FileText, Variable } from "lucide-react";
|
import { FileText, Variable } from "lucide-react";
|
||||||
import { useContext, useEffect, useRef, useState } from "react";
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
|
import SanitizedHTMLWrapper from "../../components/SanitizedDiv";
|
||||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||||
import { Badge } from "../../components/ui/badge";
|
import { Badge } from "../../components/ui/badge";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
} from "../../components/ui/dialog";
|
} from "../../components/ui/dialog";
|
||||||
import { Textarea } from "../../components/ui/textarea";
|
import { Textarea } from "../../components/ui/textarea";
|
||||||
import {
|
import {
|
||||||
HIGHLIGH_CSS,
|
HIGHLIGHT_CSS,
|
||||||
PROMPT_DIALOG_SUBTITLE,
|
PROMPT_DIALOG_SUBTITLE,
|
||||||
TEXT_DIALOG_SUBTITLE,
|
TEXT_DIALOG_SUBTITLE,
|
||||||
} from "../../constants";
|
} from "../../constants";
|
||||||
|
|
@ -120,13 +120,13 @@ export default function GenericModal({
|
||||||
|
|
||||||
const TextAreaContentView = () => {
|
const TextAreaContentView = () => {
|
||||||
return (
|
return (
|
||||||
<div
|
<SanitizedHTMLWrapper
|
||||||
className={HIGHLIGH_CSS}
|
className={HIGHLIGHT_CSS}
|
||||||
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(coloredContent) }}
|
content={coloredContent}
|
||||||
suppressContentEditableWarning={true}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsEdit(true);
|
setIsEdit(true);
|
||||||
}}
|
}}
|
||||||
|
suppressWarning={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue