plane/web/store/project-issues.ts

208 lines
6.3 KiB
TypeScript

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();
}
issueDisplayFiltersDefaultData = (): { [filter_key: string]: string[] } => {
const data: { [filter_key: string]: string[] } = {
state: (this.rootStore?.projectState?.projectStates ?? []).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"],
};
return data;
};
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[] } = this.issueDisplayFiltersDefaultData();
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[] } = this.issueDisplayFiltersDefaultData();
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"];
}
}
}