forked from github/plane
[WEB-404] chore: calendar layout add existing issue workflow improvement (#3877)
* chore: target date none filter * chore: calendar layout add existing issue functionality added for cycle and module * fix: enums export in the types package * chore: remove NestedKeyOf type --------- Co-authored-by: NarayanBavisetti <narayan3119@gmail.com> Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
This commit is contained in:
parent
a08f401452
commit
da735f318a
@ -235,6 +235,7 @@ class IssueSearchEndpoint(BaseAPIView):
|
|||||||
cycle = request.query_params.get("cycle", "false")
|
cycle = request.query_params.get("cycle", "false")
|
||||||
module = request.query_params.get("module", False)
|
module = request.query_params.get("module", False)
|
||||||
sub_issue = request.query_params.get("sub_issue", "false")
|
sub_issue = request.query_params.get("sub_issue", "false")
|
||||||
|
target_date = request.query_params.get("target_date", True)
|
||||||
|
|
||||||
issue_id = request.query_params.get("issue_id", False)
|
issue_id = request.query_params.get("issue_id", False)
|
||||||
|
|
||||||
@ -273,6 +274,9 @@ class IssueSearchEndpoint(BaseAPIView):
|
|||||||
if module:
|
if module:
|
||||||
issues = issues.exclude(issue_module__module=module)
|
issues = issues.exclude(issue_module__module=module)
|
||||||
|
|
||||||
|
if target_date == "none":
|
||||||
|
issues = issues.filter(target_date__isnull=True)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
issues.values(
|
issues.values(
|
||||||
"name",
|
"name",
|
||||||
|
1
packages/types/src/projects.d.ts
vendored
1
packages/types/src/projects.d.ts
vendored
@ -130,6 +130,7 @@ export type TProjectIssuesSearchParams = {
|
|||||||
sub_issue?: boolean;
|
sub_issue?: boolean;
|
||||||
issue_id?: string;
|
issue_id?: string;
|
||||||
workspace_search: boolean;
|
workspace_search: boolean;
|
||||||
|
target_date?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ISearchIssueResponse {
|
export interface ISearchIssueResponse {
|
||||||
|
@ -29,12 +29,21 @@ interface IBaseCalendarRoot {
|
|||||||
[EIssueActions.ARCHIVE]?: (issue: TIssue) => Promise<void>;
|
[EIssueActions.ARCHIVE]?: (issue: TIssue) => Promise<void>;
|
||||||
[EIssueActions.RESTORE]?: (issue: TIssue) => Promise<void>;
|
[EIssueActions.RESTORE]?: (issue: TIssue) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
addIssuesToView?: (issueIds: string[]) => Promise<any>;
|
||||||
viewId?: string;
|
viewId?: string;
|
||||||
isCompletedCycle?: boolean;
|
isCompletedCycle?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
||||||
const { issueStore, issuesFilterStore, QuickActions, issueActions, viewId, isCompletedCycle = false } = props;
|
const {
|
||||||
|
issueStore,
|
||||||
|
issuesFilterStore,
|
||||||
|
QuickActions,
|
||||||
|
issueActions,
|
||||||
|
addIssuesToView,
|
||||||
|
viewId,
|
||||||
|
isCompletedCycle = false,
|
||||||
|
} = props;
|
||||||
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -128,6 +137,7 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
|||||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
quickAddCallback={issueStore.quickAddIssue}
|
quickAddCallback={issueStore.quickAddIssue}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
readOnly={!isEditingAllowed || isCompletedCycle}
|
readOnly={!isEditingAllowed || isCompletedCycle}
|
||||||
|
@ -30,6 +30,7 @@ type Props = {
|
|||||||
data: TIssue,
|
data: TIssue,
|
||||||
viewId?: string
|
viewId?: string
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssue | undefined>;
|
||||||
|
addIssuesToView?: (issueIds: string[]) => Promise<any>;
|
||||||
viewId?: string;
|
viewId?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
@ -43,6 +44,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
|||||||
showWeekends,
|
showWeekends,
|
||||||
quickActions,
|
quickActions,
|
||||||
quickAddCallback,
|
quickAddCallback,
|
||||||
|
addIssuesToView,
|
||||||
viewId,
|
viewId,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
} = props;
|
} = props;
|
||||||
@ -90,6 +92,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
|||||||
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
||||||
quickActions={quickActions}
|
quickActions={quickActions}
|
||||||
quickAddCallback={quickAddCallback}
|
quickAddCallback={quickAddCallback}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
@ -106,6 +109,7 @@ export const CalendarChart: React.FC<Props> = observer((props) => {
|
|||||||
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
disableIssueCreation={!enableIssueCreation || !isEditingAllowed}
|
||||||
quickActions={quickActions}
|
quickActions={quickActions}
|
||||||
quickAddCallback={quickAddCallback}
|
quickAddCallback={quickAddCallback}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
|
@ -4,9 +4,10 @@ import { observer } from "mobx-react-lite";
|
|||||||
// components
|
// components
|
||||||
import { CalendarIssueBlocks, ICalendarDate, CalendarQuickAddIssueForm } from "components/issues";
|
import { CalendarIssueBlocks, ICalendarDate, CalendarQuickAddIssueForm } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
// constants
|
// constants
|
||||||
import { MONTHS_LIST } from "constants/calendar";
|
import { MONTHS_LIST } from "constants/calendar";
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
// types
|
||||||
import { ICycleIssuesFilter } from "store/issue/cycle";
|
import { ICycleIssuesFilter } from "store/issue/cycle";
|
||||||
import { IModuleIssuesFilter } from "store/issue/module";
|
import { IModuleIssuesFilter } from "store/issue/module";
|
||||||
import { IProjectIssuesFilter } from "store/issue/project";
|
import { IProjectIssuesFilter } from "store/issue/project";
|
||||||
@ -27,6 +28,7 @@ type Props = {
|
|||||||
data: TIssue,
|
data: TIssue,
|
||||||
viewId?: string
|
viewId?: string
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssue | undefined>;
|
||||||
|
addIssuesToView?: (issueIds: string[]) => Promise<any>;
|
||||||
viewId?: string;
|
viewId?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
@ -41,6 +43,7 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
|||||||
enableQuickIssueCreate,
|
enableQuickIssueCreate,
|
||||||
disableIssueCreation,
|
disableIssueCreation,
|
||||||
quickAddCallback,
|
quickAddCallback,
|
||||||
|
addIssuesToView,
|
||||||
viewId,
|
viewId,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
} = props;
|
} = props;
|
||||||
@ -112,6 +115,7 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
|||||||
target_date: renderFormattedPayloadDate(date.date) ?? undefined,
|
target_date: renderFormattedPayloadDate(date.date) ?? undefined,
|
||||||
}}
|
}}
|
||||||
quickAddCallback={quickAddCallback}
|
quickAddCallback={quickAddCallback}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
onOpen={() => setShowAllIssues(true)}
|
onOpen={() => setShowAllIssues(true)}
|
||||||
/>
|
/>
|
||||||
|
@ -2,20 +2,24 @@ import { useEffect, useRef, useState } from "react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
// components
|
||||||
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
// hooks
|
// hooks
|
||||||
import { PlusIcon } from "lucide-react";
|
import { useEventTracker, useIssueDetail, useProject } from "hooks/store";
|
||||||
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui";
|
|
||||||
import { ISSUE_CREATED } from "constants/event-tracker";
|
|
||||||
import { createIssuePayload } from "helpers/issue.helper";
|
|
||||||
import { useEventTracker, useProject } from "hooks/store";
|
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// helpers
|
// helpers
|
||||||
|
import { createIssuePayload } from "helpers/issue.helper";
|
||||||
// icons
|
// icons
|
||||||
|
import { PlusIcon } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
|
import { TOAST_TYPE, setPromiseToast, setToast, CustomMenu } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { ISearchIssueResponse, TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
|
import { ISSUE_CREATED } from "constants/event-tracker";
|
||||||
|
// helper
|
||||||
|
import { cn } from "helpers/common.helper";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
formKey: keyof TIssue;
|
formKey: keyof TIssue;
|
||||||
@ -28,6 +32,7 @@ type Props = {
|
|||||||
data: TIssue,
|
data: TIssue,
|
||||||
viewId?: string
|
viewId?: string
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssue | undefined>;
|
||||||
|
addIssuesToView?: (issueIds: string[]) => Promise<any>;
|
||||||
viewId?: string;
|
viewId?: string;
|
||||||
onOpen?: () => void;
|
onOpen?: () => void;
|
||||||
};
|
};
|
||||||
@ -60,21 +65,26 @@ const Inputs = (props: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
||||||
const { formKey, prePopulatedData, quickAddCallback, viewId, onOpen } = props;
|
const { formKey, prePopulatedData, quickAddCallback, addIssuesToView, viewId, onOpen } = props;
|
||||||
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
|
const { updateIssue } = useIssueDetail();
|
||||||
// refs
|
// refs
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
// states
|
// states
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
|
const [isExistingIssueModalOpen, setIsExistingIssueModalOpen] = useState(false);
|
||||||
// derived values
|
// derived values
|
||||||
const projectDetail = projectId ? getProjectById(projectId.toString()) : null;
|
const projectDetail = projectId ? getProjectById(projectId.toString()) : null;
|
||||||
|
const ExistingIssuesListModalPayload = moduleId
|
||||||
|
? { module: moduleId.toString(), target_date: "none" }
|
||||||
|
: { cycle: true, target_date: "none" };
|
||||||
|
|
||||||
const {
|
const {
|
||||||
reset,
|
reset,
|
||||||
@ -158,13 +168,50 @@ export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleAddIssuesToView = async (data: ISearchIssueResponse[]) => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
|
const issueIds = data.map((i) => i.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// To handle all updates in parallel
|
||||||
|
await Promise.all(
|
||||||
|
data.map((issue) =>
|
||||||
|
updateIssue(workspaceSlug.toString(), projectId.toString(), issue.id, prePopulatedData ?? {})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (addIssuesToView) {
|
||||||
|
await addIssuesToView(issueIds);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
title: "Error!",
|
||||||
|
message: "Something went wrong. Please try again.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNewIssue = () => {
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
if (onOpen) onOpen();
|
if (onOpen) onOpen();
|
||||||
};
|
};
|
||||||
|
const handleExistingIssue = () => {
|
||||||
|
setIsExistingIssueModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{workspaceSlug && projectId && (
|
||||||
|
<ExistingIssuesListModal
|
||||||
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
|
projectId={projectId.toString()}
|
||||||
|
isOpen={isExistingIssueModalOpen}
|
||||||
|
handleClose={() => setIsExistingIssueModalOpen(false)}
|
||||||
|
searchParams={ExistingIssuesListModalPayload}
|
||||||
|
handleOnSubmit={handleAddIssuesToView}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -182,15 +229,38 @@ export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{!isOpen && (
|
{!isOpen && (
|
||||||
<div className="hidden rounded border-[0.5px] border-custom-border-200 group-hover:block">
|
<div
|
||||||
|
className={cn("hidden rounded border-[0.5px] border-custom-border-200 group-hover:block", {
|
||||||
|
block: isMenuOpen,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{addIssuesToView ? (
|
||||||
|
<CustomMenu
|
||||||
|
placement="bottom-start"
|
||||||
|
menuButtonOnClick={() => setIsMenuOpen(true)}
|
||||||
|
onMenuClose={() => setIsMenuOpen(false)}
|
||||||
|
className="w-full"
|
||||||
|
customButtonClassName="w-full"
|
||||||
|
customButton={
|
||||||
|
<div className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-custom-primary-100">
|
||||||
|
<PlusIcon className="h-3.5 w-3.5 stroke-2 flex-shrink-0" />
|
||||||
|
<span className="text-sm font-medium flex-shrink-0 text-custom-primary-100">New Issue</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CustomMenu.MenuItem onClick={handleNewIssue}>New Issue</CustomMenu.MenuItem>
|
||||||
|
<CustomMenu.MenuItem onClick={handleExistingIssue}>Add existing issue</CustomMenu.MenuItem>
|
||||||
|
</CustomMenu>
|
||||||
|
) : (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-custom-primary-100"
|
className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-custom-primary-100"
|
||||||
onClick={handleOpen}
|
onClick={handleNewIssue}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
|
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
|
||||||
<span className="text-sm font-medium text-custom-primary-100">New Issue</span>
|
<span className="text-sm font-medium text-custom-primary-100">New Issue</span>
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
//hooks
|
//hooks
|
||||||
import { CycleIssueQuickActions } from "components/issues";
|
|
||||||
import { EIssuesStoreType } from "constants/issue";
|
|
||||||
import { useCycle, useIssues } from "hooks/store";
|
import { useCycle, useIssues } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
|
import { CycleIssueQuickActions } from "components/issues";
|
||||||
|
import { BaseCalendarRoot } from "../base-calendar-root";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { EIssueActions } from "../../types";
|
import { EIssueActions } from "../../types";
|
||||||
import { BaseCalendarRoot } from "../base-calendar-root";
|
// constants
|
||||||
|
import { EIssuesStoreType } from "constants/issue";
|
||||||
|
|
||||||
export const CycleCalendarLayout: React.FC = observer(() => {
|
export const CycleCalendarLayout: React.FC = observer(() => {
|
||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.CYCLE);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.CYCLE);
|
||||||
@ -46,11 +47,20 @@ export const CycleCalendarLayout: React.FC = observer(() => {
|
|||||||
const isCompletedCycle =
|
const isCompletedCycle =
|
||||||
cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false;
|
cycleId && currentProjectCompletedCycleIds ? currentProjectCompletedCycleIds.includes(cycleId.toString()) : false;
|
||||||
|
|
||||||
|
const addIssuesToView = useCallback(
|
||||||
|
(issueIds: string[]) => {
|
||||||
|
if (!workspaceSlug || !projectId || !cycleId) throw new Error();
|
||||||
|
return issues.addIssueToCycle(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), issueIds);
|
||||||
|
},
|
||||||
|
[issues?.addIssueToCycle, workspaceSlug, projectId, cycleId]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseCalendarRoot
|
<BaseCalendarRoot
|
||||||
issueStore={issues}
|
issueStore={issues}
|
||||||
issuesFilterStore={issuesFilter}
|
issuesFilterStore={issuesFilter}
|
||||||
QuickActions={CycleIssueQuickActions}
|
QuickActions={CycleIssueQuickActions}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
issueActions={issueActions}
|
issueActions={issueActions}
|
||||||
viewId={cycleId.toString()}
|
viewId={cycleId.toString()}
|
||||||
isCompletedCycle={isCompletedCycle}
|
isCompletedCycle={isCompletedCycle}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
import { useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// hoks
|
// hooks
|
||||||
import { ModuleIssueQuickActions } from "components/issues";
|
|
||||||
import { EIssuesStoreType } from "constants/issue";
|
|
||||||
import { useIssues } from "hooks/store";
|
import { useIssues } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
|
import { ModuleIssueQuickActions } from "components/issues";
|
||||||
|
import { BaseCalendarRoot } from "../base-calendar-root";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { EIssueActions } from "../../types";
|
import { EIssueActions } from "../../types";
|
||||||
import { BaseCalendarRoot } from "../base-calendar-root";
|
// constants
|
||||||
|
import { EIssuesStoreType } from "constants/issue";
|
||||||
|
|
||||||
export const ModuleCalendarLayout: React.FC = observer(() => {
|
export const ModuleCalendarLayout: React.FC = observer(() => {
|
||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.MODULE);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.MODULE);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, moduleId } = router.query as {
|
const { workspaceSlug, projectId, moduleId } = router.query as {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
moduleId: string;
|
moduleId: string;
|
||||||
@ -42,12 +43,21 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
|
|||||||
[issues, workspaceSlug, moduleId]
|
[issues, workspaceSlug, moduleId]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const addIssuesToView = useCallback(
|
||||||
|
(issueIds: string[]) => {
|
||||||
|
if (!workspaceSlug || !projectId || !moduleId) throw new Error();
|
||||||
|
return issues.addIssuesToModule(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), issueIds);
|
||||||
|
},
|
||||||
|
[issues?.addIssuesToModule, workspaceSlug, projectId, moduleId]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseCalendarRoot
|
<BaseCalendarRoot
|
||||||
issueStore={issues}
|
issueStore={issues}
|
||||||
issuesFilterStore={issuesFilter}
|
issuesFilterStore={issuesFilter}
|
||||||
QuickActions={ModuleIssueQuickActions}
|
QuickActions={ModuleIssueQuickActions}
|
||||||
issueActions={issueActions}
|
issueActions={issueActions}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
viewId={moduleId}
|
viewId={moduleId}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -25,6 +25,7 @@ type Props = {
|
|||||||
data: TIssue,
|
data: TIssue,
|
||||||
viewId?: string
|
viewId?: string
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssue | undefined>;
|
||||||
|
addIssuesToView?: (issueIds: string[]) => Promise<any>;
|
||||||
viewId?: string;
|
viewId?: string;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
@ -39,6 +40,7 @@ export const CalendarWeekDays: React.FC<Props> = observer((props) => {
|
|||||||
enableQuickIssueCreate,
|
enableQuickIssueCreate,
|
||||||
disableIssueCreation,
|
disableIssueCreation,
|
||||||
quickAddCallback,
|
quickAddCallback,
|
||||||
|
addIssuesToView,
|
||||||
viewId,
|
viewId,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
} = props;
|
} = props;
|
||||||
@ -68,6 +70,7 @@ export const CalendarWeekDays: React.FC<Props> = observer((props) => {
|
|||||||
enableQuickIssueCreate={enableQuickIssueCreate}
|
enableQuickIssueCreate={enableQuickIssueCreate}
|
||||||
disableIssueCreation={disableIssueCreation}
|
disableIssueCreation={disableIssueCreation}
|
||||||
quickAddCallback={quickAddCallback}
|
quickAddCallback={quickAddCallback}
|
||||||
|
addIssuesToView={addIssuesToView}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
/>
|
/>
|
||||||
|
@ -11,7 +11,6 @@ import OverdueIssuesLight from "public/empty-state/dashboard/light/overdue-issue
|
|||||||
import UpcomingIssuesLight from "public/empty-state/dashboard/light/upcoming-issues.svg";
|
import UpcomingIssuesLight from "public/empty-state/dashboard/light/upcoming-issues.svg";
|
||||||
// types
|
// types
|
||||||
import { TIssuesListTypes, TStateGroups } from "@plane/types";
|
import { TIssuesListTypes, TStateGroups } from "@plane/types";
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
import { EUserWorkspaceRoles } from "./workspace";
|
import { EUserWorkspaceRoles } from "./workspace";
|
||||||
// icons
|
// icons
|
||||||
|
Loading…
Reference in New Issue
Block a user