fix: issue peek-overview delete functionality (#3134)

* fix: peek-overview delete issue

* refactor: removed unused variables
This commit is contained in:
Lakhan Baheti 2023-12-18 12:14:57 +05:30 committed by GitHub
parent 969a51f425
commit 05e7afab8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 172 additions and 35 deletions

View File

@ -120,8 +120,8 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
workspaceSlug={workspaceSlug.toString()}
projectId={peekProjectId.toString()}
issueId={peekIssueId.toString()}
handleIssue={async (issueToUpdate) =>
await handleIssues(issueToUpdate.target_date ?? "", issueToUpdate as IIssue, EIssueActions.UPDATE)
handleIssue={async (issueToUpdate, action: EIssueActions) =>
await handleIssues(issueToUpdate.target_date ?? "", issueToUpdate as IIssue, action)
}
/>
)}

View File

@ -1,4 +1,4 @@
import React from "react";
import React, { useCallback } from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// mobx store
@ -25,6 +25,8 @@ import {
IViewIssuesStore,
} from "store/issues";
import { TUnGroupedIssues } from "store/issues/types";
import { EIssueActions } from "../types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
interface IBaseGanttRoot {
@ -35,10 +37,15 @@ interface IBaseGanttRoot {
| IViewIssuesFilterStore;
issueStore: IProjectIssuesStore | IModuleIssuesStore | ICycleIssuesStore | IViewIssuesStore;
viewId?: string;
issueActions: {
[EIssueActions.DELETE]: (issue: IIssue) => Promise<void>;
[EIssueActions.UPDATE]?: (issue: IIssue) => Promise<void>;
[EIssueActions.REMOVE]?: (issue: IIssue) => Promise<void>;
};
}
export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGanttRoot) => {
const { issueFiltersStore, issueStore, viewId } = props;
const { issueFiltersStore, issueStore, viewId, issueActions } = props;
const router = useRouter();
const { workspaceSlug, peekIssueId, peekProjectId } = router.query;
@ -64,11 +71,14 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
await issueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, payload, viewId);
};
const updateIssue = async (projectId: string, issueId: string, payload: Partial<IIssue>) => {
if (!workspaceSlug) return;
await issueStore.updateIssue(workspaceSlug.toString(), projectId, issueId, payload, viewId);
};
const handleIssues = useCallback(
async (issue: IIssue, action: EIssueActions) => {
if (issueActions[action]) {
await issueActions[action]!(issue);
}
},
[issueActions]
);
const isAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
@ -102,8 +112,8 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
workspaceSlug={workspaceSlug.toString()}
projectId={peekProjectId.toString()}
issueId={peekIssueId.toString()}
handleIssue={async (issueToUpdate) => {
await updateIssue(peekProjectId.toString(), peekIssueId.toString(), issueToUpdate);
handleIssue={async (issueToUpdate, action) => {
await handleIssues(issueToUpdate as IIssue, action);
}}
/>
)}

View File

@ -4,15 +4,43 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { BaseGanttRoot } from "./base-gantt-root";
import { useRouter } from "next/router";
// types
import { EIssueActions } from "../types";
import { IIssue } from "types";
export const CycleGanttLayout: React.FC = observer(() => {
const router = useRouter();
const { cycleId } = router.query;
const { cycleId, workspaceSlug } = router.query;
const { cycleIssues: cycleIssueStore, cycleIssuesFilter: cycleIssueFilterStore } = useMobxStore();
const issueActions = {
[EIssueActions.UPDATE]: async (issue: IIssue) => {
if (!workspaceSlug || !cycleId) return;
await cycleIssueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue, cycleId.toString());
},
[EIssueActions.DELETE]: async (issue: IIssue) => {
if (!workspaceSlug || !cycleId) return;
await cycleIssueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id, cycleId.toString());
},
[EIssueActions.REMOVE]: async (issue: IIssue) => {
if (!workspaceSlug || !cycleId || !issue.bridge_id) return;
await cycleIssueStore.removeIssueFromCycle(
workspaceSlug.toString(),
issue.project,
cycleId.toString(),
issue.id,
issue.bridge_id
);
},
};
return (
<BaseGanttRoot
issueActions={issueActions}
issueFiltersStore={cycleIssueFilterStore}
issueStore={cycleIssueStore}
viewId={cycleId?.toString()}

View File

@ -4,15 +4,43 @@ import { useMobxStore } from "lib/mobx/store-provider";
// components
import { BaseGanttRoot } from "./base-gantt-root";
import { useRouter } from "next/router";
// types
import { EIssueActions } from "../types";
import { IIssue } from "types";
export const ModuleGanttLayout: React.FC = observer(() => {
const router = useRouter();
const { moduleId } = router.query;
const { moduleId, workspaceSlug } = router.query;
const { moduleIssues: moduleIssueStore, moduleIssuesFilter: moduleIssueFilterStore } = useMobxStore();
const issueActions = {
[EIssueActions.UPDATE]: async (issue: IIssue) => {
if (!workspaceSlug || !moduleId) return;
await moduleIssueStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue, moduleId.toString());
},
[EIssueActions.DELETE]: async (issue: IIssue) => {
if (!workspaceSlug || !moduleId) return;
await moduleIssueStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id, moduleId.toString());
},
[EIssueActions.REMOVE]: async (issue: IIssue) => {
if (!workspaceSlug || !moduleId || !issue.bridge_id) return;
await moduleIssueStore.removeIssueFromModule(
workspaceSlug.toString(),
issue.project,
moduleId.toString(),
issue.id,
issue.bridge_id
);
},
};
return (
<BaseGanttRoot
issueActions={issueActions}
issueFiltersStore={moduleIssueFilterStore}
issueStore={moduleIssueStore}
viewId={moduleId?.toString()}

View File

@ -1,12 +1,36 @@
import React from "react";
import { useRouter } from "next/router";
import { observer } from "mobx-react-lite";
// hooks
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { BaseGanttRoot } from "./base-gantt-root";
// types
import { EIssueActions } from "../types";
import { IIssue } from "types";
export const GanttLayout: React.FC = observer(() => {
const { projectIssues: projectIssuesStore, projectIssuesFilter: projectIssueFiltersStore } = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
return <BaseGanttRoot issueFiltersStore={projectIssueFiltersStore} issueStore={projectIssuesStore} />;
const issueActions = {
[EIssueActions.UPDATE]: async (issue: IIssue) => {
if (!workspaceSlug) return;
await projectIssuesStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue);
},
[EIssueActions.DELETE]: async (issue: IIssue) => {
if (!workspaceSlug) return;
await projectIssuesStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id);
},
};
return (
<BaseGanttRoot
issueActions={issueActions}
issueFiltersStore={projectIssueFiltersStore}
issueStore={projectIssuesStore}
/>
);
});

View File

@ -1,11 +1,35 @@
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { BaseGanttRoot } from "./base-gantt-root";
// types
import { EIssueActions } from "../types";
import { IIssue } from "types";
export const ProjectViewGanttLayout: React.FC = observer(() => {
const { viewIssues: projectIssueViewStore, viewIssuesFilter: projectIssueViewFiltersStore } = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
return <BaseGanttRoot issueFiltersStore={projectIssueViewFiltersStore} issueStore={projectIssueViewStore} />;
const issueActions = {
[EIssueActions.UPDATE]: async (issue: IIssue) => {
if (!workspaceSlug) return;
await projectIssueViewStore.updateIssue(workspaceSlug.toString(), issue.project, issue.id, issue);
},
[EIssueActions.DELETE]: async (issue: IIssue) => {
if (!workspaceSlug) return;
await projectIssueViewStore.removeIssue(workspaceSlug.toString(), issue.project, issue.id);
},
};
return (
<BaseGanttRoot
issueActions={issueActions}
issueFiltersStore={projectIssueViewFiltersStore}
issueStore={projectIssueViewStore}
/>
);
});

View File

@ -346,8 +346,8 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
workspaceSlug={workspaceSlug.toString()}
projectId={peekProjectId.toString()}
issueId={peekIssueId.toString()}
handleIssue={async (issueToUpdate) =>
await handleIssues(sub_group_by, group_by, issueToUpdate as IIssue, EIssueActions.UPDATE)
handleIssue={async (issueToUpdate, action: EIssueActions) =>
await handleIssues(sub_group_by, group_by, issueToUpdate as IIssue, action)
}
/>
)}

View File

@ -168,7 +168,9 @@ export const BaseListRoot = observer((props: IBaseListRoot) => {
workspaceSlug={workspaceSlug.toString()}
projectId={peekProjectId.toString()}
issueId={peekIssueId.toString()}
handleIssue={async (issueToUpdate) => await handleIssues(issueToUpdate as IIssue, EIssueActions.UPDATE)}
handleIssue={async (issueToUpdate, action: EIssueActions) =>
await handleIssues(issueToUpdate as IIssue, action)
}
/>
)}
</>

View File

@ -194,7 +194,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
workspaceSlug={workspaceSlug.toString()}
projectId={peekProjectId.toString()}
issueId={peekIssueId.toString()}
handleIssue={async (issueToUpdate: any) => await handleIssues(issueToUpdate, EIssueActions.UPDATE)}
handleIssue={async (issueToUpdate: any, action: EIssueActions) => await handleIssues(issueToUpdate, action)}
/>
)}
</div>

View File

@ -11,6 +11,7 @@ import { IssueView } from "components/issues";
import { copyUrlToClipboard } from "helpers/string.helper";
// types
import { IIssue, IIssueLink } from "types";
import { EIssueActions } from "../issue-layouts/types";
// constants
import { EUserWorkspaceRoles } from "constants/workspace";
@ -18,7 +19,7 @@ interface IIssuePeekOverview {
workspaceSlug: string;
projectId: string;
issueId: string;
handleIssue: (issue: Partial<IIssue>) => void;
handleIssue: (issue: Partial<IIssue>, action: EIssueActions) => Promise<void>;
isArchived?: boolean;
children?: ReactNode;
}
@ -31,7 +32,6 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
const {
user: { currentProjectRole },
issue: { removeIssueFromStructure },
issueDetail: {
createIssueComment,
updateIssueComment,
@ -98,7 +98,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
const issueUpdate = async (_data: Partial<IIssue>) => {
if (handleIssue) {
await handleIssue(_data);
await handleIssue(_data, EIssueActions.UPDATE);
fetchIssueActivity(workspaceSlug, projectId, issueId);
}
};
@ -133,7 +133,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
const handleDeleteIssue = async () => {
if (isArchived) await deleteArchivedIssue(workspaceSlug, projectId, issue!);
else removeIssueFromStructure(workspaceSlug, projectId, issue!);
else await handleIssue(issue!, EIssueActions.DELETE);
const { query } = router;
if (query.peekIssueId) {
setPeekId(null);

View File

@ -10,6 +10,7 @@ import { CustomMenu, Tooltip } from "@plane/ui";
// types
import { IUser, IIssue } from "types";
import { ISubIssuesRootLoaders, ISubIssuesRootLoadersHandler } from "./root";
import { EIssueActions } from "../issue-layouts/types";
export interface ISubIssues {
workspaceSlug: string;
@ -29,6 +30,7 @@ export interface ISubIssues {
issue?: IIssue | null
) => void;
handleUpdateIssue: (issue: IIssue, data: Partial<IIssue>) => void;
handleDeleteIssue: (issue: IIssue) => Promise<void>;
}
export const SubIssues: React.FC<ISubIssues> = ({
@ -45,6 +47,7 @@ export const SubIssues: React.FC<ISubIssues> = ({
copyText,
handleIssueCrudOperation,
handleUpdateIssue,
handleDeleteIssue,
}) => {
const router = useRouter();
const { peekProjectId, peekIssueId } = router.query;
@ -69,7 +72,13 @@ export const SubIssues: React.FC<ISubIssues> = ({
workspaceSlug={workspaceSlug}
projectId={peekProjectId.toString()}
issueId={peekIssueId.toString()}
handleIssue={async (issueToUpdate) => await handleUpdateIssue(issue, { ...issue, ...issueToUpdate })}
handleIssue={async (issueToUpdate, action) => {
if (action === EIssueActions.UPDATE) {
await handleUpdateIssue(issue, { ...issue, ...issueToUpdate });
} else if (action === EIssueActions.DELETE) {
await handleDeleteIssue(issue);
}
}}
/>
)}
<div>
@ -180,6 +189,7 @@ export const SubIssues: React.FC<ISubIssues> = ({
{issuesLoader.visibility.includes(issue?.id) && issue?.sub_issues_count > 0 && (
<SubIssuesRootList
handleDeleteIssue={handleDeleteIssue}
workspaceSlug={workspaceSlug}
projectId={projectId}
parentIssue={issue}

View File

@ -27,6 +27,7 @@ export interface ISubIssuesRootList {
issue?: IIssue | null
) => void;
handleUpdateIssue: (issue: IIssue, data: Partial<IIssue>) => void;
handleDeleteIssue: (issue: IIssue) => Promise<void>
}
const issueService = new IssueService();
@ -44,6 +45,7 @@ export const SubIssuesRootList: React.FC<ISubIssuesRootList> = ({
copyText,
handleIssueCrudOperation,
handleUpdateIssue,
handleDeleteIssue
}) => {
const { data: issues, isLoading } = useSWR(
workspaceSlug && projectId && parentIssue && parentIssue?.id ? SUB_ISSUES(parentIssue?.id) : null,
@ -70,6 +72,7 @@ export const SubIssuesRootList: React.FC<ISubIssuesRootList> = ({
issues.sub_issues.length > 0 &&
issues.sub_issues.map((issue: IIssue) => (
<SubIssues
handleDeleteIssue={handleDeleteIssue}
key={`${issue?.id}`}
workspaceSlug={workspaceSlug}
projectId={projectId}

View File

@ -176,6 +176,16 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
[updateIssueStructure, projectId, updateIssue, user, workspaceSlug]
);
const handleDeleteIssue = useCallback(
async (issue: IIssue) => {
if (!workspaceSlug || !projectId || !user) return;
await removeIssue(workspaceSlug.toString(), projectId.toString(), issue.id);
await mutate(SUB_ISSUES(parentIssue?.id));
},
[removeIssue, projectId, user, workspaceSlug, parentIssue?.id]
);
const isEditable = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER;
const mutateSubIssues = (parentIssueId: string | null) => {
@ -236,6 +246,7 @@ export const SubIssuesRoot: React.FC<ISubIssuesRoot> = observer((props) => {
{issuesLoader.visibility.includes(parentIssue?.id) && workspaceSlug && projectId && (
<div className="border border-b-0 border-custom-border-100">
<SubIssuesRootList
handleDeleteIssue={handleDeleteIssue}
workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()}
parentIssue={parentIssue}

View File

@ -82,7 +82,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
description_html: newDescription,
})
.then(() => {
mutatePageDetails((prevData) => ({ ...prevData, description_html: newDescription }) as IPage, false);
mutatePageDetails((prevData) => ({ ...prevData, description_html: newDescription } as IPage), false);
});
};
@ -162,15 +162,12 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
}, [pageDetails?.description_html]); // TODO: Verify the exhaustive-deps warning
function createObjectFromArray(keys: string[], options: any): any {
return keys.reduce(
(obj, key) => {
if (options[key] !== undefined) {
obj[key] = options[key];
}
return obj;
},
{} as { [key: string]: any }
);
return keys.reduce((obj, key) => {
if (options[key] !== undefined) {
obj[key] = options[key];
}
return obj;
}, {} as { [key: string]: any });
}
const mutatePageDetailsHelper = (
@ -499,7 +496,7 @@ const PageDetailsPage: NextPageWithLayout = observer(() => {
projectId={projectId as string}
issueId={peekIssueId ? (peekIssueId as string) : ""}
isArchived={false}
handleIssue={(issueToUpdate) => {
handleIssue={async (issueToUpdate, action) => {
if (peekIssueId && typeof peekIssueId === "string") {
handleUpdateIssue(peekIssueId, issueToUpdate);
}