mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
dev: issues store and filters in new store
This commit is contained in:
parent
90e6d759c8
commit
ab04e7943d
@ -51,7 +51,10 @@ const SubGroupSwimlaneHeader: React.FC<ISubGroupSwimlaneHeader> = ({
|
||||
{list &&
|
||||
list.length > 0 &&
|
||||
list.map((_list: any) => (
|
||||
<div className="flex w-[340px] flex-shrink-0 flex-col">
|
||||
<div
|
||||
key={`${sub_group_by}_${getValueFromObject(_list, listKey) as string}`}
|
||||
className="flex w-[340px] flex-shrink-0 flex-col"
|
||||
>
|
||||
<KanBanGroupByHeaderRoot
|
||||
column_id={getValueFromObject(_list, listKey) as string}
|
||||
column_value={_list}
|
||||
|
@ -4,6 +4,8 @@ import { observer } from "mobx-react-lite";
|
||||
import useSWR from "swr";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// TODO: update this
|
||||
// import useStoreIssues from "hooks/use-store-issues";
|
||||
// components
|
||||
import {
|
||||
ListLayout,
|
||||
@ -15,6 +17,7 @@ import {
|
||||
ProjectEmptyState,
|
||||
} from "components/issues";
|
||||
import { Spinner } from "@plane/ui";
|
||||
// hooks
|
||||
|
||||
export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
// router
|
||||
@ -33,6 +36,19 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: update this
|
||||
// const {
|
||||
// issues: { loader: issueLoader, getIssuesIds: issueGetIssuesIds, fetchIssues: issueFetchIssues },
|
||||
// issuesFilter: { issueFilters: issueIssueFilters, fetchFilters: issueFetchFilters },
|
||||
// } = useStoreIssues("project");
|
||||
|
||||
// useSWR(workspaceSlug && projectId ? `PROJECT_ISSUES_V3_UPGRADED_${workspaceSlug}_${projectId}` : null, async () => {
|
||||
// if (workspaceSlug && projectId) {
|
||||
// await issueFetchFilters(workspaceSlug, projectId);
|
||||
// await issueFetchIssues(workspaceSlug, projectId, getIssues ? "mutation" : "init-loader");
|
||||
// }
|
||||
// });
|
||||
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
|
||||
return (
|
||||
|
@ -1 +1,7 @@
|
||||
export const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
|
||||
export const isNil = (value: any) => {
|
||||
if (value === undefined || value === null) return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
@ -13,6 +13,12 @@ import {
|
||||
TStateGroups,
|
||||
} from "types";
|
||||
|
||||
export enum EFilterType {
|
||||
FILTERS = "filters",
|
||||
DISPLAY_FILTERS = "display_filters",
|
||||
DISPLAY_PROPERTIES = "display_properties",
|
||||
}
|
||||
|
||||
export const ISSUE_PRIORITIES: {
|
||||
key: TIssuePriorities;
|
||||
title: string;
|
||||
|
122
web/hooks/use-store-issues.tsx
Normal file
122
web/hooks/use-store-issues.tsx
Normal file
@ -0,0 +1,122 @@
|
||||
// issue store provider
|
||||
import { useMobxIssueStore } from "lib/mobx/store-issues-provider";
|
||||
// types
|
||||
import { IIssueStore } from "store/issue/issue.store";
|
||||
import { IWorkspaceIssues, IWorkspaceIssuesFilter } from "store/issue/workspace";
|
||||
import { IProfileIssues, IProfileIssuesFilter } from "store/issue/profile";
|
||||
import { IProjectIssues, IProjectIssuesFilter } from "store/issue/project";
|
||||
import { ICycleIssues, ICycleIssuesFilter } from "store/issue/cycle";
|
||||
import { IModuleIssues, IModuleIssuesFilter } from "store/issue/module";
|
||||
import { IProjectViewIssues, IProjectViewIssuesFilter } from "store/issue/project-views";
|
||||
import { IArchivedIssues, IArchivedIssuesFilter } from "store/issue/archived";
|
||||
import { IDraftIssues, IDraftIssuesFilter } from "store/issue/draft";
|
||||
|
||||
interface IStoreIssues {
|
||||
// workspace: {
|
||||
// issues: IWorkspaceIssues;
|
||||
// issuesFilter: IWorkspaceIssuesFilter;
|
||||
// };
|
||||
// profile: {
|
||||
// issues: IProfileIssues;
|
||||
// issuesFilter: IProfileIssuesFilter;
|
||||
// };
|
||||
project: {
|
||||
allIssues: IIssueStore;
|
||||
issues: IProjectIssues;
|
||||
issuesFilter: IProjectIssuesFilter;
|
||||
};
|
||||
// cycle: {
|
||||
// issues: ICycleIssues;
|
||||
// issuesFilter: ICycleIssuesFilter;
|
||||
// };
|
||||
// module: {
|
||||
// issues: IModuleIssues;
|
||||
// issuesFilter: IModuleIssuesFilter;
|
||||
// };
|
||||
// projectView: {
|
||||
// issues: IProjectViewIssues;
|
||||
// issuesFilter: IProjectViewIssuesFilter;
|
||||
// };
|
||||
// archived: {
|
||||
// issues: IArchivedIssues;
|
||||
// issuesFilter: IArchivedIssuesFilter;
|
||||
// };
|
||||
// draft: {
|
||||
// issues: IDraftIssues;
|
||||
// issuesFilter: IDraftIssuesFilter;
|
||||
// };
|
||||
}
|
||||
|
||||
interface IStoreIssuesWithHelpers extends IStoreIssues {
|
||||
calendarHelper: any;
|
||||
kanbanHelper: any;
|
||||
}
|
||||
|
||||
const useStoreIssues = (issueSpace: keyof IStoreIssues) => {
|
||||
const {
|
||||
issue: {
|
||||
workspaceSlug,
|
||||
issues,
|
||||
workspaceIssues,
|
||||
workspaceIssuesFilter,
|
||||
profileIssues,
|
||||
profileIssuesFilter,
|
||||
projectIssues,
|
||||
projectIssuesFilter,
|
||||
cycleIssues,
|
||||
cycleIssuesFilter,
|
||||
moduleIssues,
|
||||
moduleIssuesFilter,
|
||||
projectViewIssues,
|
||||
projectViewIssuesFilter,
|
||||
archivedIssues,
|
||||
archivedIssuesFilter,
|
||||
draftIssues,
|
||||
draftIssuesFilter,
|
||||
},
|
||||
} = useMobxIssueStore();
|
||||
|
||||
const storeIssues: IStoreIssues = {
|
||||
// workspace: {
|
||||
// issues: workspaceIssues,
|
||||
// issuesFilter: workspaceIssuesFilter,
|
||||
// },
|
||||
// profile: {
|
||||
// issues: profileIssues,
|
||||
// issuesFilter: profileIssuesFilter,
|
||||
// },
|
||||
project: {
|
||||
allIssues: issues,
|
||||
issues: projectIssues,
|
||||
issuesFilter: projectIssuesFilter,
|
||||
},
|
||||
// cycle: {
|
||||
// issues: cycleIssues,
|
||||
// issuesFilter: cycleIssuesFilter,
|
||||
// },
|
||||
// module: {
|
||||
// issues: moduleIssues,
|
||||
// issuesFilter: moduleIssuesFilter,
|
||||
// },
|
||||
// projectView: {
|
||||
// issues: projectViewIssues,
|
||||
// issuesFilter: projectViewIssuesFilter,
|
||||
// },
|
||||
// archived: {
|
||||
// issues: archivedIssues,
|
||||
// issuesFilter: archivedIssuesFilter,
|
||||
// },
|
||||
// draft: {
|
||||
// issues: draftIssues,
|
||||
// issuesFilter: draftIssuesFilter,
|
||||
// },
|
||||
};
|
||||
|
||||
return {
|
||||
allIssues: storeIssues[issueSpace].allIssues,
|
||||
issues: storeIssues[issueSpace].issues,
|
||||
issuesFilter: storeIssues[issueSpace].issuesFilter,
|
||||
};
|
||||
};
|
||||
|
||||
export default useStoreIssues;
|
28
web/lib/mobx/store-issues-provider.tsx
Normal file
28
web/lib/mobx/store-issues-provider.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
// mobx store
|
||||
import { RootStore } from "store/root.store";
|
||||
|
||||
let rootStore: RootStore = new RootStore();
|
||||
|
||||
export const MobxStoreContext = createContext<RootStore>(rootStore);
|
||||
|
||||
const initializeStore = () => {
|
||||
const _rootStore: RootStore = rootStore ?? new RootStore();
|
||||
if (typeof window === "undefined") return _rootStore;
|
||||
if (!rootStore) rootStore = _rootStore;
|
||||
return _rootStore;
|
||||
};
|
||||
|
||||
export const MobxIssueStoreProvider = ({ children }: any) => {
|
||||
const store: RootStore = initializeStore();
|
||||
return <MobxStoreContext.Provider value={store}>{children}</MobxStoreContext.Provider>;
|
||||
};
|
||||
|
||||
// hook
|
||||
export const useMobxIssueStore = () => {
|
||||
const context = useContext(MobxStoreContext);
|
||||
if (context === undefined) throw new Error("useMobxIssueStore must be used within MobxIssueStoreProvider");
|
||||
return context;
|
||||
};
|
@ -12,6 +12,8 @@ import "styles/react-datepicker.css";
|
||||
import { SITE_TITLE } from "constants/seo-variables";
|
||||
// mobx store provider
|
||||
import { MobxStoreProvider } from "lib/mobx/store-provider";
|
||||
import { MobxIssueStoreProvider } from "lib/mobx/store-issues-provider";
|
||||
|
||||
import { AppProvider } from "lib/app-provider";
|
||||
// types
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
@ -30,7 +32,9 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
<title>{SITE_TITLE}</title>
|
||||
</Head>
|
||||
<MobxStoreProvider {...pageProps}>
|
||||
<AppProvider>{getLayout(<Component {...pageProps} />)}</AppProvider>
|
||||
<MobxIssueStoreProvider {...pageProps}>
|
||||
<AppProvider>{getLayout(<Component {...pageProps} />)}</AppProvider>
|
||||
</MobxIssueStoreProvider>
|
||||
</MobxStoreProvider>
|
||||
</>
|
||||
);
|
||||
|
142
web/store/issue/archived/filter.store.ts
Normal file
142
web/store/issue/archived/filter.store.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import { computed, makeObservable } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface IArchivedIssuesFilter {
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// action
|
||||
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ArchivedIssuesFilter extends IssueFilterHelperStore implements IArchivedIssuesFilter {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// computed
|
||||
issueFilters: computed,
|
||||
appliedFilters: computed,
|
||||
});
|
||||
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
get issueFilters() {
|
||||
const projectId = this.rootStore.projectId;
|
||||
if (!projectId) return undefined;
|
||||
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: displayFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
return;
|
||||
} catch (error) {
|
||||
throw Error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => {
|
||||
try {
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueDisplayFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.rootStore.issuesFilter.updateDisplayProperties(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filters as IIssueDisplayProperties
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/archived/index.ts
Normal file
2
web/store/issue/archived/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
5
web/store/issue/archived/issue.store.ts
Normal file
5
web/store/issue/archived/issue.store.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IArchivedIssues {}
|
||||
|
||||
export class ArchivedIssues implements IArchivedIssues {
|
||||
constructor() {}
|
||||
}
|
253
web/store/issue/base-issue-filter.store.ts
Normal file
253
web/store/issue/base-issue-filter.store.ts
Normal file
@ -0,0 +1,253 @@
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
// types
|
||||
import { IIssueRootStore } from "./root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "types";
|
||||
// constants
|
||||
import { EFilterType } from "constants/issue";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
import { ProjectMemberService, ProjectService } from "services/project";
|
||||
|
||||
interface IProjectIssuesFiltersOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
displayFilters: IIssueDisplayFilterOptions;
|
||||
}
|
||||
|
||||
interface IProjectIssuesDisplayOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
displayFilters: IIssueDisplayFilterOptions;
|
||||
displayProperties: IIssueDisplayProperties;
|
||||
}
|
||||
|
||||
export interface IIssuesFilter {
|
||||
// observables
|
||||
projectIssueFilters: { [projectId: string]: IProjectIssuesDisplayOptions } | undefined;
|
||||
// computed
|
||||
// helpers
|
||||
issueDisplayFilters: (projectId: string) => IProjectIssuesDisplayOptions | undefined;
|
||||
// actions
|
||||
fetchDisplayFilters: (workspaceSlug: string, projectId: string) => Promise<IProjectIssuesFiltersOptions>;
|
||||
updateDisplayFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
|
||||
) => Promise<IProjectIssuesFiltersOptions>;
|
||||
fetchDisplayProperties: (workspaceSlug: string, projectId: string) => Promise<IIssueDisplayProperties>;
|
||||
updateDisplayProperties: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
properties: IIssueDisplayProperties
|
||||
) => Promise<IIssueDisplayProperties>;
|
||||
}
|
||||
|
||||
export class IssuesFilter implements IIssuesFilter {
|
||||
// observables
|
||||
projectIssueFilters: { [projectId: string]: IProjectIssuesDisplayOptions } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
projectMemberService;
|
||||
projectService;
|
||||
issueService;
|
||||
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
projectIssueFilters: observable.ref,
|
||||
// computed
|
||||
// actions
|
||||
fetchDisplayFilters: action,
|
||||
updateDisplayFilters: action,
|
||||
fetchDisplayProperties: action,
|
||||
updateDisplayProperties: action,
|
||||
});
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
// services
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
this.projectService = new ProjectService();
|
||||
this.issueService = new IssueService();
|
||||
}
|
||||
|
||||
// computed
|
||||
|
||||
// helpers
|
||||
issueDisplayFilters = (projectId: string) => {
|
||||
if (!projectId) return undefined;
|
||||
return this.projectIssueFilters?.[projectId] || undefined;
|
||||
};
|
||||
|
||||
// actions
|
||||
fetchDisplayFilters = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const _filters = await this.projectMemberService.projectMemberMe(workspaceSlug, projectId);
|
||||
|
||||
const filters: IIssueFilterOptions = {
|
||||
assignees: _filters?.view_props?.filters?.assignees || null,
|
||||
mentions: _filters?.view_props?.filters?.mentions || null,
|
||||
created_by: _filters?.view_props?.filters?.created_by || null,
|
||||
labels: _filters?.view_props?.filters?.labels || null,
|
||||
priority: _filters?.view_props?.filters?.priority || null,
|
||||
project: _filters?.view_props?.filters?.project || null,
|
||||
start_date: _filters?.view_props?.filters?.start_date || null,
|
||||
state: _filters?.view_props?.filters?.state || null,
|
||||
state_group: _filters?.view_props?.filters?.state_group || null,
|
||||
subscriber: _filters?.view_props?.filters?.subscriber || null,
|
||||
target_date: _filters?.view_props?.filters?.target_date || null,
|
||||
};
|
||||
|
||||
const displayFilters: IIssueDisplayFilterOptions = {
|
||||
calendar: {
|
||||
show_weekends: _filters?.view_props?.display_filters?.calendar?.show_weekends || false,
|
||||
layout: _filters?.view_props?.display_filters?.calendar?.layout || "month",
|
||||
},
|
||||
group_by: _filters?.view_props?.display_filters?.group_by || null,
|
||||
sub_group_by: _filters?.view_props?.display_filters?.sub_group_by || null,
|
||||
layout: _filters?.view_props?.display_filters?.layout || "list",
|
||||
order_by: _filters?.view_props?.display_filters?.order_by || "-created_at",
|
||||
show_empty_groups: _filters?.view_props?.display_filters?.show_empty_groups || false,
|
||||
start_target_date: _filters?.view_props?.display_filters?.start_target_date || false,
|
||||
sub_issue: _filters?.view_props?.display_filters?.sub_issue || false,
|
||||
type: _filters?.view_props?.display_filters?.type || null,
|
||||
};
|
||||
|
||||
const issueFilters: IProjectIssuesFiltersOptions = {
|
||||
filters: filters,
|
||||
displayFilters: displayFilters,
|
||||
};
|
||||
|
||||
let _projectIssueFilters = this.projectIssueFilters;
|
||||
if (!_projectIssueFilters) _projectIssueFilters = {};
|
||||
if (!_projectIssueFilters[projectId])
|
||||
_projectIssueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
_projectIssueFilters[projectId] = {
|
||||
..._projectIssueFilters[projectId],
|
||||
...issueFilters,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _projectIssueFilters;
|
||||
});
|
||||
|
||||
return issueFilters;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateDisplayFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
|
||||
) => {
|
||||
try {
|
||||
let _projectIssueFilters = { ...this.projectIssueFilters };
|
||||
if (!_projectIssueFilters) _projectIssueFilters = {};
|
||||
if (!_projectIssueFilters[projectId])
|
||||
_projectIssueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
|
||||
const _filters = {
|
||||
filters: { ..._projectIssueFilters[projectId].filters },
|
||||
displayFilters: { ..._projectIssueFilters[projectId].displayFilters },
|
||||
};
|
||||
|
||||
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
|
||||
else if (type === EFilterType.DISPLAY_FILTERS)
|
||||
_filters.displayFilters = { ..._filters.displayFilters, ...filters };
|
||||
|
||||
// set sub_group_by to null if group_by is set to null
|
||||
if (_filters.displayFilters.group_by === null) _filters.displayFilters.sub_group_by = null;
|
||||
|
||||
// set sub_group_by to null if layout is switched to kanban group_by and sub_group_by are same
|
||||
if (
|
||||
_filters.displayFilters.layout === "kanban" &&
|
||||
_filters.displayFilters.group_by === _filters.displayFilters.sub_group_by
|
||||
)
|
||||
_filters.displayFilters.sub_group_by = null;
|
||||
|
||||
// set group_by to state if layout is switched to kanban and group_by is null
|
||||
if (_filters.displayFilters.layout === "kanban" && _filters.displayFilters.group_by === null)
|
||||
_filters.displayFilters.group_by = "state";
|
||||
|
||||
_projectIssueFilters[projectId] = {
|
||||
filters: _filters.filters,
|
||||
displayFilters: _filters.displayFilters,
|
||||
displayProperties: _projectIssueFilters[projectId].displayProperties,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _projectIssueFilters;
|
||||
});
|
||||
|
||||
await this.projectService.setProjectView(workspaceSlug, projectId, {
|
||||
view_props: { filters: _filters.filters, display_filters: _filters.displayFilters },
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
this.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchDisplayProperties = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
const _issueDisplayProperties = await this.issueService.getIssueDisplayProperties(workspaceSlug, projectId);
|
||||
|
||||
const displayProperties: IIssueDisplayProperties = {
|
||||
assignee: _issueDisplayProperties?.properties?.assignee || false,
|
||||
start_date: _issueDisplayProperties?.properties?.start_date || false,
|
||||
due_date: _issueDisplayProperties?.properties?.due_date || false,
|
||||
labels: _issueDisplayProperties?.properties?.labels || false,
|
||||
key: _issueDisplayProperties?.properties?.key || false,
|
||||
priority: _issueDisplayProperties?.properties?.priority || false,
|
||||
state: _issueDisplayProperties?.properties?.state || false,
|
||||
sub_issue_count: _issueDisplayProperties?.properties?.sub_issue_count || false,
|
||||
link: _issueDisplayProperties?.properties?.link || false,
|
||||
attachment_count: _issueDisplayProperties?.properties?.attachment_count || false,
|
||||
estimate: _issueDisplayProperties?.properties?.estimate || false,
|
||||
created_on: _issueDisplayProperties?.properties?.created_on || false,
|
||||
updated_on: _issueDisplayProperties?.properties?.updated_on || false,
|
||||
};
|
||||
|
||||
let _projectIssueFilters = { ...this.projectIssueFilters };
|
||||
if (!_projectIssueFilters) _projectIssueFilters = {};
|
||||
if (!_projectIssueFilters[projectId])
|
||||
_projectIssueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
_projectIssueFilters[projectId] = { ..._projectIssueFilters[projectId], displayProperties: displayProperties };
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _projectIssueFilters;
|
||||
});
|
||||
|
||||
return displayProperties;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateDisplayProperties = async (workspaceSlug: string, projectId: string, properties: IIssueDisplayProperties) => {
|
||||
try {
|
||||
let _issueFilters = { ...this.projectIssueFilters };
|
||||
if (!_issueFilters) _issueFilters = {};
|
||||
if (!_issueFilters[projectId])
|
||||
_issueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
|
||||
const updatedDisplayProperties = { ..._issueFilters[projectId].displayProperties, ...properties };
|
||||
_issueFilters[projectId] = { ..._issueFilters[projectId], displayProperties: updatedDisplayProperties };
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _issueFilters;
|
||||
});
|
||||
|
||||
await this.issueService.updateIssueDisplayProperties(workspaceSlug, projectId, updatedDisplayProperties);
|
||||
|
||||
return properties;
|
||||
} catch (error) {
|
||||
this.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
259
web/store/issue/cycle/filter.store.ts
Normal file
259
web/store/issue/cycle/filter.store.ts
Normal file
@ -0,0 +1,259 @@
|
||||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// services
|
||||
import { ProjectService, ProjectMemberService } from "services/project";
|
||||
import { IssueService } from "services/issue";
|
||||
import { CycleService } from "services/cycle.service";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface ICycleIssuesFilterOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
}
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface ICycleIssuesFilter {
|
||||
// observable
|
||||
loader: boolean;
|
||||
filters: { [cycleId: string]: ICycleIssuesFilterOptions } | undefined;
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// actions
|
||||
fetchCycleFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<IIssueFilterOptions>;
|
||||
updateCycleFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions
|
||||
) => Promise<ICycleIssuesFilterOptions>;
|
||||
|
||||
fetchFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
|
||||
cycleId?: string | undefined
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleIssuesFilter {
|
||||
// observables
|
||||
loader: boolean = false;
|
||||
filters: { [projectId: string]: ICycleIssuesFilterOptions } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
projectService;
|
||||
projectMemberService;
|
||||
issueService;
|
||||
cycleService;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
loader: observable.ref,
|
||||
filters: observable.ref,
|
||||
// computed
|
||||
issueFilters: computed,
|
||||
appliedFilters: computed,
|
||||
// actions
|
||||
fetchCycleFilters: action,
|
||||
updateCycleFilters: action,
|
||||
fetchFilters: action,
|
||||
updateFilters: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
this.issueService = new IssueService();
|
||||
this.cycleService = new CycleService();
|
||||
}
|
||||
|
||||
get issueFilters() {
|
||||
const projectId = this.rootStore.projectId;
|
||||
const cycleId = this.rootStore.cycleId;
|
||||
if (!projectId || !cycleId) return undefined;
|
||||
|
||||
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
|
||||
const cycleFilters = this.filters?.[cycleId];
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: cycleFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
|
||||
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchCycleFilters = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||
try {
|
||||
const cycleFilters = await this.cycleService.getCycleDetails(workspaceSlug, projectId, cycleId);
|
||||
|
||||
const filters: IIssueFilterOptions = {
|
||||
assignees: cycleFilters?.view_props?.filters?.assignees || null,
|
||||
mentions: cycleFilters?.view_props?.filters?.mentions || null,
|
||||
created_by: cycleFilters?.view_props?.filters?.created_by || null,
|
||||
labels: cycleFilters?.view_props?.filters?.labels || null,
|
||||
priority: cycleFilters?.view_props?.filters?.priority || null,
|
||||
project: cycleFilters?.view_props?.filters?.project || null,
|
||||
start_date: cycleFilters?.view_props?.filters?.start_date || null,
|
||||
state: cycleFilters?.view_props?.filters?.state || null,
|
||||
state_group: cycleFilters?.view_props?.filters?.state_group || null,
|
||||
subscriber: cycleFilters?.view_props?.filters?.subscriber || null,
|
||||
target_date: cycleFilters?.view_props?.filters?.target_date || null,
|
||||
};
|
||||
|
||||
const issueFilters: ICycleIssuesFilterOptions = {
|
||||
filters: filters,
|
||||
};
|
||||
|
||||
let _filters = { ...this.filters };
|
||||
if (!_filters) _filters = {};
|
||||
if (!_filters[cycleId]) _filters[cycleId] = { filters: {} };
|
||||
_filters[cycleId] = issueFilters;
|
||||
|
||||
runInAction(() => {
|
||||
this.filters = _filters;
|
||||
});
|
||||
|
||||
return filters;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateCycleFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions
|
||||
) => {
|
||||
try {
|
||||
let _cycleIssueFilters = { ...this.filters };
|
||||
if (!_cycleIssueFilters) _cycleIssueFilters = {};
|
||||
if (!_cycleIssueFilters[cycleId]) _cycleIssueFilters[cycleId] = { filters: {} };
|
||||
|
||||
const _filters = { filters: { ..._cycleIssueFilters[cycleId].filters } };
|
||||
|
||||
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
|
||||
|
||||
_cycleIssueFilters[cycleId] = { filters: _filters.filters };
|
||||
|
||||
runInAction(() => {
|
||||
this.filters = _cycleIssueFilters;
|
||||
});
|
||||
|
||||
await this.cycleService.patchCycle(workspaceSlug, projectId, cycleId, {
|
||||
view_props: { filters: _filters.filters },
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||
try {
|
||||
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
await this.fetchCycleFilters(workspaceSlug, projectId, cycleId);
|
||||
return;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
|
||||
cycleId?: string | undefined
|
||||
) => {
|
||||
try {
|
||||
if (!cycleId) throw new Error();
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.updateCycleFilters(workspaceSlug, projectId, cycleId, filterType, filters as IIssueFilterOptions);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueDisplayFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.rootStore.issuesFilter.updateDisplayProperties(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filters as IIssueDisplayProperties
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/cycle/index.ts
Normal file
2
web/store/issue/cycle/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
397
web/store/issue/cycle/issue.store.ts
Normal file
397
web/store/issue/cycle/issue.store.ts
Normal file
@ -0,0 +1,397 @@
|
||||
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
|
||||
// base class
|
||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
||||
// store
|
||||
import { IIssueRootStore } from "../root.store";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
import { CycleService } from "services/cycle.service";
|
||||
// types
|
||||
import {
|
||||
IGroupedIssues,
|
||||
IIssue,
|
||||
IIssueResponse,
|
||||
ISubGroupedIssues,
|
||||
TIssueGroupByOptions,
|
||||
TLoader,
|
||||
TUnGroupedIssues,
|
||||
} from "types";
|
||||
import { ViewFlags } from "store_legacy/issues/types";
|
||||
|
||||
export interface ICycleIssues {
|
||||
// observable
|
||||
loader: TLoader;
|
||||
issues: { [cycle_id: string]: IIssueResponse } | undefined;
|
||||
// computed
|
||||
getIssues: IIssueResponse | undefined;
|
||||
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
|
||||
// actions
|
||||
fetchIssues: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
loadType: TLoader,
|
||||
cycleId?: string | undefined
|
||||
) => Promise<IIssueResponse | undefined>;
|
||||
createIssue: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: Partial<IIssue>,
|
||||
cycleId?: string | undefined
|
||||
) => Promise<IIssue | undefined>;
|
||||
updateIssue: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
data: Partial<IIssue>,
|
||||
cycleId?: string | undefined
|
||||
) => Promise<IIssue | undefined>;
|
||||
removeIssue: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
cycleId?: string | undefined
|
||||
) => Promise<IIssue | undefined>;
|
||||
quickAddIssue: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: IIssue,
|
||||
cycleId?: string | undefined
|
||||
) => Promise<IIssue | undefined>;
|
||||
addIssueToCycle: (
|
||||
workspaceSlug: string,
|
||||
cycleId: string,
|
||||
issueIds: string[],
|
||||
fetchAfterAddition?: boolean,
|
||||
projectId?: string
|
||||
) => Promise<IIssue>;
|
||||
removeIssueFromCycle: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
issueId: string,
|
||||
issueBridgeId: string
|
||||
) => Promise<IIssue>;
|
||||
transferIssuesFromCycle: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
payload: {
|
||||
new_cycle_id: string;
|
||||
}
|
||||
) => Promise<IIssue>;
|
||||
viewFlags: ViewFlags;
|
||||
}
|
||||
|
||||
export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
||||
loader: TLoader = "init-loader";
|
||||
issues: { [cycle_id: string]: IIssueResponse } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
// service
|
||||
cycleService;
|
||||
issueService;
|
||||
|
||||
//viewData
|
||||
viewFlags = {
|
||||
enableQuickAdd: true,
|
||||
enableIssueCreation: true,
|
||||
enableInlineEditing: true,
|
||||
};
|
||||
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
loader: observable.ref,
|
||||
issues: observable.ref,
|
||||
// computed
|
||||
getIssues: computed,
|
||||
getIssuesIds: computed,
|
||||
// action
|
||||
fetchIssues: action,
|
||||
createIssue: action,
|
||||
updateIssue: action,
|
||||
removeIssue: action,
|
||||
quickAddIssue: action,
|
||||
addIssueToCycle: action,
|
||||
removeIssueFromCycle: action,
|
||||
transferIssuesFromCycle: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
this.issueService = new IssueService();
|
||||
this.cycleService = new CycleService();
|
||||
|
||||
autorun(() => {
|
||||
const workspaceSlug = this.rootStore.workspaceSlug;
|
||||
const projectId = this.rootStore.projectId;
|
||||
const cycleId = this.rootStore.cycleId;
|
||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||
|
||||
const userFilters = this.rootStore?.cycleIssuesFilter?.issueFilters?.filters;
|
||||
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
});
|
||||
}
|
||||
|
||||
get getIssues() {
|
||||
const cycleId = this.rootStore?.cycleId;
|
||||
if (!cycleId || !this.issues || !this.issues[cycleId]) return undefined;
|
||||
|
||||
return this.issues[cycleId];
|
||||
}
|
||||
|
||||
get getIssuesIds() {
|
||||
const cycleId = this.rootStore?.cycleId;
|
||||
const displayFilters = this.rootStore?.cycleIssuesFilter?.issueFilters?.displayFilters;
|
||||
|
||||
const subGroupBy = displayFilters?.sub_group_by;
|
||||
const groupBy = displayFilters?.group_by;
|
||||
const orderBy = displayFilters?.order_by;
|
||||
const layout = displayFilters?.layout;
|
||||
|
||||
if (!cycleId || !this.issues || !this.issues[cycleId]) return undefined;
|
||||
|
||||
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
|
||||
|
||||
if (layout === "list" && orderBy) {
|
||||
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[cycleId]);
|
||||
else issues = this.unGroupedIssues(orderBy, this.issues[cycleId]);
|
||||
} else if (layout === "kanban" && groupBy && orderBy) {
|
||||
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, this.issues[cycleId]);
|
||||
else issues = this.groupedIssues(groupBy, orderBy, this.issues[cycleId]);
|
||||
} else if (layout === "calendar")
|
||||
issues = this.groupedIssues("target_date" as TIssueGroupByOptions, "target_date", this.issues[cycleId], true);
|
||||
else if (layout === "spreadsheet") issues = this.unGroupedIssues(orderBy ?? "-created_at", this.issues[cycleId]);
|
||||
else if (layout === "gantt_chart") issues = this.unGroupedIssues(orderBy ?? "sort_order", this.issues[cycleId]);
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
fetchIssues = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
loadType: TLoader = "init-loader",
|
||||
cycleId: string | undefined = undefined
|
||||
) => {
|
||||
if (!cycleId) return undefined;
|
||||
|
||||
try {
|
||||
this.loader = loadType;
|
||||
|
||||
const params = this.rootStore?.cycleIssuesFilter?.appliedFilters;
|
||||
const response = await this.cycleService.getCycleIssuesWithParams(workspaceSlug, projectId, cycleId, params);
|
||||
|
||||
const _issues = { ...this.issues, [cycleId]: { ...response } };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
this.loader = undefined;
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.loader = undefined;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createIssue = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: Partial<IIssue>,
|
||||
cycleId: string | undefined = undefined
|
||||
) => {
|
||||
if (!cycleId) return undefined;
|
||||
|
||||
try {
|
||||
const response = await this.rootStore.projectIssues.createIssue(workspaceSlug, projectId, data);
|
||||
const issueToCycle = await this.addIssueToCycle(workspaceSlug, cycleId, [response.id], false);
|
||||
|
||||
let _issues = this.issues;
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||
_issues[cycleId] = { ..._issues[cycleId], ...{ [response.id]: response } };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
return issueToCycle;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateIssue = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
data: Partial<IIssue>,
|
||||
cycleId: string | undefined = undefined
|
||||
) => {
|
||||
if (!cycleId) return undefined;
|
||||
|
||||
try {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||
_issues[cycleId][issueId] = { ..._issues[cycleId][issueId], ...data };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
const response = await this.rootStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
removeIssue = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
cycleId: string | undefined = undefined
|
||||
) => {
|
||||
if (!cycleId) return undefined;
|
||||
try {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||
delete _issues?.[cycleId]?.[issueId];
|
||||
_issues[cycleId] = { ..._issues[cycleId] };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
const response = await this.rootStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
quickAddIssue = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
data: IIssue,
|
||||
cycleId: string | undefined = undefined
|
||||
) => {
|
||||
if (!cycleId) return;
|
||||
try {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||
_issues[cycleId] = { ..._issues[cycleId], ...{ [data.id as keyof IIssue]: data } };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
const response = await this.createIssue(workspaceSlug, projectId, data, cycleId);
|
||||
|
||||
if (this.issues) {
|
||||
delete this.issues[cycleId][data.id as keyof IIssue];
|
||||
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||
_issues[cycleId] = { ..._issues[cycleId], ...{ [response.id as keyof IIssue]: response } };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
addIssueToCycle = async (
|
||||
workspaceSlug: string,
|
||||
cycleId: string,
|
||||
issueIds: string[],
|
||||
fetchAfterAddition = true,
|
||||
projectId?: string
|
||||
) => {
|
||||
const activeProjectId = this.rootStore.projectId;
|
||||
if (!activeProjectId && !projectId) return;
|
||||
|
||||
const projectIdToUpdate: string = projectId || activeProjectId || "";
|
||||
|
||||
try {
|
||||
const issueToCycle = await this.issueService.addIssueToCycle(workspaceSlug, projectIdToUpdate, cycleId, {
|
||||
issues: issueIds,
|
||||
});
|
||||
|
||||
if (fetchAfterAddition) this.fetchIssues(workspaceSlug, projectIdToUpdate, "mutation", cycleId);
|
||||
|
||||
return issueToCycle;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectIdToUpdate, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
removeIssueFromCycle = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
issueId: string,
|
||||
issueBridgeId: string
|
||||
) => {
|
||||
try {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[cycleId]) _issues[cycleId] = {};
|
||||
delete _issues?.[cycleId]?.[issueId];
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
const response = await this.issueService.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueBridgeId);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
transferIssuesFromCycle = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
cycleId: string,
|
||||
payload: {
|
||||
new_cycle_id: string;
|
||||
}
|
||||
) => {
|
||||
try {
|
||||
const response = await this.cycleService.transferIssues(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
cycleId as string,
|
||||
payload
|
||||
);
|
||||
await this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
142
web/store/issue/draft/filter.store.ts
Normal file
142
web/store/issue/draft/filter.store.ts
Normal file
@ -0,0 +1,142 @@
|
||||
import { computed, makeObservable } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface IDraftIssuesFilter {
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// action
|
||||
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class DraftIssuesFilter extends IssueFilterHelperStore implements IDraftIssuesFilter {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// computed
|
||||
issueFilters: computed,
|
||||
appliedFilters: computed,
|
||||
});
|
||||
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
get issueFilters() {
|
||||
const projectId = this.rootStore.projectId;
|
||||
if (!projectId) return undefined;
|
||||
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: displayFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
return;
|
||||
} catch (error) {
|
||||
throw Error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => {
|
||||
try {
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueDisplayFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.rootStore.issuesFilter.updateDisplayProperties(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filters as IIssueDisplayProperties
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/draft/index.ts
Normal file
2
web/store/issue/draft/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
5
web/store/issue/draft/issue.store.ts
Normal file
5
web/store/issue/draft/issue.store.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IDraftIssues {}
|
||||
|
||||
export class DraftIssues implements IDraftIssues {
|
||||
constructor() {}
|
||||
}
|
29
web/store/issue/helpers/issue-filter-helper.store.ts
Normal file
29
web/store/issue/helpers/issue-filter-helper.store.ts
Normal file
@ -0,0 +1,29 @@
|
||||
// types
|
||||
import { IIssueRootStore } from "../root.store";
|
||||
|
||||
export interface IIssueFilterHelperStore {
|
||||
// helper methods
|
||||
computedFilter(filters: any, filteredParams: any): any;
|
||||
}
|
||||
|
||||
export class IssueFilterHelperStore implements IIssueFilterHelperStore {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
// helper methods
|
||||
computedFilter = (filters: any, filteredParams: any) => {
|
||||
const computedFilters: any = {};
|
||||
Object.keys(filters).map((key) => {
|
||||
if (filters[key] != undefined && filteredParams.includes(key))
|
||||
computedFilters[key] =
|
||||
typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(",");
|
||||
});
|
||||
|
||||
return computedFilters;
|
||||
};
|
||||
}
|
215
web/store/issue/helpers/issue-helper.store.ts
Normal file
215
web/store/issue/helpers/issue-helper.store.ts
Normal file
@ -0,0 +1,215 @@
|
||||
import sortBy from "lodash/sortBy";
|
||||
import get from "lodash/get";
|
||||
import indexOf from "lodash/indexOf";
|
||||
import reverse from "lodash/reverse";
|
||||
import values from "lodash/values";
|
||||
// types
|
||||
import { IIssue, IIssueResponse, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
|
||||
import { IIssueRootStore } from "../root.store";
|
||||
|
||||
// constants
|
||||
import { ISSUE_PRIORITIES, ISSUE_STATE_GROUPS } from "constants/issue";
|
||||
// helpers
|
||||
import { renderDateFormat } from "helpers/date-time.helper";
|
||||
|
||||
export interface IIssueHelperStore {
|
||||
groupedIssues(
|
||||
groupBy: TIssueGroupByOptions,
|
||||
orderBy: TIssueOrderByOptions,
|
||||
issues: IIssueResponse,
|
||||
isCalendarIssues?: boolean
|
||||
): { [group_id: string]: string[] };
|
||||
subGroupedIssues(
|
||||
subGroupBy: TIssueGroupByOptions,
|
||||
groupBy: TIssueGroupByOptions,
|
||||
orderBy: TIssueOrderByOptions,
|
||||
issues: IIssueResponse
|
||||
): { [sub_group_id: string]: { [group_id: string]: string[] } };
|
||||
unGroupedIssues(orderBy: TIssueOrderByOptions, issues: IIssueResponse): string[];
|
||||
issueDisplayFiltersDefaultData(groupBy: string | null): string[];
|
||||
issuesSortWithOrderBy(issueObject: IIssueResponse, key: Partial<TIssueOrderByOptions>): IIssue[];
|
||||
getGroupArray(value: string[] | string | null, isDate?: boolean): string[];
|
||||
}
|
||||
|
||||
export class IssueHelperStore implements IIssueHelperStore {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
groupedIssues = (
|
||||
groupBy: TIssueGroupByOptions,
|
||||
orderBy: TIssueOrderByOptions,
|
||||
issues: IIssueResponse,
|
||||
isCalendarIssues: boolean = false
|
||||
) => {
|
||||
const _issues: { [group_id: string]: string[] } = {};
|
||||
|
||||
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
|
||||
_issues[group] = [];
|
||||
});
|
||||
|
||||
const projectIssues = this.issuesSortWithOrderBy(issues, orderBy);
|
||||
|
||||
for (const issue in projectIssues) {
|
||||
const _issue = projectIssues[issue];
|
||||
const groupArray = this.getGroupArray(get(_issue, groupBy as keyof IIssue), isCalendarIssues);
|
||||
|
||||
for (const group of groupArray) {
|
||||
if (group && _issues[group]) _issues[group].push(_issue.id);
|
||||
else if (group) _issues[group] = [_issue.id];
|
||||
}
|
||||
}
|
||||
|
||||
return _issues;
|
||||
};
|
||||
|
||||
subGroupedIssues = (
|
||||
subGroupBy: TIssueGroupByOptions,
|
||||
groupBy: TIssueGroupByOptions,
|
||||
orderBy: TIssueOrderByOptions,
|
||||
issues: IIssueResponse
|
||||
) => {
|
||||
const _issues: { [sub_group_id: string]: { [group_id: string]: string[] } } = {};
|
||||
|
||||
this.issueDisplayFiltersDefaultData(subGroupBy).forEach((sub_group: any) => {
|
||||
const groupByIssues: { [group_id: string]: string[] } = {};
|
||||
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
|
||||
groupByIssues[group] = [];
|
||||
});
|
||||
_issues[sub_group] = groupByIssues;
|
||||
});
|
||||
|
||||
const projectIssues = this.issuesSortWithOrderBy(issues, orderBy);
|
||||
|
||||
for (const issue in projectIssues) {
|
||||
const _issue = projectIssues[issue];
|
||||
const subGroupArray = this.getGroupArray(get(_issue, subGroupBy as keyof IIssue));
|
||||
const groupArray = this.getGroupArray(get(_issue, groupBy as keyof IIssue));
|
||||
|
||||
for (const subGroup of subGroupArray) {
|
||||
for (const group of groupArray) {
|
||||
if (subGroup && group && _issues?.[subGroup]?.[group]) _issues[subGroup][group].push(_issue.id);
|
||||
else if (subGroup && group && _issues[subGroup]) _issues[subGroup][group] = [_issue.id];
|
||||
else if (subGroup && group) _issues[subGroup] = { [group]: [_issue.id] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _issues;
|
||||
};
|
||||
|
||||
unGroupedIssues = (orderBy: TIssueOrderByOptions, issues: IIssueResponse) =>
|
||||
this.issuesSortWithOrderBy(issues, orderBy).map((issue) => issue.id);
|
||||
|
||||
issueDisplayFiltersDefaultData = (groupBy: string | null): string[] => {
|
||||
switch (groupBy) {
|
||||
case "state":
|
||||
return this.rootStore?.states || [];
|
||||
case "state_detail.group":
|
||||
return ISSUE_STATE_GROUPS.map((i) => i.key);
|
||||
case "priority":
|
||||
return ISSUE_PRIORITIES.map((i) => i.key);
|
||||
case "labels":
|
||||
return this.rootStore?.labels || [];
|
||||
case "created_by":
|
||||
return this.rootStore?.members || [];
|
||||
case "assignees":
|
||||
return this.rootStore?.members || [];
|
||||
case "project":
|
||||
return this.rootStore?.projects || [];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
issuesSortWithOrderBy = (issueObject: IIssueResponse, key: Partial<TIssueOrderByOptions>): IIssue[] => {
|
||||
let array = values(issueObject);
|
||||
array = reverse(sortBy(array, "created_at"));
|
||||
switch (key) {
|
||||
case "sort_order":
|
||||
return reverse(sortBy(array, "sort_order"));
|
||||
|
||||
case "state__name":
|
||||
return reverse(sortBy(array, "state"));
|
||||
case "-state__name":
|
||||
return sortBy(array, "state");
|
||||
|
||||
//dates
|
||||
case "created_at":
|
||||
return sortBy(array, "created_at");
|
||||
case "-created_at":
|
||||
return reverse(sortBy(array, "created_at"));
|
||||
|
||||
case "updated_at":
|
||||
return sortBy(array, "updated_at");
|
||||
case "-updated_at":
|
||||
return reverse(sortBy(array, "updated_at"));
|
||||
|
||||
case "start_date":
|
||||
return sortBy(array, "start_date");
|
||||
case "-start_date":
|
||||
return reverse(sortBy(array, "start_date"));
|
||||
|
||||
case "target_date":
|
||||
return sortBy(array, "target_date");
|
||||
case "-target_date":
|
||||
return reverse(sortBy(array, "target_date"));
|
||||
|
||||
//custom
|
||||
case "priority": {
|
||||
const sortArray = ISSUE_PRIORITIES.map((i) => i.key);
|
||||
return reverse(sortBy(array, (_issue: IIssue) => indexOf(sortArray, _issue.priority)));
|
||||
}
|
||||
case "-priority": {
|
||||
const sortArray = ISSUE_PRIORITIES.map((i) => i.key);
|
||||
return sortBy(array, (_issue: IIssue) => indexOf(sortArray, _issue.priority));
|
||||
}
|
||||
|
||||
//number
|
||||
case "attachment_count":
|
||||
return sortBy(array, "attachment_count");
|
||||
case "-attachment_count":
|
||||
return reverse(sortBy(array, "attachment_count"));
|
||||
|
||||
case "estimate_point":
|
||||
return sortBy(array, "estimate_point");
|
||||
case "-estimate_point":
|
||||
return reverse(sortBy(array, "estimate_point"));
|
||||
|
||||
case "link_count":
|
||||
return sortBy(array, "link_count");
|
||||
case "-link_count":
|
||||
return reverse(sortBy(array, "link_count"));
|
||||
|
||||
case "sub_issues_count":
|
||||
return sortBy(array, "sub_issues_count");
|
||||
case "-sub_issues_count":
|
||||
return reverse(sortBy(array, "sub_issues_count"));
|
||||
|
||||
//Array
|
||||
case "labels__name":
|
||||
return reverse(sortBy(array, "labels"));
|
||||
case "-labels__name":
|
||||
return sortBy(array, "labels");
|
||||
|
||||
case "assignees__first_name":
|
||||
return reverse(sortBy(array, "assignees"));
|
||||
case "-assignees__first_name":
|
||||
return sortBy(array, "assignees");
|
||||
|
||||
default:
|
||||
return array;
|
||||
}
|
||||
};
|
||||
|
||||
getGroupArray(value: string[] | string | null, isDate: boolean = false) {
|
||||
if (Array.isArray(value)) {
|
||||
if (value.length) return value;
|
||||
else return ["None"];
|
||||
} else if (isDate) return [renderDateFormat(value) || "None"];
|
||||
else return [value || "None"];
|
||||
}
|
||||
}
|
106
web/store/issue/issue.store.ts
Normal file
106
web/store/issue/issue.store.ts
Normal file
@ -0,0 +1,106 @@
|
||||
// store
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
import { IIssueRootStore } from "./root.store";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
|
||||
export interface IIssueStore {
|
||||
issues: { [key: string]: IIssue };
|
||||
// actions
|
||||
addIssue(issues: IIssue[]): void;
|
||||
updateIssue(issueId: string, issue: Partial<IIssue>): void;
|
||||
removeIssue(issueId: string): void;
|
||||
// helper Methods
|
||||
getIssueById(id: string): undefined | IIssue;
|
||||
getIssuesByWorkspace(workspaceSlug: string): undefined | { [key: string]: IIssue };
|
||||
getIssuesByProject(projectId: string): undefined | { [key: string]: IIssue };
|
||||
getIssuesByCycle(cycleId: string): undefined | { [key: string]: IIssue };
|
||||
getIssuesByModule(moduleId: string): undefined | { [key: string]: IIssue };
|
||||
}
|
||||
|
||||
export class IssueStore implements IIssueStore {
|
||||
issues: { [key: string]: IIssue } = {};
|
||||
// root store
|
||||
rootStore: IIssueRootStore;
|
||||
|
||||
constructor(rootStore: IIssueRootStore) {
|
||||
this.rootStore = rootStore;
|
||||
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
issues: observable,
|
||||
// actions
|
||||
addIssue: action,
|
||||
updateIssue: action,
|
||||
removeIssue: action,
|
||||
});
|
||||
}
|
||||
|
||||
addIssue = (issues: IIssue[]) => {
|
||||
if (issues && issues.length <= 0) return;
|
||||
|
||||
const _issues = { ...this.issues };
|
||||
issues.forEach((issue) => {
|
||||
_issues[issue.id] = issue;
|
||||
});
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
};
|
||||
|
||||
updateIssue = (issueId: string, issue: Partial<IIssue>) => {
|
||||
if (!issue || !issueId || !this.issues[issueId]) return;
|
||||
this.issues[issueId] = { ...this.issues[issueId], ...issue };
|
||||
};
|
||||
|
||||
removeIssue = (issueId: string) => {
|
||||
if (issueId) return;
|
||||
delete this.issues[issueId];
|
||||
};
|
||||
|
||||
// helper methods
|
||||
getIssueById = (id: string) => {
|
||||
if (!id) return undefined;
|
||||
return this.issues[id];
|
||||
};
|
||||
|
||||
getIssuesByWorkspace = (workspaceSlug: string) => {
|
||||
if (!workspaceSlug || !this.issues) return undefined;
|
||||
const projectIssues = Object.values(this.issues).filter((issue) => issue?.workspace === workspaceSlug);
|
||||
const filteredIssues: { [key: string]: IIssue } = {};
|
||||
projectIssues.map((issue) => {
|
||||
filteredIssues[issue.id] = issue;
|
||||
});
|
||||
return filteredIssues;
|
||||
};
|
||||
|
||||
getIssuesByProject = (projectId: string) => {
|
||||
if (!projectId || !this.issues) return undefined;
|
||||
const projectIssues = Object.values(this.issues).filter((issue) => issue?.project === projectId);
|
||||
const filteredIssues: { [key: string]: IIssue } = {};
|
||||
projectIssues.map((issue) => {
|
||||
filteredIssues[issue.id] = issue;
|
||||
});
|
||||
return filteredIssues;
|
||||
};
|
||||
|
||||
getIssuesByCycle = (projectId: string) => {
|
||||
if (!projectId || !this.issues) return undefined;
|
||||
const projectIssues = Object.values(this.issues).filter((issue) => issue?.project === projectId);
|
||||
const filteredIssues: { [key: string]: IIssue } = {};
|
||||
projectIssues.map((issue) => {
|
||||
filteredIssues[issue.id] = issue;
|
||||
});
|
||||
return filteredIssues;
|
||||
};
|
||||
|
||||
getIssuesByModule = (projectId: string) => {
|
||||
if (!projectId || !this.issues) return undefined;
|
||||
const projectIssues = Object.values(this.issues).filter((issue) => issue?.project === projectId);
|
||||
const filteredIssues: { [key: string]: IIssue } = {};
|
||||
projectIssues.map((issue) => {
|
||||
filteredIssues[issue.id] = issue;
|
||||
});
|
||||
return filteredIssues;
|
||||
};
|
||||
}
|
267
web/store/issue/module/filter.store.ts
Normal file
267
web/store/issue/module/filter.store.ts
Normal file
@ -0,0 +1,267 @@
|
||||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// services
|
||||
import { ProjectService, ProjectMemberService } from "services/project";
|
||||
import { IssueService } from "services/issue";
|
||||
import { ModuleService } from "services/module.service";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface IModuleIssuesFilterOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
}
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface IModuleIssuesFilter {
|
||||
// observable
|
||||
loader: boolean;
|
||||
filters: { [moduleId: string]: IModuleIssuesFilterOptions } | undefined;
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// actions
|
||||
fetchModuleFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IIssueFilterOptions>;
|
||||
updateModuleFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions
|
||||
) => Promise<IModuleIssuesFilterOptions | undefined>;
|
||||
|
||||
fetchFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
|
||||
moduleId?: string | undefined
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModuleIssuesFilter {
|
||||
// observables
|
||||
loader: boolean = false;
|
||||
filters: { [projectId: string]: IModuleIssuesFilterOptions } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
projectService;
|
||||
projectMemberService;
|
||||
issueService;
|
||||
moduleService;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
loader: observable.ref,
|
||||
filters: observable.ref,
|
||||
// computed
|
||||
issueFilters: computed,
|
||||
appliedFilters: computed,
|
||||
// actions
|
||||
fetchModuleFilters: action,
|
||||
updateModuleFilters: action,
|
||||
fetchFilters: action,
|
||||
updateFilters: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
this.issueService = new IssueService();
|
||||
this.moduleService = new ModuleService();
|
||||
}
|
||||
|
||||
get issueFilters() {
|
||||
const projectId = this.rootStore.projectId;
|
||||
const moduleId = this.rootStore.moduleId;
|
||||
if (!projectId || !moduleId) return undefined;
|
||||
|
||||
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
|
||||
const moduleFilters = this.filters?.[moduleId];
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: moduleFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
|
||||
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchModuleFilters = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||
try {
|
||||
const moduleFilters = await this.moduleService.getModuleDetails(workspaceSlug, projectId, moduleId);
|
||||
|
||||
const filters: IIssueFilterOptions = {
|
||||
assignees: moduleFilters?.view_props?.filters?.assignees || null,
|
||||
mentions: moduleFilters?.view_props?.filters?.mentions || null,
|
||||
created_by: moduleFilters?.view_props?.filters?.created_by || null,
|
||||
labels: moduleFilters?.view_props?.filters?.labels || null,
|
||||
priority: moduleFilters?.view_props?.filters?.priority || null,
|
||||
project: moduleFilters?.view_props?.filters?.project || null,
|
||||
start_date: moduleFilters?.view_props?.filters?.start_date || null,
|
||||
state: moduleFilters?.view_props?.filters?.state || null,
|
||||
state_group: moduleFilters?.view_props?.filters?.state_group || null,
|
||||
subscriber: moduleFilters?.view_props?.filters?.subscriber || null,
|
||||
target_date: moduleFilters?.view_props?.filters?.target_date || null,
|
||||
};
|
||||
|
||||
const issueFilters: IModuleIssuesFilterOptions = {
|
||||
filters: filters,
|
||||
};
|
||||
|
||||
let _filters = { ...this.filters };
|
||||
if (!_filters) _filters = {};
|
||||
if (!_filters[moduleId]) _filters[moduleId] = { filters: {} };
|
||||
_filters[moduleId] = issueFilters;
|
||||
|
||||
runInAction(() => {
|
||||
this.filters = _filters;
|
||||
});
|
||||
|
||||
return filters;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, moduleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateModuleFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions
|
||||
) => {
|
||||
if (!moduleId) return;
|
||||
try {
|
||||
let _moduleIssueFilters = { ...this.filters };
|
||||
if (!_moduleIssueFilters) _moduleIssueFilters = {};
|
||||
if (!_moduleIssueFilters[moduleId]) _moduleIssueFilters[moduleId] = { filters: {} };
|
||||
|
||||
const _filters = { filters: { ..._moduleIssueFilters[moduleId].filters } };
|
||||
|
||||
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
|
||||
|
||||
_moduleIssueFilters[moduleId] = { filters: _filters.filters };
|
||||
|
||||
runInAction(() => {
|
||||
this.filters = _moduleIssueFilters;
|
||||
});
|
||||
|
||||
await this.moduleService.patchModule(workspaceSlug, projectId, moduleId, {
|
||||
view_props: { filters: _filters.filters },
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, moduleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||
try {
|
||||
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
await this.fetchModuleFilters(workspaceSlug, projectId, moduleId);
|
||||
return;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, moduleId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
|
||||
moduleId?: string | undefined
|
||||
) => {
|
||||
try {
|
||||
if (!moduleId) throw new Error();
|
||||
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.updateModuleFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
moduleId,
|
||||
filterType,
|
||||
filters as IIssueFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueDisplayFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.rootStore.issuesFilter.updateDisplayProperties(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filters as IIssueDisplayProperties
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/module/index.ts
Normal file
2
web/store/issue/module/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
5
web/store/issue/module/issue.store.ts
Normal file
5
web/store/issue/module/issue.store.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IModuleIssues {}
|
||||
|
||||
export class ModuleIssues implements IModuleIssues {
|
||||
constructor() {}
|
||||
}
|
344
web/store/issue/profile/filter.store.ts
Normal file
344
web/store/issue/profile/filter.store.ts
Normal file
@ -0,0 +1,344 @@
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface IProjectIssuesFiltersOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
displayFilters: IIssueDisplayFilterOptions;
|
||||
}
|
||||
|
||||
interface IProjectIssuesDisplayOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
displayFilters: IIssueDisplayFilterOptions;
|
||||
displayProperties: IIssueDisplayProperties;
|
||||
}
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface IProfileIssuesFilter {
|
||||
// observables
|
||||
projectIssueFilters: { [workspaceId: string]: IProjectIssuesDisplayOptions } | undefined;
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// helpers
|
||||
issueDisplayFilters: (workspaceId: string) => IProjectIssuesDisplayOptions | undefined;
|
||||
// actions
|
||||
fetchDisplayFilters: (workspaceSlug: string) => Promise<IProjectIssuesFiltersOptions>;
|
||||
updateDisplayFilters: (
|
||||
workspaceSlug: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
|
||||
) => Promise<IProjectIssuesFiltersOptions>;
|
||||
fetchDisplayProperties: (workspaceSlug: string) => Promise<IIssueDisplayProperties>;
|
||||
updateDisplayProperties: (
|
||||
workspaceSlug: string,
|
||||
properties: IIssueDisplayProperties
|
||||
) => Promise<IIssueDisplayProperties>;
|
||||
fetchFilters: (workspaceSlug: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProfileIssuesFilter extends IssueFilterHelperStore implements IProfileIssuesFilter {
|
||||
// observables
|
||||
projectIssueFilters: { [projectId: string]: IProjectIssuesDisplayOptions } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
projectIssueFilters: observable.ref,
|
||||
// computed
|
||||
// actions
|
||||
fetchDisplayFilters: action,
|
||||
updateDisplayFilters: action,
|
||||
fetchDisplayProperties: action,
|
||||
updateDisplayProperties: action,
|
||||
});
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
// computed
|
||||
|
||||
// helpers
|
||||
issueDisplayFilters = (workspaceId: string) => {
|
||||
if (!workspaceId) return undefined;
|
||||
return this.projectIssueFilters?.[workspaceId] || undefined;
|
||||
};
|
||||
|
||||
// actions
|
||||
fetchDisplayFilters = async (workspaceSlug: string) => {
|
||||
try {
|
||||
const filters: IIssueFilterOptions = {
|
||||
assignees: null,
|
||||
mentions: null,
|
||||
created_by: null,
|
||||
labels: null,
|
||||
priority: null,
|
||||
project: null,
|
||||
start_date: null,
|
||||
state: null,
|
||||
state_group: null,
|
||||
subscriber: null,
|
||||
target_date: null,
|
||||
};
|
||||
|
||||
const displayFilters: IIssueDisplayFilterOptions = {
|
||||
calendar: {
|
||||
show_weekends: false,
|
||||
layout: "month",
|
||||
},
|
||||
group_by: "state_detail.group",
|
||||
sub_group_by: null,
|
||||
layout: "list",
|
||||
order_by: "-created_at",
|
||||
show_empty_groups: false,
|
||||
start_target_date: false,
|
||||
sub_issue: false,
|
||||
type: null,
|
||||
};
|
||||
|
||||
const issueFilters: IProjectIssuesFiltersOptions = {
|
||||
filters: filters,
|
||||
displayFilters: displayFilters,
|
||||
};
|
||||
|
||||
let _projectIssueFilters = this.projectIssueFilters;
|
||||
if (!_projectIssueFilters) _projectIssueFilters = {};
|
||||
if (!_projectIssueFilters[workspaceSlug]) {
|
||||
_projectIssueFilters[workspaceSlug] = { displayProperties: {} } as IProjectIssuesDisplayOptions;
|
||||
}
|
||||
|
||||
if (
|
||||
isEmpty(_projectIssueFilters[workspaceSlug].filters) ||
|
||||
isEmpty(_projectIssueFilters[workspaceSlug].displayFilters)
|
||||
) {
|
||||
_projectIssueFilters[workspaceSlug] = {
|
||||
..._projectIssueFilters[workspaceSlug],
|
||||
...issueFilters,
|
||||
};
|
||||
}
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _projectIssueFilters;
|
||||
});
|
||||
|
||||
return issueFilters;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateDisplayFilters = async (
|
||||
workspaceSlug: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
|
||||
) => {
|
||||
try {
|
||||
let _projectIssueFilters = { ...this.projectIssueFilters };
|
||||
if (!_projectIssueFilters) _projectIssueFilters = {};
|
||||
if (!_projectIssueFilters[workspaceSlug])
|
||||
_projectIssueFilters[workspaceSlug] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
|
||||
const _filters = {
|
||||
filters: { ..._projectIssueFilters[workspaceSlug].filters },
|
||||
displayFilters: { ..._projectIssueFilters[workspaceSlug].displayFilters },
|
||||
};
|
||||
|
||||
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
|
||||
else if (type === EFilterType.DISPLAY_FILTERS)
|
||||
_filters.displayFilters = { ..._filters.displayFilters, ...filters };
|
||||
|
||||
// set sub_group_by to null if group_by is set to null
|
||||
if (_filters.displayFilters.group_by === null) _filters.displayFilters.sub_group_by = null;
|
||||
|
||||
// set sub_group_by to null if layout is switched to kanban group_by and sub_group_by are same
|
||||
if (
|
||||
_filters.displayFilters.layout === "kanban" &&
|
||||
_filters.displayFilters.group_by === _filters.displayFilters.sub_group_by
|
||||
)
|
||||
_filters.displayFilters.sub_group_by = null;
|
||||
|
||||
// set group_by to state if layout is switched to kanban and group_by is null
|
||||
if (_filters.displayFilters.layout === "kanban" && _filters.displayFilters.group_by === null)
|
||||
_filters.displayFilters.group_by = "state";
|
||||
|
||||
_projectIssueFilters[workspaceSlug] = {
|
||||
filters: _filters.filters,
|
||||
displayFilters: _filters.displayFilters,
|
||||
displayProperties: _projectIssueFilters[workspaceSlug].displayProperties,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _projectIssueFilters;
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchDisplayProperties = async (workspaceSlug: string) => {
|
||||
try {
|
||||
const displayProperties: IIssueDisplayProperties = {
|
||||
assignee: true,
|
||||
start_date: true,
|
||||
due_date: true,
|
||||
labels: true,
|
||||
key: true,
|
||||
priority: true,
|
||||
state: false,
|
||||
sub_issue_count: true,
|
||||
link: true,
|
||||
attachment_count: false,
|
||||
estimate: false,
|
||||
created_on: false,
|
||||
updated_on: false,
|
||||
};
|
||||
|
||||
let _projectIssueFilters = { ...this.projectIssueFilters };
|
||||
if (!_projectIssueFilters) _projectIssueFilters = {};
|
||||
if (!_projectIssueFilters[workspaceSlug]) {
|
||||
_projectIssueFilters[workspaceSlug] = { filters: {}, displayFilters: {} } as IProjectIssuesDisplayOptions;
|
||||
}
|
||||
if (isEmpty(_projectIssueFilters[workspaceSlug].displayProperties)) {
|
||||
_projectIssueFilters[workspaceSlug] = {
|
||||
..._projectIssueFilters[workspaceSlug],
|
||||
displayProperties: displayProperties,
|
||||
};
|
||||
}
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _projectIssueFilters;
|
||||
});
|
||||
|
||||
return displayProperties;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateDisplayProperties = async (workspaceSlug: string, properties: IIssueDisplayProperties) => {
|
||||
try {
|
||||
let _issueFilters = { ...this.projectIssueFilters };
|
||||
if (!_issueFilters) _issueFilters = {};
|
||||
if (!_issueFilters[workspaceSlug])
|
||||
_issueFilters[workspaceSlug] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
|
||||
const updatedDisplayProperties = { ..._issueFilters[workspaceSlug].displayProperties, ...properties };
|
||||
_issueFilters[workspaceSlug] = { ..._issueFilters[workspaceSlug], displayProperties: updatedDisplayProperties };
|
||||
|
||||
runInAction(() => {
|
||||
this.projectIssueFilters = _issueFilters;
|
||||
});
|
||||
|
||||
return properties;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
get issueFilters() {
|
||||
const workspaceSlug = this.rootStore.workspaceSlug;
|
||||
if (!workspaceSlug) return undefined;
|
||||
const displayFilters = this.issueDisplayFilters(workspaceSlug);
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: displayFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "profile_issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
|
||||
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchFilters = async (workspaceSlug: string) => {
|
||||
try {
|
||||
await this.fetchDisplayFilters(workspaceSlug);
|
||||
await this.fetchDisplayProperties(workspaceSlug);
|
||||
return;
|
||||
} catch (error) {
|
||||
throw Error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => {
|
||||
try {
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.updateDisplayFilters(workspaceSlug, filterType, filters as IIssueFilterOptions);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.updateDisplayFilters(workspaceSlug, filterType, filters as IIssueDisplayFilterOptions);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.updateDisplayProperties(workspaceSlug, filters as IIssueDisplayProperties);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/profile/index.ts
Normal file
2
web/store/issue/profile/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
5
web/store/issue/profile/issue.store.ts
Normal file
5
web/store/issue/profile/issue.store.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IProfileIssues {}
|
||||
|
||||
export class ProfileIssues implements IProfileIssues {
|
||||
constructor() {}
|
||||
}
|
261
web/store/issue/project-views/filter.store.ts
Normal file
261
web/store/issue/project-views/filter.store.ts
Normal file
@ -0,0 +1,261 @@
|
||||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// services
|
||||
import { ProjectService, ProjectMemberService } from "services/project";
|
||||
import { IssueService } from "services/issue";
|
||||
import { ViewService } from "services/view.service";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface IViewIssuesFilterOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
}
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface IProjectViewIssuesFilter {
|
||||
// observable
|
||||
loader: boolean;
|
||||
filters: { [view_id: string]: IViewIssuesFilterOptions } | undefined;
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// actions
|
||||
fetchViewFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise<IIssueFilterOptions>;
|
||||
updateViewFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
viewId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions
|
||||
) => Promise<IViewIssuesFilterOptions | undefined>;
|
||||
|
||||
fetchFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
|
||||
viewId?: string | undefined
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements IProjectViewIssuesFilter {
|
||||
// observables
|
||||
loader: boolean = false;
|
||||
filters: { [projectId: string]: IViewIssuesFilterOptions } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
// services
|
||||
projectService;
|
||||
projectMemberService;
|
||||
issueService;
|
||||
viewService;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
loader: observable.ref,
|
||||
filters: observable.ref,
|
||||
// computed
|
||||
issueFilters: computed,
|
||||
appliedFilters: computed,
|
||||
// actions
|
||||
fetchViewFilters: action,
|
||||
updateViewFilters: action,
|
||||
fetchFilters: action,
|
||||
updateFilters: action,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
|
||||
this.projectService = new ProjectService();
|
||||
this.projectMemberService = new ProjectMemberService();
|
||||
this.issueService = new IssueService();
|
||||
this.viewService = new ViewService();
|
||||
}
|
||||
|
||||
get issueFilters() {
|
||||
const projectId = this.rootStore.projectId;
|
||||
const viewId = this.rootStore.projectViewId;
|
||||
if (!projectId || !viewId) return undefined;
|
||||
|
||||
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
|
||||
const viewFilters = this.filters?.[viewId];
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: viewFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
|
||||
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchViewFilters = async (workspaceSlug: string, projectId: string, viewId: string) => {
|
||||
try {
|
||||
const viewFilters = await this.viewService.getViewDetails(workspaceSlug, projectId, viewId);
|
||||
|
||||
const filters: IIssueFilterOptions = {
|
||||
assignees: viewFilters?.query_data?.assignees || null,
|
||||
mentions: viewFilters?.query_data?.mentions || null,
|
||||
created_by: viewFilters?.query_data?.created_by || null,
|
||||
labels: viewFilters?.query_data?.labels || null,
|
||||
priority: viewFilters?.query_data?.priority || null,
|
||||
project: viewFilters?.query_data?.project || null,
|
||||
start_date: viewFilters?.query_data?.start_date || null,
|
||||
state: viewFilters?.query_data?.state || null,
|
||||
state_group: viewFilters?.query_data?.state_group || null,
|
||||
subscriber: viewFilters?.query_data?.subscriber || null,
|
||||
target_date: viewFilters?.query_data?.target_date || null,
|
||||
};
|
||||
|
||||
const issueFilters: IViewIssuesFilterOptions = {
|
||||
filters: filters,
|
||||
};
|
||||
|
||||
let _filters = { ...this.filters };
|
||||
if (!_filters) _filters = {};
|
||||
if (!_filters[viewId]) _filters[viewId] = { filters: {} };
|
||||
_filters[viewId] = issueFilters;
|
||||
|
||||
runInAction(() => {
|
||||
this.filters = _filters;
|
||||
});
|
||||
|
||||
return filters;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, viewId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateViewFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
viewId: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions
|
||||
) => {
|
||||
if (!viewId) return;
|
||||
try {
|
||||
let _moduleIssueFilters = { ...this.filters };
|
||||
if (!_moduleIssueFilters) _moduleIssueFilters = {};
|
||||
if (!_moduleIssueFilters[viewId]) _moduleIssueFilters[viewId] = { filters: {} };
|
||||
|
||||
const _filters = { filters: { ..._moduleIssueFilters[viewId].filters } };
|
||||
|
||||
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
|
||||
|
||||
_moduleIssueFilters[viewId] = { filters: _filters.filters };
|
||||
|
||||
runInAction(() => {
|
||||
this.filters = _moduleIssueFilters;
|
||||
});
|
||||
|
||||
await this.viewService.patchView(workspaceSlug, projectId, viewId, {
|
||||
query_data: { ..._filters.filters },
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, viewId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, projectId: string, viewId: string) => {
|
||||
try {
|
||||
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
await this.fetchViewFilters(workspaceSlug, projectId, viewId);
|
||||
return;
|
||||
} catch (error) {
|
||||
this.fetchFilters(workspaceSlug, projectId, viewId);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
|
||||
viewId?: string | undefined
|
||||
) => {
|
||||
try {
|
||||
if (!viewId) throw new Error();
|
||||
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.updateViewFilters(workspaceSlug, projectId, viewId, filterType, filters as IIssueFilterOptions);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueDisplayFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.rootStore.issuesFilter.updateDisplayProperties(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filters as IIssueDisplayProperties
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/project-views/index.ts
Normal file
2
web/store/issue/project-views/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
5
web/store/issue/project-views/issue.store.ts
Normal file
5
web/store/issue/project-views/issue.store.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IProjectViewIssues {}
|
||||
|
||||
export class ProjectViewIssues implements IProjectViewIssues {
|
||||
constructor() {}
|
||||
}
|
145
web/store/issue/project/filter.store.ts
Normal file
145
web/store/issue/project/filter.store.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import { computed, makeObservable } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
import { isNil } from "constants/common";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
// constants
|
||||
import { EFilterType } from "constants/issue";
|
||||
|
||||
interface IProjectIssuesFilters {
|
||||
filters: IIssueFilterOptions | undefined;
|
||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||
displayProperties: IIssueDisplayProperties | undefined;
|
||||
}
|
||||
|
||||
export interface IProjectIssuesFilter {
|
||||
// computed
|
||||
issueFilters: IProjectIssuesFilters | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// action
|
||||
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProjectIssuesFilter {
|
||||
// root store
|
||||
rootStore;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// computed
|
||||
issueFilters: computed,
|
||||
appliedFilters: computed,
|
||||
});
|
||||
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
}
|
||||
|
||||
get issueFilters() {
|
||||
const projectId = this.rootStore.projectId;
|
||||
if (!projectId) return undefined;
|
||||
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
|
||||
|
||||
const _filters: IProjectIssuesFilters = {
|
||||
filters: displayFilters?.filters,
|
||||
displayFilters: displayFilters?.displayFilters,
|
||||
displayProperties: displayFilters?.displayProperties,
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
|
||||
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
||||
try {
|
||||
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
|
||||
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
|
||||
return;
|
||||
} catch (error) {
|
||||
throw Error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => {
|
||||
try {
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.rootStore.issuesFilter.updateDisplayFilters(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filterType,
|
||||
filters as IIssueDisplayFilterOptions
|
||||
);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.rootStore.issuesFilter.updateDisplayProperties(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
filters as IIssueDisplayProperties
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/project/index.ts
Normal file
2
web/store/issue/project/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
213
web/store/issue/project/issue.store.ts
Normal file
213
web/store/issue/project/issue.store.ts
Normal file
@ -0,0 +1,213 @@
|
||||
import { action, makeObservable, observable, runInAction, computed } from "mobx";
|
||||
// base class
|
||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
||||
// store
|
||||
import { IIssueRootStore } from "../root.store";
|
||||
// services
|
||||
import { IssueService } from "services/issue/issue.service";
|
||||
// types
|
||||
import {
|
||||
IGroupedIssues,
|
||||
IIssue,
|
||||
IIssueResponse,
|
||||
ISubGroupedIssues,
|
||||
TIssueGroupByOptions,
|
||||
TLoader,
|
||||
TUnGroupedIssues,
|
||||
} from "types";
|
||||
|
||||
export interface IProjectIssues {
|
||||
loader: TLoader;
|
||||
issues: { [project_id: string]: string[] };
|
||||
// computed
|
||||
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
|
||||
// action
|
||||
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<IIssueResponse>;
|
||||
createIssue: (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => Promise<IIssue>;
|
||||
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => Promise<IIssue>;
|
||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<IIssue>;
|
||||
quickAddIssue: (workspaceSlug: string, projectId: string, data: IIssue) => Promise<IIssue>;
|
||||
}
|
||||
|
||||
export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
||||
// observable
|
||||
loader: TLoader = "init-loader";
|
||||
issues: { [project_id: string]: string[] } = {};
|
||||
// services
|
||||
issueService;
|
||||
// root store
|
||||
rootIssueStore: IIssueRootStore;
|
||||
|
||||
constructor(_rootStore: IIssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observable
|
||||
loader: observable.ref,
|
||||
issues: observable,
|
||||
// computed
|
||||
getIssuesIds: computed,
|
||||
// action
|
||||
fetchIssues: action,
|
||||
createIssue: action,
|
||||
updateIssue: action,
|
||||
removeIssue: action,
|
||||
quickAddIssue: action,
|
||||
});
|
||||
|
||||
// services
|
||||
this.issueService = new IssueService();
|
||||
// root store
|
||||
this.rootIssueStore = _rootStore;
|
||||
}
|
||||
|
||||
get getIssues() {
|
||||
const projectId = this.rootStore?.projectId;
|
||||
if (!projectId) return undefined;
|
||||
|
||||
const _issues = this.rootStore.issues.getIssuesByProject(projectId);
|
||||
if (!_issues) return undefined;
|
||||
|
||||
return _issues;
|
||||
}
|
||||
|
||||
get getIssuesIds() {
|
||||
const displayFilters = this.rootStore?.projectIssuesFilter?.issueFilters?.displayFilters;
|
||||
if (!displayFilters) return undefined;
|
||||
|
||||
const subGroupBy = displayFilters?.sub_group_by;
|
||||
const groupBy = displayFilters?.group_by;
|
||||
const orderBy = displayFilters?.order_by;
|
||||
const layout = displayFilters?.layout;
|
||||
|
||||
const _issues = this.getIssues;
|
||||
if (!_issues) return undefined;
|
||||
|
||||
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
|
||||
|
||||
if (layout === "list" && orderBy) {
|
||||
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, _issues);
|
||||
else issues = this.unGroupedIssues(orderBy, _issues);
|
||||
} else if (layout === "kanban" && groupBy && orderBy) {
|
||||
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, _issues);
|
||||
else issues = this.groupedIssues(groupBy, orderBy, _issues);
|
||||
} else if (layout === "calendar")
|
||||
issues = this.groupedIssues("target_date" as TIssueGroupByOptions, "target_date", _issues, true);
|
||||
else if (layout === "spreadsheet") issues = this.unGroupedIssues(orderBy ?? "-created_at", _issues);
|
||||
else if (layout === "gantt_chart") issues = this.unGroupedIssues(orderBy ?? "sort_order", _issues);
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
|
||||
try {
|
||||
this.loader = loadType;
|
||||
|
||||
const params = this.rootStore?.projectIssuesFilter?.appliedFilters;
|
||||
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||
|
||||
const _issues = { ...this.issues, [projectId]: Object.keys(response) };
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
this.loader = undefined;
|
||||
});
|
||||
|
||||
this.rootStore.issues.addIssue(Object.values(response));
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.loader = undefined;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => {
|
||||
try {
|
||||
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
|
||||
|
||||
let _issues = this.issues;
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[projectId]) _issues[projectId] = [];
|
||||
_issues[projectId] = [..._issues[projectId], response.id];
|
||||
this.rootStore.issues.addIssue([response]);
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => {
|
||||
try {
|
||||
this.rootStore.issues.updateIssue(issueId, data);
|
||||
const response = await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||
try {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[projectId]) _issues[projectId] = [];
|
||||
_issues[projectId] = _issues?.[projectId].filter((id) => id !== issueId);
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
this.rootStore.issues.removeIssue(issueId);
|
||||
const response = await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
quickAddIssue = async (workspaceSlug: string, projectId: string, data: IIssue) => {
|
||||
try {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[projectId]) _issues[projectId] = [];
|
||||
|
||||
_issues[projectId] = [..._issues[projectId], data.id];
|
||||
this.rootStore.issues.updateIssue(data.id, data);
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
|
||||
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
|
||||
|
||||
if (this.issues) {
|
||||
let _issues = { ...this.issues };
|
||||
if (!_issues) _issues = {};
|
||||
if (!_issues[projectId]) _issues[projectId] = [];
|
||||
|
||||
_issues[projectId] = [..._issues[projectId].filter((issueId) => issueId != data.id), response.id];
|
||||
this.rootStore.issues.removeIssue(data.id);
|
||||
this.rootStore.issues.addIssue([response]);
|
||||
|
||||
runInAction(() => {
|
||||
this.issues = _issues;
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
164
web/store/issue/root.store.ts
Normal file
164
web/store/issue/root.store.ts
Normal file
@ -0,0 +1,164 @@
|
||||
import { autorun, makeObservable, observable } from "mobx";
|
||||
// root store
|
||||
import { RootStore } from "../root.store";
|
||||
// issues data store
|
||||
import { IIssueStore, IssueStore } from "./issue.store";
|
||||
// issues filter base store
|
||||
import { IIssuesFilter, IssuesFilter } from "./base-issue-filter.store";
|
||||
import { IWorkspaceIssuesFilter, WorkspaceIssuesFilter, IWorkspaceIssues, WorkspaceIssues } from "./workspace";
|
||||
import { IProfileIssuesFilter, ProfileIssuesFilter, IProfileIssues, ProfileIssues } from "./profile";
|
||||
import { IProjectIssuesFilter, ProjectIssuesFilter, IProjectIssues, ProjectIssues } from "./project";
|
||||
import { ICycleIssuesFilter, CycleIssuesFilter, ICycleIssues, CycleIssues } from "./cycle";
|
||||
import { IModuleIssuesFilter, ModuleIssuesFilter, IModuleIssues, ModuleIssues } from "./module";
|
||||
import {
|
||||
IProjectViewIssuesFilter,
|
||||
ProjectViewIssuesFilter,
|
||||
IProjectViewIssues,
|
||||
ProjectViewIssues,
|
||||
} from "./project-views";
|
||||
import { IArchivedIssuesFilter, ArchivedIssuesFilter, IArchivedIssues, ArchivedIssues } from "./archived";
|
||||
import { IDraftIssuesFilter, DraftIssuesFilter, IDraftIssues, DraftIssues } from "./draft";
|
||||
|
||||
export interface IIssueRootStore {
|
||||
currentUserId: string | undefined;
|
||||
workspaceSlug: string | undefined;
|
||||
profileView: string | undefined;
|
||||
projectId: string | undefined;
|
||||
cycleId: string | undefined;
|
||||
moduleId: string | undefined;
|
||||
projectViewId: string | undefined;
|
||||
states: any | undefined;
|
||||
labels: any | undefined;
|
||||
members: any | undefined;
|
||||
projects: any | undefined;
|
||||
|
||||
issues: IIssueStore;
|
||||
|
||||
issuesFilter: IIssuesFilter;
|
||||
|
||||
workspaceIssuesFilter: IWorkspaceIssuesFilter;
|
||||
workspaceIssues: IWorkspaceIssues;
|
||||
|
||||
profileIssuesFilter: IProfileIssuesFilter;
|
||||
profileIssues: IProfileIssues;
|
||||
|
||||
projectIssuesFilter: IProjectIssuesFilter;
|
||||
projectIssues: IProjectIssues;
|
||||
|
||||
cycleIssuesFilter: ICycleIssuesFilter;
|
||||
cycleIssues: ICycleIssues;
|
||||
|
||||
moduleIssuesFilter: IModuleIssuesFilter;
|
||||
moduleIssues: IModuleIssues;
|
||||
|
||||
projectViewIssuesFilter: IProjectViewIssuesFilter;
|
||||
projectViewIssues: IProjectViewIssues;
|
||||
|
||||
archivedIssuesFilter: IArchivedIssuesFilter;
|
||||
archivedIssues: IArchivedIssues;
|
||||
|
||||
draftIssuesFilter: IDraftIssuesFilter;
|
||||
draftIssues: IDraftIssues;
|
||||
}
|
||||
|
||||
export class IssueRootStore {
|
||||
currentUserId: string | undefined = undefined;
|
||||
workspaceSlug: string | undefined = undefined;
|
||||
projectId: string | undefined = undefined;
|
||||
cycleId: string | undefined = undefined;
|
||||
moduleId: string | undefined = undefined;
|
||||
projectViewId: string | undefined = undefined;
|
||||
profileView: string | undefined = undefined;
|
||||
states: any | undefined = undefined;
|
||||
labels: any | undefined = undefined;
|
||||
members: any | undefined = undefined;
|
||||
projects: any | undefined = undefined;
|
||||
|
||||
issues: IIssueStore;
|
||||
|
||||
issuesFilter: IIssuesFilter;
|
||||
|
||||
workspaceIssuesFilter: IWorkspaceIssuesFilter;
|
||||
workspaceIssues: IWorkspaceIssues;
|
||||
|
||||
profileIssuesFilter: IProfileIssuesFilter;
|
||||
profileIssues: IProfileIssues;
|
||||
|
||||
projectIssuesFilter: IProjectIssuesFilter;
|
||||
projectIssues: IProjectIssues;
|
||||
|
||||
cycleIssuesFilter: ICycleIssuesFilter;
|
||||
cycleIssues: ICycleIssues;
|
||||
|
||||
moduleIssuesFilter: IModuleIssuesFilter;
|
||||
moduleIssues: IModuleIssues;
|
||||
|
||||
projectViewIssuesFilter: IProjectViewIssuesFilter;
|
||||
projectViewIssues: IProjectViewIssues;
|
||||
|
||||
archivedIssuesFilter: IArchivedIssuesFilter;
|
||||
archivedIssues: IArchivedIssues;
|
||||
|
||||
draftIssuesFilter: IDraftIssuesFilter;
|
||||
draftIssues: IDraftIssues;
|
||||
|
||||
constructor(rootStore: RootStore) {
|
||||
makeObservable(this, {
|
||||
currentUserId: observable.ref,
|
||||
workspaceSlug: observable.ref,
|
||||
projectId: observable.ref,
|
||||
cycleId: observable.ref,
|
||||
moduleId: observable.ref,
|
||||
projectViewId: observable.ref,
|
||||
profileView: observable.ref,
|
||||
states: observable,
|
||||
labels: observable,
|
||||
members: observable,
|
||||
projects: observable,
|
||||
});
|
||||
|
||||
autorun(() => {
|
||||
if (rootStore?.user?.currentUser?.id) this.currentUserId = rootStore?.user?.currentUser?.id;
|
||||
if (rootStore?.workspace?.currentWorkspace?.slug)
|
||||
this.workspaceSlug = rootStore?.workspace?.currentWorkspace?.slug;
|
||||
if (rootStore?.project?.projects?.projectId) this.projectId = rootStore?.project?.projects?.projectId;
|
||||
if (rootStore?.cycle?.cycleId) this.cycleId = rootStore?.cycle?.cycleId;
|
||||
if (rootStore?.module?.moduleId) this.moduleId = rootStore?.module?.moduleId;
|
||||
if (rootStore?.projectView?.viewId) this.projectViewId = rootStore?.projectView?.viewId;
|
||||
|
||||
// if (rootStore?.workspace?.profileView) this.profileView = rootStore?.workspace?.profileView;
|
||||
// if (rootStore?.states) this.states = rootStore?.states;
|
||||
// if (rootStore?.labels) this.labels = rootStore?.labels;
|
||||
// if (rootStore?.members) this.members = rootStore?.members;
|
||||
// if (rootStore?.projects) this.projects = rootStore?.projects;
|
||||
});
|
||||
|
||||
this.issues = new IssueStore(this);
|
||||
|
||||
this.issuesFilter = new IssuesFilter(this);
|
||||
|
||||
this.workspaceIssuesFilter = new WorkspaceIssuesFilter(this);
|
||||
this.workspaceIssues = new WorkspaceIssues();
|
||||
|
||||
this.profileIssuesFilter = new ProfileIssuesFilter(this);
|
||||
this.profileIssues = new ProfileIssues();
|
||||
|
||||
this.projectIssuesFilter = new ProjectIssuesFilter(this);
|
||||
this.projectIssues = new ProjectIssues(this);
|
||||
|
||||
this.cycleIssuesFilter = new CycleIssuesFilter(this);
|
||||
this.cycleIssues = new CycleIssues(this);
|
||||
|
||||
this.moduleIssuesFilter = new ModuleIssuesFilter(this);
|
||||
this.moduleIssues = new ModuleIssues();
|
||||
|
||||
this.projectViewIssuesFilter = new ProjectViewIssuesFilter(this);
|
||||
this.projectViewIssues = new ProjectViewIssues();
|
||||
|
||||
this.archivedIssuesFilter = new ArchivedIssuesFilter(this);
|
||||
this.archivedIssues = new ArchivedIssues();
|
||||
|
||||
this.draftIssuesFilter = new DraftIssuesFilter(this);
|
||||
this.draftIssues = new DraftIssues();
|
||||
}
|
||||
}
|
434
web/store/issue/workspace/filter.store.ts
Normal file
434
web/store/issue/workspace/filter.store.ts
Normal file
@ -0,0 +1,434 @@
|
||||
import { action, makeObservable, observable, runInAction } from "mobx";
|
||||
// base class
|
||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// helpers
|
||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||
// constants
|
||||
import { isNil } from "constants/common";
|
||||
import { EFilterType } from "constants/issue";
|
||||
// types
|
||||
import { IssueRootStore } from "../root.store";
|
||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
|
||||
|
||||
interface IIssuesDisplayOptions {
|
||||
filters: IIssueFilterOptions;
|
||||
}
|
||||
|
||||
type TIssueViewTypes = "all-issues" | "assigned" | "created" | "subscribed" | string;
|
||||
|
||||
interface IIssueViewOptions {
|
||||
"all-issues": IIssuesDisplayOptions;
|
||||
assigned: IIssuesDisplayOptions;
|
||||
created: IIssuesDisplayOptions;
|
||||
subscribed: IIssuesDisplayOptions;
|
||||
[view_id: string]: IIssuesDisplayOptions;
|
||||
}
|
||||
|
||||
interface IWorkspaceProperties {
|
||||
filters: IIssueFilterOptions;
|
||||
displayFilters: IIssueDisplayFilterOptions;
|
||||
displayProperties: IIssueDisplayProperties;
|
||||
}
|
||||
|
||||
export interface IWorkspaceIssuesFilter {
|
||||
// observables
|
||||
currentView: TIssueViewTypes;
|
||||
workspaceProperties: { [workspaceId: string]: IWorkspaceProperties } | undefined;
|
||||
workspaceViewFilters: { [workspaceId: string]: IIssueViewOptions } | undefined;
|
||||
// computed
|
||||
issueFilters: IWorkspaceProperties | undefined;
|
||||
appliedFilters: TIssueParams[] | undefined;
|
||||
// helpers
|
||||
issueDisplayFilters: (workspaceId: string) => IIssuesDisplayOptions | undefined;
|
||||
// actions
|
||||
setCurrentView: (view: TIssueViewTypes) => void;
|
||||
fetchWorkspaceProperties: (workspaceSlug: string) => Promise<IWorkspaceProperties>;
|
||||
updateWorkspaceProperties: (
|
||||
workspaceSlug: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => Promise<IWorkspaceProperties>;
|
||||
|
||||
fetchWorkspaceViewFilters: (workspaceId: string, view: TIssueViewTypes) => Promise<IIssueFilterOptions>;
|
||||
updateWorkspaceViewFilters: (workspaceId: string, filters: IIssueFilterOptions) => Promise<IIssueFilterOptions>;
|
||||
|
||||
fetchFilters: (workspaceSlug: string, view: TIssueViewTypes) => Promise<void>;
|
||||
updateFilters: (
|
||||
workspaceSlug: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => Promise<void>;
|
||||
}
|
||||
|
||||
export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWorkspaceIssuesFilter {
|
||||
// observables
|
||||
currentView: TIssueViewTypes = "all-issues";
|
||||
workspaceProperties: { [workspaceId: string]: IWorkspaceProperties } | undefined = undefined;
|
||||
workspaceViewFilters: { [workspaceId: string]: IIssueViewOptions } | undefined = undefined;
|
||||
// root store
|
||||
rootStore;
|
||||
// service
|
||||
workspaceService;
|
||||
|
||||
constructor(_rootStore: IssueRootStore) {
|
||||
super(_rootStore);
|
||||
|
||||
makeObservable(this, {
|
||||
// observables
|
||||
currentView: observable.ref,
|
||||
workspaceProperties: observable.ref,
|
||||
workspaceViewFilters: observable.ref,
|
||||
// computed
|
||||
// actions
|
||||
setCurrentView: action,
|
||||
fetchWorkspaceProperties: action,
|
||||
updateWorkspaceProperties: action,
|
||||
fetchWorkspaceViewFilters: action,
|
||||
updateWorkspaceViewFilters: action,
|
||||
});
|
||||
// root store
|
||||
this.rootStore = _rootStore;
|
||||
// services
|
||||
this.workspaceService = new WorkspaceService();
|
||||
}
|
||||
|
||||
// computed
|
||||
|
||||
// helpers
|
||||
issueDisplayFilters = (workspaceId: string) => {
|
||||
if (!workspaceId || !this.currentView) return undefined;
|
||||
const filters: IWorkspaceProperties = {
|
||||
filters: this.workspaceProperties?.[workspaceId]?.filters || {},
|
||||
displayFilters: this.workspaceProperties?.[workspaceId]?.displayFilters || {},
|
||||
displayProperties: this.workspaceProperties?.[workspaceId]?.displayProperties || {},
|
||||
};
|
||||
|
||||
if (!["all-issues", "assigned", "created", "subscribed"].includes(this.currentView)) {
|
||||
const viewFilters = this.workspaceViewFilters?.[workspaceId]?.[this.currentView];
|
||||
if (viewFilters) {
|
||||
filters.filters = { ...filters.filters, ...viewFilters?.filters };
|
||||
}
|
||||
}
|
||||
|
||||
return filters;
|
||||
};
|
||||
|
||||
// actions
|
||||
setCurrentView = (view: TIssueViewTypes) => {
|
||||
this.currentView = view;
|
||||
};
|
||||
|
||||
fetchWorkspaceProperties = async (workspaceSlug: string) => {
|
||||
try {
|
||||
let _filters: IWorkspaceProperties = {} as IWorkspaceProperties;
|
||||
|
||||
const filtersResponse = await this.workspaceService.workspaceMemberMe(workspaceSlug);
|
||||
_filters = {
|
||||
filters: { ...filtersResponse?.view_props?.filters } || null,
|
||||
displayFilters: { ...filtersResponse?.view_props?.display_filters } || null,
|
||||
displayProperties: { ...filtersResponse?.view_props?.display_properties } || null,
|
||||
};
|
||||
|
||||
let filters: IIssueFilterOptions = {
|
||||
assignees: _filters?.filters?.assignees || null,
|
||||
mentions: _filters?.filters?.mentions || null,
|
||||
created_by: _filters?.filters?.created_by || null,
|
||||
labels: _filters?.filters?.labels || null,
|
||||
priority: _filters?.filters?.priority || null,
|
||||
project: _filters?.filters?.project || null,
|
||||
start_date: _filters?.filters?.start_date || null,
|
||||
state: _filters?.filters?.state || null,
|
||||
state_group: _filters?.filters?.state_group || null,
|
||||
subscriber: _filters?.filters?.subscriber || null,
|
||||
target_date: _filters?.filters?.target_date || null,
|
||||
};
|
||||
|
||||
const currentUserId = this.rootStore.currentUserId;
|
||||
if (currentUserId && this.currentView === "assigned")
|
||||
filters = {
|
||||
...filters,
|
||||
assignees: [currentUserId],
|
||||
created_by: null,
|
||||
subscriber: null,
|
||||
};
|
||||
|
||||
if (currentUserId && this.currentView === "created")
|
||||
filters = {
|
||||
...filters,
|
||||
assignees: null,
|
||||
created_by: [currentUserId],
|
||||
subscriber: null,
|
||||
};
|
||||
if (currentUserId && this.currentView === "subscribed")
|
||||
filters = {
|
||||
...filters,
|
||||
assignees: null,
|
||||
created_by: null,
|
||||
subscriber: [currentUserId],
|
||||
};
|
||||
|
||||
const displayFilters: IIssueDisplayFilterOptions = {
|
||||
calendar: {
|
||||
show_weekends: _filters?.displayFilters?.calendar?.show_weekends || false,
|
||||
layout: _filters?.displayFilters?.calendar?.layout || "month",
|
||||
},
|
||||
group_by: _filters?.displayFilters?.group_by || null,
|
||||
sub_group_by: _filters?.displayFilters?.sub_group_by || null,
|
||||
layout: _filters?.displayFilters?.layout || "list",
|
||||
order_by: _filters?.displayFilters?.order_by || "-created_at",
|
||||
show_empty_groups: _filters?.displayFilters?.show_empty_groups || false,
|
||||
start_target_date: _filters?.displayFilters?.start_target_date || false,
|
||||
sub_issue: _filters?.displayFilters?.sub_issue || false,
|
||||
type: _filters?.displayFilters?.type || null,
|
||||
};
|
||||
|
||||
const displayProperties: IIssueDisplayProperties = {
|
||||
assignee: _filters?.displayProperties?.assignee || false,
|
||||
start_date: _filters?.displayProperties?.start_date || false,
|
||||
due_date: _filters?.displayProperties?.due_date || false,
|
||||
labels: _filters?.displayProperties?.labels || false,
|
||||
key: _filters?.displayProperties?.key || false,
|
||||
priority: _filters?.displayProperties?.priority || false,
|
||||
state: _filters?.displayProperties?.state || false,
|
||||
sub_issue_count: _filters?.displayProperties?.sub_issue_count || false,
|
||||
link: _filters?.displayProperties?.link || false,
|
||||
attachment_count: _filters?.displayProperties?.attachment_count || false,
|
||||
estimate: _filters?.displayProperties?.estimate || false,
|
||||
created_on: _filters?.displayProperties?.created_on || false,
|
||||
updated_on: _filters?.displayProperties?.updated_on || false,
|
||||
};
|
||||
|
||||
const issueFilters: IWorkspaceProperties = {
|
||||
filters: filters,
|
||||
displayFilters: displayFilters,
|
||||
displayProperties: displayProperties,
|
||||
};
|
||||
|
||||
let _workspaceProperties = { ...this.workspaceProperties };
|
||||
if (!_workspaceProperties) _workspaceProperties = {};
|
||||
if (!_workspaceProperties[workspaceSlug])
|
||||
_workspaceProperties[workspaceSlug] = {
|
||||
filters: {},
|
||||
displayFilters: {},
|
||||
displayProperties: {},
|
||||
};
|
||||
_workspaceProperties[workspaceSlug] = { ...issueFilters };
|
||||
|
||||
runInAction(() => {
|
||||
this.workspaceProperties = _workspaceProperties;
|
||||
});
|
||||
|
||||
return issueFilters;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateWorkspaceProperties = async (
|
||||
workspaceSlug: string,
|
||||
type: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => {
|
||||
try {
|
||||
let _workspaceProperties = { ...this.workspaceProperties };
|
||||
if (!_workspaceProperties) _workspaceProperties = {};
|
||||
if (!_workspaceProperties[workspaceSlug])
|
||||
_workspaceProperties[workspaceSlug] = { filters: {}, displayFilters: {}, displayProperties: {} };
|
||||
|
||||
const _filters = {
|
||||
filters: { ..._workspaceProperties[workspaceSlug].filters },
|
||||
displayFilters: { ..._workspaceProperties[workspaceSlug].displayFilters },
|
||||
displayProperties: { ..._workspaceProperties[workspaceSlug].displayProperties },
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case EFilterType.FILTERS:
|
||||
_filters.filters = { ..._filters.filters, ...(filters as IIssueFilterOptions) };
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
_filters.displayFilters = { ..._filters.displayFilters, ...(filters as IIssueDisplayFilterOptions) };
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
_filters.displayProperties = { ..._filters.displayProperties, ...(filters as IIssueDisplayProperties) };
|
||||
break;
|
||||
}
|
||||
|
||||
_workspaceProperties[workspaceSlug] = {
|
||||
..._workspaceProperties[workspaceSlug],
|
||||
filters: _filters?.filters,
|
||||
displayFilters: _filters?.displayFilters,
|
||||
displayProperties: _filters?.displayProperties,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.workspaceProperties = _workspaceProperties;
|
||||
});
|
||||
|
||||
await this.workspaceService.updateWorkspaceView(workspaceSlug, {
|
||||
view_props: {
|
||||
filters: _filters.filters,
|
||||
display_filters: _filters.displayFilters,
|
||||
display_properties: _filters.displayProperties,
|
||||
},
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
this.fetchWorkspaceProperties(workspaceSlug);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
fetchWorkspaceViewFilters = async (workspaceSlug: string, view: TIssueViewTypes) => {
|
||||
try {
|
||||
let _workspaceViewFilters = { ...this.workspaceViewFilters };
|
||||
if (!_workspaceViewFilters) _workspaceViewFilters = {};
|
||||
if (!_workspaceViewFilters[workspaceSlug]) _workspaceViewFilters[workspaceSlug] = {} as IIssueViewOptions;
|
||||
if (!_workspaceViewFilters[workspaceSlug][view]) _workspaceViewFilters[workspaceSlug][view] = { filters: {} };
|
||||
|
||||
const filtersResponse = await this.workspaceService.getViewDetails(workspaceSlug, view);
|
||||
|
||||
const _filters: IIssueFilterOptions = {
|
||||
assignees: filtersResponse?.query_data?.filters?.assignees || null,
|
||||
mentions: filtersResponse?.query_data?.filters?.mentions || null,
|
||||
created_by: filtersResponse?.query_data?.filters?.created_by || null,
|
||||
labels: filtersResponse?.query_data?.filters?.labels || null,
|
||||
priority: filtersResponse?.query_data?.filters?.priority || null,
|
||||
project: filtersResponse?.query_data?.filters?.project || null,
|
||||
start_date: filtersResponse?.query_data?.filters?.start_date || null,
|
||||
state: filtersResponse?.query_data?.filters?.state || null,
|
||||
state_group: filtersResponse?.query_data?.filters?.state_group || null,
|
||||
subscriber: filtersResponse?.query_data?.filters?.subscriber || null,
|
||||
target_date: filtersResponse?.query_data?.filters?.target_date || null,
|
||||
};
|
||||
|
||||
_workspaceViewFilters[workspaceSlug][view].filters = { ..._filters };
|
||||
|
||||
runInAction(() => {
|
||||
this.workspaceViewFilters = _workspaceViewFilters;
|
||||
});
|
||||
|
||||
return _filters;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
updateWorkspaceViewFilters = async (workspaceSlug: string, filters: IIssueFilterOptions) => {
|
||||
try {
|
||||
let _workspaceViewFilters = { ...this.workspaceViewFilters };
|
||||
if (!_workspaceViewFilters) _workspaceViewFilters = {};
|
||||
if (!_workspaceViewFilters[workspaceSlug]) _workspaceViewFilters[workspaceSlug] = {} as IIssueViewOptions;
|
||||
if (!_workspaceViewFilters[workspaceSlug][this.currentView])
|
||||
_workspaceViewFilters[workspaceSlug][this.currentView] = { filters: {} };
|
||||
|
||||
const _filters = {
|
||||
filters: { ..._workspaceViewFilters[workspaceSlug][this.currentView].filters, ...filters },
|
||||
};
|
||||
|
||||
_workspaceViewFilters[workspaceSlug][this.currentView] = {
|
||||
..._workspaceViewFilters[workspaceSlug][this.currentView],
|
||||
filters: _filters?.filters,
|
||||
};
|
||||
|
||||
runInAction(() => {
|
||||
this.workspaceViewFilters = _workspaceViewFilters;
|
||||
});
|
||||
|
||||
await this.workspaceService.updateView(workspaceSlug, this.currentView, {
|
||||
query_data: {
|
||||
filters: _filters.filters,
|
||||
} as any,
|
||||
});
|
||||
|
||||
return _filters.filters;
|
||||
} catch (error) {
|
||||
this.fetchWorkspaceViewFilters(workspaceSlug, this.currentView);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
get issueFilters() {
|
||||
const workspaceSlug = this.rootStore.workspaceSlug;
|
||||
if (!workspaceSlug) return undefined;
|
||||
const displayFilters = this.issueDisplayFilters(workspaceSlug);
|
||||
|
||||
const _filters: IWorkspaceProperties = {
|
||||
filters: displayFilters?.filters || {},
|
||||
displayFilters: displayFilters?.displayFilters || {},
|
||||
displayProperties: displayFilters?.displayProperties || {},
|
||||
};
|
||||
|
||||
return _filters;
|
||||
}
|
||||
|
||||
get appliedFilters() {
|
||||
const userFilters = this.issueFilters;
|
||||
if (!userFilters) return undefined;
|
||||
|
||||
let filteredRouteParams: any = {
|
||||
priority: userFilters?.filters?.priority || undefined,
|
||||
project: userFilters?.filters?.project || undefined,
|
||||
state_group: userFilters?.filters?.state_group || undefined,
|
||||
state: userFilters?.filters?.state || undefined,
|
||||
assignees: userFilters?.filters?.assignees || undefined,
|
||||
mentions: userFilters?.filters?.mentions || undefined,
|
||||
created_by: userFilters?.filters?.created_by || undefined,
|
||||
labels: userFilters?.filters?.labels || undefined,
|
||||
start_date: userFilters?.filters?.start_date || undefined,
|
||||
target_date: userFilters?.filters?.target_date || undefined,
|
||||
type: userFilters?.displayFilters?.type || undefined,
|
||||
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
|
||||
? true
|
||||
: userFilters?.displayFilters?.show_empty_groups,
|
||||
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
|
||||
? true
|
||||
: userFilters?.displayFilters?.start_target_date,
|
||||
sub_issue: false,
|
||||
};
|
||||
|
||||
const filteredParams = handleIssueQueryParamsByLayout("spreadsheet", "my_issues");
|
||||
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||
|
||||
return filteredRouteParams;
|
||||
}
|
||||
|
||||
fetchFilters = async (workspaceSlug: string, view: TIssueViewTypes) => {
|
||||
try {
|
||||
await this.fetchWorkspaceProperties(workspaceSlug);
|
||||
if (!["all-issues", "assigned", "created", "subscribed"].includes(view))
|
||||
await this.fetchWorkspaceViewFilters(workspaceSlug, view);
|
||||
return;
|
||||
} catch (error) {
|
||||
throw Error;
|
||||
}
|
||||
};
|
||||
|
||||
updateFilters = async (
|
||||
workspaceSlug: string,
|
||||
filterType: EFilterType,
|
||||
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
|
||||
) => {
|
||||
try {
|
||||
switch (filterType) {
|
||||
case EFilterType.FILTERS:
|
||||
if (["all-issues", "assigned", "created", "subscribed"].includes(this.currentView))
|
||||
await this.updateWorkspaceProperties(workspaceSlug, filterType, filters as IIssueDisplayFilterOptions);
|
||||
else await this.updateWorkspaceViewFilters(workspaceSlug, filters as IIssueFilterOptions);
|
||||
break;
|
||||
case EFilterType.DISPLAY_FILTERS:
|
||||
await this.updateWorkspaceProperties(workspaceSlug, filterType, filters as IIssueDisplayFilterOptions);
|
||||
break;
|
||||
case EFilterType.DISPLAY_PROPERTIES:
|
||||
await this.updateWorkspaceProperties(workspaceSlug, filterType, filters as IIssueDisplayProperties);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
2
web/store/issue/workspace/index.ts
Normal file
2
web/store/issue/workspace/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./filter.store";
|
||||
export * from "./issue.store";
|
5
web/store/issue/workspace/issue.store.ts
Normal file
5
web/store/issue/workspace/issue.store.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface IWorkspaceIssues {}
|
||||
|
||||
export class WorkspaceIssues implements IWorkspaceIssues {
|
||||
constructor() {}
|
||||
}
|
@ -8,6 +8,7 @@ import { IModuleStore, ModulesStore } from "./module.store";
|
||||
import { IUserStore, UserStore } from "./user";
|
||||
import { ILabelStore, LabelStore } from "./label.store";
|
||||
import { IWorkspaceRootStore, WorkspaceRootStore } from "./workspace";
|
||||
import { IssueRootStore, IIssueRootStore } from "./issue/root.store";
|
||||
|
||||
enableStaticRendering(typeof window === "undefined");
|
||||
|
||||
@ -20,9 +21,10 @@ export class RootStore {
|
||||
module: IModuleStore;
|
||||
projectView: IProjectViewsStore;
|
||||
label: ILabelStore;
|
||||
issue: IIssueRootStore;
|
||||
|
||||
constructor() {
|
||||
this.app = new AppRootStore(this);
|
||||
this.app = new AppRootStore();
|
||||
this.user = new UserStore(this);
|
||||
this.workspace = new WorkspaceRootStore(this);
|
||||
this.project = new ProjectRootStore(this);
|
||||
@ -30,9 +32,9 @@ export class RootStore {
|
||||
this.module = new ModulesStore(this);
|
||||
this.projectView = new ProjectViewsStore(this);
|
||||
// this.page = new PageRootStore();
|
||||
// this.issue = new IssueRootStore();
|
||||
// independent stores
|
||||
this.label = new LabelStore(this);
|
||||
// this.state = new stateStore();
|
||||
this.issue = new IssueRootStore(this);
|
||||
}
|
||||
}
|
||||
|
18
web/types/issues.d.ts
vendored
18
web/types/issues.d.ts
vendored
@ -254,3 +254,21 @@ export interface IIssueViewProps {
|
||||
}
|
||||
|
||||
export type TIssuePriorities = "urgent" | "high" | "medium" | "low" | "none";
|
||||
|
||||
export type TLoader = "init-loader" | "mutation" | undefined;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -2790,7 +2790,7 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^18.2.39", "@types/react@^18.2.42":
|
||||
"@types/react@*", "@types/react@18.2.42", "@types/react@^18.2.39", "@types/react@^18.2.42":
|
||||
version "18.2.42"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.42.tgz#6f6b11a904f6d96dda3c2920328a97011a00aba7"
|
||||
integrity sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==
|
||||
|
Loading…
Reference in New Issue
Block a user