mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
refactor: created global component for kanban board
This commit is contained in:
parent
4f85773a48
commit
58eda658c8
@ -35,7 +35,6 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = ({ email }: EmailCodeFormValues) => {
|
const onSubmit = ({ email }: EmailCodeFormValues) => {
|
||||||
console.log(email);
|
|
||||||
authenticationService
|
authenticationService
|
||||||
.emailCode({ email })
|
.emailCode({ email })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -1,37 +1,38 @@
|
|||||||
// TODO: Refactor this component: into a different file, use this file to export the components
|
// TODO: Refactor this component: into a different file, use this file to export the components
|
||||||
import React, { useState, useCallback, useEffect } from "react";
|
import React, { useState, useCallback, useEffect } from "react";
|
||||||
// next
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// swr
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
// hooks
|
|
||||||
|
// headless ui
|
||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
|
// services
|
||||||
|
import userService from "services/user.service";
|
||||||
|
// hooks
|
||||||
|
import useTheme from "hooks/use-theme";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
|
import useUser from "hooks/use-user";
|
||||||
|
// components
|
||||||
|
import ShortcutsModal from "components/command-palette/shortcuts";
|
||||||
|
import { BulkDeleteIssuesModal } from "components/core";
|
||||||
|
import { CreateProjectModal } from "components/project";
|
||||||
|
import { CreateUpdateIssueModal } from "components/issues";
|
||||||
|
import { CreateUpdateModuleModal } from "components/modules";
|
||||||
|
import CreateUpdateCycleModal from "components/project/cycles/create-update-cycle-modal";
|
||||||
|
// ui
|
||||||
|
import { Button } from "components/ui";
|
||||||
|
// icons
|
||||||
import {
|
import {
|
||||||
FolderIcon,
|
FolderIcon,
|
||||||
RectangleStackIcon,
|
RectangleStackIcon,
|
||||||
ClipboardDocumentListIcon,
|
ClipboardDocumentListIcon,
|
||||||
MagnifyingGlassIcon,
|
MagnifyingGlassIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import useTheme from "hooks/use-theme";
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useUser from "hooks/use-user";
|
|
||||||
// services
|
|
||||||
import userService from "services/user.service";
|
|
||||||
// components
|
|
||||||
import ShortcutsModal from "components/command-palette/shortcuts";
|
|
||||||
import { CreateProjectModal } from "components/project";
|
|
||||||
import { CreateUpdateIssueModal } from "components/issues";
|
|
||||||
import { CreateUpdateModuleModal } from "components/modules";
|
|
||||||
import CreateUpdateCycleModal from "components/project/cycles/create-update-cycle-modal";
|
|
||||||
import BulkDeleteIssuesModal from "components/common/bulk-delete-issues-modal";
|
|
||||||
// headless ui
|
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
// ui
|
|
||||||
import { Button } from "components/ui";
|
|
||||||
// icons
|
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { USER_ISSUE } from "constants/fetch-keys";
|
import { USER_ISSUE } from "constants/fetch-keys";
|
||||||
|
|
||||||
@ -111,7 +112,6 @@ const CommandPalette: React.FC = () => {
|
|||||||
if (!router.query.issueId) return;
|
if (!router.query.issueId) return;
|
||||||
|
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
console.log(url);
|
|
||||||
copyTextToClipboard(url.href)
|
copyTextToClipboard(url.href)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
const SingleBoard = () => <></>;
|
|
||||||
|
|
||||||
export default SingleBoard;
|
|
@ -22,7 +22,7 @@ type Props = {
|
|||||||
selectedGroup: NestedKeyOf<IIssue> | null;
|
selectedGroup: NestedKeyOf<IIssue> | null;
|
||||||
groupTitle: string;
|
groupTitle: string;
|
||||||
createdBy: string | null;
|
createdBy: string | null;
|
||||||
bgColor: string;
|
bgColor?: string;
|
||||||
addIssueToState: () => void;
|
addIssueToState: () => void;
|
||||||
provided?: DraggableProvided;
|
provided?: DraggableProvided;
|
||||||
};
|
};
|
@ -1,70 +1,68 @@
|
|||||||
import React, { useState } from "react";
|
import { Dispatch, SetStateAction, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
// react-beautiful-dnd
|
// react-beautiful-dnd
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
||||||
|
import { Draggable, DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd";
|
||||||
// services
|
// services
|
||||||
import workspaceService from "services/workspace.service";
|
import workspaceService from "services/workspace.service";
|
||||||
|
// hooks
|
||||||
|
import useIssuesProperties from "hooks/use-issue-properties";
|
||||||
// components
|
// components
|
||||||
import SingleIssue from "components/common/board-view/single-issue";
|
import BoardHeader from "components/core/board-view/board-header";
|
||||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
import SingleIssue from "components/core/board-view/single-issue";
|
||||||
import BoardHeader from "components/common/board-view/board-header";
|
|
||||||
// ui
|
|
||||||
import { CustomMenu } from "components/ui";
|
|
||||||
// icons
|
// icons
|
||||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IWorkspaceMember, NestedKeyOf, Properties, UserAuth } from "types";
|
import { IIssue, IWorkspaceMember, NestedKeyOf, UserAuth } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { WORKSPACE_MEMBERS } from "constants/fetch-keys";
|
import { WORKSPACE_MEMBERS } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
properties: Properties;
|
provided?: DraggableProvided;
|
||||||
|
snapshot?: DraggableStateSnapshot;
|
||||||
|
bgColor?: string;
|
||||||
|
groupTitle: string;
|
||||||
groupedByIssues: {
|
groupedByIssues: {
|
||||||
[key: string]: IIssue[];
|
[key: string]: IIssue[];
|
||||||
};
|
};
|
||||||
selectedGroup: NestedKeyOf<IIssue> | null;
|
selectedGroup: NestedKeyOf<IIssue> | null;
|
||||||
groupTitle: string;
|
addIssueToState: () => void;
|
||||||
createdBy: string | null;
|
handleDeleteIssue?: Dispatch<SetStateAction<string | undefined>> | undefined;
|
||||||
bgColor?: string;
|
|
||||||
openCreateIssueModal: (issue?: IIssue, actionType?: "create" | "edit" | "delete") => void;
|
|
||||||
openIssuesListModal: () => void;
|
|
||||||
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
||||||
setPreloadedData: React.Dispatch<
|
|
||||||
React.SetStateAction<
|
|
||||||
| (Partial<IIssue> & {
|
|
||||||
actionType: "createIssue" | "edit" | "delete";
|
|
||||||
})
|
|
||||||
| null
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
stateId: string | null;
|
|
||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SingleModuleBoard: React.FC<Props> = ({
|
export const CommonSingleBoard: React.FC<Props> = ({
|
||||||
properties,
|
provided,
|
||||||
|
snapshot,
|
||||||
|
bgColor,
|
||||||
|
groupTitle,
|
||||||
groupedByIssues,
|
groupedByIssues,
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
groupTitle,
|
addIssueToState,
|
||||||
createdBy,
|
|
||||||
bgColor,
|
|
||||||
openCreateIssueModal,
|
|
||||||
openIssuesListModal,
|
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
setPreloadedData,
|
|
||||||
stateId,
|
|
||||||
userAuth,
|
userAuth,
|
||||||
}) => {
|
}) => {
|
||||||
// collapse/expand
|
// collapse/expand
|
||||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { workspaceSlug, cycleId } = router.query;
|
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
||||||
|
|
||||||
|
const { data: members } = useSWR<IWorkspaceMember[]>(
|
||||||
|
workspaceSlug ? WORKSPACE_MEMBERS : null,
|
||||||
|
workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug as string) : null
|
||||||
|
);
|
||||||
|
|
||||||
|
const createdBy =
|
||||||
|
selectedGroup === "created_by"
|
||||||
|
? members?.find((m) => m.member.id === groupTitle)?.member.first_name ?? "loading..."
|
||||||
|
: null;
|
||||||
|
|
||||||
if (selectedGroup === "priority")
|
if (selectedGroup === "priority")
|
||||||
groupTitle === "high"
|
groupTitle === "high"
|
||||||
@ -75,32 +73,25 @@ const SingleModuleBoard: React.FC<Props> = ({
|
|||||||
? (bgColor = "#22c55e")
|
? (bgColor = "#22c55e")
|
||||||
: (bgColor = "#ff0000");
|
: (bgColor = "#ff0000");
|
||||||
|
|
||||||
const { data: people } = useSWR<IWorkspaceMember[]>(
|
|
||||||
workspaceSlug ? WORKSPACE_MEMBERS : null,
|
|
||||||
workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug as string) : null
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`h-full flex-shrink-0 rounded ${!isCollapsed ? "" : "w-80 border bg-gray-50"}`}>
|
<div
|
||||||
|
className={`h-full flex-shrink-0 rounded ${
|
||||||
|
snapshot && snapshot.isDragging ? "border-theme shadow-lg" : ""
|
||||||
|
} ${!isCollapsed ? "" : "w-80 border bg-gray-50"}`}
|
||||||
|
ref={provided?.innerRef}
|
||||||
|
{...provided?.draggableProps}
|
||||||
|
>
|
||||||
<div className={`${!isCollapsed ? "" : "flex h-full flex-col space-y-3 overflow-y-auto"}`}>
|
<div className={`${!isCollapsed ? "" : "flex h-full flex-col space-y-3 overflow-y-auto"}`}>
|
||||||
<BoardHeader
|
<BoardHeader
|
||||||
addIssueToState={() => {
|
addIssueToState={addIssueToState}
|
||||||
openCreateIssueModal();
|
bgColor={bgColor}
|
||||||
if (selectedGroup !== null) {
|
|
||||||
setPreloadedData({
|
|
||||||
state: stateId !== null ? stateId : undefined,
|
|
||||||
[selectedGroup]: groupTitle,
|
|
||||||
actionType: "createIssue",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
bgColor={bgColor ?? ""}
|
|
||||||
createdBy={createdBy}
|
createdBy={createdBy}
|
||||||
groupTitle={groupTitle}
|
groupTitle={groupTitle}
|
||||||
groupedByIssues={groupedByIssues}
|
groupedByIssues={groupedByIssues}
|
||||||
isCollapsed={isCollapsed}
|
isCollapsed={isCollapsed}
|
||||||
setIsCollapsed={setIsCollapsed}
|
setIsCollapsed={setIsCollapsed}
|
||||||
selectedGroup={selectedGroup}
|
selectedGroup={selectedGroup}
|
||||||
|
provided={provided}
|
||||||
/>
|
/>
|
||||||
<StrictModeDroppable key={groupTitle} droppableId={groupTitle}>
|
<StrictModeDroppable key={groupTitle} droppableId={groupTitle}>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
@ -116,7 +107,7 @@ const SingleModuleBoard: React.FC<Props> = ({
|
|||||||
...(childIssue?.assignees_list ?? []),
|
...(childIssue?.assignees_list ?? []),
|
||||||
...(childIssue?.assignees ?? []),
|
...(childIssue?.assignees ?? []),
|
||||||
]?.map((assignee) => {
|
]?.map((assignee) => {
|
||||||
const tempPerson = people?.find((p) => p.member.id === assignee)?.member;
|
const tempPerson = members?.find((p) => p.member.id === assignee)?.member;
|
||||||
|
|
||||||
return tempPerson;
|
return tempPerson;
|
||||||
});
|
});
|
||||||
@ -130,13 +121,11 @@ const SingleModuleBoard: React.FC<Props> = ({
|
|||||||
{...provided.dragHandleProps}
|
{...provided.dragHandleProps}
|
||||||
>
|
>
|
||||||
<SingleIssue
|
<SingleIssue
|
||||||
type="cycle"
|
|
||||||
typeId={cycleId as string}
|
|
||||||
issue={childIssue}
|
issue={childIssue}
|
||||||
properties={properties}
|
properties={properties}
|
||||||
snapshot={snapshot}
|
snapshot={snapshot}
|
||||||
|
people={members}
|
||||||
assignees={assignees}
|
assignees={assignees}
|
||||||
people={people}
|
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
userAuth={userAuth}
|
userAuth={userAuth}
|
||||||
/>
|
/>
|
||||||
@ -146,35 +135,14 @@ const SingleModuleBoard: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
<CustomMenu
|
{/* <button
|
||||||
label={
|
type="button"
|
||||||
<span className="flex items-center gap-1">
|
className="flex items-center rounded p-2 text-xs font-medium outline-none duration-300 hover:bg-gray-100"
|
||||||
<PlusIcon className="h-3 w-3" />
|
onClick={addIssueToState}
|
||||||
Add issue
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
className="mt-1"
|
|
||||||
optionsPosition="left"
|
|
||||||
noBorder
|
|
||||||
>
|
>
|
||||||
<CustomMenu.MenuItem
|
<PlusIcon className="mr-1 h-3 w-3" />
|
||||||
onClick={() => {
|
Create
|
||||||
openCreateIssueModal();
|
</button> */}
|
||||||
if (selectedGroup !== null) {
|
|
||||||
setPreloadedData({
|
|
||||||
state: stateId !== null ? stateId : undefined,
|
|
||||||
[selectedGroup]: groupTitle,
|
|
||||||
actionType: "createIssue",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Create new
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
<CustomMenu.MenuItem onClick={() => openIssuesListModal()}>
|
|
||||||
Add an existing issue
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
</CustomMenu>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</StrictModeDroppable>
|
</StrictModeDroppable>
|
||||||
@ -182,5 +150,3 @@ const SingleModuleBoard: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SingleModuleBoard;
|
|
@ -8,7 +8,7 @@ import useSWR, { mutate } from "swr";
|
|||||||
import { SubmitHandler, useForm } from "react-hook-form";
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
// services
|
// services
|
||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
import { FolderIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
||||||
import issuesServices from "services/issues.service";
|
import issuesServices from "services/issues.service";
|
||||||
import projectService from "services/project.service";
|
import projectService from "services/project.service";
|
||||||
// hooks
|
// hooks
|
||||||
@ -32,7 +32,7 @@ type Props = {
|
|||||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -256,5 +256,3 @@ const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen }) => {
|
|||||||
</Transition.Root>
|
</Transition.Root>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BulkDeleteIssuesModal;
|
|
@ -32,7 +32,7 @@ type Props = {
|
|||||||
handleOnSubmit: any;
|
handleOnSubmit: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExistingIssuesListModal: React.FC<Props> = ({
|
export const ExistingIssuesListModal: React.FC<Props> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
handleClose: onClose,
|
handleClose: onClose,
|
||||||
issues,
|
issues,
|
||||||
@ -233,5 +233,3 @@ const ExistingIssuesListModal: React.FC<Props> = ({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ExistingIssuesListModal;
|
|
@ -1 +1,5 @@
|
|||||||
export * from "./not-authorized-view";
|
export * from "./not-authorized-view";
|
||||||
|
export * from "./bulk-delete-issues-modal";
|
||||||
|
export * from "./existing-issues-list-modal";
|
||||||
|
export * from "./image-upload-modal";
|
||||||
|
export * from "./view";
|
||||||
|
@ -23,7 +23,7 @@ type Props = {
|
|||||||
issues?: IIssue[];
|
issues?: IIssue[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const View: React.FC<Props> = ({ issues }) => {
|
export const IssuesFilterView: React.FC<Props> = ({ issues }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
@ -203,5 +203,3 @@ const View: React.FC<Props> = ({ issues }) => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default View;
|
|
||||||
|
@ -5,16 +5,14 @@ import { useRouter } from "next/router";
|
|||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
|
||||||
// react-beautiful-dnd
|
// react-beautiful-dnd
|
||||||
import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
import { DragDropContext, Draggable, DropResult } from "react-beautiful-dnd";
|
||||||
// hook
|
// hook
|
||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
|
||||||
import useIssueView from "hooks/use-issue-view";
|
import useIssueView from "hooks/use-issue-view";
|
||||||
// services
|
// services
|
||||||
import stateServices from "services/state.service";
|
import stateServices from "services/state.service";
|
||||||
import issuesServices from "services/issues.service";
|
import issuesServices from "services/issues.service";
|
||||||
import projectService from "services/project.service";
|
|
||||||
// components
|
// components
|
||||||
import SingleBoard from "components/issues/board-view/single-board";
|
import { CommonSingleBoard } from "components/core/board-view/single-board";
|
||||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
// ui
|
// ui
|
||||||
@ -22,7 +20,7 @@ import { Spinner } from "components/ui";
|
|||||||
// types
|
// types
|
||||||
import type { IState, IIssue, IssueResponse, UserAuth } from "types";
|
import type { IState, IIssue, IssueResponse, UserAuth } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { STATE_LIST, PROJECT_ISSUES_LIST, PROJECT_MEMBERS } from "constants/fetch-keys";
|
import { STATE_LIST, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issues: IIssue[];
|
issues: IIssue[];
|
||||||
@ -30,7 +28,7 @@ type Props = {
|
|||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BoardView: React.FC<Props> = ({ issues, handleDeleteIssue, userAuth }) => {
|
export const IssuesBoardView: React.FC<Props> = ({ issues, handleDeleteIssue, userAuth }) => {
|
||||||
const [createIssueModal, setCreateIssueModal] = useState(false);
|
const [createIssueModal, setCreateIssueModal] = useState(false);
|
||||||
const [isIssueDeletionOpen, setIsIssueDeletionOpen] = useState(false);
|
const [isIssueDeletionOpen, setIsIssueDeletionOpen] = useState(false);
|
||||||
const [issueDeletionData, setIssueDeletionData] = useState<IIssue | undefined>();
|
const [issueDeletionData, setIssueDeletionData] = useState<IIssue | undefined>();
|
||||||
@ -50,21 +48,6 @@ const BoardView: React.FC<Props> = ({ issues, handleDeleteIssue, userAuth }) =>
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.projectMembers(workspaceSlug as string, projectId as string)
|
|
||||||
: null,
|
|
||||||
{
|
|
||||||
onErrorRetry(err, _, __, revalidate, revalidateOpts) {
|
|
||||||
if (err?.status === 403) return;
|
|
||||||
setTimeout(() => revalidate(revalidateOpts), 5000);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
|
||||||
|
|
||||||
const handleOnDragEnd = useCallback(
|
const handleOnDragEnd = useCallback(
|
||||||
(result: DropResult) => {
|
(result: DropResult) => {
|
||||||
if (!result.destination || !workspaceSlug || !projectId) return;
|
if (!result.destination || !workspaceSlug || !projectId) return;
|
||||||
@ -208,36 +191,42 @@ const BoardView: React.FC<Props> = ({ issues, handleDeleteIssue, userAuth }) =>
|
|||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
>
|
>
|
||||||
<div className="flex h-full gap-x-4 overflow-x-auto overflow-y-hidden">
|
<div className="flex h-full gap-x-4 overflow-x-auto overflow-y-hidden">
|
||||||
{Object.keys(groupedByIssues).map((singleGroup, index) => (
|
{Object.keys(groupedByIssues).map((singleGroup, index) => {
|
||||||
<SingleBoard
|
const stateId =
|
||||||
key={singleGroup}
|
selectedGroup === "state_detail.name"
|
||||||
selectedGroup={selectedGroup}
|
? states?.find((s) => s.name === singleGroup)?.id ?? null
|
||||||
groupTitle={singleGroup}
|
: null;
|
||||||
createdBy={
|
|
||||||
selectedGroup === "created_by"
|
return (
|
||||||
? members?.find((m) => m.member.id === singleGroup)?.member
|
<Draggable key={singleGroup} draggableId={singleGroup} index={index}>
|
||||||
.first_name ?? "loading..."
|
{(provided, snapshot) => (
|
||||||
: null
|
<CommonSingleBoard
|
||||||
}
|
provided={provided}
|
||||||
groupedByIssues={groupedByIssues}
|
snapshot={snapshot}
|
||||||
index={index}
|
bgColor={
|
||||||
setIsIssueOpen={setCreateIssueModal}
|
selectedGroup === "state_detail.name"
|
||||||
properties={properties}
|
? states?.find((s) => s.name === singleGroup)?.color
|
||||||
setPreloadedData={setPreloadedData}
|
: "#000000"
|
||||||
stateId={
|
}
|
||||||
selectedGroup === "state_detail.name"
|
groupTitle={singleGroup}
|
||||||
? states?.find((s) => s.name === singleGroup)?.id ?? null
|
groupedByIssues={groupedByIssues}
|
||||||
: null
|
selectedGroup={selectedGroup}
|
||||||
}
|
addIssueToState={() => {
|
||||||
bgColor={
|
setCreateIssueModal(true);
|
||||||
selectedGroup === "state_detail.name"
|
if (selectedGroup)
|
||||||
? states?.find((s) => s.name === singleGroup)?.color
|
setPreloadedData({
|
||||||
: "#000000"
|
state: stateId !== null ? stateId : undefined,
|
||||||
}
|
[selectedGroup]: singleGroup,
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
actionType: "createIssue",
|
||||||
userAuth={userAuth}
|
});
|
||||||
/>
|
}}
|
||||||
))}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
|
userAuth={userAuth}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
</div>
|
</div>
|
||||||
@ -254,5 +243,3 @@ const BoardView: React.FC<Props> = ({ issues, handleDeleteIssue, userAuth }) =>
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BoardView;
|
|
@ -1,174 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
|
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
// react-beautiful-dnd
|
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
|
||||||
// components
|
|
||||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
|
||||||
import SingleIssue from "components/common/board-view/single-issue";
|
|
||||||
import BoardHeader from "components/common/board-view/board-header";
|
|
||||||
// icons
|
|
||||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
|
||||||
// services
|
|
||||||
import workspaceService from "services/workspace.service";
|
|
||||||
// types
|
|
||||||
import { IIssue, Properties, NestedKeyOf, IWorkspaceMember, UserAuth } from "types";
|
|
||||||
// fetch-keys
|
|
||||||
import { WORKSPACE_MEMBERS } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
selectedGroup: NestedKeyOf<IIssue> | null;
|
|
||||||
groupTitle: string;
|
|
||||||
groupedByIssues: {
|
|
||||||
[key: string]: IIssue[];
|
|
||||||
};
|
|
||||||
index: number;
|
|
||||||
setIsIssueOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
||||||
properties: Properties;
|
|
||||||
setPreloadedData: React.Dispatch<
|
|
||||||
React.SetStateAction<
|
|
||||||
| (Partial<IIssue> & {
|
|
||||||
actionType: "createIssue" | "edit" | "delete";
|
|
||||||
})
|
|
||||||
| undefined
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
bgColor?: string;
|
|
||||||
stateId: string | null;
|
|
||||||
createdBy: string | null;
|
|
||||||
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
||||||
userAuth: UserAuth;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SingleBoard: React.FC<Props> = ({
|
|
||||||
selectedGroup,
|
|
||||||
groupTitle,
|
|
||||||
groupedByIssues,
|
|
||||||
index,
|
|
||||||
setIsIssueOpen,
|
|
||||||
properties,
|
|
||||||
setPreloadedData,
|
|
||||||
bgColor = "#0f2b16",
|
|
||||||
stateId,
|
|
||||||
createdBy,
|
|
||||||
handleDeleteIssue,
|
|
||||||
userAuth,
|
|
||||||
}) => {
|
|
||||||
// Collapse/Expand
|
|
||||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug } = router.query;
|
|
||||||
|
|
||||||
if (selectedGroup === "priority")
|
|
||||||
groupTitle === "high"
|
|
||||||
? (bgColor = "#dc2626")
|
|
||||||
: groupTitle === "medium"
|
|
||||||
? (bgColor = "#f97316")
|
|
||||||
: groupTitle === "low"
|
|
||||||
? (bgColor = "#22c55e")
|
|
||||||
: (bgColor = "#ff0000");
|
|
||||||
|
|
||||||
const { data: people } = useSWR<IWorkspaceMember[]>(
|
|
||||||
workspaceSlug ? WORKSPACE_MEMBERS : null,
|
|
||||||
workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug as string) : null
|
|
||||||
);
|
|
||||||
|
|
||||||
const addIssueToState = () => {
|
|
||||||
setIsIssueOpen(true);
|
|
||||||
if (selectedGroup)
|
|
||||||
setPreloadedData({
|
|
||||||
state: stateId !== null ? stateId : undefined,
|
|
||||||
[selectedGroup]: groupTitle,
|
|
||||||
actionType: "createIssue",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Draggable draggableId={groupTitle} index={index}>
|
|
||||||
{(provided, snapshot) => (
|
|
||||||
<div
|
|
||||||
className={`h-full flex-shrink-0 rounded ${
|
|
||||||
snapshot.isDragging ? "border-theme shadow-lg" : ""
|
|
||||||
} ${!isCollapsed ? "" : "w-80 border bg-gray-50"}`}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.draggableProps}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`${!isCollapsed ? "" : "flex h-full flex-col space-y-3 overflow-y-auto"}`}
|
|
||||||
>
|
|
||||||
<BoardHeader
|
|
||||||
addIssueToState={addIssueToState}
|
|
||||||
bgColor={bgColor}
|
|
||||||
createdBy={createdBy}
|
|
||||||
groupTitle={groupTitle}
|
|
||||||
groupedByIssues={groupedByIssues}
|
|
||||||
isCollapsed={isCollapsed}
|
|
||||||
setIsCollapsed={setIsCollapsed}
|
|
||||||
selectedGroup={selectedGroup}
|
|
||||||
provided={provided}
|
|
||||||
/>
|
|
||||||
<StrictModeDroppable key={groupTitle} droppableId={groupTitle}>
|
|
||||||
{(provided, snapshot) => (
|
|
||||||
<div
|
|
||||||
className={`mt-3 h-full space-y-3 overflow-y-auto px-3 pb-3 ${
|
|
||||||
snapshot.isDraggingOver ? "bg-indigo-50 bg-opacity-50" : ""
|
|
||||||
} ${!isCollapsed ? "hidden" : "block"}`}
|
|
||||||
{...provided.droppableProps}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
>
|
|
||||||
{groupedByIssues[groupTitle].map((childIssue, index: number) => {
|
|
||||||
const assignees = [
|
|
||||||
...(childIssue?.assignees_list ?? []),
|
|
||||||
...(childIssue?.assignees ?? []),
|
|
||||||
]?.map((assignee) => {
|
|
||||||
const tempPerson = people?.find((p) => p.member.id === assignee)?.member;
|
|
||||||
|
|
||||||
return tempPerson;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Draggable key={childIssue.id} draggableId={childIssue.id} index={index}>
|
|
||||||
{(provided, snapshot) => (
|
|
||||||
<div
|
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.draggableProps}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
>
|
|
||||||
<SingleIssue
|
|
||||||
issue={childIssue}
|
|
||||||
properties={properties}
|
|
||||||
snapshot={snapshot}
|
|
||||||
people={people}
|
|
||||||
assignees={assignees}
|
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
|
||||||
userAuth={userAuth}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{provided.placeholder}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="flex items-center rounded p-2 text-xs font-medium outline-none duration-300 hover:bg-gray-100"
|
|
||||||
onClick={addIssueToState}
|
|
||||||
>
|
|
||||||
<PlusIcon className="mr-1 h-3 w-3" />
|
|
||||||
Create
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</StrictModeDroppable>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SingleBoard;
|
|
@ -1,7 +1,7 @@
|
|||||||
export * from "./board-view";
|
|
||||||
export * from "./comment";
|
export * from "./comment";
|
||||||
export * from "./sidebar-select";
|
export * from "./sidebar-select";
|
||||||
export * from "./activity";
|
export * from "./activity";
|
||||||
|
export * from "./board-view";
|
||||||
export * from "./delete-issue-modal";
|
export * from "./delete-issue-modal";
|
||||||
export * from "./description-form";
|
export * from "./description-form";
|
||||||
export * from "./form";
|
export * from "./form";
|
||||||
|
@ -16,7 +16,7 @@ import workspaceService from "services/workspace.service";
|
|||||||
import { Spinner } from "components/ui";
|
import { Spinner } from "components/ui";
|
||||||
// components
|
// components
|
||||||
import { CreateUpdateIssueModal } from "components/issues/modal";
|
import { CreateUpdateIssueModal } from "components/issues/modal";
|
||||||
import SingleListIssue from "components/common/list-view/single-issue";
|
import SingleListIssue from "components/core/list-view/single-issue";
|
||||||
// helpers
|
// helpers
|
||||||
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
import { addSpaceIfCamelCase } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
|
@ -209,6 +209,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
|
|
||||||
const payload: Partial<IIssue> = {
|
const payload: Partial<IIssue> = {
|
||||||
...formData,
|
...formData,
|
||||||
|
description: formData.description ? formData.description : "",
|
||||||
|
description_html: formData.description_html ? formData.description_html : "<p></p>",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!data) await createIssue(payload);
|
if (!data) await createIssue(payload);
|
||||||
|
@ -177,7 +177,6 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
|
|||||||
<form>
|
<form>
|
||||||
<Combobox
|
<Combobox
|
||||||
onChange={(val: string) => {
|
onChange={(val: string) => {
|
||||||
console.log("Triggered");
|
|
||||||
const selectedIssues = watchBlocked("blocked_issue_ids");
|
const selectedIssues = watchBlocked("blocked_issue_ids");
|
||||||
if (selectedIssues.includes(val))
|
if (selectedIssues.includes(val))
|
||||||
setValue(
|
setValue(
|
||||||
|
@ -151,7 +151,7 @@ export const SubIssuesListModal: React.FC<Props> = ({ isOpen, handleClose, paren
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={`block h-1.5 w-1.5 rounded-full`}
|
className="block flex-shrink-0 h-1.5 w-1.5 rounded-full"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: issue.state_detail.color,
|
backgroundColor: issue.state_detail.color,
|
||||||
}}
|
}}
|
||||||
|
@ -113,7 +113,7 @@ export const SubIssuesList: FC<SubIssueListProps> = ({
|
|||||||
<Link href={`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`}>
|
||||||
<a className="flex items-center gap-2 rounded text-xs">
|
<a className="flex items-center gap-2 rounded text-xs">
|
||||||
<span
|
<span
|
||||||
className={`block h-1.5 w-1.5 rounded-full`}
|
className="block flex-shrink-0 h-1.5 w-1.5 rounded-full"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: issue.state_detail.color,
|
backgroundColor: issue.state_detail.color,
|
||||||
}}
|
}}
|
||||||
|
@ -10,20 +10,18 @@ import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
|||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
|
||||||
import useIssueView from "hooks/use-issue-view";
|
import useIssueView from "hooks/use-issue-view";
|
||||||
// components
|
// components
|
||||||
import SingleBoard from "components/modules/board-view/single-board";
|
import { CommonSingleBoard } from "components/core/board-view/single-board";
|
||||||
// ui
|
// ui
|
||||||
import { Spinner } from "components/ui";
|
import { Spinner } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IProjectMember, ModuleIssueResponse, UserAuth } from "types";
|
import { IIssue, ModuleIssueResponse, UserAuth } from "types";
|
||||||
// constants
|
// constants
|
||||||
import { STATE_LIST, MODULE_ISSUES } from "constants/fetch-keys";
|
import { STATE_LIST, MODULE_ISSUES } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issues: IIssue[];
|
issues: IIssue[];
|
||||||
members: IProjectMember[] | undefined;
|
|
||||||
openCreateIssueModal: (issue?: IIssue, actionType?: "create" | "edit" | "delete") => void;
|
openCreateIssueModal: (issue?: IIssue, actionType?: "create" | "edit" | "delete") => void;
|
||||||
openIssuesListModal: () => void;
|
openIssuesListModal: () => void;
|
||||||
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||||
@ -38,9 +36,8 @@ type Props = {
|
|||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ModulesBoardView: React.FC<Props> = ({
|
export const ModulesBoardView: React.FC<Props> = ({
|
||||||
issues,
|
issues,
|
||||||
members,
|
|
||||||
openCreateIssueModal,
|
openCreateIssueModal,
|
||||||
openIssuesListModal,
|
openIssuesListModal,
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
@ -50,7 +47,6 @@ const ModulesBoardView: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
|
|
||||||
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
|
||||||
const { issueView, groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
|
const { issueView, groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
@ -134,36 +130,39 @@ const ModulesBoardView: React.FC<Props> = ({
|
|||||||
<div className="h-full w-full overflow-hidden">
|
<div className="h-full w-full overflow-hidden">
|
||||||
<div className="h-full w-full">
|
<div className="h-full w-full">
|
||||||
<div className="flex h-full gap-x-4 overflow-x-auto overflow-y-hidden">
|
<div className="flex h-full gap-x-4 overflow-x-auto overflow-y-hidden">
|
||||||
{Object.keys(groupedByIssues).map((singleGroup) => (
|
{Object.keys(groupedByIssues).map((singleGroup) => {
|
||||||
<SingleBoard
|
const stateId =
|
||||||
key={singleGroup}
|
selectedGroup === "state_detail.name"
|
||||||
selectedGroup={selectedGroup}
|
? states?.find((s) => s.name === singleGroup)?.id ?? null
|
||||||
groupTitle={singleGroup}
|
: null;
|
||||||
createdBy={
|
|
||||||
selectedGroup === "created_by"
|
return (
|
||||||
? members?.find((m) => m.member.id === singleGroup)?.member.first_name ??
|
<CommonSingleBoard
|
||||||
"loading..."
|
key={singleGroup}
|
||||||
: null
|
bgColor={
|
||||||
}
|
selectedGroup === "state_detail.name"
|
||||||
groupedByIssues={groupedByIssues}
|
? states?.find((s) => s.name === singleGroup)?.color
|
||||||
bgColor={
|
: "#000000"
|
||||||
selectedGroup === "state_detail.name"
|
}
|
||||||
? states?.find((s) => s.name === singleGroup)?.color
|
groupTitle={singleGroup}
|
||||||
: "#000000"
|
groupedByIssues={groupedByIssues}
|
||||||
}
|
selectedGroup={selectedGroup}
|
||||||
properties={properties}
|
addIssueToState={() => {
|
||||||
openIssuesListModal={openIssuesListModal}
|
openCreateIssueModal();
|
||||||
openCreateIssueModal={openCreateIssueModal}
|
if (selectedGroup !== null) {
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
setPreloadedData({
|
||||||
setPreloadedData={setPreloadedData}
|
state: stateId !== null ? stateId : undefined,
|
||||||
stateId={
|
[selectedGroup]: singleGroup,
|
||||||
selectedGroup === "state_detail.name"
|
actionType: "createIssue",
|
||||||
? states?.find((s) => s.name === singleGroup)?.id ?? null
|
});
|
||||||
: null
|
}
|
||||||
}
|
}}
|
||||||
userAuth={userAuth}
|
// openIssuesListModal={openIssuesListModal}
|
||||||
/>
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
))}
|
userAuth={userAuth}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -177,5 +176,3 @@ const ModulesBoardView: React.FC<Props> = ({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ModulesBoardView;
|
|
@ -1,185 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
|
|
||||||
import useSWR from "swr";
|
|
||||||
|
|
||||||
// react-beautiful-dnd
|
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
|
||||||
// services
|
|
||||||
import workspaceService from "services/workspace.service";
|
|
||||||
// components
|
|
||||||
import SingleIssue from "components/common/board-view/single-issue";
|
|
||||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
|
||||||
import BoardHeader from "components/common/board-view/board-header";
|
|
||||||
// ui
|
|
||||||
import { CustomMenu } from "components/ui";
|
|
||||||
// icons
|
|
||||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
|
||||||
// types
|
|
||||||
import { IIssue, IWorkspaceMember, NestedKeyOf, Properties, UserAuth } from "types";
|
|
||||||
// fetch-keys
|
|
||||||
import { WORKSPACE_MEMBERS } from "constants/fetch-keys";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
properties: Properties;
|
|
||||||
groupedByIssues: {
|
|
||||||
[key: string]: IIssue[];
|
|
||||||
};
|
|
||||||
selectedGroup: NestedKeyOf<IIssue> | null;
|
|
||||||
groupTitle: string;
|
|
||||||
createdBy: string | null;
|
|
||||||
bgColor?: string;
|
|
||||||
openCreateIssueModal: (issue?: IIssue, actionType?: "create" | "edit" | "delete") => void;
|
|
||||||
openIssuesListModal: () => void;
|
|
||||||
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
|
||||||
setPreloadedData: React.Dispatch<
|
|
||||||
React.SetStateAction<
|
|
||||||
| (Partial<IIssue> & {
|
|
||||||
actionType: "createIssue" | "edit" | "delete";
|
|
||||||
})
|
|
||||||
| null
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
stateId: string | null;
|
|
||||||
userAuth: UserAuth;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SingleModuleBoard: React.FC<Props> = ({
|
|
||||||
properties,
|
|
||||||
groupedByIssues,
|
|
||||||
selectedGroup,
|
|
||||||
groupTitle,
|
|
||||||
createdBy,
|
|
||||||
bgColor,
|
|
||||||
openCreateIssueModal,
|
|
||||||
openIssuesListModal,
|
|
||||||
handleDeleteIssue,
|
|
||||||
setPreloadedData,
|
|
||||||
stateId,
|
|
||||||
userAuth,
|
|
||||||
}) => {
|
|
||||||
// Collapse/Expand
|
|
||||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const { workspaceSlug, moduleId } = router.query;
|
|
||||||
|
|
||||||
if (selectedGroup === "priority")
|
|
||||||
groupTitle === "high"
|
|
||||||
? (bgColor = "#dc2626")
|
|
||||||
: groupTitle === "medium"
|
|
||||||
? (bgColor = "#f97316")
|
|
||||||
: groupTitle === "low"
|
|
||||||
? (bgColor = "#22c55e")
|
|
||||||
: (bgColor = "#ff0000");
|
|
||||||
|
|
||||||
const { data: people } = useSWR<IWorkspaceMember[]>(
|
|
||||||
workspaceSlug ? WORKSPACE_MEMBERS : null,
|
|
||||||
workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug as string) : null
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`h-full flex-shrink-0 rounded ${!isCollapsed ? "" : "w-80 border bg-gray-50"}`}>
|
|
||||||
<div className={`${!isCollapsed ? "" : "flex h-full flex-col space-y-3 overflow-y-auto"}`}>
|
|
||||||
<BoardHeader
|
|
||||||
addIssueToState={() => {
|
|
||||||
openCreateIssueModal();
|
|
||||||
if (selectedGroup !== null) {
|
|
||||||
setPreloadedData({
|
|
||||||
state: stateId !== null ? stateId : undefined,
|
|
||||||
[selectedGroup]: groupTitle,
|
|
||||||
actionType: "createIssue",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
bgColor={bgColor ?? ""}
|
|
||||||
createdBy={createdBy}
|
|
||||||
groupTitle={groupTitle}
|
|
||||||
groupedByIssues={groupedByIssues}
|
|
||||||
isCollapsed={isCollapsed}
|
|
||||||
setIsCollapsed={setIsCollapsed}
|
|
||||||
selectedGroup={selectedGroup}
|
|
||||||
/>
|
|
||||||
<StrictModeDroppable key={groupTitle} droppableId={groupTitle}>
|
|
||||||
{(provided, snapshot) => (
|
|
||||||
<div
|
|
||||||
className={`mt-3 h-full space-y-3 overflow-y-auto px-3 pb-3 ${
|
|
||||||
snapshot.isDraggingOver ? "bg-indigo-50 bg-opacity-50" : ""
|
|
||||||
} ${!isCollapsed ? "hidden" : "block"}`}
|
|
||||||
{...provided.droppableProps}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
>
|
|
||||||
{groupedByIssues[groupTitle].map((issue, index: number) => {
|
|
||||||
const assignees = [
|
|
||||||
...(issue?.assignees_list ?? []),
|
|
||||||
...(issue?.assignees ?? []),
|
|
||||||
]?.map((assignee) => {
|
|
||||||
const tempPerson = people?.find((p) => p.member.id === assignee)?.member;
|
|
||||||
|
|
||||||
return tempPerson;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Draggable key={issue.id} draggableId={issue.id} index={index}>
|
|
||||||
{(provided, snapshot) => (
|
|
||||||
<div
|
|
||||||
ref={provided.innerRef}
|
|
||||||
{...provided.draggableProps}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
>
|
|
||||||
<SingleIssue
|
|
||||||
type="module"
|
|
||||||
typeId={moduleId as string}
|
|
||||||
issue={issue}
|
|
||||||
properties={properties}
|
|
||||||
snapshot={snapshot}
|
|
||||||
assignees={assignees}
|
|
||||||
people={people}
|
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
|
||||||
userAuth={userAuth}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Draggable>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{provided.placeholder}
|
|
||||||
<CustomMenu
|
|
||||||
label={
|
|
||||||
<span className="flex items-center gap-1">
|
|
||||||
<PlusIcon className="h-3 w-3" />
|
|
||||||
Add issue
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
className="mt-1"
|
|
||||||
optionsPosition="left"
|
|
||||||
noBorder
|
|
||||||
>
|
|
||||||
<CustomMenu.MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
openCreateIssueModal();
|
|
||||||
if (selectedGroup !== null) {
|
|
||||||
setPreloadedData({
|
|
||||||
state: stateId !== null ? stateId : undefined,
|
|
||||||
[selectedGroup]: groupTitle,
|
|
||||||
actionType: "createIssue",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Create new
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
<CustomMenu.MenuItem onClick={() => openIssuesListModal()}>
|
|
||||||
Add an existing issue
|
|
||||||
</CustomMenu.MenuItem>
|
|
||||||
</CustomMenu>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</StrictModeDroppable>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SingleModuleBoard;
|
|
@ -1,6 +1,6 @@
|
|||||||
export * from "./board-view";
|
|
||||||
export * from "./select";
|
export * from "./select";
|
||||||
export * from "./sidebar-select";
|
export * from "./sidebar-select";
|
||||||
|
export * from "./board-view";
|
||||||
export * from "./delete-module-modal";
|
export * from "./delete-module-modal";
|
||||||
export * from "./form";
|
export * from "./form";
|
||||||
export * from "./list-view";
|
export * from "./list-view";
|
||||||
|
@ -12,7 +12,7 @@ import stateService from "services/state.service";
|
|||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
import useIssuesProperties from "hooks/use-issue-properties";
|
||||||
import useIssueView from "hooks/use-issue-view";
|
import useIssueView from "hooks/use-issue-view";
|
||||||
// components
|
// components
|
||||||
import SingleListIssue from "components/common/list-view/single-issue";
|
import SingleListIssue from "components/core/list-view/single-issue";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu, Spinner } from "components/ui";
|
import { CustomMenu, Spinner } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
|
@ -6,21 +6,19 @@ import { useRouter } from "next/router";
|
|||||||
import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
||||||
import stateService from "services/state.service";
|
import stateService from "services/state.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
|
||||||
import useIssueView from "hooks/use-issue-view";
|
import useIssueView from "hooks/use-issue-view";
|
||||||
// components
|
// components
|
||||||
import SingleBoard from "components/project/cycles/board-view/single-board";
|
import { CommonSingleBoard } from "components/core/board-view/single-board";
|
||||||
// ui
|
// ui
|
||||||
import { Spinner } from "components/ui";
|
import { Spinner } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import { CycleIssueResponse, IIssue, IProjectMember, UserAuth } from "types";
|
import { CycleIssueResponse, IIssue, UserAuth } from "types";
|
||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
// constants
|
// constants
|
||||||
import { STATE_LIST, CYCLE_ISSUES } from "constants/fetch-keys";
|
import { STATE_LIST, CYCLE_ISSUES } from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issues: IIssue[];
|
issues: IIssue[];
|
||||||
members: IProjectMember[] | undefined;
|
|
||||||
openCreateIssueModal: (issue?: IIssue, actionType?: "create" | "edit" | "delete") => void;
|
openCreateIssueModal: (issue?: IIssue, actionType?: "create" | "edit" | "delete") => void;
|
||||||
openIssuesListModal: () => void;
|
openIssuesListModal: () => void;
|
||||||
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
handleDeleteIssue: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||||
@ -37,7 +35,6 @@ type Props = {
|
|||||||
|
|
||||||
const CyclesBoardView: React.FC<Props> = ({
|
const CyclesBoardView: React.FC<Props> = ({
|
||||||
issues,
|
issues,
|
||||||
members,
|
|
||||||
openCreateIssueModal,
|
openCreateIssueModal,
|
||||||
openIssuesListModal,
|
openIssuesListModal,
|
||||||
handleDeleteIssue,
|
handleDeleteIssue,
|
||||||
@ -47,7 +44,6 @@ const CyclesBoardView: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||||
|
|
||||||
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
|
|
||||||
const { issueView, groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
|
const { issueView, groupedByIssues, groupByProperty: selectedGroup } = useIssueView(issues);
|
||||||
|
|
||||||
const { data: states } = useSWR(
|
const { data: states } = useSWR(
|
||||||
@ -131,36 +127,39 @@ const CyclesBoardView: React.FC<Props> = ({
|
|||||||
<div className="h-full w-full overflow-hidden">
|
<div className="h-full w-full overflow-hidden">
|
||||||
<div className="h-full w-full">
|
<div className="h-full w-full">
|
||||||
<div className="flex h-full gap-x-4 overflow-x-auto overflow-y-hidden">
|
<div className="flex h-full gap-x-4 overflow-x-auto overflow-y-hidden">
|
||||||
{Object.keys(groupedByIssues).map((singleGroup) => (
|
{Object.keys(groupedByIssues).map((singleGroup) => {
|
||||||
<SingleBoard
|
const stateId =
|
||||||
key={singleGroup}
|
selectedGroup === "state_detail.name"
|
||||||
selectedGroup={selectedGroup}
|
? states?.find((s) => s.name === singleGroup)?.id ?? null
|
||||||
groupTitle={singleGroup}
|
: null;
|
||||||
createdBy={
|
|
||||||
selectedGroup === "created_by"
|
return (
|
||||||
? members?.find((m) => m.member.id === singleGroup)?.member.first_name ??
|
<CommonSingleBoard
|
||||||
"loading..."
|
key={singleGroup}
|
||||||
: null
|
bgColor={
|
||||||
}
|
selectedGroup === "state_detail.name"
|
||||||
groupedByIssues={groupedByIssues}
|
? states?.find((s) => s.name === singleGroup)?.color
|
||||||
bgColor={
|
: "#000000"
|
||||||
selectedGroup === "state_detail.name"
|
}
|
||||||
? states?.find((s) => s.name === singleGroup)?.color
|
groupTitle={singleGroup}
|
||||||
: "#000000"
|
groupedByIssues={groupedByIssues}
|
||||||
}
|
selectedGroup={selectedGroup}
|
||||||
properties={properties}
|
addIssueToState={() => {
|
||||||
openIssuesListModal={openIssuesListModal}
|
openCreateIssueModal();
|
||||||
openCreateIssueModal={openCreateIssueModal}
|
if (selectedGroup !== null) {
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
setPreloadedData({
|
||||||
setPreloadedData={setPreloadedData}
|
state: stateId !== null ? stateId : undefined,
|
||||||
stateId={
|
[selectedGroup]: singleGroup,
|
||||||
selectedGroup === "state_detail.name"
|
actionType: "createIssue",
|
||||||
? states?.find((s) => s.name === singleGroup)?.id ?? null
|
});
|
||||||
: null
|
}
|
||||||
}
|
}}
|
||||||
userAuth={userAuth}
|
// openIssuesListModal={openIssuesListModal}
|
||||||
/>
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
))}
|
userAuth={userAuth}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -15,7 +15,7 @@ import stateService from "services/state.service";
|
|||||||
import useIssuesProperties from "hooks/use-issue-properties";
|
import useIssuesProperties from "hooks/use-issue-properties";
|
||||||
import useIssueView from "hooks/use-issue-view";
|
import useIssueView from "hooks/use-issue-view";
|
||||||
// components
|
// components
|
||||||
import SingleListIssue from "components/common/list-view/single-issue";
|
import SingleListIssue from "components/core/list-view/single-issue";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu, Spinner } from "components/ui";
|
import { CustomMenu, Spinner } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
|
@ -3,8 +3,29 @@ import React, { useEffect, useState } from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
// react-hook-form
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
// lib
|
||||||
|
import { requiredAuth } from "lib/auth";
|
||||||
|
// services
|
||||||
|
import projectService from "services/project.service";
|
||||||
|
// hooks
|
||||||
|
import useUser from "hooks/use-user";
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
|
// layouts
|
||||||
|
import AppLayout from "layouts/app-layout";
|
||||||
|
// services
|
||||||
|
import userService from "services/user.service";
|
||||||
|
import workspaceService from "services/workspace.service";
|
||||||
|
// components
|
||||||
|
import { ImageUploadModal } from "components/core";
|
||||||
|
// ui
|
||||||
|
import { Button, Input, Spinner } from "components/ui";
|
||||||
|
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||||
|
// icons
|
||||||
import {
|
import {
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
ClipboardDocumentListIcon,
|
ClipboardDocumentListIcon,
|
||||||
@ -14,30 +35,11 @@ import {
|
|||||||
UserPlusIcon,
|
UserPlusIcon,
|
||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import type { NextPage, NextPageContext } from "next";
|
|
||||||
|
|
||||||
// hooks
|
|
||||||
import type { IIssue, IUser } from "types";
|
|
||||||
import useUser from "hooks/use-user";
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// lib
|
|
||||||
import { requiredAuth } from "lib/auth";
|
|
||||||
// services
|
|
||||||
import projectService from "services/project.service";
|
|
||||||
// layouts
|
|
||||||
import AppLayout from "layouts/app-layout";
|
|
||||||
// constants
|
|
||||||
import { USER_ISSUE, USER_WORKSPACE_INVITATIONS, PROJECTS_LIST } from "constants/fetch-keys";
|
|
||||||
// services
|
|
||||||
import userService from "services/user.service";
|
|
||||||
import workspaceService from "services/workspace.service";
|
|
||||||
// components
|
|
||||||
import { ImageUploadModal } from "components/common/image-upload-modal";
|
|
||||||
// ui
|
|
||||||
import { Button, Input, Spinner } from "components/ui";
|
|
||||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
|
||||||
// icons
|
|
||||||
// types
|
// types
|
||||||
|
import type { NextPage, NextPageContext } from "next";
|
||||||
|
import type { IIssue, IUser } from "types";
|
||||||
|
// fetch-keys
|
||||||
|
import { USER_ISSUE, USER_WORKSPACE_INVITATIONS, PROJECTS_LIST } from "constants/fetch-keys";
|
||||||
|
|
||||||
const defaultValues: Partial<IUser> = {
|
const defaultValues: Partial<IUser> = {
|
||||||
avatar: "",
|
avatar: "",
|
||||||
|
@ -14,9 +14,8 @@ import { IssueViewContextProvider } from "contexts/issue-view.context";
|
|||||||
import CyclesListView from "components/project/cycles/list-view";
|
import CyclesListView from "components/project/cycles/list-view";
|
||||||
import CyclesBoardView from "components/project/cycles/board-view";
|
import CyclesBoardView from "components/project/cycles/board-view";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
import ExistingIssuesListModal from "components/common/existing-issues-list-modal";
|
import { ExistingIssuesListModal, IssuesFilterView } from "components/core";
|
||||||
import CycleDetailSidebar from "components/project/cycles/cycle-detail-sidebar";
|
import CycleDetailSidebar from "components/project/cycles/cycle-detail-sidebar";
|
||||||
import View from "components/core/view";
|
|
||||||
// services
|
// services
|
||||||
import issuesServices from "services/issues.service";
|
import issuesServices from "services/issues.service";
|
||||||
import cycleServices from "services/cycles.service";
|
import cycleServices from "services/cycles.service";
|
||||||
@ -35,7 +34,6 @@ import {
|
|||||||
CYCLE_ISSUES,
|
CYCLE_ISSUES,
|
||||||
CYCLE_LIST,
|
CYCLE_LIST,
|
||||||
PROJECT_ISSUES_LIST,
|
PROJECT_ISSUES_LIST,
|
||||||
PROJECT_MEMBERS,
|
|
||||||
PROJECT_DETAILS,
|
PROJECT_DETAILS,
|
||||||
CYCLE_DETAILS,
|
CYCLE_DETAILS,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
@ -107,19 +105,6 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
cycle: cycleId as string,
|
cycle: cycleId as string,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_MEMBERS(workspaceSlug as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.projectMembers(workspaceSlug as string, projectId as string)
|
|
||||||
: null,
|
|
||||||
{
|
|
||||||
onErrorRetry(err, _, __, revalidate, revalidateOpts) {
|
|
||||||
if (err?.status === 403) return;
|
|
||||||
setTimeout(() => revalidate(revalidateOpts), 5000);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const openCreateIssueModal = (
|
const openCreateIssueModal = (
|
||||||
issue?: IIssue,
|
issue?: IIssue,
|
||||||
actionType: "create" | "edit" | "delete" = "create"
|
actionType: "create" | "edit" | "delete" = "create"
|
||||||
@ -233,7 +218,7 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
<div
|
<div
|
||||||
className={`flex items-center gap-2 ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}
|
className={`flex items-center gap-2 ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}
|
||||||
>
|
>
|
||||||
<View issues={cycleIssuesArray ?? []} />
|
<IssuesFilterView issues={cycleIssuesArray ?? []} />
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-gray-100 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-gray-100 ${
|
||||||
@ -259,7 +244,6 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
/>
|
/>
|
||||||
<CyclesBoardView
|
<CyclesBoardView
|
||||||
issues={cycleIssuesArray ?? []}
|
issues={cycleIssuesArray ?? []}
|
||||||
members={members}
|
|
||||||
openCreateIssueModal={openCreateIssueModal}
|
openCreateIssueModal={openCreateIssueModal}
|
||||||
openIssuesListModal={openIssuesListModal}
|
openIssuesListModal={openIssuesListModal}
|
||||||
handleDeleteIssue={setDeleteIssue}
|
handleDeleteIssue={setDeleteIssue}
|
||||||
|
@ -13,9 +13,13 @@ import AppLayout from "layouts/app-layout";
|
|||||||
// contexts
|
// contexts
|
||||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||||
// components
|
// components
|
||||||
import BoardView from "components/issues/board-view";
|
import {
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal, IssuesListView } from "components/issues";
|
CreateUpdateIssueModal,
|
||||||
import View from "components/core/view";
|
DeleteIssueModal,
|
||||||
|
IssuesBoardView,
|
||||||
|
IssuesListView,
|
||||||
|
} from "components/issues";
|
||||||
|
import { IssuesFilterView } from "components/core";
|
||||||
// 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";
|
||||||
@ -77,7 +81,9 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
|
|||||||
}
|
}
|
||||||
right={
|
right={
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<View issues={projectIssues?.results.filter((p) => p.parent === null) ?? []} />
|
<IssuesFilterView
|
||||||
|
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
|
||||||
|
/>
|
||||||
<HeaderButton
|
<HeaderButton
|
||||||
Icon={PlusIcon}
|
Icon={PlusIcon}
|
||||||
label="Add Issue"
|
label="Add Issue"
|
||||||
@ -113,7 +119,7 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
|
|||||||
handleEditIssue={handleEditIssue}
|
handleEditIssue={handleEditIssue}
|
||||||
userAuth={props}
|
userAuth={props}
|
||||||
/>
|
/>
|
||||||
<BoardView
|
<IssuesBoardView
|
||||||
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
|
issues={projectIssues?.results.filter((p) => p.parent === null) ?? []}
|
||||||
handleDeleteIssue={setDeleteIssue}
|
handleDeleteIssue={setDeleteIssue}
|
||||||
userAuth={props}
|
userAuth={props}
|
||||||
|
@ -8,18 +8,20 @@ import useSWR, { mutate } from "swr";
|
|||||||
import { requiredAdmin, requiredAuth } from "lib/auth";
|
import { requiredAdmin, requiredAuth } from "lib/auth";
|
||||||
// services
|
// services
|
||||||
import modulesService from "services/modules.service";
|
import modulesService from "services/modules.service";
|
||||||
import projectService from "services/project.service";
|
|
||||||
import issuesService from "services/issues.service";
|
import issuesService from "services/issues.service";
|
||||||
// layouts
|
// layouts
|
||||||
import AppLayout from "layouts/app-layout";
|
import AppLayout from "layouts/app-layout";
|
||||||
// contexts
|
// contexts
|
||||||
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
import { IssueViewContextProvider } from "contexts/issue-view.context";
|
||||||
// components
|
// components
|
||||||
import ExistingIssuesListModal from "components/common/existing-issues-list-modal";
|
import { ExistingIssuesListModal, IssuesFilterView } from "components/core";
|
||||||
import ModulesBoardView from "components/modules/board-view";
|
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
import { DeleteModuleModal, ModuleDetailsSidebar, ModulesListView } from "components/modules";
|
import {
|
||||||
import View from "components/core/view";
|
DeleteModuleModal,
|
||||||
|
ModuleDetailsSidebar,
|
||||||
|
ModulesListView,
|
||||||
|
ModulesBoardView,
|
||||||
|
} from "components/modules";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu, EmptySpace, EmptySpaceItem, Spinner } from "components/ui";
|
import { CustomMenu, EmptySpace, EmptySpaceItem, Spinner } from "components/ui";
|
||||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||||
@ -47,7 +49,6 @@ import {
|
|||||||
MODULE_ISSUES,
|
MODULE_ISSUES,
|
||||||
MODULE_LIST,
|
MODULE_LIST,
|
||||||
PROJECT_ISSUES_LIST,
|
PROJECT_ISSUES_LIST,
|
||||||
PROJECT_MEMBERS,
|
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
|
||||||
const SingleModule: React.FC<UserAuth> = (props) => {
|
const SingleModule: React.FC<UserAuth> = (props) => {
|
||||||
@ -105,19 +106,6 @@ const SingleModule: React.FC<UserAuth> = (props) => {
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: members } = useSWR(
|
|
||||||
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
|
|
||||||
workspaceSlug && projectId
|
|
||||||
? () => projectService.projectMembers(workspaceSlug as string, projectId as string)
|
|
||||||
: null,
|
|
||||||
{
|
|
||||||
onErrorRetry(err, _, __, revalidate, revalidateOpts) {
|
|
||||||
if (err?.status === 403) return;
|
|
||||||
setTimeout(() => revalidate(revalidateOpts), 5000);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const moduleIssuesArray = moduleIssues?.map((issue) => ({
|
const moduleIssuesArray = moduleIssues?.map((issue) => ({
|
||||||
...issue.issue_detail,
|
...issue.issue_detail,
|
||||||
sub_issues_count: issue.sub_issues_count,
|
sub_issues_count: issue.sub_issues_count,
|
||||||
@ -254,7 +242,7 @@ const SingleModule: React.FC<UserAuth> = (props) => {
|
|||||||
<div
|
<div
|
||||||
className={`flex items-center gap-2 ${moduleSidebar ? "mr-[24rem]" : ""} duration-300`}
|
className={`flex items-center gap-2 ${moduleSidebar ? "mr-[24rem]" : ""} duration-300`}
|
||||||
>
|
>
|
||||||
<View issues={moduleIssuesArray ?? []} />
|
<IssuesFilterView issues={moduleIssuesArray ?? []} />
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-gray-100 ${
|
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-gray-100 ${
|
||||||
@ -280,7 +268,6 @@ const SingleModule: React.FC<UserAuth> = (props) => {
|
|||||||
/>
|
/>
|
||||||
<ModulesBoardView
|
<ModulesBoardView
|
||||||
issues={moduleIssuesArray ?? []}
|
issues={moduleIssuesArray ?? []}
|
||||||
members={members}
|
|
||||||
openCreateIssueModal={openCreateIssueModal}
|
openCreateIssueModal={openCreateIssueModal}
|
||||||
openIssuesListModal={openIssuesListModal}
|
openIssuesListModal={openIssuesListModal}
|
||||||
handleDeleteIssue={setDeleteIssue}
|
handleDeleteIssue={setDeleteIssue}
|
||||||
|
@ -21,7 +21,7 @@ import SettingsLayout from "layouts/settings-layout";
|
|||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { ImageUploadModal } from "components/common/image-upload-modal";
|
import { ImageUploadModal } from "components/core";
|
||||||
import ConfirmWorkspaceDeletion from "components/workspace/confirm-workspace-deletion";
|
import ConfirmWorkspaceDeletion from "components/workspace/confirm-workspace-deletion";
|
||||||
// ui
|
// ui
|
||||||
import { Spinner, Button, Input, CustomSelect } from "components/ui";
|
import { Spinner, Button, Input, CustomSelect } from "components/ui";
|
||||||
|
Loading…
Reference in New Issue
Block a user