diff --git a/web/core/components/issues/delete-issue-modal.tsx b/web/core/components/issues/delete-issue-modal.tsx index 06fa4cafa4c..e6109a028a4 100644 --- a/web/core/components/issues/delete-issue-modal.tsx +++ b/web/core/components/issues/delete-issue-modal.tsx @@ -8,7 +8,7 @@ import { AlertModalCore, TOAST_TYPE, setToast } from "@plane/ui"; // constants import { PROJECT_ERROR_MESSAGES } from "@/constants/project"; // hooks -import { useIssues, useProject } from "@/hooks/store"; +import { useIssues, useProject, useUser } from "@/hooks/store"; type Props = { isOpen: boolean; @@ -26,6 +26,7 @@ export const DeleteIssueModal: React.FC = (props) => { // store hooks const { issueMap } = useIssues(); const { getProjectById } = useProject(); + const { data: currentUser, canPerformProjectAdminActions } = useUser(); useEffect(() => { setIsDeleting(false); @@ -36,6 +37,8 @@ export const DeleteIssueModal: React.FC = (props) => { // derived values const issue = data ? data : issueMap[dataId!]; const projectDetails = getProjectById(issue?.project_id); + const isIssueCreator = issue?.created_by === currentUser?.id; + const authorized = isIssueCreator || canPerformProjectAdminActions; const onClose = () => { setIsDeleting(false); @@ -44,6 +47,16 @@ export const DeleteIssueModal: React.FC = (props) => { const handleIssueDelete = async () => { setIsDeleting(true); + + if (!authorized) { + setToast({ + title: PROJECT_ERROR_MESSAGES.permissionError.title, + type: TOAST_TYPE.ERROR, + message: PROJECT_ERROR_MESSAGES.permissionError.message, + }); + onClose(); + return; + } if (onSubmit) await onSubmit() .then(() => { diff --git a/web/core/components/issues/issue-detail-widgets/relations/helper.tsx b/web/core/components/issues/issue-detail-widgets/relations/helper.tsx index f2366f7d435..fe3be8ca4a2 100644 --- a/web/core/components/issues/issue-detail-widgets/relations/helper.tsx +++ b/web/core/components/issues/issue-detail-widgets/relations/helper.tsx @@ -70,11 +70,12 @@ export const useRelationOperations = (): TRelationIssueOperations => { }, remove: async (workspaceSlug: string, projectId: string, issueId: string) => { try { - await removeIssue(workspaceSlug, projectId, issueId); - captureIssueEvent({ - eventName: ISSUE_DELETED, - payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" }, - path: pathname, + return removeIssue(workspaceSlug, projectId, issueId).then(() => { + captureIssueEvent({ + eventName: ISSUE_DELETED, + payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" }, + path: pathname, + }); }); } catch (error) { captureIssueEvent({ diff --git a/web/core/components/issues/issue-detail-widgets/sub-issues/helper.tsx b/web/core/components/issues/issue-detail-widgets/sub-issues/helper.tsx index dbf295a0009..7df432d5d21 100644 --- a/web/core/components/issues/issue-detail-widgets/sub-issues/helper.tsx +++ b/web/core/components/issues/issue-detail-widgets/sub-issues/helper.tsx @@ -150,13 +150,14 @@ export const useSubIssueOperations = (): TSubIssueOperations => { deleteSubIssue: async (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => { try { setSubIssueHelpers(parentIssueId, "issue_loader", issueId); - await deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId); - captureIssueEvent({ - eventName: "Sub-issue deleted", - payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" }, - path: pathname, + return deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId).then(() => { + captureIssueEvent({ + eventName: "Sub-issue deleted", + payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" }, + path: pathname, + }); + setSubIssueHelpers(parentIssueId, "issue_loader", issueId); }); - setSubIssueHelpers(parentIssueId, "issue_loader", issueId); } catch (error) { captureIssueEvent({ eventName: "Sub-issue removed", diff --git a/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx b/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx index 8c720261ee3..54cce976fde 100644 --- a/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx +++ b/web/core/components/issues/issue-detail/issue-detail-quick-actions.tsx @@ -78,14 +78,18 @@ export const IssueDetailQuickActions: FC = observer((props) => { const handleDeleteIssue = async () => { try { - if (issue?.archived_at) await removeArchivedIssue(workspaceSlug, projectId, issueId); - else await removeIssue(workspaceSlug, projectId, issueId); - router.push(`/${workspaceSlug}/projects/${projectId}/issues`); - captureIssueEvent({ - eventName: ISSUE_DELETED, - payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" }, - path: pathname, - }); + if (issue?.archived_at) { + return removeArchivedIssue(workspaceSlug, projectId, issueId).then(() => { + router.push(`/${workspaceSlug}/projects/${projectId}/issues`); + captureIssueEvent({ + eventName: ISSUE_DELETED, + payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" }, + path: pathname, + }); + }); + } else { + return removeIssue(workspaceSlug, projectId, issueId); + } } catch (error) { setToast({ title: "Error!", diff --git a/web/core/components/issues/peek-overview/root.tsx b/web/core/components/issues/peek-overview/root.tsx index 0f46f8f6807..a55b0d5464f 100644 --- a/web/core/components/issues/peek-overview/root.tsx +++ b/web/core/components/issues/peek-overview/root.tsx @@ -34,6 +34,7 @@ export const IssuePeekOverview: FC = observer((props) => { } = useIssues(EIssuesStoreType.ARCHIVED); const { peekIssue, + setPeekIssue, issue: { fetchIssue }, fetchActivities, } = useIssueDetail(); @@ -44,6 +45,11 @@ export const IssuePeekOverview: FC = observer((props) => { const [loader, setLoader] = useState(true); const [error, setError] = useState(false); + const removeRoutePeekId = () => { + setPeekIssue(undefined); + if (embedIssue) embedRemoveCurrentNotification && embedRemoveCurrentNotification(); + }; + const issueOperations: TIssueOperations = useMemo( () => ({ fetch: async (workspaceSlug: string, projectId: string, issueId: string, loader = true) => { @@ -95,16 +101,13 @@ export const IssuePeekOverview: FC = observer((props) => { }, remove: async (workspaceSlug: string, projectId: string, issueId: string) => { try { - issues?.removeIssue(workspaceSlug, projectId, issueId); - setToast({ - title: "Success!", - type: TOAST_TYPE.SUCCESS, - message: "Issue deleted successfully", - }); - captureIssueEvent({ - eventName: ISSUE_DELETED, - payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" }, - path: pathname, + return issues?.removeIssue(workspaceSlug, projectId, issueId).then(() => { + captureIssueEvent({ + eventName: ISSUE_DELETED, + payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" }, + path: pathname, + }); + removeRoutePeekId(); }); } catch (error) { setToast({ diff --git a/web/core/components/issues/peek-overview/view.tsx b/web/core/components/issues/peek-overview/view.tsx index 865e93fbf1a..617c36dfa1d 100644 --- a/web/core/components/issues/peek-overview/view.tsx +++ b/web/core/components/issues/peek-overview/view.tsx @@ -131,7 +131,7 @@ export const IssueView: FC = observer((props) => { toggleDeleteIssueModal(null); }} data={issue} - onSubmit={() => issueOperations.remove(workspaceSlug, projectId, issueId).then(() => removeRoutePeekId())} + onSubmit={async () => issueOperations.remove(workspaceSlug, projectId, issueId)} /> )}