mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
refactor: removed unnecessary api calls
This commit is contained in:
parent
d673aedf48
commit
0e07c1e19f
@ -34,7 +34,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SingleBoard: React.FC<Props> = ({
|
export const SingleBoard: React.FC<Props> = ({
|
||||||
type = "issue",
|
type,
|
||||||
provided,
|
provided,
|
||||||
snapshot,
|
snapshot,
|
||||||
bgColor,
|
bgColor,
|
||||||
@ -117,6 +117,7 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
{...provided.dragHandleProps}
|
{...provided.dragHandleProps}
|
||||||
>
|
>
|
||||||
<SingleBoardIssue
|
<SingleBoardIssue
|
||||||
|
type={type}
|
||||||
issue={childIssue}
|
issue={childIssue}
|
||||||
properties={properties}
|
properties={properties}
|
||||||
snapshot={snapshot}
|
snapshot={snapshot}
|
||||||
|
@ -15,7 +15,6 @@ import { TrashIcon } from "@heroicons/react/24/outline";
|
|||||||
// services
|
// services
|
||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
import projectService from "services/project.service";
|
|
||||||
// components
|
// components
|
||||||
import { AssigneesList, CustomDatePicker } from "components/ui";
|
import { AssigneesList, CustomDatePicker } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
@ -34,18 +33,11 @@ import {
|
|||||||
} from "types";
|
} from "types";
|
||||||
// common
|
// common
|
||||||
import { PRIORITIES } from "constants/";
|
import { PRIORITIES } from "constants/";
|
||||||
import {
|
import { STATE_LIST, CYCLE_ISSUES, MODULE_ISSUES, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
||||||
STATE_LIST,
|
|
||||||
PROJECT_DETAILS,
|
|
||||||
CYCLE_ISSUES,
|
|
||||||
MODULE_ISSUES,
|
|
||||||
PROJECT_ISSUES_LIST,
|
|
||||||
} from "constants/fetch-keys";
|
|
||||||
import { getPriorityIcon } from "constants/global";
|
import { getPriorityIcon } from "constants/global";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: string;
|
type?: string;
|
||||||
typeId?: string;
|
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
properties: Properties;
|
properties: Properties;
|
||||||
snapshot: DraggableStateSnapshot;
|
snapshot: DraggableStateSnapshot;
|
||||||
@ -57,7 +49,6 @@ type Props = {
|
|||||||
|
|
||||||
export const SingleBoardIssue: React.FC<Props> = ({
|
export const SingleBoardIssue: React.FC<Props> = ({
|
||||||
type,
|
type,
|
||||||
typeId,
|
|
||||||
issue,
|
issue,
|
||||||
properties,
|
properties,
|
||||||
snapshot,
|
snapshot,
|
||||||
@ -67,7 +58,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
userAuth,
|
userAuth,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
||||||
@ -76,19 +67,12 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: projectDetails } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const partialUpdateIssue = (formData: Partial<IIssue>) => {
|
const partialUpdateIssue = (formData: Partial<IIssue>) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
if (typeId) {
|
if (cycleId)
|
||||||
mutate<CycleIssueResponse[]>(
|
mutate<CycleIssueResponse[]>(
|
||||||
CYCLE_ISSUES(typeId ?? ""),
|
CYCLE_ISSUES(cycleId as string),
|
||||||
(prevData) => {
|
(prevData) => {
|
||||||
const updatedIssues = (prevData ?? []).map((p) => {
|
const updatedIssues = (prevData ?? []).map((p) => {
|
||||||
if (p.issue_detail.id === issue.id) {
|
if (p.issue_detail.id === issue.id) {
|
||||||
@ -107,8 +91,9 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (moduleId)
|
||||||
mutate<ModuleIssueResponse[]>(
|
mutate<ModuleIssueResponse[]>(
|
||||||
MODULE_ISSUES(typeId ?? ""),
|
MODULE_ISSUES(moduleId as string),
|
||||||
(prevData) => {
|
(prevData) => {
|
||||||
const updatedIssues = (prevData ?? []).map((p) => {
|
const updatedIssues = (prevData ?? []).map((p) => {
|
||||||
if (p.issue_detail.id === issue.id) {
|
if (p.issue_detail.id === issue.id) {
|
||||||
@ -126,7 +111,6 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
mutate<IssueResponse>(
|
mutate<IssueResponse>(
|
||||||
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
||||||
@ -143,10 +127,14 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
issuesService
|
issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (typeId) {
|
mutate(
|
||||||
mutate(CYCLE_ISSUES(typeId ?? ""));
|
cycleId ? CYCLE_ISSUES(cycleId as string) : CYCLE_ISSUES(issue?.issue_cycle?.cycle ?? "")
|
||||||
mutate(MODULE_ISSUES(typeId ?? ""));
|
);
|
||||||
}
|
mutate(
|
||||||
|
moduleId
|
||||||
|
? MODULE_ISSUES(moduleId as string)
|
||||||
|
: MODULE_ISSUES(issue?.issue_module?.module ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
|
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
|
||||||
})
|
})
|
||||||
@ -179,7 +167,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
<a>
|
<a>
|
||||||
{properties.key && (
|
{properties.key && (
|
||||||
<div className="mb-2 text-xs font-medium text-gray-500">
|
<div className="mb-2 text-xs font-medium text-gray-500">
|
||||||
{projectDetails?.identifier}-{issue.sequence_id}
|
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<h5
|
<h5
|
||||||
@ -312,11 +300,6 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</Listbox>
|
</Listbox>
|
||||||
)}
|
)}
|
||||||
{/* {properties.cycle && !typeId && (
|
|
||||||
<div className="flex flex-shrink-0 items-center gap-1 rounded border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
|
||||||
{issue.issue_cycle ? issue.issue_cycle.cycle_detail.name : "None"}
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
{properties.due_date && (
|
{properties.due_date && (
|
||||||
<div
|
<div
|
||||||
className={`group relative ${
|
className={`group relative ${
|
||||||
|
@ -1,27 +1,26 @@
|
|||||||
// react
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
// next
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// swr
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
|
||||||
// react hook form
|
// react hook form
|
||||||
import { SubmitHandler, useForm } from "react-hook-form";
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
// services
|
// headless ui
|
||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
// services
|
||||||
import issuesServices from "services/issues.service";
|
import issuesServices from "services/issues.service";
|
||||||
import projectService from "services/project.service";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// headless ui
|
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "components/ui";
|
import { Button } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
|
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
||||||
import { LayerDiagonalIcon } from "components/icons";
|
import { LayerDiagonalIcon } from "components/icons";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IssueResponse } from "types";
|
import { IIssue, IssueResponse } from "types";
|
||||||
// fetch keys
|
// fetch keys
|
||||||
import { PROJECT_ISSUES_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
|
import { PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type FormInput = {
|
type FormInput = {
|
||||||
delete_issue_ids: string[];
|
delete_issue_ids: string[];
|
||||||
@ -50,13 +49,6 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) =>
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: projectDetails } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -213,7 +205,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) =>
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="flex-shrink-0 text-xs text-gray-500">
|
<span className="flex-shrink-0 text-xs text-gray-500">
|
||||||
{projectDetails?.identifier}-{issue.sequence_id}
|
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
<span>{issue.name}</span>
|
<span>{issue.name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,24 +1,17 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
|
|
||||||
import useSWR from "swr";
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { Controller, SubmitHandler, useForm } from "react-hook-form";
|
import { Controller, SubmitHandler, useForm } from "react-hook-form";
|
||||||
// hooks
|
// hooks
|
||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
import { MagnifyingGlassIcon, RectangleStackIcon } from "@heroicons/react/24/outline";
|
import { MagnifyingGlassIcon, RectangleStackIcon } from "@heroicons/react/24/outline";
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// services
|
|
||||||
import projectService from "services/project.service";
|
|
||||||
// headless ui
|
// headless ui
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "components/ui";
|
import { Button } from "components/ui";
|
||||||
import { LayerDiagonalIcon } from "components/icons";
|
import { LayerDiagonalIcon } from "components/icons";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
// fetch-keys
|
|
||||||
import { PROJECT_DETAILS } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
type FormInput = {
|
type FormInput = {
|
||||||
issues: string[];
|
issues: string[];
|
||||||
@ -41,16 +34,6 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, projectId } = router.query;
|
|
||||||
|
|
||||||
const { data: projectDetails } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.getProject(workspaceSlug as string, projectId as string)
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
@ -175,7 +158,7 @@ export const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<span className="flex-shrink-0 text-xs text-gray-500">
|
<span className="flex-shrink-0 text-xs text-gray-500">
|
||||||
{projectDetails?.identifier}-{issue.sequence_id}
|
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||||
</span>
|
</span>
|
||||||
{issue.name}
|
{issue.name}
|
||||||
</>
|
</>
|
||||||
|
@ -10,10 +10,11 @@ import { DropResult } from "react-beautiful-dnd";
|
|||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
|
import modulesService from "services/modules.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useIssueView from "hooks/use-issue-view";
|
import useIssueView from "hooks/use-issue-view";
|
||||||
// components
|
// components
|
||||||
import { AllLists, AllBoards } from "components/core";
|
import { AllLists, AllBoards, ExistingIssuesListModal } from "components/core";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
@ -124,6 +125,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const draggedItem = groupedByIssues[source.droppableId][source.index];
|
const draggedItem = groupedByIssues[source.droppableId][source.index];
|
||||||
|
console.log(draggedItem);
|
||||||
if (source.droppableId !== destination.droppableId) {
|
if (source.droppableId !== destination.droppableId) {
|
||||||
const sourceGroup = source.droppableId; // source group id
|
const sourceGroup = source.droppableId; // source group id
|
||||||
const destinationGroup = destination.droppableId; // destination group id
|
const destinationGroup = destination.droppableId; // destination group id
|
||||||
@ -217,6 +219,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
? MODULE_ISSUES(moduleId as string)
|
? MODULE_ISSUES(moduleId as string)
|
||||||
: MODULE_ISSUES(draggedItem.issue_module?.module ?? "")
|
: MODULE_ISSUES(draggedItem.issue_module?.module ?? "")
|
||||||
);
|
);
|
||||||
|
|
||||||
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
|
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
|
||||||
});
|
});
|
||||||
} else if (selectedGroup === "state_detail.name") {
|
} else if (selectedGroup === "state_detail.name") {
|
||||||
@ -358,6 +361,54 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
setIssueToDelete(issue);
|
setIssueToDelete(issue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const removeIssueFromCycle = (bridgeId: string) => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
mutate<CycleIssueResponse[]>(
|
||||||
|
CYCLE_ISSUES(cycleId as string),
|
||||||
|
(prevData) => prevData?.filter((p) => p.id !== bridgeId),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
issuesService
|
||||||
|
.removeIssueFromCycle(
|
||||||
|
workspaceSlug as string,
|
||||||
|
projectId as string,
|
||||||
|
cycleId as string,
|
||||||
|
bridgeId
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeIssueFromModule = (bridgeId: string) => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
mutate<ModuleIssueResponse[]>(
|
||||||
|
MODULE_ISSUES(moduleId as string),
|
||||||
|
(prevData) => prevData?.filter((p) => p.id !== bridgeId),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
modulesService
|
||||||
|
.removeIssueFromModule(
|
||||||
|
workspaceSlug as string,
|
||||||
|
projectId as string,
|
||||||
|
moduleId as string,
|
||||||
|
bridgeId
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CreateUpdateIssueModal
|
<CreateUpdateIssueModal
|
||||||
@ -385,9 +436,16 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
states={states}
|
states={states}
|
||||||
members={members}
|
members={members}
|
||||||
addIssueToState={addIssueToState}
|
addIssueToState={addIssueToState}
|
||||||
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
|
||||||
handleEditIssue={handleEditIssue}
|
handleEditIssue={handleEditIssue}
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
|
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
||||||
|
removeIssue={
|
||||||
|
type === "cycle"
|
||||||
|
? removeIssueFromCycle
|
||||||
|
: type === "module"
|
||||||
|
? removeIssueFromModule
|
||||||
|
: null
|
||||||
|
}
|
||||||
userAuth={userAuth}
|
userAuth={userAuth}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -12,9 +12,10 @@ type Props = {
|
|||||||
states: IState[] | undefined;
|
states: IState[] | undefined;
|
||||||
members: IProjectMember[] | undefined;
|
members: IProjectMember[] | undefined;
|
||||||
addIssueToState: (groupTitle: string, stateId: string | null) => void;
|
addIssueToState: (groupTitle: string, stateId: string | null) => void;
|
||||||
openIssuesListModal?: (() => void) | null;
|
|
||||||
handleEditIssue: (issue: IIssue) => void;
|
handleEditIssue: (issue: IIssue) => void;
|
||||||
handleDeleteIssue: (issue: IIssue) => void;
|
handleDeleteIssue: (issue: IIssue) => void;
|
||||||
|
openIssuesListModal?: (() => void) | null;
|
||||||
|
removeIssue: ((bridgeId: string) => void) | null;
|
||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ export const AllLists: React.FC<Props> = ({
|
|||||||
openIssuesListModal,
|
openIssuesListModal,
|
||||||
handleEditIssue,
|
handleEditIssue,
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
|
removeIssue,
|
||||||
userAuth,
|
userAuth,
|
||||||
}) => {
|
}) => {
|
||||||
const { groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
|
const { groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
|
||||||
@ -51,6 +53,7 @@ export const AllLists: React.FC<Props> = ({
|
|||||||
handleEditIssue={handleEditIssue}
|
handleEditIssue={handleEditIssue}
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
||||||
|
removeIssue={removeIssue}
|
||||||
userAuth={userAuth}
|
userAuth={userAuth}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@ -11,8 +11,6 @@ import { Listbox, Transition } from "@headlessui/react";
|
|||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
import workspaceService from "services/workspace.service";
|
import workspaceService from "services/workspace.service";
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
// components
|
|
||||||
import { DeleteIssueModal } from "components/issues";
|
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu, CustomSelect, AssigneesList, Avatar, CustomDatePicker } from "components/ui";
|
import { CustomMenu, CustomSelect, AssigneesList, Avatar, CustomDatePicker } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
@ -42,18 +40,16 @@ import { PRIORITIES } from "constants/";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: string;
|
type?: string;
|
||||||
typeId?: string;
|
|
||||||
issue: IIssue;
|
issue: IIssue;
|
||||||
properties: Properties;
|
properties: Properties;
|
||||||
editIssue: () => void;
|
editIssue: () => void;
|
||||||
removeIssue?: () => void;
|
removeIssue?: (() => void) | null;
|
||||||
handleDeleteIssue: (issue: IIssue) => void;
|
handleDeleteIssue: (issue: IIssue) => void;
|
||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SingleListIssue: React.FC<Props> = ({
|
export const SingleListIssue: React.FC<Props> = ({
|
||||||
type,
|
type,
|
||||||
typeId,
|
|
||||||
issue,
|
issue,
|
||||||
properties,
|
properties,
|
||||||
editIssue,
|
editIssue,
|
||||||
@ -62,7 +58,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
userAuth,
|
userAuth,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
workspaceSlug && projectId ? STATE_LIST(projectId as string) : null,
|
||||||
@ -79,9 +75,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
const partialUpdateIssue = (formData: Partial<IIssue>) => {
|
const partialUpdateIssue = (formData: Partial<IIssue>) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
if (typeId) {
|
if (cycleId)
|
||||||
mutate<CycleIssueResponse[]>(
|
mutate<CycleIssueResponse[]>(
|
||||||
CYCLE_ISSUES(typeId ?? ""),
|
CYCLE_ISSUES(cycleId as string),
|
||||||
(prevData) => {
|
(prevData) => {
|
||||||
const updatedIssues = (prevData ?? []).map((p) => {
|
const updatedIssues = (prevData ?? []).map((p) => {
|
||||||
if (p.issue_detail.id === issue.id) {
|
if (p.issue_detail.id === issue.id) {
|
||||||
@ -100,8 +96,9 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (moduleId)
|
||||||
mutate<ModuleIssueResponse[]>(
|
mutate<ModuleIssueResponse[]>(
|
||||||
MODULE_ISSUES(typeId ?? ""),
|
MODULE_ISSUES(moduleId as string),
|
||||||
(prevData) => {
|
(prevData) => {
|
||||||
const updatedIssues = (prevData ?? []).map((p) => {
|
const updatedIssues = (prevData ?? []).map((p) => {
|
||||||
if (p.issue_detail.id === issue.id) {
|
if (p.issue_detail.id === issue.id) {
|
||||||
@ -119,7 +116,6 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
mutate<IssueResponse>(
|
mutate<IssueResponse>(
|
||||||
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string),
|
||||||
@ -136,10 +132,14 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
issuesService
|
issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (typeId) {
|
mutate(
|
||||||
mutate(CYCLE_ISSUES(typeId ?? ""));
|
cycleId ? CYCLE_ISSUES(cycleId as string) : CYCLE_ISSUES(issue?.issue_cycle?.cycle ?? "")
|
||||||
mutate(MODULE_ISSUES(typeId ?? ""));
|
);
|
||||||
}
|
mutate(
|
||||||
|
moduleId
|
||||||
|
? MODULE_ISSUES(moduleId as string)
|
||||||
|
: MODULE_ISSUES(issue?.issue_module?.module ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
|
mutate(PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string));
|
||||||
})
|
})
|
||||||
@ -154,7 +154,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
<div className="flex items-center justify-between gap-2 px-4 py-3 text-sm">
|
<div className="flex items-center justify-between gap-2 px-4 py-3 text-sm">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span
|
<span
|
||||||
className={`block h-1.5 w-1.5 flex-shrink-0 rounded-full`}
|
className="block h-1.5 w-1.5 flex-shrink-0 rounded-full"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: issue.state_detail.color,
|
backgroundColor: issue.state_detail.color,
|
||||||
}}
|
}}
|
||||||
@ -288,11 +288,6 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
))}
|
))}
|
||||||
</CustomSelect>
|
</CustomSelect>
|
||||||
)}
|
)}
|
||||||
{/* {properties.cycle && !typeId && (
|
|
||||||
<div className="flex flex-shrink-0 items-center gap-1 rounded border px-2 py-1 text-xs shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
|
||||||
{issue.issue_cycle ? issue.issue_cycle.cycle_detail.name : "None"}
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
{properties.due_date && (
|
{properties.due_date && (
|
||||||
<div
|
<div
|
||||||
className={`group relative ${
|
className={`group relative ${
|
||||||
@ -409,7 +404,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
{type && !isNotAllowed && (
|
{type && !isNotAllowed && (
|
||||||
<CustomMenu width="auto" ellipsis>
|
<CustomMenu width="auto" ellipsis>
|
||||||
<CustomMenu.MenuItem onClick={editIssue}>Edit</CustomMenu.MenuItem>
|
<CustomMenu.MenuItem onClick={editIssue}>Edit</CustomMenu.MenuItem>
|
||||||
{type !== "issue" && (
|
{type !== "issue" && removeIssue && (
|
||||||
<CustomMenu.MenuItem onClick={removeIssue}>
|
<CustomMenu.MenuItem onClick={removeIssue}>
|
||||||
<>Remove from {type}</>
|
<>Remove from {type}</>
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
|
@ -12,6 +12,7 @@ import { ChevronDownIcon, PlusIcon } from "@heroicons/react/24/outline";
|
|||||||
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IProjectMember, NestedKeyOf, UserAuth } from "types";
|
import { IIssue, IProjectMember, NestedKeyOf, UserAuth } from "types";
|
||||||
|
import { CustomMenu } from "components/ui";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: "issue" | "cycle" | "module";
|
type?: "issue" | "cycle" | "module";
|
||||||
@ -25,11 +26,12 @@ type Props = {
|
|||||||
handleEditIssue: (issue: IIssue) => void;
|
handleEditIssue: (issue: IIssue) => void;
|
||||||
handleDeleteIssue: (issue: IIssue) => void;
|
handleDeleteIssue: (issue: IIssue) => void;
|
||||||
openIssuesListModal?: (() => void) | null;
|
openIssuesListModal?: (() => void) | null;
|
||||||
|
removeIssue: ((bridgeId: string) => void) | null;
|
||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SingleList: React.FC<Props> = ({
|
export const SingleList: React.FC<Props> = ({
|
||||||
type = "issue",
|
type,
|
||||||
groupTitle,
|
groupTitle,
|
||||||
groupedByIssues,
|
groupedByIssues,
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
@ -38,6 +40,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
handleEditIssue,
|
handleEditIssue,
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
openIssuesListModal,
|
openIssuesListModal,
|
||||||
|
removeIssue,
|
||||||
userAuth,
|
userAuth,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -105,11 +108,14 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<SingleListIssue
|
<SingleListIssue
|
||||||
key={issue.id}
|
key={issue.id}
|
||||||
type="issue"
|
type={type}
|
||||||
issue={issue}
|
issue={issue}
|
||||||
properties={properties}
|
properties={properties}
|
||||||
editIssue={() => handleEditIssue(issue)}
|
editIssue={() => handleEditIssue(issue)}
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
|
removeIssue={() => {
|
||||||
|
removeIssue && removeIssue(issue.bridge);
|
||||||
|
}}
|
||||||
userAuth={userAuth}
|
userAuth={userAuth}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -133,7 +139,25 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
<PlusIcon className="h-3 w-3" />
|
<PlusIcon className="h-3 w-3" />
|
||||||
Add issue
|
Add issue
|
||||||
</button>
|
</button>
|
||||||
) : null}
|
) : (
|
||||||
|
<CustomMenu
|
||||||
|
label={
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<PlusIcon className="h-3 w-3" />
|
||||||
|
Add issue
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
optionsPosition="left"
|
||||||
|
noBorder
|
||||||
|
>
|
||||||
|
<CustomMenu.MenuItem onClick={addIssueToState}>Create new</CustomMenu.MenuItem>
|
||||||
|
{openIssuesListModal && (
|
||||||
|
<CustomMenu.MenuItem onClick={openIssuesListModal}>
|
||||||
|
Add an existing issue
|
||||||
|
</CustomMenu.MenuItem>
|
||||||
|
)}
|
||||||
|
</CustomMenu>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -132,30 +132,6 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeIssueFromCycle = (bridgeId: string) => {
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutate<CycleIssueResponse[]>(
|
|
||||||
CYCLE_ISSUES(cycleId as string),
|
|
||||||
(prevData) => prevData?.filter((p) => p.id !== bridgeId),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
issuesServices
|
|
||||||
.removeIssueFromCycle(
|
|
||||||
workspaceSlug as string,
|
|
||||||
projectId as string,
|
|
||||||
cycleId as string,
|
|
||||||
bridgeId
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
console.log(res);
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IssueViewContextProvider>
|
<IssueViewContextProvider>
|
||||||
<CreateUpdateIssueModal
|
<CreateUpdateIssueModal
|
||||||
@ -226,15 +202,12 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
{cycleIssuesArray ? (
|
{cycleIssuesArray ? (
|
||||||
cycleIssuesArray.length > 0 ? (
|
cycleIssuesArray.length > 0 ? (
|
||||||
<div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}>
|
<div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}>
|
||||||
{/* <CyclesListView
|
<IssuesView
|
||||||
|
type="cycle"
|
||||||
issues={cycleIssuesArray ?? []}
|
issues={cycleIssuesArray ?? []}
|
||||||
openCreateIssueModal={openCreateIssueModal}
|
|
||||||
openIssuesListModal={openIssuesListModal}
|
|
||||||
removeIssueFromCycle={removeIssueFromCycle}
|
|
||||||
setPreloadedData={setPreloadedData}
|
|
||||||
userAuth={props}
|
userAuth={props}
|
||||||
/> */}
|
openIssuesListModal={openIssuesListModal}
|
||||||
<IssuesView issues={cycleIssuesArray ?? []} userAuth={props} />
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { RectangleStackIcon } from "@heroicons/react/24/outline";
|
|
||||||
import { PlusIcon } from "@heroicons/react/20/solid";
|
|
||||||
// lib
|
// lib
|
||||||
import { requiredAdmin, requiredAuth } from "lib/auth";
|
import { requiredAdmin, requiredAuth } from "lib/auth";
|
||||||
// services
|
// services
|
||||||
@ -14,25 +13,20 @@ import AppLayout from "layouts/app-layout";
|
|||||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||||
// components
|
// components
|
||||||
import { IssuesFilterView, IssuesView } from "components/core";
|
import { IssuesFilterView, IssuesView } from "components/core";
|
||||||
import { CreateUpdateIssueModal } from "components/issues";
|
|
||||||
// ui
|
// ui
|
||||||
import { Spinner, EmptySpace, EmptySpaceItem, HeaderButton } from "components/ui";
|
import { Spinner, EmptySpace, EmptySpaceItem, HeaderButton } from "components/ui";
|
||||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||||
|
// icons
|
||||||
|
import { RectangleStackIcon, PlusIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import type { IIssue, UserAuth } from "types";
|
import type { UserAuth } from "types";
|
||||||
import type { NextPage, NextPageContext } from "next";
|
import type { NextPage, NextPageContext } from "next";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PROJECT_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
import { PROJECT_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
const ProjectIssues: NextPage<UserAuth> = (props) => {
|
const ProjectIssues: NextPage<UserAuth> = (props) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const router = useRouter();
|
||||||
const [selectedIssue, setSelectedIssue] = useState<
|
const { workspaceSlug, projectId } = router.query;
|
||||||
(IIssue & { actionType: "edit" | "delete" }) | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
const {
|
|
||||||
query: { workspaceSlug, projectId },
|
|
||||||
} = useRouter();
|
|
||||||
|
|
||||||
const { data: projectIssues } = useSWR(
|
const { data: projectIssues } = useSWR(
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
@ -50,23 +44,8 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isOpen) {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setSelectedIssue(undefined);
|
|
||||||
clearTimeout(timer);
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IssueViewContextProvider>
|
<IssueViewContextProvider>
|
||||||
<CreateUpdateIssueModal
|
|
||||||
isOpen={isOpen && selectedIssue?.actionType !== "delete"}
|
|
||||||
prePopulateData={{ ...selectedIssue }}
|
|
||||||
handleClose={() => setIsOpen(false)}
|
|
||||||
data={selectedIssue}
|
|
||||||
/>
|
|
||||||
<AppLayout
|
<AppLayout
|
||||||
breadcrumbs={
|
breadcrumbs={
|
||||||
<Breadcrumbs>
|
<Breadcrumbs>
|
||||||
@ -92,11 +71,8 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{!projectIssues ? (
|
{projectIssues ? (
|
||||||
<div className="flex h-full w-full items-center justify-center">
|
projectIssues.count > 0 ? (
|
||||||
<Spinner />
|
|
||||||
</div>
|
|
||||||
) : projectIssues.count > 0 ? (
|
|
||||||
<IssuesView
|
<IssuesView
|
||||||
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
|
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
|
||||||
userAuth={props}
|
userAuth={props}
|
||||||
@ -117,10 +93,20 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
Icon={PlusIcon}
|
Icon={PlusIcon}
|
||||||
action={() => setIsOpen(true)}
|
action={() => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "c",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</EmptySpace>
|
</EmptySpace>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
<Spinner />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
</IssueViewContextProvider>
|
</IssueViewContextProvider>
|
||||||
|
@ -135,30 +135,6 @@ const SingleModule: React.FC<UserAuth> = (props) => {
|
|||||||
setModuleIssuesListModal(true);
|
setModuleIssuesListModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeIssueFromModule = (issueId: string) => {
|
|
||||||
if (!workspaceSlug || !projectId) return;
|
|
||||||
|
|
||||||
mutate<ModuleIssueResponse[]>(
|
|
||||||
MODULE_ISSUES(moduleId as string),
|
|
||||||
(prevData) => prevData?.filter((p) => p.id !== issueId),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
modulesService
|
|
||||||
.removeIssueFromModule(
|
|
||||||
workspaceSlug as string,
|
|
||||||
projectId as string,
|
|
||||||
moduleId as string,
|
|
||||||
issueId
|
|
||||||
)
|
|
||||||
.then((res) => {
|
|
||||||
console.log(res);
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteModule = () => {
|
const handleDeleteModule = () => {
|
||||||
if (!moduleDetails) return;
|
if (!moduleDetails) return;
|
||||||
|
|
||||||
@ -247,15 +223,12 @@ const SingleModule: React.FC<UserAuth> = (props) => {
|
|||||||
{moduleIssuesArray ? (
|
{moduleIssuesArray ? (
|
||||||
moduleIssuesArray.length > 0 ? (
|
moduleIssuesArray.length > 0 ? (
|
||||||
<div className={`h-full ${moduleSidebar ? "mr-[24rem]" : ""} duration-300`}>
|
<div className={`h-full ${moduleSidebar ? "mr-[24rem]" : ""} duration-300`}>
|
||||||
{/* <ModulesListView
|
<IssuesView
|
||||||
|
type="module"
|
||||||
issues={moduleIssuesArray ?? []}
|
issues={moduleIssuesArray ?? []}
|
||||||
openCreateIssueModal={openCreateIssueModal}
|
|
||||||
openIssuesListModal={openIssuesListModal}
|
|
||||||
removeIssueFromModule={removeIssueFromModule}
|
|
||||||
setPreloadedData={setPreloadedData}
|
|
||||||
userAuth={props}
|
userAuth={props}
|
||||||
/> */}
|
openIssuesListModal={openIssuesListModal}
|
||||||
<IssuesView issues={moduleIssuesArray ?? []} userAuth={props} />
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
Loading…
Reference in New Issue
Block a user