added workspace slug to all tiptap instances

This commit is contained in:
Palanikannan1437 2023-08-18 12:04:28 +05:30
parent 1633765ebb
commit 9bca3ac48d
16 changed files with 113 additions and 87 deletions

View File

@ -140,14 +140,14 @@ export const GptAssistantModal: React.FC<Props> = ({
return ( return (
<div <div
className={`absolute ${inset} z-20 w-full space-y-4 rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4 shadow ${ className={`absolute ${inset} z-20 w-full space-y-4 rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4 shadow ${isOpen ? "block" : "hidden"
isOpen ? "block" : "hidden"
}`} }`}
> >
{((content && content !== "") || (htmlContent && htmlContent !== "<p></p>")) && ( {((content && content !== "") || (htmlContent && htmlContent !== "<p></p>")) && (
<div className="text-sm"> <div className="text-sm">
Content: Content:
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
value={htmlContent ?? `<p>${content}</p>`} value={htmlContent ?? `<p>${content}</p>`}
customClassName="-m-3" customClassName="-m-3"
noBorder noBorder
@ -161,6 +161,7 @@ export const GptAssistantModal: React.FC<Props> = ({
<div className="page-block-section text-sm"> <div className="page-block-section text-sm">
Response: Response:
<Tiptap <Tiptap
workspaceSlug={workspaceSlug as string}
value={`<p>${response}</p>`} value={`<p>${response}</p>`}
customClassName="-mx-3 -my-3" customClassName="-mx-3 -my-3"
noBorder noBorder
@ -179,8 +180,7 @@ export const GptAssistantModal: React.FC<Props> = ({
type="text" type="text"
name="task" name="task"
register={register} register={register}
placeholder={`${ placeholder={`${content && content !== ""
content && content !== ""
? "Tell AI what action to perform on this content..." ? "Tell AI what action to perform on this content..."
: "Ask AI anything..." : "Ask AI anything..."
}`} }`}

View File

@ -293,6 +293,7 @@ export const InboxMainContent: React.FC = () => {
</div> </div>
<div> <div>
<IssueDescriptionForm <IssueDescriptionForm
workspaceSlug={workspaceSlug as string}
issue={{ issue={{
name: issueDetails.name, name: issueDetails.name,
description: issueDetails.description, description: issueDetails.description,

View File

@ -171,6 +171,7 @@ export const IssueActivitySection: React.FC<Props> = ({ issueId, user }) => {
return ( return (
<div key={activityItem.id} className="mt-4"> <div key={activityItem.id} className="mt-4">
<CommentCard <CommentCard
workspaceSlug={workspaceSlug as string}
comment={activityItem as IIssueComment} comment={activityItem as IIssueComment}
onSubmit={handleCommentUpdate} onSubmit={handleCommentUpdate}
handleCommentDeletion={handleCommentDelete} handleCommentDeletion={handleCommentDelete}

View File

@ -93,6 +93,7 @@ export const AddComment: React.FC<Props> = ({ issueId, user, disabled = false })
control={control} control={control}
render={({ field: { value, onChange } }) => ( render={({ field: { value, onChange } }) => (
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef} ref={editorRef}
value={ value={
!value || !value ||

View File

@ -22,12 +22,13 @@ const TiptapEditor = React.forwardRef<ITiptapRichTextEditor, ITiptapRichTextEdit
TiptapEditor.displayName = "TiptapEditor"; TiptapEditor.displayName = "TiptapEditor";
type Props = { type Props = {
workspaceSlug: string;
comment: IIssueComment; comment: IIssueComment;
onSubmit: (comment: IIssueComment) => void; onSubmit: (comment: IIssueComment) => void;
handleCommentDeletion: (comment: string) => void; handleCommentDeletion: (comment: string) => void;
}; };
export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentDeletion }) => { export const CommentCard: React.FC<Props> = ({ comment, workspaceSlug, onSubmit, handleCommentDeletion }) => {
const { user } = useUser(); const { user } = useUser();
const editorRef = React.useRef<any>(null); const editorRef = React.useRef<any>(null);
@ -103,6 +104,7 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
> >
<div> <div>
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef} ref={editorRef}
value={watch("comment_html")} value={watch("comment_html")}
debouncedUpdatesEnabled={false} debouncedUpdatesEnabled={false}
@ -132,6 +134,7 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
</form> </form>
<div className={`${isEditing ? "hidden" : ""}`}> <div className={`${isEditing ? "hidden" : ""}`}>
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={showEditorRef} ref={showEditorRef}
value={comment.comment_html} value={comment.comment_html}
editable={false} editable={false}

View File

@ -24,6 +24,7 @@ export interface IssueDetailsProps {
description: string; description: string;
description_html: string; description_html: string;
}; };
workspaceSlug: string;
handleFormSubmit: (value: IssueDescriptionFormValues) => Promise<void>; handleFormSubmit: (value: IssueDescriptionFormValues) => Promise<void>;
isAllowed: boolean; isAllowed: boolean;
} }
@ -31,6 +32,7 @@ export interface IssueDetailsProps {
export const IssueDescriptionForm: FC<IssueDetailsProps> = ({ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
issue, issue,
handleFormSubmit, handleFormSubmit,
workspaceSlug,
isAllowed, isAllowed,
}) => { }) => {
const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved"); const [isSubmitting, setIsSubmitting] = useState<"submitting" | "submitted" | "saved">("saved");
@ -140,6 +142,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
? watch("description_html") ? watch("description_html")
: value : value
} }
workspaceSlug={workspaceSlug}
debouncedUpdatesEnabled={true} debouncedUpdatesEnabled={true}
setShouldShowAlert={setShowAlert} setShouldShowAlert={setShowAlert}
setIsSubmitting={setIsSubmitting} setIsSubmitting={setIsSubmitting}

View File

@ -370,6 +370,7 @@ export const IssueForm: FC<IssueFormProps> = ({
return ( return (
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef} ref={editorRef}
debouncedUpdatesEnabled={false} debouncedUpdatesEnabled={false}
value={ value={

View File

@ -124,6 +124,7 @@ export const IssueMainContent: React.FC<Props> = ({
</div> </div>
) : null} ) : null}
<IssueDescriptionForm <IssueDescriptionForm
workspaceSlug={workspaceSlug as string}
issue={issueDetails} issue={issueDetails}
handleFormSubmit={submitChanges} handleFormSubmit={submitChanges}
isAllowed={memberRole.isMember || memberRole.isOwner || !uneditable} isAllowed={memberRole.isMember || memberRole.isOwner || !uneditable}

View File

@ -292,6 +292,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
if (!data) if (!data)
return ( return (
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef} ref={editorRef}
value={"<p></p>"} value={"<p></p>"}
debouncedUpdatesEnabled={false} debouncedUpdatesEnabled={false}
@ -311,6 +312,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
return ( return (
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
ref={editorRef} ref={editorRef}
value={ value={
value && value !== "" && Object.keys(value).length > 0 value && value !== "" && Object.keys(value).length > 0
@ -334,8 +336,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
<div className="m-2 mt-6 flex"> <div className="m-2 mt-6 flex">
<button <button
type="button" type="button"
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-80 ${ className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-80 ${iAmFeelingLucky ? "cursor-wait bg-custom-background-90" : ""
iAmFeelingLucky ? "cursor-wait bg-custom-background-90" : ""
}`} }`}
onClick={handleAutoGenerateDescription} onClick={handleAutoGenerateDescription}
disabled={iAmFeelingLucky} disabled={iAmFeelingLucky}

View File

@ -456,6 +456,7 @@ export const SinglePageBlock: React.FC<Props> = ({
{showBlockDetails {showBlockDetails
? block.description_html.length > 7 && ( ? block.description_html.length > 7 && (
<TiptapEditor <TiptapEditor
workspaceSlug={workspaceSlug as string}
value={block.description_html} value={block.description_html}
customClassName="text-sm min-h-[150px]" customClassName="text-sm min-h-[150px]"
noBorder noBorder

View File

@ -23,7 +23,7 @@ import isValidHttpUrl from "../bubble-menu/utils/link-validator";
lowlight.registerLanguage("ts", ts); lowlight.registerLanguage("ts", ts);
export const TiptapExtensions = [ export const TiptapExtensions = (workspaceSlug: string) => [
StarterKit.configure({ StarterKit.configure({
bulletList: { bulletList: {
HTMLAttributes: { HTMLAttributes: {
@ -112,7 +112,7 @@ export const TiptapExtensions = [
UniqueID.configure({ UniqueID.configure({
types: ["image"], types: ["image"],
}), }),
SlashCommand, SlashCommand(workspaceSlug),
TiptapUnderline, TiptapUnderline,
TextStyle, TextStyle,
Color, Color,

View File

@ -20,6 +20,7 @@ export interface ITiptapRichTextEditor {
onChange?: (json: any, html: string) => void; onChange?: (json: any, html: string) => void;
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void;
setShouldShowAlert?: (showAlert: boolean) => void; setShouldShowAlert?: (showAlert: boolean) => void;
workspaceSlug: string;
editable?: boolean; editable?: boolean;
forwardedRef?: any; forwardedRef?: any;
debouncedUpdatesEnabled?: boolean; debouncedUpdatesEnabled?: boolean;
@ -36,14 +37,15 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
editorContentCustomClassNames, editorContentCustomClassNames,
value, value,
noBorder, noBorder,
workspaceSlug,
borderOnFocus, borderOnFocus,
customClassName, customClassName,
} = props; } = props;
const editor = useEditor({ const editor = useEditor({
editable: editable ?? true, editable: editable ?? true,
editorProps: TiptapEditorProps, editorProps: TiptapEditorProps(workspaceSlug),
extensions: TiptapExtensions, extensions: TiptapExtensions(workspaceSlug),
content: value, content: value,
onUpdate: async ({ editor }) => { onUpdate: async ({ editor }) => {
// for instant feedback loop // for instant feedback loop

View File

@ -57,7 +57,7 @@ function findPlaceholder(state: EditorState, id: {}) {
return found.length ? found[0].from : null; return found.length ? found[0].from : null;
} }
export async function startImageUpload(file: File, view: EditorView, pos: number) { export async function startImageUpload(file: File, view: EditorView, pos: number, workspaceSlug: string) {
if (!file.type.includes("image/")) { if (!file.type.includes("image/")) {
return; return;
} else if (file.size / 1024 / 1024 > 20) { } else if (file.size / 1024 / 1024 > 20) {
@ -82,7 +82,10 @@ export async function startImageUpload(file: File, view: EditorView, pos: number
view.dispatch(tr); view.dispatch(tr);
}; };
const src = await UploadImageHandler(file); if (!workspaceSlug) {
return;
}
const src = await UploadImageHandler(file, workspaceSlug);
const { schema } = view.state; const { schema } = view.state;
pos = findPlaceholder(view.state, id); pos = findPlaceholder(view.state, id);
@ -96,19 +99,24 @@ export async function startImageUpload(file: File, view: EditorView, pos: number
view.dispatch(transaction); view.dispatch(transaction);
} }
const UploadImageHandler = (file: File): Promise<string> => { const UploadImageHandler = (file: File, workspaceSlug: string): Promise<string> => {
if (!workspaceSlug) {
return Promise.reject("Workspace slug is missing");
}
try { try {
console.log("in here",workspaceSlug)
const formData = new FormData(); const formData = new FormData();
formData.append("asset", file); formData.append("asset", file);
formData.append("attributes", JSON.stringify({})); formData.append("attributes", JSON.stringify({}));
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const imageUrl = await fileService const imageUrl = await fileService
.uploadFile("plane", formData) .uploadFile(workspaceSlug, formData)
.then((response) => response.asset); .then((response) => response.asset);
const image = new Image(); const image = new Image();
image.src = imageUrl; image.src = imageUrl;
console.log("image uploaded", imageUrl)
image.onload = () => { image.onload = () => {
resolve(imageUrl); resolve(imageUrl);
}; };

View File

@ -1,7 +1,8 @@
import { EditorProps } from "@tiptap/pm/view"; import { EditorProps } from "@tiptap/pm/view";
import { startImageUpload } from "./plugins/upload-image"; import { startImageUpload } from "./plugins/upload-image";
export const TiptapEditorProps: EditorProps = { export function TiptapEditorProps(workspaceSlug: string): EditorProps {
return {
attributes: { attributes: {
class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`, class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`,
}, },
@ -26,7 +27,7 @@ export const TiptapEditorProps: EditorProps = {
const file = event.clipboardData.files[0]; const file = event.clipboardData.files[0];
const pos = view.state.selection.from; const pos = view.state.selection.from;
startImageUpload(file, view, pos); startImageUpload(file, view, pos, workspaceSlug);
return true; return true;
} }
return false; return false;
@ -46,11 +47,11 @@ export const TiptapEditorProps: EditorProps = {
}); });
// here we deduct 1 from the pos or else the image will create an extra node // here we deduct 1 from the pos or else the image will create an extra node
if (coordinates) { if (coordinates) {
startImageUpload(file, view, coordinates.pos - 1); startImageUpload(file, view, coordinates.pos - 1, workspaceSlug);
} }
return true; return true;
} }
return false; return false;
}, },
}; };
}

View File

@ -52,7 +52,7 @@ const Command = Extension.create({
}, },
}); });
const getSuggestionItems = ({ query }: { query: string }) => const getSuggestionItems = (workspaceSlug: string) => ({ query }: { query: string }) =>
[ [
{ {
title: "Text", title: "Text",
@ -163,7 +163,7 @@ const getSuggestionItems = ({ query }: { query: string }) =>
if (input.files?.length) { if (input.files?.length) {
const file = input.files[0]; const file = input.files[0];
const pos = editor.view.state.selection.from; const pos = editor.view.state.selection.from;
startImageUpload(file, editor.view, pos); startImageUpload(file, editor.view, pos, workspaceSlug);
} }
}; };
input.click(); input.click();
@ -328,9 +328,10 @@ const renderItems = () => {
}; };
}; };
const SlashCommand = Command.configure({ export const SlashCommand = (workspaceSlug: string) =>
Command.configure({
suggestion: { suggestion: {
items: getSuggestionItems, items: getSuggestionItems(workspaceSlug),
render: renderItems, render: renderItems,
}, },
}); });

View File

@ -106,6 +106,7 @@ const ProfileActivity = () => {
</div> </div>
<div className="issue-comments-section p-0"> <div className="issue-comments-section p-0">
<Tiptap <Tiptap
workspaceSlug={workspaceSlug as string}
value={ value={
activityItem?.new_value !== "" activityItem?.new_value !== ""
? activityItem.new_value ? activityItem.new_value