forked from github/plane
feat: sidebar progress (#252)
* feat: cycle assignees and labels progress added * fix: build fix * feat: sidebar progress stats added and refactor * refactor: progress stats and cycle sidebar * feat: module sidebar progress added * feat: sidebar progress no assignee added * feat: states tab added --------- Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
This commit is contained in:
parent
76cc634a46
commit
c978632938
179
apps/app/components/core/sidebar/sidebar-progress-stats.tsx
Normal file
179
apps/app/components/core/sidebar/sidebar-progress-stats.tsx
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Tab } from "@headlessui/react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import Image from "next/image";
|
||||||
|
// ui
|
||||||
|
import SingleProgressStats from "./single-progress-stats";
|
||||||
|
import { Avatar } from "components/ui";
|
||||||
|
// icons
|
||||||
|
import User from "public/user.png";
|
||||||
|
// types
|
||||||
|
import { IIssue, IIssueLabels } from "types";
|
||||||
|
// constants
|
||||||
|
import { PROJECT_ISSUE_LABELS, PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||||
|
// services
|
||||||
|
import issuesServices from "services/issues.service";
|
||||||
|
import projectService from "services/project.service";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
groupedIssues: any;
|
||||||
|
issues: IIssue[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const stateGroupColours: {
|
||||||
|
[key: string]: string;
|
||||||
|
} = {
|
||||||
|
backlog: "#3f76ff",
|
||||||
|
unstarted: "#ff9e9e",
|
||||||
|
started: "#d687ff",
|
||||||
|
cancelled: "#ff5353",
|
||||||
|
completed: "#096e8d",
|
||||||
|
};
|
||||||
|
|
||||||
|
const SidebarProgressStats: React.FC<Props> = ({ groupedIssues, issues }) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
const { data: issueLabels } = useSWR<IIssueLabels[]>(
|
||||||
|
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
||||||
|
workspaceSlug && projectId
|
||||||
|
? () => issuesServices.getIssueLabels(workspaceSlug as string, projectId as string)
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: members } = useSWR(
|
||||||
|
workspaceSlug && projectId ? PROJECT_MEMBERS(workspaceSlug as string) : null,
|
||||||
|
workspaceSlug && projectId
|
||||||
|
? () => projectService.projectMembers(workspaceSlug as string, projectId as string)
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center w-full gap-2 ">
|
||||||
|
<Tab.Group>
|
||||||
|
<Tab.List
|
||||||
|
as="div"
|
||||||
|
className="flex items-center justify-between w-full rounded bg-gray-100 text-xs"
|
||||||
|
>
|
||||||
|
<Tab
|
||||||
|
className={({ selected }) =>
|
||||||
|
`w-1/2 rounded py-1 ${selected ? "bg-gray-300" : "hover:bg-gray-200"}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Assignees
|
||||||
|
</Tab>
|
||||||
|
<Tab
|
||||||
|
className={({ selected }) =>
|
||||||
|
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Labels
|
||||||
|
</Tab>
|
||||||
|
<Tab
|
||||||
|
className={({ selected }) =>
|
||||||
|
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
States
|
||||||
|
</Tab>
|
||||||
|
</Tab.List>
|
||||||
|
<Tab.Panels className="flex items-center justify-between w-full">
|
||||||
|
<Tab.Panel as="div" className="w-full flex flex-col ">
|
||||||
|
{members?.map((member, index) => {
|
||||||
|
const totalArray = issues?.filter((i) => i.assignees?.includes(member.member.id));
|
||||||
|
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
|
||||||
|
if (totalArray.length > 0) {
|
||||||
|
return (
|
||||||
|
<SingleProgressStats
|
||||||
|
key={index}
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<Avatar user={member.member} />
|
||||||
|
<span>{member.member.first_name}</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
completed={completeArray.length}
|
||||||
|
total={totalArray.length}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
{issues?.filter((i) => i.assignees?.length === 0).length > 0 ? (
|
||||||
|
<SingleProgressStats
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<div className="h-5 w-5 rounded-full border-2 border-white bg-white">
|
||||||
|
<Image
|
||||||
|
src={User}
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
className="rounded-full"
|
||||||
|
alt="User"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span>No assignee</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
completed={
|
||||||
|
issues?.filter(
|
||||||
|
(i) => i.state_detail.group === "completed" && i.assignees?.length === 0
|
||||||
|
).length
|
||||||
|
}
|
||||||
|
total={issues?.filter((i) => i.assignees?.length === 0).length}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</Tab.Panel>
|
||||||
|
<Tab.Panel as="div" className="w-full flex flex-col ">
|
||||||
|
{issueLabels?.map((issue, index) => {
|
||||||
|
const totalArray = issues?.filter((i) => i.labels?.includes(issue.id));
|
||||||
|
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
|
||||||
|
if (totalArray.length > 0) {
|
||||||
|
return (
|
||||||
|
<SingleProgressStats
|
||||||
|
key={index}
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<span
|
||||||
|
className="block h-2 w-2 rounded-full "
|
||||||
|
style={{
|
||||||
|
backgroundColor: issue.color,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className="text-xs capitalize">{issue.name}</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
completed={completeArray.length}
|
||||||
|
total={totalArray.length}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Tab.Panel>
|
||||||
|
<Tab.Panel as="div" className="w-full flex flex-col ">
|
||||||
|
{Object.keys(groupedIssues).map((group, index) => (
|
||||||
|
<SingleProgressStats
|
||||||
|
key={index}
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<span
|
||||||
|
className="block h-2 w-2 rounded-full "
|
||||||
|
style={{
|
||||||
|
backgroundColor: stateGroupColours[group],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className="text-xs capitalize">{group}</span>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
completed={groupedIssues[group].length}
|
||||||
|
total={issues.length}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Tab.Panel>
|
||||||
|
</Tab.Panels>
|
||||||
|
</Tab.Group>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SidebarProgressStats;
|
29
apps/app/components/core/sidebar/single-progress-stats.tsx
Normal file
29
apps/app/components/core/sidebar/single-progress-stats.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { CircularProgressbar } from "react-circular-progressbar";
|
||||||
|
|
||||||
|
type TSingleProgressStatsProps = {
|
||||||
|
title: any;
|
||||||
|
completed: number;
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SingleProgressStats: React.FC<TSingleProgressStatsProps> = ({ title, completed, total }) => (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center justify-between w-full py-3 text-xs border-b-[1px] border-gray-200">
|
||||||
|
<div className="flex items-center justify-start w-1/2 gap-2">{title}</div>
|
||||||
|
<div className="flex items-center justify-end w-1/2 gap-1 px-2">
|
||||||
|
<div className="flex h-5 justify-center items-center gap-1 ">
|
||||||
|
<span className="h-4 w-4 ">
|
||||||
|
<CircularProgressbar value={completed} maxValue={total} strokeWidth={10} />
|
||||||
|
</span>
|
||||||
|
<span className="w-8 text-right">{Math.floor((completed / total) * 100)}%</span>
|
||||||
|
</div>
|
||||||
|
<span>of</span>
|
||||||
|
<span>{total}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default SingleProgressStats;
|
@ -7,6 +7,16 @@ import { mutate } from "swr";
|
|||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
// icons
|
||||||
|
import {
|
||||||
|
CalendarDaysIcon,
|
||||||
|
ChartPieIcon,
|
||||||
|
LinkIcon,
|
||||||
|
PlusIcon,
|
||||||
|
TrashIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
|
// progress-bar
|
||||||
|
import { CircularProgressbar } from "react-circular-progressbar";
|
||||||
// services
|
// services
|
||||||
import modulesService from "services/modules.service";
|
import modulesService from "services/modules.service";
|
||||||
// hooks
|
// hooks
|
||||||
@ -18,27 +28,19 @@ import {
|
|||||||
SidebarMembersSelect,
|
SidebarMembersSelect,
|
||||||
SidebarStatusSelect,
|
SidebarStatusSelect,
|
||||||
} from "components/modules";
|
} from "components/modules";
|
||||||
// progress-bar
|
|
||||||
import { CircularProgressbar } from "react-circular-progressbar";
|
|
||||||
import "react-circular-progressbar/dist/styles.css";
|
import "react-circular-progressbar/dist/styles.css";
|
||||||
// ui
|
// ui
|
||||||
import { CustomDatePicker, Loader } from "components/ui";
|
import { CustomDatePicker, Loader } from "components/ui";
|
||||||
// icons
|
|
||||||
import {
|
|
||||||
CalendarDaysIcon,
|
|
||||||
ChartPieIcon,
|
|
||||||
LinkIcon,
|
|
||||||
PlusIcon,
|
|
||||||
TrashIcon,
|
|
||||||
} from "@heroicons/react/24/outline";
|
|
||||||
// helpers
|
// helpers
|
||||||
import { timeAgo } from "helpers/date-time.helper";
|
import { timeAgo } from "helpers/date-time.helper";
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
import { groupBy } from "helpers/array.helper";
|
import { groupBy } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
import { IModule, ModuleIssueResponse } from "types";
|
import { IIssue, IModule, ModuleIssueResponse } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
import { MODULE_DETAILS } from "constants/fetch-keys";
|
||||||
|
import SidebarProgressStats from "components/core/sidebar/sidebar-progress-stats";
|
||||||
|
|
||||||
const defaultValues: Partial<IModule> = {
|
const defaultValues: Partial<IModule> = {
|
||||||
lead: "",
|
lead: "",
|
||||||
@ -49,6 +51,7 @@ const defaultValues: Partial<IModule> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
issues: IIssue[];
|
||||||
module?: IModule;
|
module?: IModule;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
moduleIssues: ModuleIssueResponse[] | undefined;
|
moduleIssues: ModuleIssueResponse[] | undefined;
|
||||||
@ -56,6 +59,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ModuleDetailsSidebar: React.FC<Props> = ({
|
export const ModuleDetailsSidebar: React.FC<Props> = ({
|
||||||
|
issues,
|
||||||
module,
|
module,
|
||||||
isOpen,
|
isOpen,
|
||||||
moduleIssues,
|
moduleIssues,
|
||||||
@ -290,6 +294,9 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<SidebarProgressStats issues={issues} groupedIssues={groupedIssues} />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Loader>
|
<Loader>
|
||||||
|
@ -9,24 +9,27 @@ import { mutate } from "swr";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// icons
|
// icons
|
||||||
import { CalendarDaysIcon, ChartPieIcon, LinkIcon, UserIcon } from "@heroicons/react/24/outline";
|
import { CalendarDaysIcon, ChartPieIcon, LinkIcon, UserIcon } from "@heroicons/react/24/outline";
|
||||||
// services
|
|
||||||
import cyclesService from "services/cycles.service";
|
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
|
||||||
import { Loader, CustomDatePicker } from "components/ui";
|
|
||||||
// progress-bar
|
// progress-bar
|
||||||
import { CircularProgressbar } from "react-circular-progressbar";
|
import { CircularProgressbar } from "react-circular-progressbar";
|
||||||
|
// ui
|
||||||
|
import { Loader, CustomDatePicker } from "components/ui";
|
||||||
import "react-circular-progressbar/dist/styles.css";
|
import "react-circular-progressbar/dist/styles.css";
|
||||||
|
// hooks
|
||||||
|
import useToast from "hooks/use-toast";
|
||||||
|
// services
|
||||||
|
import cyclesService from "services/cycles.service";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
import { groupBy } from "helpers/array.helper";
|
import { groupBy } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
import { CycleIssueResponse, ICycle } from "types";
|
import { CycleIssueResponse, ICycle, IIssue } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { CYCLE_DETAILS } from "constants/fetch-keys";
|
import { CYCLE_DETAILS } from "constants/fetch-keys";
|
||||||
|
import SidebarProgressStats from "components/core/sidebar/sidebar-progress-stats";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
issues: IIssue[];
|
||||||
cycle: ICycle | undefined;
|
cycle: ICycle | undefined;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
cycleIssues: CycleIssueResponse[];
|
cycleIssues: CycleIssueResponse[];
|
||||||
@ -37,7 +40,7 @@ const defaultValues: Partial<ICycle> = {
|
|||||||
end_date: new Date().toString(),
|
end_date: new Date().toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const CycleDetailSidebar: React.FC<Props> = ({ cycle, isOpen, cycleIssues }) => {
|
const CycleDetailSidebar: React.FC<Props> = ({ issues, cycle, isOpen, cycleIssues }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||||
|
|
||||||
@ -219,6 +222,9 @@ const CycleDetailSidebar: React.FC<Props> = ({ cycle, isOpen, cycleIssues }) =>
|
|||||||
</div>
|
</div>
|
||||||
<div className="py-1" />
|
<div className="py-1" />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<SidebarProgressStats issues={issues} groupedIssues={groupedIssues} />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Loader>
|
<Loader>
|
||||||
|
@ -3,7 +3,10 @@ import React, { useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
import { NextPageContext } from "next";
|
||||||
|
// icons
|
||||||
|
import { ArrowLeftIcon, ListBulletIcon, PlusIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { CyclesIcon } from "components/icons";
|
||||||
// lib
|
// lib
|
||||||
import { requiredAdmin, requiredAuth } from "lib/auth";
|
import { requiredAdmin, requiredAuth } from "lib/auth";
|
||||||
// layouts
|
// layouts
|
||||||
@ -21,19 +24,17 @@ import projectService from "services/project.service";
|
|||||||
// 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";
|
||||||
// icons
|
|
||||||
import { ArrowLeftIcon, ListBulletIcon, PlusIcon } from "@heroicons/react/24/outline";
|
|
||||||
import { CyclesIcon } from "components/icons";
|
|
||||||
// types
|
// types
|
||||||
import { CycleIssueResponse, IIssue, SelectIssue, UserAuth } from "types";
|
import { CycleIssueResponse, IIssue, IIssueLabels, SelectIssue, UserAuth } from "types";
|
||||||
import { NextPageContext } from "next";
|
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import {
|
import {
|
||||||
CYCLE_ISSUES,
|
CYCLE_ISSUES,
|
||||||
CYCLE_LIST,
|
CYCLE_LIST,
|
||||||
PROJECT_ISSUES_LIST,
|
PROJECT_ISSUES_LIST,
|
||||||
PROJECT_DETAILS,
|
PROJECT_DETAILS,
|
||||||
|
PROJECT_ISSUE_LABELS,
|
||||||
CYCLE_DETAILS,
|
CYCLE_DETAILS,
|
||||||
|
PROJECT_MEMBERS,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
|
||||||
const SingleCycle: React.FC<UserAuth> = (props) => {
|
const SingleCycle: React.FC<UserAuth> = (props) => {
|
||||||
@ -95,6 +96,7 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
)
|
)
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const cycleIssuesArray = cycleIssues?.map((issue) => ({
|
const cycleIssuesArray = cycleIssues?.map((issue) => ({
|
||||||
...issue.issue_detail,
|
...issue.issue_detail,
|
||||||
sub_issues_count: issue.sub_issues_count,
|
sub_issues_count: issue.sub_issues_count,
|
||||||
@ -241,6 +243,7 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<CycleDetailSidebar
|
<CycleDetailSidebar
|
||||||
|
issues={cycleIssuesArray ?? []}
|
||||||
cycle={cycleDetails}
|
cycle={cycleDetails}
|
||||||
isOpen={cycleSidebar}
|
isOpen={cycleSidebar}
|
||||||
cycleIssues={cycleIssues ?? []}
|
cycleIssues={cycleIssues ?? []}
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import { NextPageContext } from "next";
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
|
||||||
|
// icons
|
||||||
|
import {
|
||||||
|
ArrowLeftIcon,
|
||||||
|
ListBulletIcon,
|
||||||
|
PlusIcon,
|
||||||
|
RectangleGroupIcon,
|
||||||
|
RectangleStackIcon,
|
||||||
|
} from "@heroicons/react/24/outline";
|
||||||
// lib
|
// lib
|
||||||
import { requiredAdmin, requiredAuth } from "lib/auth";
|
import { requiredAdmin, requiredAuth } from "lib/auth";
|
||||||
// services
|
// services
|
||||||
@ -20,14 +28,6 @@ import { DeleteModuleModal, ModuleDetailsSidebar } 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";
|
||||||
// icons
|
|
||||||
import {
|
|
||||||
ArrowLeftIcon,
|
|
||||||
ListBulletIcon,
|
|
||||||
PlusIcon,
|
|
||||||
RectangleGroupIcon,
|
|
||||||
RectangleStackIcon,
|
|
||||||
} from "@heroicons/react/24/outline";
|
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
IIssue,
|
IIssue,
|
||||||
@ -37,7 +37,7 @@ import {
|
|||||||
SelectModuleType,
|
SelectModuleType,
|
||||||
UserAuth,
|
UserAuth,
|
||||||
} from "types";
|
} from "types";
|
||||||
import { NextPageContext } from "next";
|
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import {
|
import {
|
||||||
MODULE_DETAILS,
|
MODULE_DETAILS,
|
||||||
@ -262,6 +262,7 @@ const SingleModule: React.FC<UserAuth> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ModuleDetailsSidebar
|
<ModuleDetailsSidebar
|
||||||
|
issues={moduleIssuesArray ?? []}
|
||||||
module={moduleDetails}
|
module={moduleDetails}
|
||||||
isOpen={moduleSidebar}
|
isOpen={moduleSidebar}
|
||||||
moduleIssues={moduleIssues}
|
moduleIssues={moduleIssues}
|
||||||
|
Loading…
Reference in New Issue
Block a user