From 756a71ca78248e7bed36f45421949e95adabd588 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:01:32 +0530 Subject: [PATCH] [WEB-2907] chore: issue store updated and code refactor (#6279) * chore: issue and epic store updated and code refactor * chore: layout ux copy updated --- web/ce/components/issues/quick-add/root.tsx | 4 +++- .../store/issue/issue-details/activity.store.ts | 7 ++++--- .../issues/create-issue-toast-action-items.tsx | 9 +++++---- .../calendar/quick-add-issue-actions.tsx | 10 ++++++---- .../issues/issue-layouts/kanban/default.tsx | 1 + .../issues/issue-layouts/kanban/kanban-group.tsx | 4 +++- .../issues/issue-layouts/list/default.tsx | 1 + .../issue-layouts/quick-add/form/calendar.tsx | 11 ++++++----- .../issue-layouts/quick-add/form/gantt.tsx | 8 ++++---- .../issue-layouts/quick-add/form/kanban.tsx | 6 +++--- .../issues/issue-layouts/quick-add/form/list.tsx | 8 ++++---- .../issue-layouts/quick-add/form/spreadsheet.tsx | 8 ++++---- .../issues/issue-layouts/quick-add/root.tsx | 16 +++++++++++----- .../components/issues/issue-layouts/utils.tsx | 4 +++- web/core/hooks/store/use-issue-detail.ts | 2 +- web/core/store/issue/issue.store.ts | 12 +++++++----- web/core/store/issue/root.store.ts | 7 +++++-- web/core/store/root.store.ts | 3 --- 18 files changed, 71 insertions(+), 50 deletions(-) diff --git a/web/ce/components/issues/quick-add/root.tsx b/web/ce/components/issues/quick-add/root.tsx index c0bd3914ed..72daa259e1 100644 --- a/web/ce/components/issues/quick-add/root.tsx +++ b/web/ce/components/issues/quick-add/root.tsx @@ -30,10 +30,11 @@ export type TQuickAddIssueFormRoot = { register: UseFormRegister; onSubmit: () => void; onClose: () => void; + isEpic: boolean; }; export const QuickAddIssueFormRoot: FC = observer((props) => { - const { isOpen, layout, projectId, hasError = false, setFocus, register, onSubmit, onClose } = props; + const { isOpen, layout, projectId, hasError = false, setFocus, register, onSubmit, onClose, isEpic } = props; // store hooks const { getProjectById } = useProject(); // derived values @@ -70,6 +71,7 @@ export const QuickAddIssueFormRoot: FC = observer((props hasError={hasError} register={register} onSubmit={onSubmit} + isEpic={isEpic} /> ); }); diff --git a/web/ce/store/issue/issue-details/activity.store.ts b/web/ce/store/issue/issue-details/activity.store.ts index de84fb87d9..2ec70f3cc1 100644 --- a/web/ce/store/issue/issue-details/activity.store.ts +++ b/web/ce/store/issue/issue-details/activity.store.ts @@ -93,10 +93,11 @@ export class IssueActivityStore implements IIssueActivityStore { let activityComments: TIssueActivityComment[] = []; - const currentStore = this.serviceType === EIssueServiceType.EPICS ? this.store.epic : this.store.issue; + const currentStore = + this.serviceType === EIssueServiceType.EPICS ? this.store.issue.epicDetail : this.store.issue.issueDetail; const activities = this.getActivitiesByIssueId(issueId) || []; - const comments = currentStore.issueDetail.comment.getCommentsByIssueId(issueId) || []; + const comments = currentStore.comment.getCommentsByIssueId(issueId) || []; activities.forEach((activityId) => { const activity = this.getActivityById(activityId); @@ -109,7 +110,7 @@ export class IssueActivityStore implements IIssueActivityStore { }); comments.forEach((commentId) => { - const comment = currentStore.issueDetail.comment.getCommentById(commentId); + const comment = currentStore.comment.getCommentById(commentId); if (!comment) return; activityComments.push({ id: comment.id, diff --git a/web/core/components/issues/create-issue-toast-action-items.tsx b/web/core/components/issues/create-issue-toast-action-items.tsx index 0fe76fb9b6..aff00f0003 100644 --- a/web/core/components/issues/create-issue-toast-action-items.tsx +++ b/web/core/components/issues/create-issue-toast-action-items.tsx @@ -10,10 +10,11 @@ type TCreateIssueToastActionItems = { workspaceSlug: string; projectId: string; issueId: string; + isEpic?: boolean; }; export const CreateIssueToastActionItems: FC = observer((props) => { - const { workspaceSlug, projectId, issueId } = props; + const { workspaceSlug, projectId, issueId, isEpic = false } = props; // state const [copied, setCopied] = useState(false); // store hooks @@ -26,7 +27,7 @@ export const CreateIssueToastActionItems: FC = obs if (!issue) return null; - const issueLink = `${workspaceSlug}/projects/${projectId}/issues/${issueId}`; + const issueLink = `${workspaceSlug}/projects/${projectId}/${isEpic ? "epics" : "issues"}/${issueId}`; const copyToClipboard = async (e: React.MouseEvent) => { try { @@ -43,12 +44,12 @@ export const CreateIssueToastActionItems: FC = obs return (
- View issue + {`View ${isEpic ? "epic" : "issue"}`} {copied ? ( diff --git a/web/core/components/issues/issue-layouts/calendar/quick-add-issue-actions.tsx b/web/core/components/issues/issue-layouts/calendar/quick-add-issue-actions.tsx index 79779e54a1..75afad975e 100644 --- a/web/core/components/issues/issue-layouts/calendar/quick-add-issue-actions.tsx +++ b/web/core/components/issues/issue-layouts/calendar/quick-add-issue-actions.tsx @@ -24,10 +24,11 @@ type TCalendarQuickAddIssueActions = { quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise; addIssuesToView?: (issueIds: string[]) => Promise; onOpen?: () => void; + isEpic?: boolean; }; export const CalendarQuickAddIssueActions: FC = observer((props) => { - const { prePopulatedData, quickAddCallback, addIssuesToView, onOpen } = props; + const { prePopulatedData, quickAddCallback, addIssuesToView, onOpen, isEpic = false } = props; // router const { workspaceSlug, projectId, moduleId } = useParams(); // states @@ -118,15 +119,16 @@ export const CalendarQuickAddIssueActions: FC = o customButton={
- New issue + {`New ${isEpic ? "Epic" : "Issue"}`}
} > - New issue - Add existing issue + {`New ${isEpic ? "Epic" : "Issue"}`} + {!isEpic && Add existing issue}
} + isEpic={isEpic} /> ); diff --git a/web/core/components/issues/issue-layouts/kanban/default.tsx b/web/core/components/issues/issue-layouts/kanban/default.tsx index 3f20646d1c..661c2fee58 100644 --- a/web/core/components/issues/issue-layouts/kanban/default.tsx +++ b/web/core/components/issues/issue-layouts/kanban/default.tsx @@ -98,6 +98,7 @@ export const KanBan: React.FC = observer((props) => { groupBy: group_by as GroupByColumnTypes, includeNone: true, isWorkspaceLevel: isWorkspaceLevel(storeType), + isEpic: isEpic, }); if (!list) return null; diff --git a/web/core/components/issues/issue-layouts/kanban/kanban-group.tsx b/web/core/components/issues/issue-layouts/kanban/kanban-group.tsx index 7e1a2f0287..3134b110c0 100644 --- a/web/core/components/issues/issue-layouts/kanban/kanban-group.tsx +++ b/web/core/components/issues/issue-layouts/kanban/kanban-group.tsx @@ -82,7 +82,7 @@ export const KanbanGroup = observer((props: IKanbanGroup) => { quickAddCallback, scrollableContainerRef, handleOnDrop, - isEpic =false + isEpic = false, } = props; // hooks const projectState = useProjectState(); @@ -285,6 +285,7 @@ export const KanbanGroup = observer((props: IKanbanGroup) => { dropErrorMessage={dropErrorMessage} orderBy={orderBy} isDraggingOverColumn={isDraggingOverColumn} + isEpic={isEpic} /> { ...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)), }} quickAddCallback={quickAddCallback} + isEpic={isEpic} /> )} diff --git a/web/core/components/issues/issue-layouts/list/default.tsx b/web/core/components/issues/issue-layouts/list/default.tsx index b09802c24e..be7e783655 100644 --- a/web/core/components/issues/issue-layouts/list/default.tsx +++ b/web/core/components/issues/issue-layouts/list/default.tsx @@ -84,6 +84,7 @@ export const List: React.FC = observer((props) => { groupBy: group_by as GroupByColumnTypes, includeNone: true, isWorkspaceLevel: isWorkspaceLevel(storeType), + isEpic: isEpic, }); // Enable Auto Scroll for Main Kanban diff --git a/web/core/components/issues/issue-layouts/quick-add/form/calendar.tsx b/web/core/components/issues/issue-layouts/quick-add/form/calendar.tsx index 66e7990569..8b8d108d5e 100644 --- a/web/core/components/issues/issue-layouts/quick-add/form/calendar.tsx +++ b/web/core/components/issues/issue-layouts/quick-add/form/calendar.tsx @@ -3,12 +3,13 @@ import { observer } from "mobx-react"; import { TQuickAddIssueForm } from "../root"; export const CalendarQuickAddIssueForm: FC = observer((props) => { - const { ref, isOpen, projectDetail, register, onSubmit } = props; + const { ref, isOpen, projectDetail, register, onSubmit, isEpic } = props; return (
= observer((props diff --git a/web/core/components/issues/issue-layouts/quick-add/form/gantt.tsx b/web/core/components/issues/issue-layouts/quick-add/form/gantt.tsx index d0afadb098..e9b7bb38d0 100644 --- a/web/core/components/issues/issue-layouts/quick-add/form/gantt.tsx +++ b/web/core/components/issues/issue-layouts/quick-add/form/gantt.tsx @@ -4,7 +4,7 @@ import { cn } from "@/helpers/common.helper"; import { TQuickAddIssueForm } from "../root"; export const GanttQuickAddIssueForm: FC = observer((props) => { - const { ref, projectDetail, hasError, register, onSubmit } = props; + const { ref, projectDetail, hasError, register, onSubmit, isEpic } = props; return (
@@ -18,15 +18,15 @@ export const GanttQuickAddIssueForm: FC = observer((props) =
-
{`Press 'Enter' to add another issue`}
+
{`Press 'Enter' to add another ${isEpic ? "epic" : "issue"}`}
); }); diff --git a/web/core/components/issues/issue-layouts/quick-add/form/kanban.tsx b/web/core/components/issues/issue-layouts/quick-add/form/kanban.tsx index 8111f539e4..1f25be6e94 100644 --- a/web/core/components/issues/issue-layouts/quick-add/form/kanban.tsx +++ b/web/core/components/issues/issue-layouts/quick-add/form/kanban.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { TQuickAddIssueForm } from "../root"; export const KanbanQuickAddIssueForm: FC = observer((props) => { - const { ref, projectDetail, register, onSubmit } = props; + const { ref, projectDetail, register, onSubmit, isEpic } = props; return (
@@ -12,7 +12,7 @@ export const KanbanQuickAddIssueForm: FC = observer((props)

{projectDetail?.identifier ?? "..."}

= observer((props) />
-
{`Press 'Enter' to add another issue`}
+
{`Press 'Enter' to add another ${isEpic ? "epic" : "issue"}`}
); }); diff --git a/web/core/components/issues/issue-layouts/quick-add/form/list.tsx b/web/core/components/issues/issue-layouts/quick-add/form/list.tsx index 0a894511ff..75e2c8d3a9 100644 --- a/web/core/components/issues/issue-layouts/quick-add/form/list.tsx +++ b/web/core/components/issues/issue-layouts/quick-add/form/list.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { TQuickAddIssueForm } from "../root"; export const ListQuickAddIssueForm: FC = observer((props) => { - const { ref, projectDetail, register, onSubmit } = props; + const { ref, projectDetail, register, onSubmit, isEpic } = props; return (
@@ -17,15 +17,15 @@ export const ListQuickAddIssueForm: FC = observer((props) =>
-
{`Press 'Enter' to add another issue`}
+
{`Press 'Enter' to add another ${isEpic ? "epic" : "issue"}`}
); }); diff --git a/web/core/components/issues/issue-layouts/quick-add/form/spreadsheet.tsx b/web/core/components/issues/issue-layouts/quick-add/form/spreadsheet.tsx index b4317f3593..4918157c74 100644 --- a/web/core/components/issues/issue-layouts/quick-add/form/spreadsheet.tsx +++ b/web/core/components/issues/issue-layouts/quick-add/form/spreadsheet.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { TQuickAddIssueForm } from "../root"; export const SpreadsheetQuickAddIssueForm: FC = observer((props) => { - const { ref, projectDetail, register, onSubmit } = props; + const { ref, projectDetail, register, onSubmit, isEpic } = props; return (
@@ -16,15 +16,15 @@ export const SpreadsheetQuickAddIssueForm: FC = observer((pr

- Press {"'"}Enter{"'"} to add another issue + {`Press Enter to add another ${isEpic ? "epic" : "issue"}`}

); diff --git a/web/core/components/issues/issue-layouts/quick-add/root.tsx b/web/core/components/issues/issue-layouts/quick-add/root.tsx index 61575fb23b..73be7ef1fc 100644 --- a/web/core/components/issues/issue-layouts/quick-add/root.tsx +++ b/web/core/components/issues/issue-layouts/quick-add/root.tsx @@ -6,7 +6,7 @@ import { useParams, usePathname } from "next/navigation"; import { useForm, UseFormRegister } from "react-hook-form"; import { PlusIcon } from "lucide-react"; // plane constants -import { EIssueLayoutTypes } from "@plane/constants"; +import { EIssueLayoutTypes, EIssueServiceType } from "@plane/constants"; // types import { IProject, TIssue } from "@plane/types"; // ui @@ -30,9 +30,11 @@ export type TQuickAddIssueForm = { hasError: boolean; register: UseFormRegister; onSubmit: () => void; + isEpic: boolean; }; export type TQuickAddIssueButton = { + isEpic?: boolean; onClick: () => void; }; @@ -45,6 +47,7 @@ type TQuickAddIssueRoot = { containerClassName?: string; setIsQuickAddOpen?: (isOpen: boolean) => void; quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise; + isEpic?: boolean; }; const defaultValues: Partial = { @@ -61,6 +64,7 @@ export const QuickAddIssueRoot: FC = observer((props) => { containerClassName = "", setIsQuickAddOpen, quickAddCallback, + isEpic = false, } = props; // router const { workspaceSlug, projectId } = useParams(); @@ -109,15 +113,16 @@ export const QuickAddIssueRoot: FC = observer((props) => { if (quickAddCallback) { const quickAddPromise = quickAddCallback(projectId.toString(), { ...payload }); setPromiseToast(quickAddPromise, { - loading: "Adding issue...", + loading: `Adding ${isEpic ? "epic" : "issue"}...`, success: { title: "Success!", - message: () => "Issue created successfully.", + message: () => `${isEpic ? "Epic" : "Issue"} created successfully.`, actionItems: (data) => ( ), }, @@ -165,10 +170,11 @@ export const QuickAddIssueRoot: FC = observer((props) => { register={register} onSubmit={handleSubmit(onSubmitHandler)} onClose={() => handleIsOpen(false)} + isEpic={isEpic} /> ) : ( <> - {QuickAddButton && handleIsOpen(true)} />} + {QuickAddButton && handleIsOpen(true)} />} {customQuickAddButton && <>{customQuickAddButton}} {!QuickAddButton && !customQuickAddButton && (
= observer((props) => { onClick={() => handleIsOpen(true)} > - New Issue + {`New ${isEpic ? "Epic" : "Issue"}`}
)} diff --git a/web/core/components/issues/issue-layouts/utils.tsx b/web/core/components/issues/issue-layouts/utils.tsx index 3e7d72b1bd..77d8ae1922 100644 --- a/web/core/components/issues/issue-layouts/utils.tsx +++ b/web/core/components/issues/issue-layouts/utils.tsx @@ -68,6 +68,7 @@ type TGetGroupByColumns = { groupBy: GroupByColumnTypes | null; includeNone: boolean; isWorkspaceLevel: boolean; + isEpic?: boolean; }; // NOTE: Type of groupBy is different compared to what's being passed from the components. @@ -77,13 +78,14 @@ export const getGroupByColumns = ({ groupBy, includeNone, isWorkspaceLevel, + isEpic = false, }: TGetGroupByColumns): IGroupByColumn[] | undefined => { // If no groupBy is specified and includeNone is true, return "All Issues" group if (!groupBy && includeNone) { return [ { id: "All Issues", - name: "All Issues", + name: isEpic ? "All Epics" : "All Issues", payload: {}, icon: undefined, }, diff --git a/web/core/hooks/store/use-issue-detail.ts b/web/core/hooks/store/use-issue-detail.ts index 786173fd3f..309bfedbaa 100644 --- a/web/core/hooks/store/use-issue-detail.ts +++ b/web/core/hooks/store/use-issue-detail.ts @@ -9,6 +9,6 @@ import { IIssueDetail } from "@/store/issue/issue-details/root.store"; export const useIssueDetail = (serviceType: TIssueServiceType = EIssueServiceType.ISSUES): IIssueDetail => { const context = useContext(StoreContext); if (context === undefined) throw new Error("useIssueDetail must be used within StoreProvider"); - if (serviceType === EIssueServiceType.EPICS) return context.epic.issueDetail; + if (serviceType === EIssueServiceType.EPICS) return context.issue.epicDetail; else return context.issue.issueDetail; }; diff --git a/web/core/store/issue/issue.store.ts b/web/core/store/issue/issue.store.ts index a6ff334b9a..e5ba1b1079 100644 --- a/web/core/store/issue/issue.store.ts +++ b/web/core/store/issue/issue.store.ts @@ -3,7 +3,7 @@ import update from "lodash/update"; import { action, makeObservable, observable, runInAction } from "mobx"; import { computedFn } from "mobx-utils"; // types -import { TIssue, TIssueServiceType } from "@plane/types"; +import { TIssue } from "@plane/types"; // helpers import { getCurrentDateTimeInISO } from "@/helpers/date-time.helper"; // services @@ -30,7 +30,7 @@ export class IssueStore implements IIssueStore { // service issueService; - constructor(serviceType: TIssueServiceType) { + constructor() { makeObservable(this, { // observable issuesMap: observable, @@ -39,8 +39,7 @@ export class IssueStore implements IIssueStore { updateIssue: action, removeIssue: action, }); - - this.issueService = new IssueService(serviceType); + this.issueService = new IssueService(); } // actions @@ -85,7 +84,10 @@ export class IssueStore implements IIssueStore { set(this.issuesMap, [issueId, key], issue[key as keyof TIssue]); }); }); - updatePersistentLayer(issueId); + + if (!this.issuesMap[issueId]?.is_epic) { + updatePersistentLayer(issueId); + } }; /** diff --git a/web/core/store/issue/root.store.ts b/web/core/store/issue/root.store.ts index 002ede3ba4..7df2f24a08 100644 --- a/web/core/store/issue/root.store.ts +++ b/web/core/store/issue/root.store.ts @@ -67,6 +67,7 @@ export interface IIssueRootStore { issues: IIssueStore; issueDetail: IIssueDetail; + epicDetail: IIssueDetail; workspaceIssuesFilter: IWorkspaceIssuesFilter; workspaceIssues: IWorkspaceIssues; @@ -134,6 +135,7 @@ export class IssueRootStore implements IIssueRootStore { issues: IIssueStore; issueDetail: IIssueDetail; + epicDetail: IIssueDetail; workspaceIssuesFilter: IWorkspaceIssuesFilter; workspaceIssues: IWorkspaceIssues; @@ -221,9 +223,10 @@ export class IssueRootStore implements IIssueRootStore { if (!isEmpty(rootStore?.cycle?.cycleMap)) this.cycleMap = rootStore?.cycle?.cycleMap; }); - this.issues = new IssueStore(this.serviceType); + this.issues = new IssueStore(); - this.issueDetail = new IssueDetail(this, this.serviceType); + this.issueDetail = new IssueDetail(this, EIssueServiceType.ISSUES); + this.epicDetail = new IssueDetail(this, EIssueServiceType.EPICS); this.workspaceIssuesFilter = new WorkspaceIssuesFilter(this); this.workspaceIssues = new WorkspaceIssues(this, this.workspaceIssuesFilter); diff --git a/web/core/store/root.store.ts b/web/core/store/root.store.ts index ebd118da87..6dc0b89f0c 100644 --- a/web/core/store/root.store.ts +++ b/web/core/store/root.store.ts @@ -43,7 +43,6 @@ export class CoreRootStore { projectView: IProjectViewStore; globalView: IGlobalViewStore; issue: IIssueRootStore; - epic: IIssueRootStore; state: IStateStore; label: ILabelStore; dashboard: IDashboardStore; @@ -77,7 +76,6 @@ export class CoreRootStore { this.projectView = new ProjectViewStore(this); this.globalView = new GlobalViewStore(this); this.issue = new IssueRootStore(this as unknown as RootStore); - this.epic = new IssueRootStore(this as unknown as RootStore, EIssueServiceType.EPICS); this.state = new StateStore(this as unknown as RootStore); this.label = new LabelStore(this); this.dashboard = new DashboardStore(this); @@ -109,7 +107,6 @@ export class CoreRootStore { this.projectView = new ProjectViewStore(this); this.globalView = new GlobalViewStore(this); this.issue = new IssueRootStore(this as unknown as RootStore); - this.epic = new IssueRootStore(this as unknown as RootStore, EIssueServiceType.EPICS); this.state = new StateStore(this as unknown as RootStore); this.label = new LabelStore(this); this.dashboard = new DashboardStore(this);