[WEB-2907] chore: issue store updated and code refactor (#6279)

* chore: issue and epic store updated and code refactor

* chore: layout ux copy updated
This commit is contained in:
Anmol Singh Bhatia 2024-12-26 20:01:32 +05:30 committed by GitHub
parent 36b3328c5e
commit 756a71ca78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 71 additions and 50 deletions

View file

@ -30,10 +30,11 @@ export type TQuickAddIssueFormRoot = {
register: UseFormRegister<TIssue>; register: UseFormRegister<TIssue>;
onSubmit: () => void; onSubmit: () => void;
onClose: () => void; onClose: () => void;
isEpic: boolean;
}; };
export const QuickAddIssueFormRoot: FC<TQuickAddIssueFormRoot> = observer((props) => { export const QuickAddIssueFormRoot: FC<TQuickAddIssueFormRoot> = 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 // store hooks
const { getProjectById } = useProject(); const { getProjectById } = useProject();
// derived values // derived values
@ -70,6 +71,7 @@ export const QuickAddIssueFormRoot: FC<TQuickAddIssueFormRoot> = observer((props
hasError={hasError} hasError={hasError}
register={register} register={register}
onSubmit={onSubmit} onSubmit={onSubmit}
isEpic={isEpic}
/> />
); );
}); });

View file

@ -93,10 +93,11 @@ export class IssueActivityStore implements IIssueActivityStore {
let activityComments: TIssueActivityComment[] = []; 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 activities = this.getActivitiesByIssueId(issueId) || [];
const comments = currentStore.issueDetail.comment.getCommentsByIssueId(issueId) || []; const comments = currentStore.comment.getCommentsByIssueId(issueId) || [];
activities.forEach((activityId) => { activities.forEach((activityId) => {
const activity = this.getActivityById(activityId); const activity = this.getActivityById(activityId);
@ -109,7 +110,7 @@ export class IssueActivityStore implements IIssueActivityStore {
}); });
comments.forEach((commentId) => { comments.forEach((commentId) => {
const comment = currentStore.issueDetail.comment.getCommentById(commentId); const comment = currentStore.comment.getCommentById(commentId);
if (!comment) return; if (!comment) return;
activityComments.push({ activityComments.push({
id: comment.id, id: comment.id,

View file

@ -10,10 +10,11 @@ type TCreateIssueToastActionItems = {
workspaceSlug: string; workspaceSlug: string;
projectId: string; projectId: string;
issueId: string; issueId: string;
isEpic?: boolean;
}; };
export const CreateIssueToastActionItems: FC<TCreateIssueToastActionItems> = observer((props) => { export const CreateIssueToastActionItems: FC<TCreateIssueToastActionItems> = observer((props) => {
const { workspaceSlug, projectId, issueId } = props; const { workspaceSlug, projectId, issueId, isEpic = false } = props;
// state // state
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
// store hooks // store hooks
@ -26,7 +27,7 @@ export const CreateIssueToastActionItems: FC<TCreateIssueToastActionItems> = obs
if (!issue) return null; 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<HTMLButtonElement, MouseEvent>) => { const copyToClipboard = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
try { try {
@ -43,12 +44,12 @@ export const CreateIssueToastActionItems: FC<TCreateIssueToastActionItems> = obs
return ( return (
<div className="flex items-center gap-1 text-xs text-custom-text-200"> <div className="flex items-center gap-1 text-xs text-custom-text-200">
<a <a
href={`/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`} href={`/${workspaceSlug}/projects/${projectId}/${isEpic ? "epics" : "issues"}/${issueId}/`}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-custom-primary px-2 py-1 hover:bg-custom-background-90 font-medium rounded" className="text-custom-primary px-2 py-1 hover:bg-custom-background-90 font-medium rounded"
> >
View issue {`View ${isEpic ? "epic" : "issue"}`}
</a> </a>
{copied ? ( {copied ? (

View file

@ -24,10 +24,11 @@ type TCalendarQuickAddIssueActions = {
quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>; quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>;
addIssuesToView?: (issueIds: string[]) => Promise<any>; addIssuesToView?: (issueIds: string[]) => Promise<any>;
onOpen?: () => void; onOpen?: () => void;
isEpic?: boolean;
}; };
export const CalendarQuickAddIssueActions: FC<TCalendarQuickAddIssueActions> = observer((props) => { export const CalendarQuickAddIssueActions: FC<TCalendarQuickAddIssueActions> = observer((props) => {
const { prePopulatedData, quickAddCallback, addIssuesToView, onOpen } = props; const { prePopulatedData, quickAddCallback, addIssuesToView, onOpen, isEpic = false } = props;
// router // router
const { workspaceSlug, projectId, moduleId } = useParams(); const { workspaceSlug, projectId, moduleId } = useParams();
// states // states
@ -118,15 +119,16 @@ export const CalendarQuickAddIssueActions: FC<TCalendarQuickAddIssueActions> = o
customButton={ customButton={
<div className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-custom-text-350 hover:text-custom-text-300"> <div className="flex w-full items-center gap-x-[6px] rounded-md px-2 py-1.5 text-custom-text-350 hover:text-custom-text-300">
<PlusIcon className="h-3.5 w-3.5 stroke-2 flex-shrink-0" /> <PlusIcon className="h-3.5 w-3.5 stroke-2 flex-shrink-0" />
<span className="text-sm font-medium flex-shrink-0">New issue</span> <span className="text-sm font-medium flex-shrink-0">{`New ${isEpic ? "Epic" : "Issue"}`}</span>
</div> </div>
} }
> >
<CustomMenu.MenuItem onClick={handleNewIssue}>New issue</CustomMenu.MenuItem> <CustomMenu.MenuItem onClick={handleNewIssue}>{`New ${isEpic ? "Epic" : "Issue"}`}</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={handleExistingIssue}>Add existing issue</CustomMenu.MenuItem> {!isEpic && <CustomMenu.MenuItem onClick={handleExistingIssue}>Add existing issue</CustomMenu.MenuItem>}
</CustomMenu> </CustomMenu>
</div> </div>
} }
isEpic={isEpic}
/> />
</> </>
); );

View file

@ -98,6 +98,7 @@ export const KanBan: React.FC<IKanBan> = observer((props) => {
groupBy: group_by as GroupByColumnTypes, groupBy: group_by as GroupByColumnTypes,
includeNone: true, includeNone: true,
isWorkspaceLevel: isWorkspaceLevel(storeType), isWorkspaceLevel: isWorkspaceLevel(storeType),
isEpic: isEpic,
}); });
if (!list) return null; if (!list) return null;

View file

@ -82,7 +82,7 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
quickAddCallback, quickAddCallback,
scrollableContainerRef, scrollableContainerRef,
handleOnDrop, handleOnDrop,
isEpic =false isEpic = false,
} = props; } = props;
// hooks // hooks
const projectState = useProjectState(); const projectState = useProjectState();
@ -285,6 +285,7 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
dropErrorMessage={dropErrorMessage} dropErrorMessage={dropErrorMessage}
orderBy={orderBy} orderBy={orderBy}
isDraggingOverColumn={isDraggingOverColumn} isDraggingOverColumn={isDraggingOverColumn}
isEpic={isEpic}
/> />
<KanbanIssueBlocksList <KanbanIssueBlocksList
sub_group_id={sub_group_id} sub_group_id={sub_group_id}
@ -312,6 +313,7 @@ export const KanbanGroup = observer((props: IKanbanGroup) => {
...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)), ...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)),
}} }}
quickAddCallback={quickAddCallback} quickAddCallback={quickAddCallback}
isEpic={isEpic}
/> />
</div> </div>
)} )}

View file

@ -84,6 +84,7 @@ export const List: React.FC<IList> = observer((props) => {
groupBy: group_by as GroupByColumnTypes, groupBy: group_by as GroupByColumnTypes,
includeNone: true, includeNone: true,
isWorkspaceLevel: isWorkspaceLevel(storeType), isWorkspaceLevel: isWorkspaceLevel(storeType),
isEpic: isEpic,
}); });
// Enable Auto Scroll for Main Kanban // Enable Auto Scroll for Main Kanban

View file

@ -3,12 +3,13 @@ import { observer } from "mobx-react";
import { TQuickAddIssueForm } from "../root"; import { TQuickAddIssueForm } from "../root";
export const CalendarQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => { export const CalendarQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => {
const { ref, isOpen, projectDetail, register, onSubmit } = props; const { ref, isOpen, projectDetail, register, onSubmit, isEpic } = props;
return ( return (
<div <div
className={`z-20 w-full transition-all ${isOpen ? "scale-100 opacity-100" : "pointer-events-none scale-95 opacity-0" className={`z-20 w-full transition-all ${
}`} isOpen ? "scale-100 opacity-100" : "pointer-events-none scale-95 opacity-0"
}`}
> >
<form <form
ref={ref} ref={ref}
@ -19,9 +20,9 @@ export const CalendarQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props
<input <input
type="text" type="text"
autoComplete="off" autoComplete="off"
placeholder="Issue Title" placeholder={isEpic ? "Epic Title" : "Issue Title"}
{...register("name", { {...register("name", {
required: "Issue title is required.", required: `${isEpic ? "Epic" : "Issue"} title is required.`,
})} })}
className="w-full rounded-md bg-transparent py-1.5 pr-2 text-sm md:text-xs font-medium leading-5 text-custom-text-200 outline-none" className="w-full rounded-md bg-transparent py-1.5 pr-2 text-sm md:text-xs font-medium leading-5 text-custom-text-200 outline-none"
/> />

View file

@ -4,7 +4,7 @@ import { cn } from "@/helpers/common.helper";
import { TQuickAddIssueForm } from "../root"; import { TQuickAddIssueForm } from "../root";
export const GanttQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => { export const GanttQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => {
const { ref, projectDetail, hasError, register, onSubmit } = props; const { ref, projectDetail, hasError, register, onSubmit, isEpic } = props;
return ( return (
<div className={cn("shadow-custom-shadow-sm", hasError && "border border-red-500/20 bg-red-500/10")}> <div className={cn("shadow-custom-shadow-sm", hasError && "border border-red-500/20 bg-red-500/10")}>
@ -18,15 +18,15 @@ export const GanttQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) =
<input <input
type="text" type="text"
autoComplete="off" autoComplete="off"
placeholder="Issue Title" placeholder={isEpic ? "Epic Title" : "Issue Title"}
{...register("name", { {...register("name", {
required: "Issue title is required.", required: `${isEpic ? "Epic" : "Issue"} title is required.`,
})} })}
className="w-full rounded-md bg-transparent px-2 py-3 text-sm font-medium leading-5 text-custom-text-200 outline-none" className="w-full rounded-md bg-transparent px-2 py-3 text-sm font-medium leading-5 text-custom-text-200 outline-none"
/> />
</div> </div>
</form> </form>
<div className="px-3 py-2 text-xs bg-custom-background-100 italic text-custom-text-200">{`Press 'Enter' to add another issue`}</div> <div className="px-3 py-2 text-xs bg-custom-background-100 italic text-custom-text-200">{`Press 'Enter' to add another ${isEpic ? "epic" : "issue"}`}</div>
</div> </div>
); );
}); });

View file

@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { TQuickAddIssueForm } from "../root"; import { TQuickAddIssueForm } from "../root";
export const KanbanQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => { export const KanbanQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => {
const { ref, projectDetail, register, onSubmit } = props; const { ref, projectDetail, register, onSubmit, isEpic } = props;
return ( return (
<div className="m-1 overflow-hidden rounded shadow-custom-shadow-sm"> <div className="m-1 overflow-hidden rounded shadow-custom-shadow-sm">
@ -12,7 +12,7 @@ export const KanbanQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props)
<h4 className="text-xs font-medium leading-5 text-custom-text-300">{projectDetail?.identifier ?? "..."}</h4> <h4 className="text-xs font-medium leading-5 text-custom-text-300">{projectDetail?.identifier ?? "..."}</h4>
<input <input
autoComplete="off" autoComplete="off"
placeholder="Issue Title" placeholder={isEpic ? "Epic Title" : "Issue Title"}
{...register("name", { {...register("name", {
required: "Issue title is required.", required: "Issue title is required.",
})} })}
@ -20,7 +20,7 @@ export const KanbanQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props)
/> />
</div> </div>
</form> </form>
<div className="px-3 py-2 text-xs italic text-custom-text-200">{`Press 'Enter' to add another issue`}</div> <div className="px-3 py-2 text-xs italic text-custom-text-200">{`Press 'Enter' to add another ${isEpic ? "epic" : "issue"}`}</div>
</div> </div>
); );
}); });

View file

@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { TQuickAddIssueForm } from "../root"; import { TQuickAddIssueForm } from "../root";
export const ListQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => { export const ListQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => {
const { ref, projectDetail, register, onSubmit } = props; const { ref, projectDetail, register, onSubmit, isEpic } = props;
return ( return (
<div className="shadow-custom-shadow-sm"> <div className="shadow-custom-shadow-sm">
@ -17,15 +17,15 @@ export const ListQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) =>
<input <input
type="text" type="text"
autoComplete="off" autoComplete="off"
placeholder="Issue Title" placeholder={isEpic ? "Epic Title" : "Issue Title"}
{...register("name", { {...register("name", {
required: "Issue title is required.", required: `${isEpic ? "Epic" : "Issue"} title is required.`,
})} })}
className="w-full rounded-md bg-transparent px-2 py-3 text-sm font-medium leading-5 text-custom-text-200 outline-none" className="w-full rounded-md bg-transparent px-2 py-3 text-sm font-medium leading-5 text-custom-text-200 outline-none"
/> />
</div> </div>
</form> </form>
<div className="px-3 py-2 text-xs italic text-custom-text-200">{`Press 'Enter' to add another issue`}</div> <div className="px-3 py-2 text-xs italic text-custom-text-200">{`Press 'Enter' to add another ${isEpic ? "epic" : "issue"}`}</div>
</div> </div>
); );
}); });

View file

@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { TQuickAddIssueForm } from "../root"; import { TQuickAddIssueForm } from "../root";
export const SpreadsheetQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => { export const SpreadsheetQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((props) => {
const { ref, projectDetail, register, onSubmit } = props; const { ref, projectDetail, register, onSubmit, isEpic } = props;
return ( return (
<div className="pb-2"> <div className="pb-2">
@ -16,15 +16,15 @@ export const SpreadsheetQuickAddIssueForm: FC<TQuickAddIssueForm> = observer((pr
<input <input
type="text" type="text"
autoComplete="off" autoComplete="off"
placeholder="Issue Title" placeholder={isEpic ? "Epic Title" : "Issue Title"}
{...register("name", { {...register("name", {
required: "Issue title is required.", required: `${isEpic ? "Epic" : "Issue"} title is required.`,
})} })}
className="w-full rounded-md bg-transparent py-3 text-sm leading-5 text-custom-text-200 outline-none" className="w-full rounded-md bg-transparent py-3 text-sm leading-5 text-custom-text-200 outline-none"
/> />
</form> </form>
<p className="ml-3 mt-3 text-xs italic text-custom-text-200"> <p className="ml-3 mt-3 text-xs italic text-custom-text-200">
Press {"'"}Enter{"'"} to add another issue {`Press Enter to add another ${isEpic ? "epic" : "issue"}`}
</p> </p>
</div> </div>
); );

View file

@ -6,7 +6,7 @@ import { useParams, usePathname } from "next/navigation";
import { useForm, UseFormRegister } from "react-hook-form"; import { useForm, UseFormRegister } from "react-hook-form";
import { PlusIcon } from "lucide-react"; import { PlusIcon } from "lucide-react";
// plane constants // plane constants
import { EIssueLayoutTypes } from "@plane/constants"; import { EIssueLayoutTypes, EIssueServiceType } from "@plane/constants";
// types // types
import { IProject, TIssue } from "@plane/types"; import { IProject, TIssue } from "@plane/types";
// ui // ui
@ -30,9 +30,11 @@ export type TQuickAddIssueForm = {
hasError: boolean; hasError: boolean;
register: UseFormRegister<TIssue>; register: UseFormRegister<TIssue>;
onSubmit: () => void; onSubmit: () => void;
isEpic: boolean;
}; };
export type TQuickAddIssueButton = { export type TQuickAddIssueButton = {
isEpic?: boolean;
onClick: () => void; onClick: () => void;
}; };
@ -45,6 +47,7 @@ type TQuickAddIssueRoot = {
containerClassName?: string; containerClassName?: string;
setIsQuickAddOpen?: (isOpen: boolean) => void; setIsQuickAddOpen?: (isOpen: boolean) => void;
quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>; quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>;
isEpic?: boolean;
}; };
const defaultValues: Partial<TIssue> = { const defaultValues: Partial<TIssue> = {
@ -61,6 +64,7 @@ export const QuickAddIssueRoot: FC<TQuickAddIssueRoot> = observer((props) => {
containerClassName = "", containerClassName = "",
setIsQuickAddOpen, setIsQuickAddOpen,
quickAddCallback, quickAddCallback,
isEpic = false,
} = props; } = props;
// router // router
const { workspaceSlug, projectId } = useParams(); const { workspaceSlug, projectId } = useParams();
@ -109,15 +113,16 @@ export const QuickAddIssueRoot: FC<TQuickAddIssueRoot> = observer((props) => {
if (quickAddCallback) { if (quickAddCallback) {
const quickAddPromise = quickAddCallback(projectId.toString(), { ...payload }); const quickAddPromise = quickAddCallback(projectId.toString(), { ...payload });
setPromiseToast<any>(quickAddPromise, { setPromiseToast<any>(quickAddPromise, {
loading: "Adding issue...", loading: `Adding ${isEpic ? "epic" : "issue"}...`,
success: { success: {
title: "Success!", title: "Success!",
message: () => "Issue created successfully.", message: () => `${isEpic ? "Epic" : "Issue"} created successfully.`,
actionItems: (data) => ( actionItems: (data) => (
<CreateIssueToastActionItems <CreateIssueToastActionItems
workspaceSlug={workspaceSlug.toString()} workspaceSlug={workspaceSlug.toString()}
projectId={projectId.toString()} projectId={projectId.toString()}
issueId={data.id} issueId={data.id}
isEpic={isEpic}
/> />
), ),
}, },
@ -165,10 +170,11 @@ export const QuickAddIssueRoot: FC<TQuickAddIssueRoot> = observer((props) => {
register={register} register={register}
onSubmit={handleSubmit(onSubmitHandler)} onSubmit={handleSubmit(onSubmitHandler)}
onClose={() => handleIsOpen(false)} onClose={() => handleIsOpen(false)}
isEpic={isEpic}
/> />
) : ( ) : (
<> <>
{QuickAddButton && <QuickAddButton onClick={() => handleIsOpen(true)} />} {QuickAddButton && <QuickAddButton isEpic={isEpic} onClick={() => handleIsOpen(true)} />}
{customQuickAddButton && <>{customQuickAddButton}</>} {customQuickAddButton && <>{customQuickAddButton}</>}
{!QuickAddButton && !customQuickAddButton && ( {!QuickAddButton && !customQuickAddButton && (
<div <div
@ -176,7 +182,7 @@ export const QuickAddIssueRoot: FC<TQuickAddIssueRoot> = observer((props) => {
onClick={() => handleIsOpen(true)} onClick={() => handleIsOpen(true)}
> >
<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">New Issue</span> <span className="text-sm font-medium">{`New ${isEpic ? "Epic" : "Issue"}`}</span>
</div> </div>
)} )}
</> </>

View file

@ -68,6 +68,7 @@ type TGetGroupByColumns = {
groupBy: GroupByColumnTypes | null; groupBy: GroupByColumnTypes | null;
includeNone: boolean; includeNone: boolean;
isWorkspaceLevel: boolean; isWorkspaceLevel: boolean;
isEpic?: boolean;
}; };
// NOTE: Type of groupBy is different compared to what's being passed from the components. // NOTE: Type of groupBy is different compared to what's being passed from the components.
@ -77,13 +78,14 @@ export const getGroupByColumns = ({
groupBy, groupBy,
includeNone, includeNone,
isWorkspaceLevel, isWorkspaceLevel,
isEpic = false,
}: TGetGroupByColumns): IGroupByColumn[] | undefined => { }: TGetGroupByColumns): IGroupByColumn[] | undefined => {
// If no groupBy is specified and includeNone is true, return "All Issues" group // If no groupBy is specified and includeNone is true, return "All Issues" group
if (!groupBy && includeNone) { if (!groupBy && includeNone) {
return [ return [
{ {
id: "All Issues", id: "All Issues",
name: "All Issues", name: isEpic ? "All Epics" : "All Issues",
payload: {}, payload: {},
icon: undefined, icon: undefined,
}, },

View file

@ -9,6 +9,6 @@ import { IIssueDetail } from "@/store/issue/issue-details/root.store";
export const useIssueDetail = (serviceType: TIssueServiceType = EIssueServiceType.ISSUES): IIssueDetail => { export const useIssueDetail = (serviceType: TIssueServiceType = EIssueServiceType.ISSUES): IIssueDetail => {
const context = useContext(StoreContext); const context = useContext(StoreContext);
if (context === undefined) throw new Error("useIssueDetail must be used within StoreProvider"); 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; else return context.issue.issueDetail;
}; };

View file

@ -3,7 +3,7 @@ import update from "lodash/update";
import { action, makeObservable, observable, runInAction } from "mobx"; import { action, makeObservable, observable, runInAction } from "mobx";
import { computedFn } from "mobx-utils"; import { computedFn } from "mobx-utils";
// types // types
import { TIssue, TIssueServiceType } from "@plane/types"; import { TIssue } from "@plane/types";
// helpers // helpers
import { getCurrentDateTimeInISO } from "@/helpers/date-time.helper"; import { getCurrentDateTimeInISO } from "@/helpers/date-time.helper";
// services // services
@ -30,7 +30,7 @@ export class IssueStore implements IIssueStore {
// service // service
issueService; issueService;
constructor(serviceType: TIssueServiceType) { constructor() {
makeObservable(this, { makeObservable(this, {
// observable // observable
issuesMap: observable, issuesMap: observable,
@ -39,8 +39,7 @@ export class IssueStore implements IIssueStore {
updateIssue: action, updateIssue: action,
removeIssue: action, removeIssue: action,
}); });
this.issueService = new IssueService();
this.issueService = new IssueService(serviceType);
} }
// actions // actions
@ -85,7 +84,10 @@ export class IssueStore implements IIssueStore {
set(this.issuesMap, [issueId, key], issue[key as keyof TIssue]); set(this.issuesMap, [issueId, key], issue[key as keyof TIssue]);
}); });
}); });
updatePersistentLayer(issueId);
if (!this.issuesMap[issueId]?.is_epic) {
updatePersistentLayer(issueId);
}
}; };
/** /**

View file

@ -67,6 +67,7 @@ export interface IIssueRootStore {
issues: IIssueStore; issues: IIssueStore;
issueDetail: IIssueDetail; issueDetail: IIssueDetail;
epicDetail: IIssueDetail;
workspaceIssuesFilter: IWorkspaceIssuesFilter; workspaceIssuesFilter: IWorkspaceIssuesFilter;
workspaceIssues: IWorkspaceIssues; workspaceIssues: IWorkspaceIssues;
@ -134,6 +135,7 @@ export class IssueRootStore implements IIssueRootStore {
issues: IIssueStore; issues: IIssueStore;
issueDetail: IIssueDetail; issueDetail: IIssueDetail;
epicDetail: IIssueDetail;
workspaceIssuesFilter: IWorkspaceIssuesFilter; workspaceIssuesFilter: IWorkspaceIssuesFilter;
workspaceIssues: IWorkspaceIssues; workspaceIssues: IWorkspaceIssues;
@ -221,9 +223,10 @@ export class IssueRootStore implements IIssueRootStore {
if (!isEmpty(rootStore?.cycle?.cycleMap)) this.cycleMap = rootStore?.cycle?.cycleMap; 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.workspaceIssuesFilter = new WorkspaceIssuesFilter(this);
this.workspaceIssues = new WorkspaceIssues(this, this.workspaceIssuesFilter); this.workspaceIssues = new WorkspaceIssues(this, this.workspaceIssuesFilter);

View file

@ -43,7 +43,6 @@ export class CoreRootStore {
projectView: IProjectViewStore; projectView: IProjectViewStore;
globalView: IGlobalViewStore; globalView: IGlobalViewStore;
issue: IIssueRootStore; issue: IIssueRootStore;
epic: IIssueRootStore;
state: IStateStore; state: IStateStore;
label: ILabelStore; label: ILabelStore;
dashboard: IDashboardStore; dashboard: IDashboardStore;
@ -77,7 +76,6 @@ export class CoreRootStore {
this.projectView = new ProjectViewStore(this); this.projectView = new ProjectViewStore(this);
this.globalView = new GlobalViewStore(this); this.globalView = new GlobalViewStore(this);
this.issue = new IssueRootStore(this as unknown as RootStore); 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.state = new StateStore(this as unknown as RootStore);
this.label = new LabelStore(this); this.label = new LabelStore(this);
this.dashboard = new DashboardStore(this); this.dashboard = new DashboardStore(this);
@ -109,7 +107,6 @@ export class CoreRootStore {
this.projectView = new ProjectViewStore(this); this.projectView = new ProjectViewStore(this);
this.globalView = new GlobalViewStore(this); this.globalView = new GlobalViewStore(this);
this.issue = new IssueRootStore(this as unknown as RootStore); 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.state = new StateStore(this as unknown as RootStore);
this.label = new LabelStore(this); this.label = new LabelStore(this);
this.dashboard = new DashboardStore(this); this.dashboard = new DashboardStore(this);