mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: bulk delete and archive confirmation modals
This commit is contained in:
parent
5c328ff0b2
commit
51c0794a65
@ -1,4 +1,4 @@
|
|||||||
import { AlertTriangle, LucideIcon } from "lucide-react";
|
import { AlertTriangle, Info, LucideIcon } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button, TButtonVariant } from "@plane/ui";
|
import { Button, TButtonVariant } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
@ -6,14 +6,14 @@ import { EModalPosition, EModalWidth, ModalCore } from "@/components/core";
|
|||||||
// helpers
|
// helpers
|
||||||
import { cn } from "@/helpers/common.helper";
|
import { cn } from "@/helpers/common.helper";
|
||||||
|
|
||||||
export type TModalVariant = "danger";
|
export type TModalVariant = "danger" | "primary";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
content: React.ReactNode | string;
|
content: React.ReactNode | string;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
handleSubmit: () => Promise<void>;
|
handleSubmit: () => Promise<void>;
|
||||||
hideIcon?: boolean;
|
hideIcon?: boolean;
|
||||||
isDeleting: boolean;
|
isSubmitting: boolean;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
position?: EModalPosition;
|
position?: EModalPosition;
|
||||||
primaryButtonText?: {
|
primaryButtonText?: {
|
||||||
@ -28,14 +28,17 @@ type Props = {
|
|||||||
|
|
||||||
const VARIANT_ICONS: Record<TModalVariant, LucideIcon> = {
|
const VARIANT_ICONS: Record<TModalVariant, LucideIcon> = {
|
||||||
danger: AlertTriangle,
|
danger: AlertTriangle,
|
||||||
|
primary: Info,
|
||||||
};
|
};
|
||||||
|
|
||||||
const BUTTON_VARIANTS: Record<TModalVariant, TButtonVariant> = {
|
const BUTTON_VARIANTS: Record<TModalVariant, TButtonVariant> = {
|
||||||
danger: "danger",
|
danger: "danger",
|
||||||
|
primary: "primary",
|
||||||
};
|
};
|
||||||
|
|
||||||
const VARIANT_CLASSES: Record<TModalVariant, string> = {
|
const VARIANT_CLASSES: Record<TModalVariant, string> = {
|
||||||
danger: "bg-red-500/20 text-red-500",
|
danger: "bg-red-500/20 text-red-500",
|
||||||
|
primary: "bg-custom-primary-100/20 text-custom-primary-100",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AlertModalCore: React.FC<Props> = (props) => {
|
export const AlertModalCore: React.FC<Props> = (props) => {
|
||||||
@ -44,7 +47,7 @@ export const AlertModalCore: React.FC<Props> = (props) => {
|
|||||||
handleClose,
|
handleClose,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
hideIcon = false,
|
hideIcon = false,
|
||||||
isDeleting,
|
isSubmitting,
|
||||||
isOpen,
|
isOpen,
|
||||||
position = EModalPosition.CENTER,
|
position = EModalPosition.CENTER,
|
||||||
primaryButtonText = {
|
primaryButtonText = {
|
||||||
@ -81,8 +84,8 @@ export const AlertModalCore: React.FC<Props> = (props) => {
|
|||||||
<Button variant="neutral-primary" size="sm" onClick={handleClose}>
|
<Button variant="neutral-primary" size="sm" onClick={handleClose}>
|
||||||
{secondaryButtonText}
|
{secondaryButtonText}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant={BUTTON_VARIANTS[variant]} size="sm" tabIndex={1} onClick={handleSubmit} loading={isDeleting}>
|
<Button variant={BUTTON_VARIANTS[variant]} size="sm" tabIndex={1} onClick={handleSubmit} loading={isSubmitting}>
|
||||||
{isDeleting ? primaryButtonText.loading : primaryButtonText.default}
|
{isSubmitting ? primaryButtonText.loading : primaryButtonText.default}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ModalCore>
|
</ModalCore>
|
||||||
|
@ -73,7 +73,7 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={formSubmit}
|
handleSubmit={formSubmit}
|
||||||
isDeleting={loader}
|
isSubmitting={loader}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Cycle"
|
title="Delete Cycle"
|
||||||
content={
|
content={
|
||||||
|
@ -64,7 +64,7 @@ export const DeleteEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={onClose}
|
handleClose={onClose}
|
||||||
handleSubmit={handleEstimateDelete}
|
handleSubmit={handleEstimateDelete}
|
||||||
isDeleting={isDeleteLoading}
|
isSubmitting={isDeleteLoading}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Estimate"
|
title="Delete Estimate"
|
||||||
content={
|
content={
|
||||||
|
@ -36,7 +36,7 @@ export const DeclineIssueModal: React.FC<Props> = (props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDecline}
|
handleSubmit={handleDecline}
|
||||||
isDeleting={isDeclining}
|
isSubmitting={isDeclining}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Decline Issue"
|
title="Decline Issue"
|
||||||
content={
|
content={
|
||||||
|
@ -36,7 +36,7 @@ export const DeleteInboxIssueModal: React.FC<Props> = observer(({ isOpen, onClos
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDelete}
|
handleSubmit={handleDelete}
|
||||||
isDeleting={isDeleting}
|
isSubmitting={isDeleting}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Issue"
|
title="Delete Issue"
|
||||||
content={
|
content={
|
||||||
|
@ -35,7 +35,7 @@ export const IssueAttachmentDeleteModal: FC<Props> = (props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={() => handleDeletion(data.id)}
|
handleSubmit={() => handleDeletion(data.id)}
|
||||||
isDeleting={loader}
|
isSubmitting={loader}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete attachment"
|
title="Delete attachment"
|
||||||
content={
|
content={
|
||||||
|
@ -60,7 +60,7 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={onClose}
|
handleClose={onClose}
|
||||||
handleSubmit={handleIssueDelete}
|
handleSubmit={handleIssueDelete}
|
||||||
isDeleting={isDeleting}
|
isSubmitting={isDeleting}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Issue"
|
title="Delete Issue"
|
||||||
content={
|
content={
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
// components
|
||||||
|
import { AlertModalCore, EModalPosition, EModalWidth } from "@/components/core";
|
||||||
|
// constants
|
||||||
|
import { EIssuesStoreType } from "@/constants/issue";
|
||||||
|
// hooks
|
||||||
|
import { useBulkIssueOperations, useIssues } from "@/hooks/store";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
handleClose: () => void;
|
||||||
|
isOpen: boolean;
|
||||||
|
issueIds: string[];
|
||||||
|
projectId: string;
|
||||||
|
workspaceSlug: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BulkArchiveConfirmationModal: React.FC<Props> = observer((props) => {
|
||||||
|
const { handleClose, isOpen, issueIds, projectId, workspaceSlug } = props;
|
||||||
|
// states
|
||||||
|
const [isArchiving, setIsDeleting] = useState(false);
|
||||||
|
// store hooks
|
||||||
|
const {
|
||||||
|
issues: { archiveBulkIssues },
|
||||||
|
} = useIssues(EIssuesStoreType.PROJECT);
|
||||||
|
const { clearSelection } = useBulkIssueOperations();
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
setIsDeleting(true);
|
||||||
|
|
||||||
|
await archiveBulkIssues(workspaceSlug, projectId, issueIds)
|
||||||
|
.then(() => {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.SUCCESS,
|
||||||
|
title: "Success!",
|
||||||
|
message: "Issues archived successfully.",
|
||||||
|
});
|
||||||
|
clearSelection();
|
||||||
|
handleClose();
|
||||||
|
})
|
||||||
|
.catch(() =>
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.finally(() => setIsDeleting(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
const issueVariant = issueIds.length > 1 ? "issues" : "issue";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AlertModalCore
|
||||||
|
handleClose={handleClose}
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
isSubmitting={isArchiving}
|
||||||
|
isOpen={isOpen}
|
||||||
|
variant="primary"
|
||||||
|
position={EModalPosition.CENTER}
|
||||||
|
width={EModalWidth.XL}
|
||||||
|
title={`Archive ${issueVariant}`}
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
Are you sure you want to archive {issueIds.length} {issueVariant}? Sub issues of selected {issueVariant} will
|
||||||
|
also be archived. Once archived {issueIds.length > 1 ? "they" : "it"} can be restored later via the archives
|
||||||
|
section.
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
primaryButtonText={{
|
||||||
|
loading: "Archiving",
|
||||||
|
default: `Archive ${issueVariant}`,
|
||||||
|
}}
|
||||||
|
hideIcon
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,78 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
// components
|
||||||
|
import { AlertModalCore, EModalPosition, EModalWidth } from "@/components/core";
|
||||||
|
// constants
|
||||||
|
import { EIssuesStoreType } from "@/constants/issue";
|
||||||
|
// hooks
|
||||||
|
import { useBulkIssueOperations, useIssues } from "@/hooks/store";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
handleClose: () => void;
|
||||||
|
isOpen: boolean;
|
||||||
|
issueIds: string[];
|
||||||
|
projectId: string;
|
||||||
|
workspaceSlug: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BulkDeleteConfirmationModal: React.FC<Props> = observer((props) => {
|
||||||
|
const { handleClose, isOpen, issueIds, projectId, workspaceSlug } = props;
|
||||||
|
// states
|
||||||
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
|
// store hooks
|
||||||
|
const {
|
||||||
|
issues: { removeBulkIssues },
|
||||||
|
} = useIssues(EIssuesStoreType.PROJECT);
|
||||||
|
const { clearSelection } = useBulkIssueOperations();
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
setIsDeleting(true);
|
||||||
|
|
||||||
|
await removeBulkIssues(workspaceSlug, projectId, issueIds)
|
||||||
|
.then(() => {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.SUCCESS,
|
||||||
|
title: "Success!",
|
||||||
|
message: "Issues deleted successfully.",
|
||||||
|
});
|
||||||
|
clearSelection();
|
||||||
|
handleClose();
|
||||||
|
})
|
||||||
|
.catch(() =>
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.finally(() => setIsDeleting(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
const issueVariant = issueIds.length > 1 ? "issues" : "issue";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AlertModalCore
|
||||||
|
handleClose={handleClose}
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
isSubmitting={isDeleting}
|
||||||
|
isOpen={isOpen}
|
||||||
|
variant="danger"
|
||||||
|
position={EModalPosition.CENTER}
|
||||||
|
width={EModalWidth.XL}
|
||||||
|
title={`Delete ${issueVariant}`}
|
||||||
|
content={
|
||||||
|
<>
|
||||||
|
Are you sure you want to delete {issueIds.length} {issueVariant}? Sub issues of selected {issueVariant} will
|
||||||
|
also be deleted. All of the data related to the {issueVariant} will be permanently removed. This action cannot
|
||||||
|
be undone.
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
primaryButtonText={{
|
||||||
|
loading: "Deleting",
|
||||||
|
default: `Delete ${issueVariant}`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
@ -1,2 +1,4 @@
|
|||||||
|
export * from "./bulk-archive-modal";
|
||||||
|
export * from "./bulk-delete-modal";
|
||||||
export * from "./properties";
|
export * from "./properties";
|
||||||
export * from "./root";
|
export * from "./root";
|
||||||
|
@ -1,26 +1,78 @@
|
|||||||
|
import { useState } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
import { Trash2 } from "lucide-react";
|
import { Trash2 } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { ArchiveIcon, Tooltip } from "@plane/ui";
|
import { ArchiveIcon, Tooltip } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { IssueBulkOperationsProperties } from "@/components/issues";
|
import {
|
||||||
|
BulkArchiveConfirmationModal,
|
||||||
|
BulkDeleteConfirmationModal,
|
||||||
|
IssueBulkOperationsProperties,
|
||||||
|
} from "@/components/issues";
|
||||||
|
// helpers
|
||||||
|
import { cn } from "@/helpers/common.helper";
|
||||||
|
// hooks
|
||||||
|
import { useBulkIssueOperations } from "@/hooks/store";
|
||||||
|
|
||||||
export const IssueBulkOperationsRoot: React.FC<any> = observer((props) => {
|
export const IssueBulkOperationsRoot = observer(() => {
|
||||||
const {} = props;
|
// states
|
||||||
|
const [isBulkArchiveModalOpen, setIsBulkArchiveModalOpen] = useState(false);
|
||||||
|
const [isBulkDeleteModalOpen, setIsBulkDeleteModalOpen] = useState(false);
|
||||||
|
// router
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
// store hooks
|
||||||
|
const { issueIds } = useBulkIssueOperations();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{workspaceSlug && projectId && (
|
||||||
|
<BulkArchiveConfirmationModal
|
||||||
|
isOpen={isBulkArchiveModalOpen}
|
||||||
|
handleClose={() => setIsBulkArchiveModalOpen(false)}
|
||||||
|
issueIds={issueIds}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{workspaceSlug && projectId && (
|
||||||
|
<BulkDeleteConfirmationModal
|
||||||
|
isOpen={isBulkDeleteModalOpen}
|
||||||
|
handleClose={() => setIsBulkDeleteModalOpen(false)}
|
||||||
|
issueIds={issueIds}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="h-full w-full bg-custom-background-100 border-t border-custom-border-200 py-4 px-3.5 flex items-center divide-x-[0.5px] divide-custom-border-200 text-custom-text-300">
|
<div className="h-full w-full bg-custom-background-100 border-t border-custom-border-200 py-4 px-3.5 flex items-center divide-x-[0.5px] divide-custom-border-200 text-custom-text-300">
|
||||||
<div className="h-7 pr-3 text-sm flex items-center">2 selected</div>
|
<div className="h-7 pr-3 text-sm flex items-center">2 selected</div>
|
||||||
<div className="h-7 px-3 flex items-center">
|
<div className="h-7 px-3 flex items-center">
|
||||||
<Tooltip tooltipContent="Archive">
|
<Tooltip tooltipContent="Archive">
|
||||||
<button type="button" className="outline-none grid place-items-center">
|
<button
|
||||||
|
type="button"
|
||||||
|
className={cn("outline-none grid place-items-center", {
|
||||||
|
"cursor-not-allowed text-custom-text-400": issueIds.length === 0,
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (issueIds.length > 0) setIsBulkArchiveModalOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ArchiveIcon className="size-4" />
|
<ArchiveIcon className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-7 px-3 flex items-center">
|
<div className="h-7 px-3 flex items-center">
|
||||||
<Tooltip tooltipContent="Delete">
|
<Tooltip tooltipContent="Delete">
|
||||||
<button type="button" className="outline-none grid place-items-center">
|
<button
|
||||||
|
type="button"
|
||||||
|
className={cn("outline-none grid place-items-center", {
|
||||||
|
"cursor-not-allowed text-custom-text-400": issueIds.length === 0,
|
||||||
|
})}
|
||||||
|
onClick={() => {
|
||||||
|
if (issueIds.length > 0) setIsBulkDeleteModalOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Trash2 className="size-4" />
|
<Trash2 className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -29,5 +81,6 @@ export const IssueBulkOperationsRoot: React.FC<any> = observer((props) => {
|
|||||||
<IssueBulkOperationsProperties />
|
<IssueBulkOperationsProperties />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -56,7 +56,7 @@ export const DeleteLabelModal: React.FC<Props> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDeletion}
|
handleSubmit={handleDeletion}
|
||||||
isDeleting={isDeleteLoading}
|
isSubmitting={isDeleteLoading}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Label"
|
title="Delete Label"
|
||||||
content={
|
content={
|
||||||
|
@ -73,7 +73,7 @@ export const DeleteModuleModal: React.FC<Props> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDeletion}
|
handleSubmit={handleDeletion}
|
||||||
isDeleting={isDeleteLoading}
|
isSubmitting={isDeleteLoading}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Module"
|
title="Delete Module"
|
||||||
content={
|
content={
|
||||||
|
@ -74,7 +74,7 @@ export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = observer((pr
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDelete}
|
handleSubmit={handleDelete}
|
||||||
isDeleting={isDeleting}
|
isSubmitting={isDeleting}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete Page"
|
title="Delete Page"
|
||||||
content={
|
content={
|
||||||
|
@ -81,7 +81,7 @@ export const DeleteStateModal: React.FC<Props> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDeletion}
|
handleSubmit={handleDeletion}
|
||||||
isDeleting={isDeleteLoading}
|
isSubmitting={isDeleteLoading}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete State"
|
title="Delete State"
|
||||||
content={
|
content={
|
||||||
|
@ -62,7 +62,7 @@ export const DeleteProjectViewModal: React.FC<Props> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDeleteView}
|
handleSubmit={handleDeleteView}
|
||||||
isDeleting={isDeleteLoading}
|
isSubmitting={isDeleteLoading}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete View"
|
title="Delete View"
|
||||||
content={
|
content={
|
||||||
|
@ -55,7 +55,7 @@ export const DeleteWebhookModal: FC<IDeleteWebhook> = (props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDelete}
|
handleSubmit={handleDelete}
|
||||||
isDeleting={isDeleting}
|
isSubmitting={isDeleting}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete webhook"
|
title="Delete webhook"
|
||||||
content={
|
content={
|
||||||
|
@ -67,7 +67,7 @@ export const DeleteGlobalViewModal: React.FC<Props> = observer((props) => {
|
|||||||
<AlertModalCore
|
<AlertModalCore
|
||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
handleSubmit={handleDeletion}
|
handleSubmit={handleDeletion}
|
||||||
isDeleting={isDeleteLoading}
|
isSubmitting={isDeleteLoading}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title="Delete View"
|
title="Delete View"
|
||||||
content={
|
content={
|
||||||
|
@ -266,7 +266,9 @@ export class IssueService extends APIService {
|
|||||||
data: {
|
data: {
|
||||||
issue_ids: string[];
|
issue_ids: string[];
|
||||||
}
|
}
|
||||||
): Promise<any> {
|
): Promise<{
|
||||||
|
archived_at: string;
|
||||||
|
}> {
|
||||||
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-archive-issues/`, data)
|
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-archive-issues/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -27,6 +27,7 @@ export interface IProjectIssues {
|
|||||||
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue>;
|
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue>;
|
||||||
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
||||||
|
archiveBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
||||||
@ -59,6 +60,7 @@ export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
|||||||
removeIssue: action,
|
removeIssue: action,
|
||||||
archiveIssue: action,
|
archiveIssue: action,
|
||||||
removeBulkIssues: action,
|
removeBulkIssues: action,
|
||||||
|
archiveBulkIssues: action,
|
||||||
quickAddIssue: action,
|
quickAddIssue: action,
|
||||||
});
|
});
|
||||||
// root store
|
// root store
|
||||||
@ -260,4 +262,20 @@ export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
archiveBulkIssues = async (workspaceSlug: string, projectId: string, issueIds: string[]) => {
|
||||||
|
try {
|
||||||
|
const response = await this.issueService.bulkArchiveIssues(workspaceSlug, projectId, { issue_ids: issueIds });
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
issueIds.forEach((issueId) => {
|
||||||
|
this.rootStore.issues.updateIssue(issueId, {
|
||||||
|
archived_at: response.archived_at,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user