diff --git a/packages/editor/src/ee/helpers/parser.ts b/packages/editor/src/ee/helpers/parser.ts
new file mode 100644
index 0000000000..18b6e9f303
--- /dev/null
+++ b/packages/editor/src/ee/helpers/parser.ts
@@ -0,0 +1,46 @@
+/**
+ * @description function to extract all additional assets from HTML content
+ * @param htmlContent
+ * @returns {string[]} array of additional asset sources
+ */
+export const extractAdditionalAssetsFromHTMLContent = (htmlContent: string): string[] => {
+ // create a DOM parser
+ const parser = new DOMParser();
+ // parse the HTML string into a DOM document
+ const doc = parser.parseFromString(htmlContent, "text/html");
+ // collect all unique asset sources
+ const assetSources = new Set();
+ // extract sources from attachment components
+ const attachmentComponents = doc.querySelectorAll("attachment-component");
+ attachmentComponents.forEach((component) => {
+ const src = component.getAttribute("src");
+ if (src) assetSources.add(src);
+ });
+ return Array.from(assetSources);
+};
+
+/**
+ * @description function to replace additional assets in HTML content with new IDs
+ * @param props
+ * @returns {string} HTML content with replaced additional assets
+ */
+export const replaceAdditionalAssetsInHTMLContent = (props: {
+ htmlContent: string;
+ assetMap: Record;
+}): string => {
+ const { htmlContent, assetMap } = props;
+ // create a DOM parser
+ const parser = new DOMParser();
+ // parse the HTML string into a DOM document
+ const doc = parser.parseFromString(htmlContent, "text/html");
+ // replace sources in attachment components
+ const attachmentComponents = doc.querySelectorAll("attachment-component");
+ attachmentComponents.forEach((component) => {
+ const oldSrc = component.getAttribute("src");
+ if (oldSrc && assetMap[oldSrc]) {
+ component.setAttribute("src", assetMap[oldSrc]);
+ }
+ });
+ // serialize the document back into a string
+ return doc.body.innerHTML;
+};
diff --git a/web/ee/components/epics/peek-overview/view.tsx b/web/ee/components/epics/peek-overview/view.tsx
index 84d31ab187..c1e9aee6b6 100644
--- a/web/ee/components/epics/peek-overview/view.tsx
+++ b/web/ee/components/epics/peek-overview/view.tsx
@@ -1,17 +1,19 @@
import { FC, useRef, useState } from "react";
import { observer } from "mobx-react";
+// plane imports
import { EIssueServiceType } from "@plane/constants";
+import { cn } from "@plane/utils";
+// components
import { TIssueOperations } from "@/components/issues";
-// helpers
-import { cn } from "@plane/utils";
// hooks
import { useIssueDetail } from "@/hooks/store";
import useKeypress from "@/hooks/use-keypress";
import usePeekOverviewOutsideClickDetector from "@/hooks/use-peek-overview-outside-click";
-// local components
+// plane web imports
import { useCustomers } from "@/plane-web/hooks/store";
import { useEpics } from "@/plane-web/hooks/store/epics/use-epics";
import { useInitiatives } from "@/plane-web/hooks/store/use-initiatives";
+// local imports
import { EpicDetailRoot } from "../details/root";
import { EpicPeekOverviewError } from "./error";
import { EpicPeekOverviewHeader, TPeekModes } from "./header";
@@ -95,8 +97,9 @@ export const EpicView: FC = observer((props) => {
const handleKeyDown = () => {
const slashCommandDropdownElement = document.querySelector("#slash-command");
+ const editorImageFullScreenModalElement = document.querySelector(".editor-image-full-screen-modal");
const dropdownElement = document.activeElement?.tagName === "INPUT";
- if (!isAnyModalOpen && !slashCommandDropdownElement && !dropdownElement) {
+ if (!isAnyModalOpen && !slashCommandDropdownElement && !dropdownElement && !editorImageFullScreenModalElement) {
removeRoutePeekId();
const issueElement = document.getElementById(`issue-${issueId}`);
if (issueElement) issueElement?.focus();
diff --git a/web/ee/components/pages/modals/template-select-modal.tsx b/web/ee/components/pages/modals/template-select-modal.tsx
index cbeaa4bddc..39c362ab3c 100644
--- a/web/ee/components/pages/modals/template-select-modal.tsx
+++ b/web/ee/components/pages/modals/template-select-modal.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { Check, Search, Shapes } from "lucide-react";
import { Combobox } from "@headlessui/react";
// plane imports
-import { EditorTitleRefApi, getEditorContentWithReplacedImageAssets } from "@plane/editor";
+import { EditorTitleRefApi, getEditorContentWithReplacedAssets } from "@plane/editor";
import { useTranslation } from "@plane/i18n";
import { FileService } from "@plane/services";
import { TPageTemplate } from "@plane/types";
@@ -68,7 +68,7 @@ export const TemplateSelectModal: React.FC = observer
setIsApplyingTemplate(true);
// duplicate template assets and replace the old assets with the new ones
const duplicateAssetService = fileService.duplicateAssets.bind(fileService, workspaceSlug);
- const documentPayload = await getEditorContentWithReplacedImageAssets({
+ const documentPayload = await getEditorContentWithReplacedAssets({
descriptionHTML: selectedTemplate.template_data.description_html ?? "",
entityId: page.id,
entityType: EFileAssetType.PAGE_DESCRIPTION,
diff --git a/web/ee/components/templates/settings/list/action-wrapper.tsx b/web/ee/components/templates/settings/list/action-wrapper.tsx
index ee529fc90b..197e052338 100644
--- a/web/ee/components/templates/settings/list/action-wrapper.tsx
+++ b/web/ee/components/templates/settings/list/action-wrapper.tsx
@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { observer } from "mobx-react";
// plane imports
import { EIssuesStoreType, ETemplateLevel, ETemplateType } from "@plane/constants";
-import { getEditorContentWithReplacedImageAssets } from "@plane/editor";
+import { getEditorContentWithReplacedAssets } from "@plane/editor";
import { useTranslation } from "@plane/i18n";
import { FileService } from "@plane/services";
import { TPage } from "@plane/types";
@@ -107,7 +107,7 @@ export const TemplateListActionWrapper = observer((props: TTemplateListActionWra
// duplicate the assets
const duplicateAssetService = fileService.duplicateAssets.bind(fileService, workspaceSlug);
- const documentPayload = await getEditorContentWithReplacedImageAssets({
+ const documentPayload = await getEditorContentWithReplacedAssets({
descriptionHTML: pageData.description_html ?? "",
entityId: page.id,
entityType: EFileAssetType.PAGE_DESCRIPTION,
diff --git a/web/ee/components/templates/settings/publish/form/basic-details.tsx b/web/ee/components/templates/settings/publish/form/basic-details.tsx
index 792cb291a2..06af633a12 100644
--- a/web/ee/components/templates/settings/publish/form/basic-details.tsx
+++ b/web/ee/components/templates/settings/publish/form/basic-details.tsx
@@ -135,13 +135,11 @@ export const TemplateBasicDetails = observer(
"}
- workspaceSlug={workspaceSlug}
+ workspaceSlug={workspaceSlug.toString()}
workspaceId={workspaceId}
- projectId={projectId ? projectId : undefined}
+ projectId={projectId ?? undefined}
ref={editorRef}
- onChange={(description_json: object, description_html: string) => {
- onChange(description_html);
- }}
+ onChange={(_description_json, description_html) => onChange(description_html)}
searchMentionCallback={searchEntity}
placeholder={(isFocused, value) =>
isEditorEmpty(value)
@@ -149,7 +147,7 @@ export const TemplateBasicDetails = observer(
: t(`${getDescriptionPlaceholderI18n(isFocused, value)}`)
}
containerClassName="min-h-[240px] md:min-h-[120px] border-[0.5px] py-2 border-custom-border-200 rounded-md"
- disabledExtensions={["image", "issue-embed"]}
+ disabledExtensions={["image", "issue-embed", "attachments"]}
uploadFile={() => Promise.resolve("")}
/>
)}
diff --git a/web/ee/components/templates/settings/work-item/form/work-item-details.tsx b/web/ee/components/templates/settings/work-item/form/work-item-details.tsx
index 96c3eb6060..310407f76e 100644
--- a/web/ee/components/templates/settings/work-item/form/work-item-details.tsx
+++ b/web/ee/components/templates/settings/work-item/form/work-item-details.tsx
@@ -106,21 +106,19 @@ export const WorkItemDetails = observer((props: TWorkItemDetailsProps) => {
"}
- workspaceSlug={workspaceSlug as string}
+ workspaceSlug={workspaceSlug.toString()}
workspaceId={workspaceId}
- projectId={projectId ? projectId : undefined}
+ projectId={projectId ?? undefined}
ref={editorRef}
searchMentionCallback={searchEntity}
- onChange={(description_json: object, description_html: string) => {
- onChange(description_html);
- }}
+ onChange={(_description_json, description_html) => onChange(description_html)}
placeholder={(isFocused, value) =>
isEditorEmpty(value)
? t("templates.settings.form.work_item.description.placeholder")
: t(`${getDescriptionPlaceholderI18n(isFocused, value)}`)
}
containerClassName="min-h-[80px] px-0"
- disabledExtensions={["image"]}
+ disabledExtensions={["image", "attachments"]}
uploadFile={async (blockId, file) => {
try {
const { asset_id } = await uploadEditorAsset({