forked from github/plane
fix: delete mutations for issues, cycles and modules (#634)
This commit is contained in:
parent
29ea592c4a
commit
66d07e340b
@ -26,6 +26,7 @@ import {
|
|||||||
LinkIcon,
|
LinkIcon,
|
||||||
PencilIcon,
|
PencilIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
|
XMarkIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
||||||
@ -38,6 +39,7 @@ import {
|
|||||||
MODULE_ISSUES_WITH_PARAMS,
|
MODULE_ISSUES_WITH_PARAMS,
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
import { DIVIDER } from "@blueprintjs/core/lib/esm/common/classes";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: string;
|
type?: string;
|
||||||
@ -258,27 +260,30 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
{type && !isNotAllowed && (
|
{type && !isNotAllowed && (
|
||||||
<CustomMenu width="auto" ellipsis>
|
<CustomMenu width="auto" ellipsis>
|
||||||
<CustomMenu.MenuItem onClick={editIssue}>
|
<CustomMenu.MenuItem onClick={editIssue}>
|
||||||
<span className="flex items-center justify-start gap-2">
|
<div className="flex items-center justify-start gap-2">
|
||||||
<PencilIcon className="h-4 w-4" />
|
<PencilIcon className="h-4 w-4" />
|
||||||
<span>Edit issue</span>
|
<span>Edit issue</span>
|
||||||
</span>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
{type !== "issue" && removeIssue && (
|
{type !== "issue" && removeIssue && (
|
||||||
<CustomMenu.MenuItem onClick={removeIssue}>
|
<CustomMenu.MenuItem onClick={removeIssue}>
|
||||||
<>Remove from {type}</>
|
<div className="flex items-center justify-start gap-2">
|
||||||
|
<XMarkIcon className="h-4 w-4" />
|
||||||
|
<span>Remove from {type}</span>
|
||||||
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
)}
|
)}
|
||||||
<CustomMenu.MenuItem onClick={() => handleDeleteIssue(issue)}>
|
<CustomMenu.MenuItem onClick={() => handleDeleteIssue(issue)}>
|
||||||
<span className="flex items-center justify-start gap-2">
|
<div className="flex items-center justify-start gap-2">
|
||||||
<TrashIcon className="h-4 w-4" />
|
<TrashIcon className="h-4 w-4" />
|
||||||
<span>Delete issue</span>
|
<span>Delete issue</span>
|
||||||
</span>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
<CustomMenu.MenuItem onClick={handleCopyText}>
|
<CustomMenu.MenuItem onClick={handleCopyText}>
|
||||||
<span className="flex items-center justify-start gap-2">
|
<div className="flex items-center justify-start gap-2">
|
||||||
<LinkIcon className="h-4 w-4" />
|
<LinkIcon className="h-4 w-4" />
|
||||||
<span>Copy issue link</span>
|
<span>Copy issue link</span>
|
||||||
</span>
|
</div>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
)}
|
)}
|
||||||
|
@ -14,14 +14,25 @@ import { DangerButton, SecondaryButton } from "components/ui";
|
|||||||
// icons
|
// icons
|
||||||
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import type { ICycle } from "types";
|
import type {
|
||||||
|
CompletedCyclesResponse,
|
||||||
|
CurrentAndUpcomingCyclesResponse,
|
||||||
|
DraftCyclesResponse,
|
||||||
|
ICycle,
|
||||||
|
} from "types";
|
||||||
type TConfirmCycleDeletionProps = {
|
type TConfirmCycleDeletionProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
data?: ICycle;
|
data?: ICycle;
|
||||||
};
|
};
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { CYCLE_LIST } from "constants/fetch-keys";
|
import {
|
||||||
|
CYCLE_COMPLETE_LIST,
|
||||||
|
CYCLE_CURRENT_AND_UPCOMING_LIST,
|
||||||
|
CYCLE_DRAFT_LIST,
|
||||||
|
CYCLE_LIST,
|
||||||
|
} from "constants/fetch-keys";
|
||||||
|
import { getDateRangeStatus } from "helpers/date-time.helper";
|
||||||
|
|
||||||
export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
@ -31,7 +42,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -41,16 +52,68 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeletion = async () => {
|
const handleDeletion = async () => {
|
||||||
setIsDeleteLoading(true);
|
|
||||||
if (!data || !workspaceSlug) return;
|
if (!data || !workspaceSlug) return;
|
||||||
|
|
||||||
|
setIsDeleteLoading(true);
|
||||||
|
|
||||||
await cycleService
|
await cycleService
|
||||||
.deleteCycle(workspaceSlug as string, data.project, data.id)
|
.deleteCycle(workspaceSlug as string, data.project, data.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate<ICycle[]>(
|
switch (getDateRangeStatus(data.start_date, data.end_date)) {
|
||||||
CYCLE_LIST(data.project),
|
case "completed":
|
||||||
(prevData) => prevData?.filter((cycle) => cycle.id !== data?.id),
|
mutate<CompletedCyclesResponse>(
|
||||||
|
CYCLE_COMPLETE_LIST(projectId as string),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return;
|
||||||
|
|
||||||
|
return {
|
||||||
|
completed_cycles: prevData.completed_cycles?.filter(
|
||||||
|
(cycle) => cycle.id !== data?.id
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
case "current":
|
||||||
|
mutate<CurrentAndUpcomingCyclesResponse>(
|
||||||
|
CYCLE_CURRENT_AND_UPCOMING_LIST(projectId as string),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return;
|
||||||
|
return {
|
||||||
|
current_cycle: prevData.current_cycle?.filter((c) => c.id !== data?.id),
|
||||||
|
upcoming_cycle: prevData.upcoming_cycle,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "upcoming":
|
||||||
|
mutate<CurrentAndUpcomingCyclesResponse>(
|
||||||
|
CYCLE_CURRENT_AND_UPCOMING_LIST(projectId as string),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return;
|
||||||
|
|
||||||
|
return {
|
||||||
|
current_cycle: prevData.current_cycle,
|
||||||
|
upcoming_cycle: prevData.upcoming_cycle?.filter((c) => c.id !== data?.id),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mutate<DraftCyclesResponse>(
|
||||||
|
CYCLE_DRAFT_LIST(projectId as string),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return;
|
||||||
|
return {
|
||||||
|
draft_cycles: prevData.draft_cycles?.filter((cycle) => cycle.id !== data?.id),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
handleClose();
|
handleClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -59,8 +122,7 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
message: "Cycle deleted successfully",
|
message: "Cycle deleted successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(() => {
|
||||||
console.log(error);
|
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -107,9 +169,8 @@ export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
|
|||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
Are you sure you want to delete cycle-{" "}
|
Are you sure you want to delete cycle-{" "}
|
||||||
<span className="font-bold">{data?.name}</span>
|
<span className="font-bold">{data?.name}</span>? All of the data related
|
||||||
? All of the data related to the cycle will be permanently removed.
|
to the cycle will be permanently removed. This action cannot be undone.
|
||||||
This action cannot be undone.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
@ -17,7 +17,15 @@ import { SecondaryButton, DangerButton } from "components/ui";
|
|||||||
// types
|
// types
|
||||||
import type { CycleIssueResponse, IIssue, ModuleIssueResponse } from "types";
|
import type { CycleIssueResponse, IIssue, ModuleIssueResponse } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { CYCLE_ISSUES, PROJECT_ISSUES_LIST, MODULE_ISSUES, USER_ISSUE } from "constants/fetch-keys";
|
import {
|
||||||
|
CYCLE_ISSUES,
|
||||||
|
CYCLE_ISSUES_WITH_PARAMS,
|
||||||
|
MODULE_ISSUES,
|
||||||
|
MODULE_ISSUES_WITH_PARAMS,
|
||||||
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
|
USER_ISSUE,
|
||||||
|
} from "constants/fetch-keys";
|
||||||
|
import useIssuesView from "hooks/use-issues-view";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -29,7 +37,9 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
|||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId: queryProjectId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
|
const { params } = useIssuesView();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -44,37 +54,14 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
|||||||
|
|
||||||
const handleDeletion = async () => {
|
const handleDeletion = async () => {
|
||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
if (!data || !workspaceSlug) return;
|
if (!workspaceSlug || !projectId || !data) return;
|
||||||
|
|
||||||
const projectId = data.project;
|
|
||||||
await issueServices
|
await issueServices
|
||||||
.deleteIssue(workspaceSlug as string, projectId, data.id)
|
.deleteIssue(workspaceSlug as string, projectId as string, data.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const cycleId = data?.cycle;
|
if (cycleId) mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
|
||||||
const moduleId = data?.module;
|
else if (moduleId) mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
||||||
|
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
||||||
if (cycleId) {
|
|
||||||
mutate<CycleIssueResponse[]>(
|
|
||||||
CYCLE_ISSUES(cycleId),
|
|
||||||
(prevData) => prevData?.filter((i) => i.issue !== data.id),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleId) {
|
|
||||||
mutate<ModuleIssueResponse[]>(
|
|
||||||
MODULE_ISSUES(moduleId),
|
|
||||||
(prevData) => prevData?.filter((i) => i.issue !== data.id),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryProjectId)
|
|
||||||
mutate<IIssue[]>(
|
|
||||||
USER_ISSUE(workspaceSlug as string),
|
|
||||||
(prevData) => prevData?.filter((i) => i.id !== data.id),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -133,8 +120,8 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data })
|
|||||||
Are you sure you want to delete issue{" "}
|
Are you sure you want to delete issue{" "}
|
||||||
<span className="break-all font-semibold">
|
<span className="break-all font-semibold">
|
||||||
{data?.project_detail.identifier}-{data?.sequence_id}
|
{data?.project_detail.identifier}-{data?.sequence_id}
|
||||||
</span>{""}
|
</span>
|
||||||
? All of the data related to the issue will be permanently removed. This
|
{""}? All of the data related to the issue will be permanently removed. This
|
||||||
action cannot be undone.
|
action cannot be undone.
|
||||||
</p>
|
</p>
|
||||||
</span>
|
</span>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
|
|||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -41,22 +41,26 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
|
|||||||
const handleDeletion = async () => {
|
const handleDeletion = async () => {
|
||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
|
|
||||||
if (!workspaceSlug || !data) return;
|
if (!workspaceSlug || !projectId || !data) return;
|
||||||
await modulesService
|
|
||||||
.deleteModule(workspaceSlug as string, data.project, data.id)
|
|
||||||
.then(() => {
|
|
||||||
mutate(MODULE_LIST(data.project));
|
|
||||||
router.push(`/${workspaceSlug}/projects/${data.project}/modules`);
|
|
||||||
handleClose();
|
|
||||||
|
|
||||||
setToastAlert({
|
mutate<IModule[]>(
|
||||||
title: "Success",
|
MODULE_LIST(projectId as string),
|
||||||
type: "success",
|
(prevData) => prevData?.filter((m) => m.id !== data.id),
|
||||||
message: "Module deleted successfully",
|
false
|
||||||
});
|
);
|
||||||
|
|
||||||
|
await modulesService
|
||||||
|
.deleteModule(workspaceSlug as string, projectId as string, data.id)
|
||||||
|
.then(() => {
|
||||||
|
if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`);
|
||||||
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(() => {
|
||||||
console.log(error);
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Module could not be deleted. Please try again.",
|
||||||
|
});
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -103,9 +107,8 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data })
|
|||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
Are you sure you want to delete module-{" "}
|
Are you sure you want to delete module-{" "}
|
||||||
<span className="font-bold">{data?.name}</span>
|
<span className="font-bold">{data?.name}</span>? All of the data related
|
||||||
? All of the data related to the module will be permanently removed.
|
to the module will be permanently removed. This action cannot be undone.
|
||||||
This action cannot be undone.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +36,7 @@ const useIssuesView = () => {
|
|||||||
setFilters,
|
setFilters,
|
||||||
resetFilterToDefault,
|
resetFilterToDefault,
|
||||||
setNewFilterDefaultView,
|
setNewFilterDefaultView,
|
||||||
setIssueView
|
setIssueView,
|
||||||
} = useContext(issueViewContext);
|
} = useContext(issueViewContext);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
Loading…
Reference in New Issue
Block a user