refactored editor to not require workspace slug

This commit is contained in:
Palanikannan1437 2023-09-28 16:05:52 +05:30
parent d639a0126d
commit 4298b0500e
10 changed files with 63 additions and 62 deletions

View File

@ -6,7 +6,10 @@
"web",
"space",
"packages/editor/*",
"packages/*"
"packages/eslint-config-custom",
"packages/tailwind-config-custom",
"packages/tsconfig",
"packages/ui"
],
"scripts": {
"build": "turbo run build",

View File

@ -1 +1 @@
export type UploadImage = (workspaceSlug: string, formData: FormData) => Promise<any>;
export type UploadImage = (file: File) => Promise<string>;

View File

@ -32,7 +32,6 @@ import "highlight.js/styles/github-dark.css";
lowlight.registerLanguage("ts", ts);
export const TiptapExtensions = (
workspaceSlug: string,
uploadFile: UploadImage,
deleteFile: DeleteImage,
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
@ -126,7 +125,7 @@ export const TiptapExtensions = (
},
includeChildren: true,
}),
SlashCommand(workspaceSlug, uploadFile, setIsSubmitting),
SlashCommand(uploadFile, setIsSubmitting),
TiptapUnderline,
TextStyle,
Color,

View File

@ -59,7 +59,6 @@ const Command = Extension.create({
const getSuggestionItems =
(
workspaceSlug: string,
uploadFile: UploadImage,
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
) =>
@ -185,7 +184,7 @@ const getSuggestionItems =
if (input.files?.length) {
const file = input.files[0];
const pos = editor.view.state.selection.from;
startImageUpload(file, editor.view, pos, workspaceSlug, uploadFile, setIsSubmitting);
startImageUpload(file, editor.view, pos, uploadFile, setIsSubmitting);
}
};
input.click();
@ -351,13 +350,12 @@ const renderItems = () => {
};
export const SlashCommand = (
workspaceSlug: string,
uploadFile: UploadImage,
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
) =>
Command.configure({
suggestion: {
items: getSuggestionItems(workspaceSlug, uploadFile, setIsSubmitting),
items: getSuggestionItems(uploadFile, setIsSubmitting),
render: renderItems,
},
});

View File

@ -24,7 +24,6 @@ interface ITiptapEditor {
onChange?: (json: any, html: string) => void;
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void;
setShouldShowAlert?: (showAlert: boolean) => void;
workspaceSlug: string;
editable?: boolean;
forwardedRef?: any;
debouncedUpdatesEnabled?: boolean;
@ -59,7 +58,6 @@ const TiptapEditor = ({
uploadFile,
deleteFile,
noBorder,
workspaceSlug,
borderOnFocus,
customClassName,
forwardedRef,
@ -69,9 +67,9 @@ const TiptapEditor = ({
}: TiptapProps) => {
const editor = useEditor({
editable: editable ?? true,
editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting),
editorProps: TiptapEditorProps(uploadFile, setIsSubmitting),
// @ts-expect-err
extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting),
extensions: TiptapExtensions(uploadFile, deleteFile, setIsSubmitting),
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
onUpdate: async ({ editor }) => {
// for instant feedback loop

View File

@ -57,7 +57,6 @@ export async function startImageUpload(
file: File,
view: EditorView,
pos: number,
workspaceSlug: string,
uploadFile: UploadImage,
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
) {
@ -83,11 +82,8 @@ export async function startImageUpload(
view.dispatch(tr);
};
if (!workspaceSlug) {
return;
}
setIsSubmitting?.("submitting");
const src = await UploadImageHandler(file, workspaceSlug, uploadFile);
const src = await UploadImageHandler(file, uploadFile);
const { schema } = view.state;
pos = findPlaceholder(view.state, id);
@ -101,21 +97,13 @@ export async function startImageUpload(
view.dispatch(transaction);
}
const UploadImageHandler = (file: File, workspaceSlug: string,
const UploadImageHandler = (file: File,
uploadFile: UploadImage
): Promise<string> => {
if (!workspaceSlug) {
return Promise.reject("Workspace slug is missing");
}
try {
const formData = new FormData();
formData.append("asset", file);
formData.append("attributes", JSON.stringify({}));
return new Promise(async (resolve, reject) => {
try {
const imageUrl = await uploadFile(workspaceSlug, formData)
.then((response: { asset: string }) => response.asset);
const imageUrl = await uploadFile(file)
const image = new Image();
image.src = imageUrl;

View File

@ -4,7 +4,6 @@ import { startImageUpload } from "@/ui/plugins/upload-image";
import { UploadImage } from "@/types/upload-image";
export function TiptapEditorProps(
workspaceSlug: string,
uploadFile: UploadImage,
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
): EditorProps {
@ -37,7 +36,7 @@ export function TiptapEditorProps(
event.preventDefault();
const file = event.clipboardData.files[0];
const pos = view.state.selection.from;
startImageUpload(file, view, pos, workspaceSlug, uploadFile, setIsSubmitting);
startImageUpload(file, view, pos, uploadFile, setIsSubmitting);
return true;
}
return false;
@ -61,7 +60,7 @@ export function TiptapEditorProps(
});
// here we deduct 1 from the pos or else the image will create an extra node
if (coordinates) {
startImageUpload(file, view, coordinates.pos - 1, workspaceSlug, uploadFile, setIsSubmitting);
startImageUpload(file, view, coordinates.pos - 1, uploadFile, setIsSubmitting);
}
return true;
}

View File

@ -1,35 +1,35 @@
import {
useEditor as useEditorCore,
} from "@tiptap/react";
useEditor as useEditorCore,
} from "@tiptap/react";
import { findTableAncestor } from "@/lib/utils";
export const useEditor = (props: any) => useEditorCore({
editorProps: {
attributes: {
class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`,
},
handleDOMEvents: {
keydown: (_view, event) => {
// prevent default event listeners from firing when slash command is active
if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
const slashCommand = document.querySelector("#slash-command");
if (slashCommand) {
return true;
}
}
},
},
handlePaste: () => {
if (typeof window !== "undefined") {
const selection: any = window?.getSelection();
if (selection.rangeCount !== 0) {
const range = selection.getRangeAt(0);
if (findTableAncestor(range.startContainer)) {
return;
}
}
editorProps: {
attributes: {
class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`,
},
handleDOMEvents: {
keydown: (_view, event) => {
// prevent default event listeners from firing when slash command is active
if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
const slashCommand = document.querySelector("#slash-command");
if (slashCommand) {
return true;
}
},
}
},
...props,
});
},
handlePaste: () => {
if (typeof window !== "undefined") {
const selection: any = window?.getSelection();
if (selection.rangeCount !== 0) {
const range = selection.getRangeAt(0);
if (findTableAncestor(range.startContainer)) {
return;
}
}
}
},
},
...props,
});

View File

@ -135,10 +135,9 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
return (
<TiptapEditor
uploadFile={fileService.uploadFile}
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
deleteFile={fileService.deleteImage}
value={value}
workspaceSlug={workspaceSlug}
debouncedUpdatesEnabled={true}
setShouldShowAlert={setShowAlert}
setIsSubmitting={setIsSubmitting}

View File

@ -34,13 +34,29 @@ class FileService extends APIService {
}
async uploadFile(workspaceSlug: string, file: FormData): Promise<any> {
return this.mediaUpload(`/api/workspaces/${workspaceSlug}/file-assets/`, file)
return this.post(`/api/workspaces/${workspaceSlug}/file-assets/`, file, {
headers: {
...this.getHeaders(),
"Content-Type": "multipart/form-data",
},
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
getUploadFileFunction(workspaceSlug: string): (file: File) => Promise<string> {
return async (file: File) => {
const formData = new FormData();
formData.append("asset", file);
formData.append("attributes", JSON.stringify({}));
const data = await this.uploadFile(workspaceSlug, formData);
return data.asset;
};
}
async deleteImage(assetUrlWithWorkspaceId: string): Promise<any> {
return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`)
.then((response) => response?.status)
@ -59,6 +75,7 @@ class FileService extends APIService {
throw error?.response?.data;
});
}
async uploadUserFile(file: FormData): Promise<any> {
return this.mediaUpload(`/api/users/file-assets/`, file)
.then((response) => response?.data)