mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: state delete validation (#930)
This commit is contained in:
parent
48e77ea81b
commit
99dd1b9f0c
@ -14,7 +14,7 @@ import stateService from "services/state.service";
|
|||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, STATE_LIST } from "constants/fetch-keys";
|
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY, STATES_LIST } from "constants/fetch-keys";
|
||||||
// icons
|
// icons
|
||||||
import { CheckIcon, getStateGroupIcon } from "components/icons";
|
import { CheckIcon, getStateGroupIcon } from "components/icons";
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export const ChangeIssueState: React.FC<Props> = ({ setIsPaletteOpen, issue }) =
|
|||||||
const { workspaceSlug, projectId, issueId } = router.query;
|
const { workspaceSlug, projectId, issueId } = router.query;
|
||||||
|
|
||||||
const { data: stateGroups, mutate: mutateIssueDetails } = useSWR(
|
const { data: stateGroups, mutate: mutateIssueDetails } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -15,7 +15,7 @@ import issuesService from "services/issues.service";
|
|||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
// types
|
// types
|
||||||
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATE_LIST } from "constants/fetch-keys";
|
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys";
|
||||||
import { IIssueFilterOptions } from "types";
|
import { IIssueFilterOptions } from "types";
|
||||||
|
|
||||||
export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
||||||
@ -37,7 +37,7 @@ export const FilterList: React.FC<any> = ({ filters, setFilters }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug
|
workspaceSlug
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -46,7 +46,7 @@ import {
|
|||||||
MODULE_DETAILS,
|
MODULE_DETAILS,
|
||||||
MODULE_ISSUES_WITH_PARAMS,
|
MODULE_ISSUES_WITH_PARAMS,
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
STATE_LIST,
|
STATES_LIST,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
// image
|
// image
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
} = useIssuesView();
|
} = useIssuesView();
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug
|
workspaceSlug
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -14,7 +14,7 @@ import { getStateGroupIcon } from "components/icons";
|
|||||||
// helpers
|
// helpers
|
||||||
import { getStatesList } from "helpers/state.helper";
|
import { getStatesList } from "helpers/state.helper";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
@ -29,7 +29,7 @@ export const IssueStateSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId)
|
? () => stateService.getStates(workspaceSlug as string, projectId)
|
||||||
: null
|
: null
|
||||||
|
@ -17,7 +17,7 @@ import { addSpaceIfCamelCase } from "helpers/string.helper";
|
|||||||
// types
|
// types
|
||||||
import { UserAuth } from "types";
|
import { UserAuth } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: string;
|
value: string;
|
||||||
@ -30,7 +30,7 @@ export const SidebarStateSelect: React.FC<Props> = ({ value, onChange, userAuth
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -15,7 +15,7 @@ import { getStatesList } from "helpers/state.helper";
|
|||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
@ -36,7 +36,7 @@ export const ViewStateSelect: React.FC<Props> = ({
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && issue ? STATE_LIST(issue.project) : null,
|
workspaceSlug && issue ? STATES_LIST(issue.project) : null,
|
||||||
workspaceSlug && issue
|
workspaceSlug && issue
|
||||||
? () => stateService.getStates(workspaceSlug as string, issue.project)
|
? () => stateService.getStates(workspaceSlug as string, issue.project)
|
||||||
: null
|
: null
|
||||||
|
@ -19,9 +19,9 @@ import { CustomSelect, Input, PrimaryButton, SecondaryButton, TextArea } from "c
|
|||||||
// icons
|
// icons
|
||||||
import { ChevronDownIcon } from "@heroicons/react/24/outline";
|
import { ChevronDownIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import type { IState } from "types";
|
import type { IState, IStateResponse } from "types";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { GROUP_CHOICES } from "constants/project";
|
import { GROUP_CHOICES } from "constants/project";
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ type Props = {
|
|||||||
const defaultValues: Partial<IState> = {
|
const defaultValues: Partial<IState> = {
|
||||||
name: "",
|
name: "",
|
||||||
description: "",
|
description: "",
|
||||||
color: "#000000",
|
color: "#858e96",
|
||||||
group: "backlog",
|
group: "backlog",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,8 +70,19 @@ export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClo
|
|||||||
|
|
||||||
await stateService
|
await stateService
|
||||||
.createState(workspaceSlug as string, projectId, payload)
|
.createState(workspaceSlug as string, projectId, payload)
|
||||||
.then(() => {
|
.then((res) => {
|
||||||
mutate(STATE_LIST(projectId));
|
mutate<IStateResponse>(
|
||||||
|
STATES_LIST(projectId.toString()),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prevData,
|
||||||
|
[res.group]: [...prevData[res.group], res],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
onClose();
|
onClose();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -17,9 +17,9 @@ import useToast from "hooks/use-toast";
|
|||||||
// ui
|
// ui
|
||||||
import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui";
|
import { CustomSelect, Input, PrimaryButton, SecondaryButton } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import type { IState } from "types";
|
import type { IState, IStateResponse } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { GROUP_CHOICES } from "constants/project";
|
import { GROUP_CHOICES } from "constants/project";
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ export type StateGroup = "backlog" | "unstarted" | "started" | "completed" | "ca
|
|||||||
|
|
||||||
const defaultValues: Partial<IState> = {
|
const defaultValues: Partial<IState> = {
|
||||||
name: "",
|
name: "",
|
||||||
color: "#000000",
|
color: "#858e96",
|
||||||
group: "backlog",
|
group: "backlog",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,11 +80,23 @@ export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, select
|
|||||||
const payload: IState = {
|
const payload: IState = {
|
||||||
...formData,
|
...formData,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
await stateService
|
await stateService
|
||||||
.createState(workspaceSlug as string, projectId as string, { ...payload })
|
.createState(workspaceSlug.toString(), projectId.toString(), { ...payload })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(STATE_LIST(projectId as string));
|
mutate<IStateResponse>(
|
||||||
|
STATES_LIST(projectId.toString()),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...prevData,
|
||||||
|
[res.group]: [...prevData[res.group], res],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
handleClose();
|
handleClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
@ -109,11 +121,11 @@ export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, select
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await stateService
|
await stateService
|
||||||
.updateState(workspaceSlug as string, projectId as string, data.id, {
|
.updateState(workspaceSlug.toString(), projectId.toString(), data.id, {
|
||||||
...payload,
|
...payload,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(STATE_LIST(projectId as string));
|
mutate(STATES_LIST(projectId.toString()));
|
||||||
handleClose();
|
handleClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR, { mutate } from "swr";
|
import { mutate } from "swr";
|
||||||
|
|
||||||
// headless ui
|
// headless ui
|
||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
@ -10,17 +10,14 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||||
// services
|
// services
|
||||||
import stateServices from "services/state.service";
|
import stateServices from "services/state.service";
|
||||||
import issuesServices from "services/issues.service";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// ui
|
// ui
|
||||||
import { DangerButton, SecondaryButton } from "components/ui";
|
import { DangerButton, SecondaryButton } from "components/ui";
|
||||||
// helpers
|
|
||||||
import { groupBy } from "helpers/array.helper";
|
|
||||||
// types
|
// types
|
||||||
import type { IState } from "types";
|
import type { IState, IStateResponse } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { STATE_LIST, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -30,54 +27,60 @@ type Props = {
|
|||||||
|
|
||||||
export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
|
export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) => {
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
const [issuesWithThisStateExist, setIssuesWithThisStateExist] = useState(true);
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { data: issues } = useSWR(
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)
|
|
||||||
: null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => issuesServices.getIssues(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeletion = async () => {
|
const handleDeletion = async () => {
|
||||||
|
if (!workspaceSlug || !data) return;
|
||||||
|
|
||||||
setIsDeleteLoading(true);
|
setIsDeleteLoading(true);
|
||||||
if (!data || !workspaceSlug || issuesWithThisStateExist) return;
|
|
||||||
await stateServices
|
await stateServices
|
||||||
.deleteState(workspaceSlug as string, data.project, data.id)
|
.deleteState(workspaceSlug as string, data.project, data.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(STATE_LIST(data.project));
|
mutate<IStateResponse>(
|
||||||
handleClose();
|
STATES_LIST(data.project),
|
||||||
|
(prevData) => {
|
||||||
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
setToastAlert({
|
const stateGroup = [...prevData[data.group]].filter((s) => s.id !== data.id);
|
||||||
title: "Success",
|
|
||||||
type: "success",
|
return {
|
||||||
message: "State deleted successfully",
|
...prevData,
|
||||||
});
|
[data.group]: stateGroup,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((err) => {
|
||||||
console.log(error);
|
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
|
|
||||||
|
if (err.status === 400)
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message:
|
||||||
|
"This state contains some issues within it, please move them to some other state to delete this state.",
|
||||||
|
});
|
||||||
|
else
|
||||||
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "State could not be deleted. Please try again.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupedIssues = groupBy(issues ?? [], "state");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (data) setIssuesWithThisStateExist(!!groupedIssues[data.id]);
|
|
||||||
}, [groupedIssues, data]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={React.Fragment}>
|
<Transition.Root show={isOpen} as={React.Fragment}>
|
||||||
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
<Dialog as="div" className="relative z-20" onClose={handleClose}>
|
||||||
@ -127,24 +130,12 @@ export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data }) =>
|
|||||||
the state will be permanently removed. This action cannot be undone.
|
the state will be permanently removed. This action cannot be undone.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2">
|
|
||||||
{issuesWithThisStateExist && (
|
|
||||||
<p className="text-sm text-red-500">
|
|
||||||
There are issues with this state. Please move them to another state
|
|
||||||
before deleting this state.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex justify-end gap-2 p-4 sm:px-6">
|
||||||
<div className="flex justify-end gap-2 bg-gray-50 p-4 sm:px-6">
|
|
||||||
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
|
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
|
||||||
<DangerButton
|
<DangerButton onClick={handleDeletion} loading={isDeleteLoading}>
|
||||||
onClick={handleDeletion}
|
|
||||||
disabled={issuesWithThisStateExist}
|
|
||||||
loading={isDeleteLoading}
|
|
||||||
>
|
|
||||||
{isDeleteLoading ? "Deleting..." : "Delete"}
|
{isDeleteLoading ? "Deleting..." : "Delete"}
|
||||||
</DangerButton>
|
</DangerButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
PencilSquareIcon,
|
PencilSquareIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
|
import { getStateGroupIcon } from "components/icons";
|
||||||
// helpers
|
// helpers
|
||||||
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
||||||
import { groupBy, orderArrayBy } from "helpers/array.helper";
|
import { groupBy, orderArrayBy } from "helpers/array.helper";
|
||||||
@ -22,8 +23,7 @@ import { orderStateGroups } from "helpers/state.helper";
|
|||||||
// types
|
// types
|
||||||
import { IState } from "types";
|
import { IState } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
import { getStateGroupIcon } from "components/icons";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
index: number;
|
index: number;
|
||||||
@ -60,7 +60,7 @@ export const SingleState: React.FC<Props> = ({
|
|||||||
newStatesList = orderArrayBy(newStatesList, "sequence", "ascending");
|
newStatesList = orderArrayBy(newStatesList, "sequence", "ascending");
|
||||||
|
|
||||||
mutate(
|
mutate(
|
||||||
STATE_LIST(projectId as string),
|
STATES_LIST(projectId as string),
|
||||||
orderStateGroups(groupBy(newStatesList, "group")),
|
orderStateGroups(groupBy(newStatesList, "group")),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
@ -76,7 +76,7 @@ export const SingleState: React.FC<Props> = ({
|
|||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(STATE_LIST(projectId as string));
|
mutate(STATES_LIST(projectId as string));
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -89,7 +89,7 @@ export const SingleState: React.FC<Props> = ({
|
|||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(STATE_LIST(projectId as string));
|
mutate(STATES_LIST(projectId as string));
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -115,7 +115,7 @@ export const SingleState: React.FC<Props> = ({
|
|||||||
newStatesList = orderArrayBy(newStatesList, "sequence", "ascending");
|
newStatesList = orderArrayBy(newStatesList, "sequence", "ascending");
|
||||||
|
|
||||||
mutate(
|
mutate(
|
||||||
STATE_LIST(projectId as string),
|
STATES_LIST(projectId as string),
|
||||||
orderStateGroups(groupBy(newStatesList, "group")),
|
orderStateGroups(groupBy(newStatesList, "group")),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
@ -126,7 +126,7 @@ export const SingleState: React.FC<Props> = ({
|
|||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
mutate(STATE_LIST(projectId as string));
|
mutate(STATES_LIST(projectId as string));
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -140,7 +140,7 @@ export const SingleState: React.FC<Props> = ({
|
|||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{getStateGroupIcon(state.group, "20", "20", state.color)}
|
{getStateGroupIcon(state.group, "20", "20", state.color)}
|
||||||
<div>
|
<div>
|
||||||
<h6 className="font-medium text-brand-muted-1">{addSpaceIfCamelCase(state.name)}</h6>
|
<h6 className="text-brand-muted-1 font-medium">{addSpaceIfCamelCase(state.name)}</h6>
|
||||||
<p className="text-xs text-gray-400">{state.description}</p>
|
<p className="text-xs text-gray-400">{state.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,7 @@ import { getStatesList } from "helpers/state.helper";
|
|||||||
// types
|
// types
|
||||||
import { IIssueFilterOptions, IQuery } from "types";
|
import { IIssueFilterOptions, IQuery } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATE_LIST } from "constants/fetch-keys";
|
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS, STATES_LIST } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { PRIORITIES } from "constants/project";
|
import { PRIORITIES } from "constants/project";
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export const SelectFilters: React.FC<Props> = ({
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -89,8 +89,8 @@ export const CYCLE_DRAFT_LIST = (projectId: string) =>
|
|||||||
export const CYCLE_COMPLETE_LIST = (projectId: string) =>
|
export const CYCLE_COMPLETE_LIST = (projectId: string) =>
|
||||||
`CYCLE_COMPLETE_LIST_${projectId.toUpperCase()}`;
|
`CYCLE_COMPLETE_LIST_${projectId.toUpperCase()}`;
|
||||||
|
|
||||||
export const STATE_LIST = (projectId: string) => `STATE_LIST_${projectId.toUpperCase()}`;
|
export const STATES_LIST = (projectId: string) => `STATES_LIST_${projectId.toUpperCase()}`;
|
||||||
export const STATE_DETAIL = "STATE_DETAILS";
|
export const STATE_DETAILS = "STATE_DETAILS";
|
||||||
|
|
||||||
export const USER_ISSUE = (workspaceSlug: string) => `USER_ISSUE_${workspaceSlug.toUpperCase()}`;
|
export const USER_ISSUE = (workspaceSlug: string) => `USER_ISSUE_${workspaceSlug.toUpperCase()}`;
|
||||||
export const USER_ACTIVITY = "USER_ACTIVITY";
|
export const USER_ACTIVITY = "USER_ACTIVITY";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// types
|
// types
|
||||||
import { IState, StateResponse } from "types";
|
import { IState, IStateResponse } from "types";
|
||||||
|
|
||||||
export const orderStateGroups = (unorderedStateGroups: StateResponse) =>
|
export const orderStateGroups = (unorderedStateGroups: IStateResponse) =>
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{ backlog: [], unstarted: [], started: [], completed: [], cancelled: [] },
|
{ backlog: [], unstarted: [], started: [], completed: [], cancelled: [] },
|
||||||
unorderedStateGroups
|
unorderedStateGroups
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
CYCLE_ISSUES_WITH_PARAMS,
|
CYCLE_ISSUES_WITH_PARAMS,
|
||||||
MODULE_ISSUES_WITH_PARAMS,
|
MODULE_ISSUES_WITH_PARAMS,
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
STATE_LIST,
|
STATES_LIST,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
|
||||||
const useIssuesView = () => {
|
const useIssuesView = () => {
|
||||||
@ -100,7 +100,7 @@ const useIssuesView = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -12,7 +12,7 @@ import { getStatesList } from "helpers/state.helper";
|
|||||||
// types
|
// types
|
||||||
import { Properties, NestedKeyOf, IIssue } from "types";
|
import { Properties, NestedKeyOf, IIssue } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
import { PRIORITIES } from "constants/project";
|
import { PRIORITIES } from "constants/project";
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ const useMyIssuesProperties = (issues?: IIssue[]) => {
|
|||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
|
||||||
const { data: stateGroups } = useSWR(
|
const { data: stateGroups } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -6,7 +6,8 @@ import useSWR from "swr";
|
|||||||
|
|
||||||
// services
|
// services
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
import projectService from "services/project.service";
|
// hooks
|
||||||
|
import useProjectDetails from "hooks/use-project-details";
|
||||||
// layouts
|
// layouts
|
||||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
|
||||||
// components
|
// components
|
||||||
@ -26,7 +27,7 @@ import { getStatesList, orderStateGroups } from "helpers/state.helper";
|
|||||||
// types
|
// types
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_DETAILS, STATE_LIST } from "constants/fetch-keys";
|
import { STATES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
const StatesSettings: NextPage = () => {
|
const StatesSettings: NextPage = () => {
|
||||||
const [activeGroup, setActiveGroup] = useState<StateGroup>(null);
|
const [activeGroup, setActiveGroup] = useState<StateGroup>(null);
|
||||||
@ -36,15 +37,10 @@ const StatesSettings: NextPage = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { data: projectDetails } = useSWR(
|
const { projectDetails } = useProjectDetails();
|
||||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
? () => stateService.getStates(workspaceSlug as string, projectId as string)
|
||||||
: null
|
: null
|
||||||
|
@ -8,7 +8,7 @@ const trackEvent =
|
|||||||
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
|
process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { IState, StateResponse } from "types";
|
import type { IState, IStateResponse } from "types";
|
||||||
|
|
||||||
class ProjectStateServices extends APIService {
|
class ProjectStateServices extends APIService {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -26,7 +26,7 @@ class ProjectStateServices extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStates(workspaceSlug: string, projectId: string): Promise<StateResponse> {
|
async getStates(workspaceSlug: string, projectId: string): Promise<IStateResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`)
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/states/`)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -96,7 +96,7 @@ class ProjectStateServices extends APIService {
|
|||||||
return response?.data;
|
return response?.data;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
apps/app/types/state.d.ts
vendored
2
apps/app/types/state.d.ts
vendored
@ -19,6 +19,6 @@ export interface IState {
|
|||||||
workspace_detail: IWorkspaceLite;
|
workspace_detail: IWorkspaceLite;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StateResponse {
|
export interface IStateResponse {
|
||||||
[key: string]: IState[];
|
[key: string]: IState[];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user