feat: completed cycle validation , fix: quick action and kanban fix (#505)

* feat: completed cycle card validation

* fix: unique key to hidden group

* feat: completed cycle sidebar validation

* fix: remove console log from progress chart hover

* feat: kanban and list view completed cycle validation

* feat: quick action validation

* refactor: code refactor

* fix: sidebar draft cycle status
This commit is contained in:
Anmol Singh Bhatia 2023-03-23 22:42:08 +05:30 committed by GitHub
parent 5191fc5f7c
commit b6a3615f66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 133 additions and 74 deletions

View File

@ -18,6 +18,7 @@ type Props = {
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
handleTrashBox: (isDragging: boolean) => void; handleTrashBox: (isDragging: boolean) => void;
removeIssue: ((bridgeId: string) => void) | null; removeIssue: ((bridgeId: string) => void) | null;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -31,6 +32,7 @@ export const AllBoards: React.FC<Props> = ({
handleDeleteIssue, handleDeleteIssue,
handleTrashBox, handleTrashBox,
removeIssue, removeIssue,
isCompleted = false,
userAuth, userAuth,
}) => { }) => {
const { const {
@ -62,6 +64,7 @@ export const AllBoards: React.FC<Props> = ({
openIssuesListModal={openIssuesListModal ?? null} openIssuesListModal={openIssuesListModal ?? null}
handleTrashBox={handleTrashBox} handleTrashBox={handleTrashBox}
removeIssue={removeIssue} removeIssue={removeIssue}
isCompleted={isCompleted}
userAuth={userAuth} userAuth={userAuth}
/> />
); );

View File

@ -15,6 +15,7 @@ type Props = {
addIssueToState: () => void; addIssueToState: () => void;
isCollapsed: boolean; isCollapsed: boolean;
setIsCollapsed: React.Dispatch<React.SetStateAction<boolean>>; setIsCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
isCompleted?: boolean;
}; };
export const BoardHeader: React.FC<Props> = ({ export const BoardHeader: React.FC<Props> = ({
@ -23,6 +24,7 @@ export const BoardHeader: React.FC<Props> = ({
addIssueToState, addIssueToState,
isCollapsed, isCollapsed,
setIsCollapsed, setIsCollapsed,
isCompleted = false,
}) => { }) => {
const { groupedByIssues, groupByProperty: selectedGroup } = useIssuesView(); const { groupedByIssues, groupByProperty: selectedGroup } = useIssuesView();
@ -81,13 +83,15 @@ export const BoardHeader: React.FC<Props> = ({
<ArrowsPointingOutIcon className="h-4 w-4" /> <ArrowsPointingOutIcon className="h-4 w-4" />
)} )}
</button> </button>
<button {!isCompleted && (
type="button" <button
className="grid h-7 w-7 place-items-center rounded p-1 text-gray-700 outline-none duration-300 hover:bg-gray-100" type="button"
onClick={addIssueToState} className="grid h-7 w-7 place-items-center rounded p-1 text-gray-700 outline-none duration-300 hover:bg-gray-100"
> onClick={addIssueToState}
<PlusIcon className="h-4 w-4" /> >
</button> <PlusIcon className="h-4 w-4" />
</button>
)}
</div> </div>
</div> </div>
); );

View File

@ -30,6 +30,7 @@ type Props = {
openIssuesListModal?: (() => void) | null; openIssuesListModal?: (() => void) | null;
handleTrashBox: (isDragging: boolean) => void; handleTrashBox: (isDragging: boolean) => void;
removeIssue: ((bridgeId: string) => void) | null; removeIssue: ((bridgeId: string) => void) | null;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -44,6 +45,7 @@ export const SingleBoard: React.FC<Props> = ({
openIssuesListModal, openIssuesListModal,
handleTrashBox, handleTrashBox,
removeIssue, removeIssue,
isCompleted = false,
userAuth, userAuth,
}) => { }) => {
// collapse/expand // collapse/expand
@ -56,7 +58,7 @@ export const SingleBoard: React.FC<Props> = ({
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string); const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
const isNotAllowed = userAuth.isGuest || userAuth.isViewer; const isNotAllowed = userAuth.isGuest || userAuth.isViewer || isCompleted;
useEffect(() => { useEffect(() => {
if (currentState?.group === "completed" || currentState?.group === "cancelled") if (currentState?.group === "completed" || currentState?.group === "cancelled")
@ -72,6 +74,7 @@ export const SingleBoard: React.FC<Props> = ({
groupTitle={groupTitle} groupTitle={groupTitle}
isCollapsed={isCollapsed} isCollapsed={isCollapsed}
setIsCollapsed={setIsCollapsed} setIsCollapsed={setIsCollapsed}
isCompleted={isCompleted}
/> />
{isCollapsed && ( {isCollapsed && (
<StrictModeDroppable key={groupTitle} droppableId={groupTitle}> <StrictModeDroppable key={groupTitle} droppableId={groupTitle}>
@ -125,6 +128,7 @@ export const SingleBoard: React.FC<Props> = ({
removeIssue={() => { removeIssue={() => {
if (removeIssue && issue.bridge_id) removeIssue(issue.bridge_id); if (removeIssue && issue.bridge_id) removeIssue(issue.bridge_id);
}} }}
isCompleted={isCompleted}
userAuth={userAuth} userAuth={userAuth}
/> />
)} )}
@ -147,26 +151,30 @@ export const SingleBoard: React.FC<Props> = ({
Add Issue Add Issue
</button> </button>
) : ( ) : (
<CustomMenu !isCompleted && (
customButton={ <CustomMenu
<button customButton={
type="button" <button
className="flex items-center gap-2 font-medium text-theme outline-none" type="button"
> className="flex items-center gap-2 font-medium text-theme outline-none"
<PlusIcon className="h-4 w-4" /> >
Add Issue <PlusIcon className="h-4 w-4" />
</button> Add Issue
} </button>
optionsPosition="left" }
noBorder optionsPosition="left"
> noBorder
<CustomMenu.MenuItem onClick={addIssueToState}>Create new</CustomMenu.MenuItem> >
{openIssuesListModal && ( <CustomMenu.MenuItem onClick={addIssueToState}>
<CustomMenu.MenuItem onClick={openIssuesListModal}> Create new
Add an existing issue
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
)} {openIssuesListModal && (
</CustomMenu> <CustomMenu.MenuItem onClick={openIssuesListModal}>
Add an existing issue
</CustomMenu.MenuItem>
)}
</CustomMenu>
)
)} )}
</div> </div>
)} )}

View File

@ -59,6 +59,7 @@ type Props = {
removeIssue?: (() => void) | null; removeIssue?: (() => void) | null;
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
handleTrashBox: (isDragging: boolean) => void; handleTrashBox: (isDragging: boolean) => void;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -76,6 +77,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
groupTitle, groupTitle,
handleDeleteIssue, handleDeleteIssue,
handleTrashBox, handleTrashBox,
isCompleted = false,
userAuth, userAuth,
}) => { }) => {
// context menu // context menu
@ -177,7 +179,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
if (snapshot.isDragging) handleTrashBox(snapshot.isDragging); if (snapshot.isDragging) handleTrashBox(snapshot.isDragging);
}, [snapshot, handleTrashBox]); }, [snapshot, handleTrashBox]);
const isNotAllowed = userAuth.isGuest || userAuth.isViewer; const isNotAllowed = userAuth.isGuest || userAuth.isViewer || isCompleted;
return ( return (
<> <>
@ -187,15 +189,19 @@ export const SingleBoardIssue: React.FC<Props> = ({
isOpen={contextMenu} isOpen={contextMenu}
setIsOpen={setContextMenu} setIsOpen={setContextMenu}
> >
<ContextMenu.Item Icon={PencilIcon} onClick={editIssue}> {!isNotAllowed &&(
Edit issue <>
</ContextMenu.Item> <ContextMenu.Item Icon={PencilIcon} onClick={editIssue}>
<ContextMenu.Item Icon={ClipboardDocumentCheckIcon} onClick={makeIssueCopy}> Edit issue
Make a copy... </ContextMenu.Item>
</ContextMenu.Item> <ContextMenu.Item Icon={ClipboardDocumentCheckIcon} onClick={makeIssueCopy}>
<ContextMenu.Item Icon={TrashIcon} onClick={() => handleDeleteIssue(issue)}> Make a copy...
Delete issue </ContextMenu.Item>
</ContextMenu.Item> <ContextMenu.Item Icon={TrashIcon} onClick={() => handleDeleteIssue(issue)}>
Delete issue
</ContextMenu.Item>
</>
)}
<ContextMenu.Item Icon={LinkIcon} onClick={handleCopyText}> <ContextMenu.Item Icon={LinkIcon} onClick={handleCopyText}>
Copy issue link Copy issue link
</ContextMenu.Item> </ContextMenu.Item>

View File

@ -55,10 +55,16 @@ import { getStateGroupIcon } from "components/icons";
type Props = { type Props = {
type?: "issue" | "cycle" | "module"; type?: "issue" | "cycle" | "module";
openIssuesListModal?: () => void; openIssuesListModal?: () => void;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModal, userAuth }) => { export const IssuesView: React.FC<Props> = ({
type = "issue",
openIssuesListModal,
isCompleted = false,
userAuth,
}) => {
// create issue modal // create issue modal
const [createIssueModal, setCreateIssueModal] = useState(false); const [createIssueModal, setCreateIssueModal] = useState(false);
const [createViewModal, setCreateViewModal] = useState<any>(null); const [createViewModal, setCreateViewModal] = useState<any>(null);
@ -592,6 +598,7 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
? removeIssueFromModule ? removeIssueFromModule
: null : null
} }
isCompleted={isCompleted}
userAuth={userAuth} userAuth={userAuth}
/> />
) : ( ) : (
@ -611,6 +618,7 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
? removeIssueFromModule ? removeIssueFromModule
: null : null
} }
isCompleted={isCompleted}
userAuth={userAuth} userAuth={userAuth}
/> />
)} )}

View File

@ -15,6 +15,7 @@ type Props = {
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
openIssuesListModal?: (() => void) | null; openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string) => void) | null; removeIssue: ((bridgeId: string) => void) | null;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -27,6 +28,7 @@ export const AllLists: React.FC<Props> = ({
handleEditIssue, handleEditIssue,
handleDeleteIssue, handleDeleteIssue,
removeIssue, removeIssue,
isCompleted = false,
userAuth, userAuth,
}) => { }) => {
const { groupedByIssues, groupByProperty: selectedGroup, showEmptyGroups } = useIssuesView(); const { groupedByIssues, groupByProperty: selectedGroup, showEmptyGroups } = useIssuesView();
@ -55,6 +57,7 @@ export const AllLists: React.FC<Props> = ({
handleDeleteIssue={handleDeleteIssue} handleDeleteIssue={handleDeleteIssue}
openIssuesListModal={type !== "issue" ? openIssuesListModal : null} openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
removeIssue={removeIssue} removeIssue={removeIssue}
isCompleted={isCompleted}
userAuth={userAuth} userAuth={userAuth}
/> />
); );

View File

@ -49,6 +49,7 @@ type Props = {
makeIssueCopy: () => void; makeIssueCopy: () => void;
removeIssue?: (() => void) | null; removeIssue?: (() => void) | null;
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -62,6 +63,7 @@ export const SingleListIssue: React.FC<Props> = ({
removeIssue, removeIssue,
groupTitle, groupTitle,
handleDeleteIssue, handleDeleteIssue,
isCompleted = false,
userAuth, userAuth,
}) => { }) => {
// context menu // context menu
@ -145,7 +147,7 @@ export const SingleListIssue: React.FC<Props> = ({
}); });
}; };
const isNotAllowed = userAuth.isGuest || userAuth.isViewer; const isNotAllowed = userAuth.isGuest || userAuth.isViewer || isCompleted;
return ( return (
<> <>
@ -155,15 +157,19 @@ export const SingleListIssue: React.FC<Props> = ({
isOpen={contextMenu} isOpen={contextMenu}
setIsOpen={setContextMenu} setIsOpen={setContextMenu}
> >
<ContextMenu.Item Icon={PencilIcon} onClick={editIssue}> {!isNotAllowed && (
Edit issue <>
</ContextMenu.Item> <ContextMenu.Item Icon={PencilIcon} onClick={editIssue}>
<ContextMenu.Item Icon={ClipboardDocumentCheckIcon} onClick={makeIssueCopy}> Edit issue
Make a copy... </ContextMenu.Item>
</ContextMenu.Item> <ContextMenu.Item Icon={ClipboardDocumentCheckIcon} onClick={makeIssueCopy}>
<ContextMenu.Item Icon={TrashIcon} onClick={() => handleDeleteIssue(issue)}> Make a copy...
Delete issue </ContextMenu.Item>
</ContextMenu.Item> <ContextMenu.Item Icon={TrashIcon} onClick={() => handleDeleteIssue(issue)}>
Delete issue
</ContextMenu.Item>
</>
)}
<ContextMenu.Item Icon={LinkIcon} onClick={handleCopyText}> <ContextMenu.Item Icon={LinkIcon} onClick={handleCopyText}>
Copy issue link Copy issue link
</ContextMenu.Item> </ContextMenu.Item>

View File

@ -30,6 +30,7 @@ type Props = {
handleDeleteIssue: (issue: IIssue) => void; handleDeleteIssue: (issue: IIssue) => void;
openIssuesListModal?: (() => void) | null; openIssuesListModal?: (() => void) | null;
removeIssue: ((bridgeId: string) => void) | null; removeIssue: ((bridgeId: string) => void) | null;
isCompleted?: boolean;
userAuth: UserAuth; userAuth: UserAuth;
}; };
@ -46,6 +47,7 @@ export const SingleList: React.FC<Props> = ({
handleDeleteIssue, handleDeleteIssue,
openIssuesListModal, openIssuesListModal,
removeIssue, removeIssue,
isCompleted = false,
userAuth, userAuth,
}) => { }) => {
const router = useRouter(); const router = useRouter();
@ -93,9 +95,11 @@ export const SingleList: React.FC<Props> = ({
> >
<PlusIcon className="h-4 w-4" /> <PlusIcon className="h-4 w-4" />
</button> </button>
) : isCompleted ? (
""
) : ( ) : (
<CustomMenu <CustomMenu
label={ customButton={
<span className="flex items-center"> <span className="flex items-center">
<PlusIcon className="h-4 w-4" /> <PlusIcon className="h-4 w-4" />
</span> </span>
@ -138,6 +142,7 @@ export const SingleList: React.FC<Props> = ({
removeIssue={() => { removeIssue={() => {
if (removeIssue !== null && issue.bridge_id) removeIssue(issue.bridge_id); if (removeIssue !== null && issue.bridge_id) removeIssue(issue.bridge_id);
}} }}
isCompleted={isCompleted}
userAuth={userAuth} userAuth={userAuth}
/> />
)) ))

View File

@ -39,7 +39,6 @@ const ProgressChart: React.FC<Props> = ({ issues, start, end }) => {
const CustomTooltip = ({ active, payload }: TooltipProps<ValueType, NameType>) => { const CustomTooltip = ({ active, payload }: TooltipProps<ValueType, NameType>) => {
if (active && payload && payload.length) { if (active && payload && payload.length) {
console.log(payload[0].payload.currentDate);
return ( return (
<div className="rounded-sm bg-gray-300 p-1 text-xs text-gray-800"> <div className="rounded-sm bg-gray-300 p-1 text-xs text-gray-800">
<p>{payload[0].payload.currentDate}</p> <p>{payload[0].payload.currentDate}</p>

View File

@ -70,6 +70,7 @@ export const CompletedCyclesList: React.FC<CompletedCyclesListProps> = ({
cycle={cycle} cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)} handleDeleteCycle={() => handleDeleteCycle(cycle)}
handleEditCycle={() => handleEditCycle(cycle)} handleEditCycle={() => handleEditCycle(cycle)}
isCompleted
/> />
))} ))}
</div> </div>

View File

@ -45,9 +45,15 @@ type Props = {
cycle: ICycle | undefined; cycle: ICycle | undefined;
isOpen: boolean; isOpen: boolean;
cycleStatus: string; cycleStatus: string;
isCompleted: boolean;
}; };
export const CycleDetailsSidebar: React.FC<Props> = ({ cycle, isOpen, cycleStatus }) => { export const CycleDetailsSidebar: React.FC<Props> = ({
cycle,
isOpen,
cycleStatus,
isCompleted,
}) => {
const [cycleDeleteModal, setCycleDeleteModal] = useState(false); const [cycleDeleteModal, setCycleDeleteModal] = useState(false);
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date()); const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
const [endDateRange, setEndDateRange] = useState<Date | null>(null); const [endDateRange, setEndDateRange] = useState<Date | null>(null);
@ -164,6 +170,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({ cycle, isOpen, cycleStatu
{({ open }) => ( {({ open }) => (
<> <>
<Popover.Button <Popover.Button
disabled={isCompleted ?? false}
className={`group flex h-full items-center gap-1 rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-gray-800 ${ className={`group flex h-full items-center gap-1 rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-gray-800 ${
open ? "bg-gray-100" : "" open ? "bg-gray-100" : ""
}`} }`}
@ -209,6 +216,7 @@ export const CycleDetailsSidebar: React.FC<Props> = ({ cycle, isOpen, cycleStatu
{({ open }) => ( {({ open }) => (
<> <>
<Popover.Button <Popover.Button
disabled={isCompleted ?? false}
className={`group flex items-center gap-1 rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-gray-800 ${ className={`group flex items-center gap-1 rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-gray-800 ${
open ? "bg-gray-100" : "" open ? "bg-gray-100" : ""
}`} }`}
@ -262,12 +270,14 @@ export const CycleDetailsSidebar: React.FC<Props> = ({ cycle, isOpen, cycleStatu
<span>Copy Link</span> <span>Copy Link</span>
</span> </span>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={() => setCycleDeleteModal(true)}> {!isCompleted && (
<span className="flex items-center justify-start gap-2 text-gray-800"> <CustomMenu.MenuItem onClick={() => setCycleDeleteModal(true)}>
<TrashIcon className="h-4 w-4" /> <span className="flex items-center justify-start gap-2 text-gray-800">
<span>Delete</span> <TrashIcon className="h-4 w-4" />
</span> <span>Delete</span>
</CustomMenu.MenuItem> </span>
</CustomMenu.MenuItem>
)}
</CustomMenu> </CustomMenu>
</div> </div>

View File

@ -43,6 +43,7 @@ type TSingleStatProps = {
cycle: ICycle; cycle: ICycle;
handleEditCycle: () => void; handleEditCycle: () => void;
handleDeleteCycle: () => void; handleDeleteCycle: () => void;
isCompleted?: boolean;
}; };
const stateGroups = [ const stateGroups = [
@ -77,6 +78,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
cycle, cycle,
handleEditCycle, handleEditCycle,
handleDeleteCycle, handleDeleteCycle,
isCompleted = false,
}) => { }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
@ -293,22 +295,26 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
<span className="text-gray-900">{cycle.owned_by.first_name}</span> <span className="text-gray-900">{cycle.owned_by.first_name}</span>
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<button {!isCompleted && (
onClick={handleEditCycle} <button
className="flex cursor-pointer items-center rounded p-1 duration-300 hover:bg-gray-100" onClick={handleEditCycle}
> className="flex cursor-pointer items-center rounded p-1 duration-300 hover:bg-gray-100"
<span> >
<PencilIcon className="h-4 w-4" /> <span>
</span> <PencilIcon className="h-4 w-4" />
</button> </span>
</button>
)}
<CustomMenu width="auto" verticalEllipsis> <CustomMenu width="auto" verticalEllipsis>
<CustomMenu.MenuItem onClick={handleDeleteCycle}> {!isCompleted && (
<span className="flex items-center justify-start gap-2 text-gray-800"> <CustomMenu.MenuItem onClick={handleDeleteCycle}>
<TrashIcon className="h-4 w-4" /> <span className="flex items-center justify-start gap-2 text-gray-800">
<span>Delete Cycle</span> <TrashIcon className="h-4 w-4" />
</span> <span>Delete Cycle</span>
</CustomMenu.MenuItem> </span>
</CustomMenu.MenuItem>
)}
<CustomMenu.MenuItem onClick={handleCopyText}> <CustomMenu.MenuItem onClick={handleCopyText}>
<span className="flex items-center justify-start gap-2 text-gray-800"> <span className="flex items-center justify-start gap-2 text-gray-800">
<DocumentDuplicateIcon className="h-4 w-4" /> <DocumentDuplicateIcon className="h-4 w-4" />

View File

@ -73,7 +73,7 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
const cycleStatus = const cycleStatus =
cycleDetails?.start_date && cycleDetails?.end_date cycleDetails?.start_date && cycleDetails?.end_date
? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date) ? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date)
: ""; : "draft";
const { data: issues } = useSWR( const { data: issues } = useSWR(
workspaceSlug && projectId workspaceSlug && projectId
@ -159,9 +159,9 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
} }
> >
<div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}> <div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}>
<IssuesView type="cycle" userAuth={props} openIssuesListModal={openIssuesListModal} /> <IssuesView type="cycle" userAuth={props} openIssuesListModal={openIssuesListModal} isCompleted={cycleStatus === "completed" ?? false} />
</div> </div>
<CycleDetailsSidebar cycleStatus={cycleStatus} cycle={cycleDetails} isOpen={cycleSidebar} /> <CycleDetailsSidebar cycleStatus={cycleStatus} cycle={cycleDetails} isOpen={cycleSidebar} isCompleted={cycleStatus === "completed" ?? false} />
</AppLayout> </AppLayout>
</IssueViewContextProvider> </IssueViewContextProvider>
); );