forked from github/plane
fix: delete and restore for dynamic urls for minio hosted images fix… (#3452)
* feat: delete and restore for dynamic urls for minio hosted images fixed in spaces * feat: delete and restore images calls fixed for web
This commit is contained in:
parent
6a2be6afc4
commit
8d3ea5bb3e
@ -14,6 +14,7 @@ import { Comment } from "types/issue";
|
|||||||
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
||||||
// service
|
// service
|
||||||
import fileService from "services/file.service";
|
import fileService from "services/file.service";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
const defaultValues: Partial<Comment> = {
|
const defaultValues: Partial<Comment> = {
|
||||||
comment_html: "",
|
comment_html: "",
|
||||||
@ -35,6 +36,9 @@ export const AddComment: React.FC<Props> = observer((props) => {
|
|||||||
} = useForm<Comment>({ defaultValues });
|
} = useForm<Comment>({ defaultValues });
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { project }: RootStore = useMobxStore();
|
||||||
|
const workspaceId = project.workspace?.id;
|
||||||
|
|
||||||
const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
|
const { workspace_slug, project_slug } = router.query as { workspace_slug: string; project_slug: string };
|
||||||
|
|
||||||
const { user: userStore, issueDetails: issueDetailStore } = useMobxStore();
|
const { user: userStore, issueDetails: issueDetailStore } = useMobxStore();
|
||||||
@ -78,8 +82,8 @@ export const AddComment: React.FC<Props> = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspace_slug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspace_slug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId as string)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId as string)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={
|
value={
|
||||||
!value || value === "" || (typeof value === "object" && Object.keys(value).length === 0)
|
!value || value === "" || (typeof value === "object" && Object.keys(value).length === 0)
|
||||||
|
@ -17,6 +17,7 @@ import { Comment } from "types/issue";
|
|||||||
import fileService from "services/file.service";
|
import fileService from "services/file.service";
|
||||||
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
||||||
|
|
||||||
|
import { RootStore } from "store/root";
|
||||||
type Props = {
|
type Props = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
comment: Comment;
|
comment: Comment;
|
||||||
@ -24,6 +25,9 @@ type Props = {
|
|||||||
|
|
||||||
export const CommentCard: React.FC<Props> = observer((props) => {
|
export const CommentCard: React.FC<Props> = observer((props) => {
|
||||||
const { comment, workspaceSlug } = props;
|
const { comment, workspaceSlug } = props;
|
||||||
|
const { project }: RootStore = useMobxStore();
|
||||||
|
const workspaceId = project.workspace?.id;
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const { user: userStore, issueDetails: issueDetailStore } = useMobxStore();
|
const { user: userStore, issueDetails: issueDetailStore } = useMobxStore();
|
||||||
// states
|
// states
|
||||||
@ -105,8 +109,8 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
|||||||
onEnterKeyPress={handleSubmit(handleCommentUpdate)}
|
onEnterKeyPress={handleSubmit(handleCommentUpdate)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId as string)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId as string)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={value}
|
value={value}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
|
@ -74,6 +74,39 @@ class FileService extends APIService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDeleteImageFunction(workspaceId: string) {
|
||||||
|
return async (src: string) => {
|
||||||
|
try {
|
||||||
|
const assetUrlWithWorkspaceId = `${workspaceId}/${this.extractAssetIdFromUrl(src, workspaceId)}`;
|
||||||
|
const data = await this.deleteImage(assetUrlWithWorkspaceId);
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getRestoreImageFunction(workspaceId: string) {
|
||||||
|
return async (src: string) => {
|
||||||
|
try {
|
||||||
|
const assetUrlWithWorkspaceId = `${workspaceId}/${this.extractAssetIdFromUrl(src, workspaceId)}`;
|
||||||
|
const data = await this.restoreImage(assetUrlWithWorkspaceId);
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extractAssetIdFromUrl(src: string, workspaceId: string): string {
|
||||||
|
const indexWhereAssetIdStarts = src.indexOf(workspaceId) + workspaceId.length + 1;
|
||||||
|
if (indexWhereAssetIdStarts === -1) {
|
||||||
|
throw new Error("Workspace ID not found in source string");
|
||||||
|
}
|
||||||
|
const assetUrl = src.substring(indexWhereAssetIdStarts);
|
||||||
|
return assetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
async deleteImage(assetUrlWithWorkspaceId: string): Promise<any> {
|
async deleteImage(assetUrlWithWorkspaceId: string): Promise<any> {
|
||||||
return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`)
|
return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`)
|
||||||
.then((response) => response?.status)
|
.then((response) => response?.status)
|
||||||
|
@ -54,6 +54,9 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
projectId: string;
|
projectId: string;
|
||||||
inboxId: string;
|
inboxId: string;
|
||||||
};
|
};
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const { createIssue } = useInboxIssues();
|
const { createIssue } = useInboxIssues();
|
||||||
const {
|
const {
|
||||||
@ -277,8 +280,8 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
<RichTextEditorWithRef
|
<RichTextEditorWithRef
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
value={!value || value === "" ? "<p></p>" : value}
|
value={!value || value === "" ? "<p></p>" : value}
|
||||||
|
@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
// hooks
|
// hooks
|
||||||
import { useMention } from "hooks/store";
|
import { useMention, useWorkspace } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
// components
|
// components
|
||||||
@ -51,6 +51,9 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAc
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
const { mentionHighlights, mentionSuggestions } = useMention();
|
||||||
// form info
|
// form info
|
||||||
@ -86,8 +89,8 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAc
|
|||||||
onEnterKeyPress={handleSubmit(handleAddComment)}
|
onEnterKeyPress={handleSubmit(handleAddComment)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||||
customClassName="p-2 h-full"
|
customClassName="p-2 h-full"
|
||||||
|
@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useMention, useUser } from "hooks/store";
|
import { useMention, useUser, useWorkspace } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
// icons
|
// icons
|
||||||
@ -29,6 +29,9 @@ type Props = {
|
|||||||
|
|
||||||
export const CommentCard: React.FC<Props> = observer((props) => {
|
export const CommentCard: React.FC<Props> = observer((props) => {
|
||||||
const { comment, handleCommentDeletion, onSubmit, showAccessSpecifier = false, workspaceSlug } = props;
|
const { comment, handleCommentDeletion, onSubmit, showAccessSpecifier = false, workspaceSlug } = props;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
// refs
|
// refs
|
||||||
@ -102,8 +105,8 @@ export const CommentCard: React.FC<Props> = observer((props) => {
|
|||||||
onEnterKeyPress={handleSubmit(onEnter)}
|
onEnterKeyPress={handleSubmit(onEnter)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={watch("comment_html") ?? ""}
|
value={watch("comment_html") ?? ""}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ChangeEvent, FC, useCallback, useEffect, useState } from "react";
|
import { ChangeEvent, FC, useCallback, useContext, useEffect, useState } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// hooks
|
// hooks
|
||||||
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
||||||
@ -11,7 +11,7 @@ import { TIssue } from "@plane/types";
|
|||||||
import { TIssueOperations } from "./issue-detail";
|
import { TIssueOperations } from "./issue-detail";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
import { useMention } from "hooks/store";
|
import { useMention, useWorkspace } from "hooks/store";
|
||||||
|
|
||||||
export interface IssueDescriptionFormValues {
|
export interface IssueDescriptionFormValues {
|
||||||
name: string;
|
name: string;
|
||||||
@ -38,6 +38,9 @@ const fileService = new FileService();
|
|||||||
|
|
||||||
export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
|
export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
|
||||||
const { workspaceSlug, projectId, issueId, issue, issueOperations, disabled, isSubmitting, setIsSubmitting } = props;
|
const { workspaceSlug, projectId, issueId, issue, issueOperations, disabled, isSubmitting, setIsSubmitting } = props;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [characterLimit, setCharacterLimit] = useState(false);
|
const [characterLimit, setCharacterLimit] = useState(false);
|
||||||
|
|
||||||
@ -172,8 +175,8 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = (props) => {
|
|||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
value={localIssueDescription.description_html}
|
value={localIssueDescription.description_html}
|
||||||
rerenderOnPropsChange={localIssueDescription}
|
rerenderOnPropsChange={localIssueDescription}
|
||||||
setShouldShowAlert={setShowAlert}
|
setShouldShowAlert={setShowAlert}
|
||||||
|
@ -4,7 +4,7 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Sparkle, X } from "lucide-react";
|
import { Sparkle, X } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEstimate, useMention, useProject } from "hooks/store";
|
import { useApplication, useEstimate, useMention, useProject, useWorkspace } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
import useLocalStorage from "hooks/use-local-storage";
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
// services
|
// services
|
||||||
@ -115,6 +115,9 @@ export const DraftIssueForm: FC<IssueFormProps> = observer((props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
@ -434,8 +437,8 @@ export const DraftIssueForm: FC<IssueFormProps> = observer((props) => {
|
|||||||
<RichTextEditorWithRef
|
<RichTextEditorWithRef
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
value={
|
value={
|
||||||
|
@ -2,7 +2,7 @@ import { FC, useEffect, useRef, useState } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { Check, Globe2, Lock, Pencil, Trash2, X } from "lucide-react";
|
import { Check, Globe2, Lock, Pencil, Trash2, X } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail, useMention, useUser } from "hooks/store";
|
import { useIssueDetail, useMention, useUser, useWorkspace } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import { IssueCommentBlock } from "./comment-block";
|
import { IssueCommentBlock } from "./comment-block";
|
||||||
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
|
||||||
@ -40,6 +40,8 @@ export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
|||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
const comment = getCommentById(commentId);
|
const comment = getCommentById(commentId);
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(comment?.workspace_detail?.slug as string)?.id as string;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting },
|
||||||
@ -118,8 +120,8 @@ export const IssueCommentCard: FC<TIssueCommentCard> = (props) => {
|
|||||||
onEnterKeyPress={handleSubmit(onEnter)}
|
onEnterKeyPress={handleSubmit(onEnter)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(comment?.workspace_detail?.slug as string)}
|
uploadFile={fileService.getUploadFileFunction(comment?.workspace_detail?.slug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={watch("comment_html") ?? ""}
|
value={watch("comment_html") ?? ""}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
|
@ -10,6 +10,7 @@ import { TActivityOperations } from "../root";
|
|||||||
import { TIssueComment } from "@plane/types";
|
import { TIssueComment } from "@plane/types";
|
||||||
// icons
|
// icons
|
||||||
import { Globe2, Lock } from "lucide-react";
|
import { Globe2, Lock } from "lucide-react";
|
||||||
|
import { useWorkspace } from "hooks/store";
|
||||||
|
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
|
|
||||||
@ -40,6 +41,9 @@ const commentAccess: commentAccessType[] = [
|
|||||||
|
|
||||||
export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
||||||
const { workspaceSlug, activityOperations, disabled, showAccessSpecifier = false } = props;
|
const { workspaceSlug, activityOperations, disabled, showAccessSpecifier = false } = props;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// refs
|
// refs
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
// react hook form
|
// react hook form
|
||||||
@ -73,8 +77,8 @@ export const IssueCommentCreate: FC<TIssueCommentCreate> = (props) => {
|
|||||||
}}
|
}}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={!value ? "<p></p>" : value}
|
value={!value ? "<p></p>" : value}
|
||||||
customClassName="p-2"
|
customClassName="p-2"
|
||||||
|
@ -6,7 +6,7 @@ import { LayoutPanelTop, Sparkle, X } from "lucide-react";
|
|||||||
// editor
|
// editor
|
||||||
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEstimate, useIssueDetail, useMention, useProject } from "hooks/store";
|
import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// services
|
// services
|
||||||
import { AIService } from "services/ai.service";
|
import { AIService } from "services/ai.service";
|
||||||
@ -85,6 +85,9 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
@ -384,8 +387,8 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
<RichTextEditorWithRef
|
<RichTextEditorWithRef
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
value={
|
value={
|
||||||
|
@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
|
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useMention } from "hooks/store";
|
import { useMention, useWorkspace } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
// ui
|
// ui
|
||||||
@ -44,6 +44,9 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||||||
issueCommentReactionCreate,
|
issueCommentReactionCreate,
|
||||||
issueCommentReactionRemove,
|
issueCommentReactionRemove,
|
||||||
} = props;
|
} = props;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug)?.id as string;
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
// refs
|
// refs
|
||||||
@ -117,8 +120,8 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||||||
onEnterKeyPress={handleSubmit(formSubmit)}
|
onEnterKeyPress={handleSubmit(formSubmit)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={watch("comment_html") ?? ""}
|
value={watch("comment_html") ?? ""}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
|
@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
|||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { Globe2, Lock } from "lucide-react";
|
import { Globe2, Lock } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useMention } from "hooks/store";
|
import { useMention, useWorkspace } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
// components
|
// components
|
||||||
@ -52,6 +52,9 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
const { mentionHighlights, mentionSuggestions } = useMention();
|
||||||
// form info
|
// form info
|
||||||
@ -87,8 +90,8 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
onEnterKeyPress={handleSubmit(handleAddComment)}
|
onEnterKeyPress={handleSubmit(handleAddComment)}
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
restoreFile={fileService.restoreImage}
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||||
customClassName="p-2 h-full"
|
customClassName="p-2 h-full"
|
||||||
|
@ -5,7 +5,7 @@ import { useRouter } from "next/router";
|
|||||||
import { ReactElement, useEffect, useRef, useState } from "react";
|
import { ReactElement, useEffect, useRef, useState } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useIssues, usePage, useUser } from "hooks/store";
|
import { useApplication, useIssues, usePage, useUser, useWorkspace } from "hooks/store";
|
||||||
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
import useReloadConfirmations from "hooks/use-reload-confirmation";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// services
|
// services
|
||||||
@ -46,6 +46,9 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { workspaceSlug, projectId, pageId } = router.query;
|
const { workspaceSlug, projectId, pageId } = router.query;
|
||||||
|
const workspaceStore = useWorkspace();
|
||||||
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
@ -312,10 +315,10 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
|
|||||||
last_updated_by: updated_by,
|
last_updated_by: updated_by,
|
||||||
}}
|
}}
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
|
deleteFile={fileService.getDeleteImageFunction(workspaceId)}
|
||||||
|
restoreFile={fileService.getRestoreImageFunction(workspaceId)}
|
||||||
value={pageDescription}
|
value={pageDescription}
|
||||||
setShouldShowAlert={setShowAlert}
|
setShouldShowAlert={setShowAlert}
|
||||||
deleteFile={fileService.deleteImage}
|
|
||||||
restoreFile={fileService.restoreImage}
|
|
||||||
cancelUploadImage={fileService.cancelUpload}
|
cancelUploadImage={fileService.cancelUpload}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
|
@ -78,6 +78,39 @@ export class FileService extends APIService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDeleteImageFunction(workspaceId: string) {
|
||||||
|
return async (src: string) => {
|
||||||
|
try {
|
||||||
|
const assetUrlWithWorkspaceId = `${workspaceId}/${this.extractAssetIdFromUrl(src, workspaceId)}`;
|
||||||
|
const data = await this.deleteImage(assetUrlWithWorkspaceId);
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getRestoreImageFunction(workspaceId: string) {
|
||||||
|
return async (src: string) => {
|
||||||
|
try {
|
||||||
|
const assetUrlWithWorkspaceId = `${workspaceId}/${this.extractAssetIdFromUrl(src, workspaceId)}`;
|
||||||
|
const data = await this.restoreImage(assetUrlWithWorkspaceId);
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extractAssetIdFromUrl(src: string, workspaceId: string): string {
|
||||||
|
const indexWhereAssetIdStarts = src.indexOf(workspaceId) + workspaceId.length + 1;
|
||||||
|
if (indexWhereAssetIdStarts === -1) {
|
||||||
|
throw new Error("Workspace ID not found in source string");
|
||||||
|
}
|
||||||
|
const assetUrl = src.substring(indexWhereAssetIdStarts);
|
||||||
|
return assetUrl;
|
||||||
|
}
|
||||||
|
|
||||||
async deleteImage(assetUrlWithWorkspaceId: string): Promise<any> {
|
async deleteImage(assetUrlWithWorkspaceId: string): Promise<any> {
|
||||||
return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`)
|
return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`)
|
||||||
.then((response) => response?.status)
|
.then((response) => response?.status)
|
||||||
|
Loading…
Reference in New Issue
Block a user