diff --git a/packages/types/src/issues.d.ts b/packages/types/src/issues.d.ts index eff81f857b..9bbfa36b1f 100644 --- a/packages/types/src/issues.d.ts +++ b/packages/types/src/issues.d.ts @@ -216,7 +216,7 @@ export type GroupByColumnTypes = export interface IGroupByColumn { id: string; name: string; - icon: ReactElement | undefined; + icon?: ReactElement | undefined; payload: Partial; isDropDisabled?: boolean; dropErrorMessage?: string; diff --git a/web/core/components/issues/issue-layouts/kanban/default.tsx b/web/core/components/issues/issue-layouts/kanban/default.tsx index d1144995c8..f1107c8fb7 100644 --- a/web/core/components/issues/issue-layouts/kanban/default.tsx +++ b/web/core/components/issues/issue-layouts/kanban/default.tsx @@ -18,7 +18,7 @@ import { ContentWrapper } from "@plane/ui"; import RenderIfVisible from "@/components/core/render-if-visible-HOC"; import { KanbanColumnLoader } from "@/components/ui"; // hooks -import { useCycle, useKanbanView, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store"; +import { useKanbanView } from "@/hooks/store"; import { useIssueStoreType } from "@/hooks/use-issue-layout-store"; // types // parent components @@ -87,30 +87,16 @@ export const KanBan: React.FC = observer((props) => { dropErrorMessage, subGroupIndex = 0, } = props; - + // store hooks const storeType = useIssueStoreType(); - - const member = useMember(); - const project = useProject(); - const label = useLabel(); - const cycle = useCycle(); - const moduleInfo = useModule(); - const projectState = useProjectState(); const issueKanBanView = useKanbanView(); - + // derived values const isDragDisabled = !issueKanBanView?.getCanUserDragDrop(group_by, sub_group_by); - - const list = getGroupByColumns( - group_by as GroupByColumnTypes, - project, - cycle, - moduleInfo, - label, - projectState, - member, - true, - isWorkspaceLevel(storeType) - ); + const list = getGroupByColumns({ + groupBy: group_by as GroupByColumnTypes, + includeNone: true, + isWorkspaceLevel: isWorkspaceLevel(storeType), + }); if (!list) return null; diff --git a/web/core/components/issues/issue-layouts/kanban/swimlanes.tsx b/web/core/components/issues/issue-layouts/kanban/swimlanes.tsx index ba1dce5c1c..e2d52e7ca5 100644 --- a/web/core/components/issues/issue-layouts/kanban/swimlanes.tsx +++ b/web/core/components/issues/issue-layouts/kanban/swimlanes.tsx @@ -15,7 +15,6 @@ import { // UI import { Row } from "@plane/ui"; // hooks -import { useCycle, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store"; import { useIssueStoreType } from "@/hooks/use-issue-layout-store"; // components import { TRenderQuickActions } from "../list/list-view-types"; @@ -262,38 +261,19 @@ export const KanBanSwimLanes: React.FC = observer((props) => { quickAddCallback, scrollableContainerRef, } = props; - + // store hooks const storeType = useIssueStoreType(); - - const member = useMember(); - const project = useProject(); - const label = useLabel(); - const cycle = useCycle(); - const projectModule = useModule(); - const projectState = useProjectState(); - - const groupByList = getGroupByColumns( - group_by as GroupByColumnTypes, - project, - cycle, - projectModule, - label, - projectState, - member, - true, - isWorkspaceLevel(storeType) - ); - const subGroupByList = getGroupByColumns( - sub_group_by as GroupByColumnTypes, - project, - cycle, - projectModule, - label, - projectState, - member, - true, - isWorkspaceLevel(storeType) - ); + // derived values + const groupByList = getGroupByColumns({ + groupBy: group_by as GroupByColumnTypes, + includeNone: true, + isWorkspaceLevel: isWorkspaceLevel(storeType), + }); + const subGroupByList = getGroupByColumns({ + groupBy: sub_group_by as GroupByColumnTypes, + includeNone: true, + isWorkspaceLevel: isWorkspaceLevel(storeType), + }); if (!groupByList || !subGroupByList) return null; diff --git a/web/core/components/issues/issue-layouts/list/default.tsx b/web/core/components/issues/issue-layouts/list/default.tsx index fca8d68eb2..01a81cc61b 100644 --- a/web/core/components/issues/issue-layouts/list/default.tsx +++ b/web/core/components/issues/issue-layouts/list/default.tsx @@ -18,9 +18,7 @@ import { } from "@plane/types"; // components import { MultipleSelectGroup } from "@/components/core"; - // hooks -import { useCycle, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store"; import { useIssueStoreType } from "@/hooks/use-issue-layout-store"; // plane web components import { IssueBulkOperationsRoot } from "@/plane-web/components/issues"; @@ -75,29 +73,16 @@ export const List: React.FC = observer((props) => { } = props; const storeType = useIssueStoreType(); - // store hooks - const member = useMember(); - const project = useProject(); - const label = useLabel(); - const projectState = useProjectState(); - const cycle = useCycle(); - const projectModule = useModule(); // plane web hooks const isBulkOperationsEnabled = useBulkOperationStatus(); const containerRef = useRef(null); - const groups = getGroupByColumns( - group_by as GroupByColumnTypes, - project, - cycle, - projectModule, - label, - projectState, - member, - true, - isWorkspaceLevel(storeType) - ); + const groups = getGroupByColumns({ + groupBy: group_by as GroupByColumnTypes, + includeNone: true, + isWorkspaceLevel: isWorkspaceLevel(storeType), + }); // Enable Auto Scroll for Main Kanban useEffect(() => { diff --git a/web/core/components/issues/issue-layouts/utils.tsx b/web/core/components/issues/issue-layouts/utils.tsx index 21f40a5bc1..9cb6fa8f5b 100644 --- a/web/core/components/issues/issue-layouts/utils.tsx +++ b/web/core/components/issues/issue-layouts/utils.tsx @@ -36,13 +36,8 @@ import { STATE_GROUPS } from "@/constants/state"; import { renderFormattedDate } from "@/helpers/date-time.helper"; import { getFileURL } from "@/helpers/file.helper"; // store -import { ICycleStore } from "@/store/cycle.store"; +import { store } from "@/lib/store-context"; import { ISSUE_FILTER_DEFAULT_DATA } from "@/store/issue/helpers/base-issues.store"; -import { ILabelStore } from "@/store/label.store"; -import { IMemberRootStore } from "@/store/member"; -import { IModuleStore } from "@/store/module.store"; -import { IProjectStore } from "@/store/project/project.store"; -import { IStateStore } from "@/store/state.store"; export const HIGHLIGHT_CLASS = "highlight"; export const HIGHLIGHT_WITH_LINE = "highlight-with-line"; @@ -65,51 +60,61 @@ export type IssueUpdates = { export const isWorkspaceLevel = (type: EIssuesStoreType) => [EIssuesStoreType.PROFILE, EIssuesStoreType.GLOBAL].includes(type) ? true : false; -export const getGroupByColumns = ( - groupBy: GroupByColumnTypes | null, - project: IProjectStore, - cycle: ICycleStore, - module: IModuleStore, - label: ILabelStore, - projectState: IStateStore, - member: IMemberRootStore, - includeNone?: boolean, - isWorkspaceLevel?: boolean -): IGroupByColumn[] | undefined => { - switch (groupBy) { - case "project": - return getProjectColumns(project); - case "cycle": - return getCycleColumns(project, cycle); - case "module": - return getModuleColumns(project, module); - case "state": - return getStateColumns(projectState); - case "state_detail.group": - return getStateGroupColumns(); - case "priority": - return getPriorityColumns(); - case "labels": - return getLabelsColumns(label, isWorkspaceLevel) as any; - case "assignees": - return getAssigneeColumns(member) as any; - case "created_by": - return getCreatedByColumns(member) as any; - default: - if (includeNone) return [{ id: `All Issues`, name: `All Issues`, payload: {}, icon: undefined }]; - } +type TGetGroupByColumns = { + groupBy: GroupByColumnTypes | null; + includeNone: boolean; + isWorkspaceLevel: boolean; }; -const getProjectColumns = (project: IProjectStore): IGroupByColumn[] | undefined => { - const { workspaceProjectIds: projectIds, projectMap } = project; +// NOTE: Type of groupBy is different compared to what's being passed from the components. +// We are using `as` to typecast it to the expected type. +// It can break the includeNone logic if not handled properly. +export const getGroupByColumns = ({ + groupBy, + includeNone, + isWorkspaceLevel, +}: 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", + payload: {}, + icon: undefined, + }, + ]; + } + // Return undefined if no valid groupBy + if (!groupBy) return undefined; + + // Map of group by options to their corresponding column getter functions + const groupByColumnMap: Record IGroupByColumn[] | undefined> = { + project: getProjectColumns, + cycle: getCycleColumns, + module: getModuleColumns, + state: getStateColumns, + "state_detail.group": getStateGroupColumns, + priority: getPriorityColumns, + labels: () => getLabelsColumns(isWorkspaceLevel), + assignees: getAssigneeColumns, + created_by: getCreatedByColumns, + }; + + // Get and return the columns for the specified group by option + return groupByColumnMap[groupBy]?.(); +}; + +const getProjectColumns = (): IGroupByColumn[] | undefined => { + const { joinedProjectIds: projectIds, projectMap } = store.projectRoot.project; + // Return undefined if no project ids if (!projectIds) return; - + // Map project ids to project columns return projectIds - .filter((projectId) => !!projectMap[projectId]) - .map((projectId) => { + .map((projectId: string) => { const project = projectMap[projectId]; - + if (!project) return; return { id: project.id, name: project.name, @@ -120,78 +125,71 @@ const getProjectColumns = (project: IProjectStore): IGroupByColumn[] | undefined ), payload: { project_id: project.id }, }; - }) as any; + }) + .filter((column) => column !== undefined) as IGroupByColumn[]; }; -const getCycleColumns = (projectStore: IProjectStore, cycleStore: ICycleStore): IGroupByColumn[] | undefined => { - const { currentProjectDetails } = projectStore; - const { getProjectCycleIds, getCycleById } = cycleStore; - +const getCycleColumns = (): IGroupByColumn[] | undefined => { + const { currentProjectDetails } = store.projectRoot.project; + // Check for the current project details if (!currentProjectDetails || !currentProjectDetails?.id) return; - - const cycleIds = currentProjectDetails?.id ? getProjectCycleIds(currentProjectDetails?.id) : undefined; - if (!cycleIds) return; - - const cycles = []; - - cycleIds.map((cycleId) => { - const cycle = getCycleById(cycleId); - if (cycle) { - const cycleStatus = cycle.status ? (cycle.status.toLocaleLowerCase() as TCycleGroups) : "draft"; - const isDropDisabled = cycleStatus === "completed"; - cycles.push({ - id: cycle.id, - name: cycle.name, - icon: , - payload: { cycle_id: cycle.id }, - isDropDisabled, - dropErrorMessage: isDropDisabled ? "Issue cannot be moved to completed cycles" : undefined, - }); - } + const { getProjectCycleDetails } = store.cycle; + // Get the cycle details for the current project + const cycleDetails = currentProjectDetails?.id ? getProjectCycleDetails(currentProjectDetails?.id) : undefined; + // Map the cycle details to the group by columns + const cycles: IGroupByColumn[] = []; + cycleDetails?.map((cycle) => { + const cycleStatus = cycle.status ? (cycle.status.toLocaleLowerCase() as TCycleGroups) : "draft"; + const isDropDisabled = cycleStatus === "completed"; + cycles.push({ + id: cycle.id, + name: cycle.name, + icon: , + payload: { cycle_id: cycle.id }, + isDropDisabled, + dropErrorMessage: isDropDisabled ? "Issue cannot be moved to completed cycles" : undefined, + }); }); cycles.push({ id: "None", name: "None", icon: , + payload: {}, }); - - return cycles as any; + return cycles; }; -const getModuleColumns = (projectStore: IProjectStore, moduleStore: IModuleStore): IGroupByColumn[] | undefined => { - const { currentProjectDetails } = projectStore; - const { getProjectModuleIds, getModuleById } = moduleStore; - +const getModuleColumns = (): IGroupByColumn[] | undefined => { + // get current project details + const { currentProjectDetails } = store.projectRoot.project; if (!currentProjectDetails || !currentProjectDetails?.id) return; - - const moduleIds = currentProjectDetails?.id ? getProjectModuleIds(currentProjectDetails?.id) : undefined; - if (!moduleIds) return; - - const modules = []; - - moduleIds.map((moduleId) => { - const moduleInfo = getModuleById(moduleId); - if (moduleInfo) - modules.push({ - id: moduleInfo.id, - name: moduleInfo.name, - icon: , - payload: { module_ids: [moduleInfo.id] }, - }); - }) as any; + // get project module ids and module details + const { getProjectModuleDetails } = store.module; + // get module details + const moduleDetails = currentProjectDetails?.id ? getProjectModuleDetails(currentProjectDetails?.id) : undefined; + // map module details to group by columns + const modules: IGroupByColumn[] = []; + moduleDetails?.map((module) => { + modules.push({ + id: module.id, + name: module.name, + icon: , + payload: { module_ids: [module.id] }, + }); + }); modules.push({ id: "None", name: "None", icon: , + payload: {}, }); - - return modules as any; + return modules; }; -const getStateColumns = (projectState: IStateStore): IGroupByColumn[] | undefined => { - const { projectStates } = projectState; +const getStateColumns = (): IGroupByColumn[] | undefined => { + const { projectStates } = store.state; if (!projectStates) return; - + // map project states to group by columns return projectStates.map((state) => ({ id: state.id, name: state.name, @@ -201,12 +199,12 @@ const getStateColumns = (projectState: IStateStore): IGroupByColumn[] | undefine ), payload: { state_id: state.id }, - })) as any; + })); }; -const getStateGroupColumns = () => { +const getStateGroupColumns = (): IGroupByColumn[] => { const stateGroups = STATE_GROUPS; - + // map state groups to group by columns return Object.values(stateGroups).map((stateGroup) => ({ id: stateGroup.key, name: stateGroup.label, @@ -219,9 +217,9 @@ const getStateGroupColumns = () => { })); }; -const getPriorityColumns = () => { +const getPriorityColumns = (): IGroupByColumn[] => { const priorities = ISSUE_PRIORITIES; - + // map priorities to group by columns return priorities.map((priority) => ({ id: priority.key, name: priority.title, @@ -230,14 +228,14 @@ const getPriorityColumns = () => { })); }; -const getLabelsColumns = (label: ILabelStore, isWorkspaceLevel: boolean = false) => { - const { workspaceLabels, projectLabels } = label; - +const getLabelsColumns = (isWorkspaceLevel: boolean = false): IGroupByColumn[] => { + const { workspaceLabels, projectLabels } = store.label; + // map labels to group by columns const labels = [ ...(isWorkspaceLevel ? workspaceLabels || [] : projectLabels || []), { id: "None", name: "None", color: "#666" }, ]; - + // map labels to group by columns return labels.map((label) => ({ id: label.id, name: label.name, @@ -248,15 +246,14 @@ const getLabelsColumns = (label: ILabelStore, isWorkspaceLevel: boolean = false) })); }; -const getAssigneeColumns = (member: IMemberRootStore) => { +const getAssigneeColumns = (): IGroupByColumn[] | undefined => { const { project: { projectMemberIds }, getUserDetails, - } = member; - + } = store.memberRoot; if (!projectMemberIds) return; - - const assigneeColumns: any = projectMemberIds.map((memberId) => { + // Map project member ids to group by assignee columns + const assigneeColumns: IGroupByColumn[] = projectMemberIds.map((memberId) => { const member = getUserDetails(memberId); return { id: memberId, @@ -265,20 +262,17 @@ const getAssigneeColumns = (member: IMemberRootStore) => { payload: { assignee_ids: [memberId] }, }; }); - assigneeColumns.push({ id: "None", name: "None", icon: , payload: {} }); - return assigneeColumns; }; -const getCreatedByColumns = (member: IMemberRootStore) => { +const getCreatedByColumns = (): IGroupByColumn[] | undefined => { const { project: { projectMemberIds }, getUserDetails, - } = member; - + } = store.memberRoot; if (!projectMemberIds) return; - + // Map project member ids to group by created by columns return projectMemberIds.map((memberId) => { const member = getUserDetails(memberId); return { diff --git a/web/core/store/cycle.store.ts b/web/core/store/cycle.store.ts index ac7d5f95fd..2cdda1118f 100644 --- a/web/core/store/cycle.store.ts +++ b/web/core/store/cycle.store.ts @@ -1,4 +1,4 @@ -import { isFuture, isPast, isToday } from "date-fns"; +import { isPast, isToday } from "date-fns"; import isEmpty from "lodash/isEmpty"; import set from "lodash/set"; import sortBy from "lodash/sortBy"; @@ -7,16 +7,14 @@ import { computedFn } from "mobx-utils"; // types import { ICycle, - CycleDateCheckData, TCyclePlotType, TProgressSnapshot, TCycleEstimateDistribution, TCycleDistribution, TCycleEstimateType, - TCycleProgress, } from "@plane/types"; // helpers -import { orderCycles, shouldFilterCycle, formatActiveCycle } from "@/helpers/cycle.helper"; +import { orderCycles, shouldFilterCycle } from "@/helpers/cycle.helper"; import { getDate } from "@/helpers/date-time.helper"; import { DistributionUpdates, updateDistribution } from "@/helpers/distribution-update.helper"; // services @@ -42,21 +40,18 @@ export interface ICycleStore { // computed currentProjectCycleIds: string[] | null; currentProjectCompletedCycleIds: string[] | null; - currentProjectUpcomingCycleIds: string[] | null; currentProjectIncompleteCycleIds: string[] | null; - currentProjectDraftCycleIds: string[] | null; currentProjectActiveCycleId: string | null; currentProjectArchivedCycleIds: string[] | null; currentProjectActiveCycle: ICycle | null; // computed actions - getActiveCycleProgress: (cycleId?: string) => { cycle: ICycle; isBurnDown: boolean; isTypeIssue: boolean } | null; getFilteredCycleIds: (projectId: string, sortByManual: boolean) => string[] | null; getFilteredCompletedCycleIds: (projectId: string) => string[] | null; getFilteredArchivedCycleIds: (projectId: string) => string[] | null; getCycleById: (cycleId: string) => ICycle | null; getCycleNameById: (cycleId: string) => string | undefined; - getActiveCycleById: (cycleId: string) => ICycle | null; + getProjectCycleDetails: (projectId: string) => ICycle[] | null; getProjectCycleIds: (projectId: string) => string[] | null; getPlotTypeByCycleId: (cycleId: string) => TCyclePlotType; getEstimateTypeByCycleId: (cycleId: string) => TCycleEstimateType; @@ -64,7 +59,6 @@ export interface ICycleStore { // actions updateCycleDistribution: (distributionUpdates: DistributionUpdates, cycleId: string) => void; - validateDate: (workspaceSlug: string, projectId: string, payload: CycleDateCheckData) => Promise; setPlotType: (cycleId: string, plotType: TCyclePlotType) => void; setEstimateType: (cycleId: string, estimateType: TCycleEstimateType) => void; updateWorkspaceUserActiveCycleCount: (workspaceSlug: string, increment: number) => void; @@ -131,15 +125,12 @@ export class CycleStore implements ICycleStore { // computed currentProjectCycleIds: computed, currentProjectCompletedCycleIds: computed, - currentProjectUpcomingCycleIds: computed, currentProjectIncompleteCycleIds: computed, - currentProjectDraftCycleIds: computed, currentProjectActiveCycleId: computed, currentProjectArchivedCycleIds: computed, currentProjectActiveCycle: computed, // actions - setPlotType: action, setEstimateType: action, fetchWorkspaceCycles: action, fetchAllCycles: action, @@ -197,22 +188,6 @@ export class CycleStore implements ICycleStore { return completedCycleIds; } - /** - * returns all upcoming cycle ids for a project - */ - get currentProjectUpcomingCycleIds() { - const projectId = this.rootStore.router.projectId; - if (!projectId || !this.fetchedMap[projectId]) return null; - let upcomingCycles = Object.values(this.cycleMap ?? {}).filter((c) => { - const startDate = getDate(c.start_date); - const isStartDateUpcoming = startDate && isFuture(startDate); - return c.project_id === projectId && isStartDateUpcoming && !c?.archived_at; - }); - upcomingCycles = sortBy(upcomingCycles, [(c) => c.sort_order]); - const upcomingCycleIds = upcomingCycles.map((c) => c.id); - return upcomingCycleIds; - } - /** * returns all incomplete cycle ids for a project */ @@ -229,20 +204,6 @@ export class CycleStore implements ICycleStore { return incompleteCycleIds; } - /** - * returns all draft cycle ids for a project - */ - get currentProjectDraftCycleIds() { - const projectId = this.rootStore.router.projectId; - if (!projectId || !this.fetchedMap[projectId]) return null; - let draftCycles = Object.values(this.cycleMap ?? {}).filter( - (c) => c.project_id === projectId && !c.start_date && !c.end_date && !c?.archived_at - ); - draftCycles = sortBy(draftCycles, [(c) => c.sort_order]); - const draftCycleIds = draftCycles.map((c) => c.id); - return draftCycleIds; - } - /** * returns active cycle id for a project */ @@ -287,19 +248,6 @@ export class CycleStore implements ICycleStore { } else return false; }); - /** - * returns active cycle progress for a project - */ - getActiveCycleProgress = computedFn((cycleId?: string) => { - const cycle = cycleId ? this.cycleMap[cycleId] : this.currentProjectActiveCycle; - if (!cycle) return null; - - const isTypeIssue = this.getEstimateTypeByCycleId(cycle.id) === "issues"; - const isBurnDown = this.getPlotTypeByCycleId(cycle.id) === "burndown"; - - return { cycle, isTypeIssue, isBurnDown }; - }); - /** * @description returns filtered cycle ids based on display filters and filters * @param {TCycleDisplayFilters} displayFilters @@ -381,37 +329,28 @@ export class CycleStore implements ICycleStore { getCycleNameById = computedFn((cycleId: string): string => this.cycleMap?.[cycleId]?.name); /** - * @description returns active cycle details by cycle id - * @param cycleId - * @returns + * @description returns list of cycle details of the project id passed as argument + * @param projectId */ - getActiveCycleById = computedFn((cycleId: string): ICycle | null => - this.activeCycleIdMap?.[cycleId] && this.cycleMap?.[cycleId] ? this.cycleMap?.[cycleId] : null - ); + getProjectCycleDetails = computedFn((projectId: string): ICycle[] | null => { + if (!this.fetchedMap[projectId]) return null; + + let cycles = Object.values(this.cycleMap ?? {}).filter((c) => c.project_id === projectId && !c?.archived_at); + cycles = sortBy(cycles, [(c) => c.sort_order]); + return cycles || null; + }); /** * @description returns list of cycle ids of the project id passed as argument * @param projectId */ getProjectCycleIds = computedFn((projectId: string): string[] | null => { - if (!this.fetchedMap[projectId]) return null; - - let cycles = Object.values(this.cycleMap ?? {}).filter((c) => c.project_id === projectId && !c?.archived_at); - cycles = sortBy(cycles, [(c) => c.sort_order]); + const cycles = this.getProjectCycleDetails(projectId); + if (!cycles) return null; const cycleIds = cycles.map((c) => c.id); return cycleIds || null; }); - /** - * @description validates cycle dates - * @param workspaceSlug - * @param projectId - * @param payload - * @returns - */ - validateDate = async (workspaceSlug: string, projectId: string, payload: CycleDateCheckData) => - await this.cycleService.cycleDateCheck(workspaceSlug, projectId, payload); - /** * @description gets the plot type for the cycle store * @param {TCyclePlotType} plotType @@ -482,14 +421,16 @@ export class CycleStore implements ICycleStore { runInAction(() => { response.forEach((cycle) => { set(this.cycleMap, [cycle.id], cycle); - cycle.status?.toLowerCase() === "current" && set(this.activeCycleIdMap, [cycle.id], true); + if (cycle.status?.toLowerCase() === "current") { + set(this.activeCycleIdMap, [cycle.id], true); + } }); set(this.fetchedMap, projectId, true); this.loader = false; }); return response; }); - } catch (error) { + } catch { this.loader = false; return undefined; } @@ -562,6 +503,7 @@ export class CycleStore implements ICycleStore { * @param cycleId * @returns */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars fetchActiveCycleProgressPro = action(async (workspaceSlug: string, projectId: string, cycleId: string) => {}); /** diff --git a/web/core/store/module.store.ts b/web/core/store/module.store.ts index 787b8b091e..06a08b92c1 100644 --- a/web/core/store/module.store.ts +++ b/web/core/store/module.store.ts @@ -32,6 +32,7 @@ export interface IModuleStore { getFilteredArchivedModuleIds: (projectId: string) => string[] | null; getModuleById: (moduleId: string) => IModule | null; getModuleNameById: (moduleId: string) => string; + getProjectModuleDetails: (projectId: string) => IModule[] | null; getProjectModuleIds: (projectId: string) => string[] | null; getPlotTypeByModuleId: (moduleId: string) => TModulePlotType; // actions @@ -210,15 +211,24 @@ export class ModulesStore implements IModuleStore { */ getModuleNameById = computedFn((moduleId: string) => this.moduleMap?.[moduleId]?.name); + /** + * @description returns list of module details of the project id passed as argument + * @param projectId + */ + getProjectModuleDetails = computedFn((projectId: string) => { + if (!this.fetchedMap[projectId]) return null; + let projectModules = Object.values(this.moduleMap).filter((m) => m.project_id === projectId && !m.archived_at); + projectModules = sortBy(projectModules, [(m) => m.sort_order]); + return projectModules; + }); + /** * @description returns list of module ids of the project id passed as argument * @param projectId */ getProjectModuleIds = computedFn((projectId: string) => { - if (!this.fetchedMap[projectId]) return null; - - let projectModules = Object.values(this.moduleMap).filter((m) => m.project_id === projectId && !m.archived_at); - projectModules = sortBy(projectModules, [(m) => m.sort_order]); + const projectModules = this.getProjectModuleDetails(projectId); + if (!projectModules) return null; const projectModuleIds = projectModules.map((m) => m.id); return projectModuleIds; }); @@ -282,7 +292,7 @@ export class ModulesStore implements IModuleStore { }); return response; }); - } catch (error) { + } catch { this.loader = false; return undefined; } @@ -308,7 +318,7 @@ export class ModulesStore implements IModuleStore { }); return projectModules; }); - } catch (error) { + } catch { this.loader = false; return undefined; }