dev: implemented the new project issues store with grouped, subGrouped and unGrouped issue computed functions

This commit is contained in:
gurusainath 2023-11-09 11:15:32 +05:30
parent a6567bbce4
commit e5343595f6
4 changed files with 228 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import useSWR from "swr";
@ -19,7 +19,6 @@ export const WorkspaceDashboardView = observer(() => {
const { workspaceSlug } = router.query;
// store
const { user: userStore, project: projectStore, commandPalette: commandPaletteStore } = useMobxStore();
const user = userStore.currentUser;
const projects = workspaceSlug ? projectStore.projects[workspaceSlug.toString()] : null;
const workspaceDashboardInfo = userStore.dashboardInfo;

View File

@ -3,6 +3,7 @@ import { APIService } from "services/api.service";
import { TrackEventService } from "services/track_event.service";
// type
import type { IUser, IIssue, IIssueActivity, ISubIssueResponse, IIssueDisplayProperties } from "types";
import type { IIssueResponse } from "store/project-issues";
// helper
import { API_BASE_URL } from "helpers/common.helper";
@ -32,6 +33,16 @@ export class IssueService extends APIService {
});
}
async getV3Issues(workspaceSlug: string, projectId: string, queries?: any): Promise<IIssueResponse> {
return this.get(`/api/v3/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, {
params: queries,
})
.then((response) => response?.data)
.catch((error) => {
throw error?.response?.data;
});
}
async getIssuesWithParams(
workspaceSlug: string,
projectId: string,

209
web/store/project-issues.ts Normal file
View File

@ -0,0 +1,209 @@
import { action, observable, makeObservable, computed, runInAction } from "mobx";
// services
import { IssueService } from "services/issue/issue.service";
// constants
import { ISSUE_PRIORITIES, ISSUE_STATE_GROUPS } from "constants/issue";
// types
import { IIssue, IState, TIssueGroupByOptions } from "types";
import { RootStore } from "store/root";
export interface IGroupedIssues {
[group_id: string]: string[];
}
export interface ISubGroupedIssues {
[sub_grouped_id: string]: {
[group_id: string]: string[];
};
}
export type TUnGroupedIssues = string[];
export interface IIssueResponse {
[issue_id: string]: IIssue;
}
enum issueGroupByKeys {
state = "state",
"state_detail.group" = "state_detail.group",
priority = "priority",
labels = "labels",
created_by = "created_by",
project = "project",
assignees = "assignees",
mentions = "assignees",
}
export interface IProjectIssueStore {
loader: "init-loader" | "mutation" | null;
projectId: string | undefined;
issues:
| {
[project_id: string]: {
[issue_id: string]: IIssue;
};
}
| undefined;
// computed
groupedIssues: IGroupedIssues | undefined;
subGroupedIssues: ISubGroupedIssues | undefined;
unGroupedIssues: TUnGroupedIssues | undefined;
// actions
fetchProjectIssues: (workspaceSlug: string, projectId: string) => Promise<IIssueResponse> | undefined;
}
export class ProjectIssueStore implements IProjectIssueStore {
loader: "init-loader" | "mutation" | null = null;
projectId: string | undefined = undefined;
issues:
| {
[project_id: string]: {
[issue_id: string]: IIssue;
};
}
| undefined = undefined;
// root store
rootStore;
// service
issueService;
constructor(_rootStore: RootStore | null = null) {
makeObservable(this, {
// observable
loader: observable.ref,
projectId: observable.ref,
issues: observable.ref,
// computed
groupedIssues: computed,
subGroupedIssues: computed,
unGroupedIssues: computed,
// action
fetchProjectIssues: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
}
get groupedIssues() {
const groupBy: TIssueGroupByOptions | undefined = this.rootStore?.issueFilter.userDisplayFilters.group_by;
const projectId: string | undefined | null = this.rootStore?.project.projectId;
if (!groupBy || !projectId || !this.issues || !this.issues[projectId]) return undefined;
const displayFiltersDefaultData: { [filter_key: string]: string[] } = {
state: (this.rootStore?.projectState?.states?.[projectId] ?? []).map((i: IState) => i.id),
"state_detail.group": ISSUE_STATE_GROUPS.map((i) => i.key),
priority: ISSUE_PRIORITIES.map((i) => i.key),
labels: [...(this.rootStore?.project?.projectLabels ?? []).map((i) => i.id), "None"],
created_by: (this.rootStore?.project?.projectMembers ?? []).map((i) => i.member.id),
project: (this.rootStore?.project.workspaceProjects ?? []).map((i) => i.id),
assignees: [...(this.rootStore?.project?.projectMembers ?? []).map((i) => i.member.id), "None"],
};
const issues: { [group_id: string]: string[] } = {};
displayFiltersDefaultData[groupBy].forEach((group) => {
issues[group] = [];
});
const projectIssues = this.issues[projectId];
for (const issue in projectIssues) {
const _issue = projectIssues[issue];
const groupArray = this.getGroupArray(_issue[issueGroupByKeys[groupBy] as keyof IIssue]);
for (const group of groupArray) {
if (group && issues[group]) {
issues[group].push(_issue.id);
}
}
}
return issues;
}
get subGroupedIssues() {
const subGroupBy: TIssueGroupByOptions | undefined = this.rootStore?.issueFilter.userDisplayFilters.sub_group_by;
const groupBy: TIssueGroupByOptions | undefined = this.rootStore?.issueFilter.userDisplayFilters.group_by;
const projectId: string | undefined | null = this.rootStore?.project.projectId;
if (!subGroupBy || !groupBy || !projectId || !this.issues || !this.issues[projectId]) return undefined;
const displayFiltersDefaultData: { [filter_key: string]: string[] } = {
state: (this.rootStore?.projectState?.states?.[projectId] ?? []).map((i: IState) => i.id),
"state_detail.group": ISSUE_STATE_GROUPS.map((i) => i.key),
priority: ISSUE_PRIORITIES.map((i) => i.key),
labels: [...(this.rootStore?.project?.projectLabels ?? []).map((i) => i.id), "None"],
created_by: (this.rootStore?.project?.projectMembers ?? []).map((i) => i.member.id),
project: (this.rootStore?.project.workspaceProjects ?? []).map((i) => i.id),
assignees: [...(this.rootStore?.project?.projectMembers ?? []).map((i) => i.member.id), "None"],
};
const issues: { [sub_group_id: string]: { [group_id: string]: string[] } } = {};
displayFiltersDefaultData[subGroupBy].forEach((sub_group: any) => {
const groupByIssues: { [group_id: string]: string[] } = {};
displayFiltersDefaultData[groupBy].forEach((group) => {
groupByIssues[group] = [];
});
issues[sub_group] = groupByIssues;
});
const projectIssues = this.issues[projectId];
for (const issue in projectIssues) {
const _issue = projectIssues[issue];
const subGroupArray = this.getGroupArray(_issue[issueGroupByKeys[subGroupBy] as keyof IIssue]);
const groupArray = this.getGroupArray(_issue[issueGroupByKeys[groupBy] as keyof IIssue]);
for (const subGroup of subGroupArray) {
for (const group of groupArray) {
if (subGroup && group && issues[subGroup]) {
issues[subGroup][group].push(_issue.id);
}
}
}
}
return issues;
}
get unGroupedIssues() {
if (!this.projectId || !this.issues || !this.issues[this.projectId]) return undefined;
return Object.keys(this.issues[this.projectId]);
}
fetchProjectIssues = async (workspaceSlug: string, projectId: string) => {
try {
this.projectId = projectId;
this.rootStore?.project.setProjectId(projectId);
const response = await this.issueService.getV3Issues(workspaceSlug, projectId);
const _issues = {
...this.issues,
[projectId]: { ...response },
};
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
throw error;
}
};
/**
*
* @description this function helps to convert the typeof value (array | string | null) to array and returns an array
*/
getGroupArray(value: string[] | string | null) {
if (Array.isArray(value)) {
return value;
} else {
return [value || "None"];
}
}
}

View File

@ -108,6 +108,9 @@ import {
InboxStore,
} from "store/inbox";
// v3
import { ProjectIssueStore, IProjectIssueStore } from "store/project-issues";
import { IMentionsStore, MentionsStore } from "store/editor";
enableStaticRendering(typeof window === "undefined");
@ -176,6 +179,8 @@ export class RootStore {
mentionsStore: IMentionsStore;
projectIssues: IProjectIssueStore;
constructor() {
this.appConfig = new AppConfigStore(this);
this.commandPalette = new CommandPaletteStore(this);
@ -239,5 +244,7 @@ export class RootStore {
this.inboxFilters = new InboxFiltersStore(this);
this.mentionsStore = new MentionsStore(this);
this.projectIssues = new ProjectIssueStore(this);
}
}