mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
make store changes for pagination
This commit is contained in:
parent
425b36e391
commit
026bc9318f
16
packages/types/src/issues/base.d.ts
vendored
16
packages/types/src/issues/base.d.ts
vendored
@ -1,3 +1,6 @@
|
|||||||
|
import { StateGroup } from "components/states";
|
||||||
|
import { TIssuePriorities } from "../issues";
|
||||||
|
|
||||||
// issues
|
// issues
|
||||||
export * from "./issue";
|
export * from "./issue";
|
||||||
export * from "./issue_reaction";
|
export * from "./issue_reaction";
|
||||||
@ -7,16 +10,17 @@ export * from "./issue_relation";
|
|||||||
export * from "./issue_sub_issues";
|
export * from "./issue_sub_issues";
|
||||||
export * from "./activity/base";
|
export * from "./activity/base";
|
||||||
|
|
||||||
export type TLoader = "init-loader" | "mutation" | undefined;
|
export type TLoader = "init-loader" | "mutation" | "pagination" | undefined;
|
||||||
|
|
||||||
export type TGroupedIssues = {
|
export type TGroupedIssues = {
|
||||||
[group_id: string]: string[];
|
[group_id: string]: { issueIds: string[]; issueCount: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSubGroupedIssues = {
|
export type TSubGroupedIssues = {
|
||||||
[sub_grouped_id: string]: {
|
[sub_grouped_id: string]: TGroupedIssues;
|
||||||
[group_id: string]: string[];
|
};
|
||||||
};
|
export type TUnGroupedIssues = {
|
||||||
|
"All Issues": { issueIds: string[]; issueCount: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUnGroupedIssues = string[];
|
export type TIssues = TGroupedIssues | TUnGroupedIssues;
|
||||||
|
38
packages/types/src/issues/issue.d.ts
vendored
38
packages/types/src/issues/issue.d.ts
vendored
@ -4,15 +4,15 @@ import { TIssueLink } from "./issue_link";
|
|||||||
import { TIssueReaction } from "./issue_reaction";
|
import { TIssueReaction } from "./issue_reaction";
|
||||||
|
|
||||||
// new issue structure types
|
// new issue structure types
|
||||||
export type TIssue = {
|
|
||||||
|
export type TBaseIssue = {
|
||||||
id: string;
|
id: string;
|
||||||
sequence_id: number;
|
sequence_id: number;
|
||||||
name: string;
|
name: string;
|
||||||
description_html: string;
|
|
||||||
sort_order: number;
|
sort_order: number;
|
||||||
|
|
||||||
state_id: string;
|
state_id: string | null;
|
||||||
priority: TIssuePriorities;
|
priority: TIssuePriorities | null;
|
||||||
label_ids: string[];
|
label_ids: string[];
|
||||||
assignee_ids: string[];
|
assignee_ids: string[];
|
||||||
estimate_point: number | null;
|
estimate_point: number | null;
|
||||||
@ -21,10 +21,10 @@ export type TIssue = {
|
|||||||
attachment_count: number;
|
attachment_count: number;
|
||||||
link_count: number;
|
link_count: number;
|
||||||
|
|
||||||
project_id: string;
|
project_id: string | null;
|
||||||
parent_id: string | null;
|
parent_id: string | null;
|
||||||
cycle_id: string | null;
|
cycle_id: string | null;
|
||||||
module_ids: string[] | null;
|
module_ids: string[];
|
||||||
|
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
@ -37,9 +37,14 @@ export type TIssue = {
|
|||||||
updated_by: string;
|
updated_by: string;
|
||||||
|
|
||||||
is_draft: boolean;
|
is_draft: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TIssue = TBaseIssue & {
|
||||||
|
description_html?: string;
|
||||||
is_subscribed?: boolean;
|
is_subscribed?: boolean;
|
||||||
|
|
||||||
parent?: partial<TIssue>;
|
parent?: partial<TIssue>;
|
||||||
|
|
||||||
issue_reactions?: TIssueReaction[];
|
issue_reactions?: TIssueReaction[];
|
||||||
issue_attachment?: TIssueAttachment[];
|
issue_attachment?: TIssueAttachment[];
|
||||||
issue_link?: TIssueLink[];
|
issue_link?: TIssueLink[];
|
||||||
@ -51,3 +56,24 @@ export type TIssue = {
|
|||||||
export type TIssueMap = {
|
export type TIssueMap = {
|
||||||
[issue_id: string]: TIssue;
|
[issue_id: string]: TIssue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TIssueResponseResults =
|
||||||
|
| TBaseIssue[]
|
||||||
|
| {
|
||||||
|
[key: string]: {
|
||||||
|
results: TBaseIssue[];
|
||||||
|
total_results: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TIssuesResponse = {
|
||||||
|
grouped_by: string;
|
||||||
|
next_cursor: string;
|
||||||
|
prev_cursor: string;
|
||||||
|
next_page_results: boolean;
|
||||||
|
prev_page_results: boolean;
|
||||||
|
count: number;
|
||||||
|
total_pages: number;
|
||||||
|
extra_stats: null;
|
||||||
|
results: TIssueResponseResults;
|
||||||
|
};
|
||||||
|
265
packages/types/src/view-props.d.ts
vendored
265
packages/types/src/view-props.d.ts
vendored
@ -13,7 +13,6 @@ export type TIssueGroupByOptions =
|
|||||||
| "state_detail.group"
|
| "state_detail.group"
|
||||||
| "project"
|
| "project"
|
||||||
| "assignees"
|
| "assignees"
|
||||||
| "mentions"
|
|
||||||
| "cycle"
|
| "cycle"
|
||||||
| "module"
|
| "module"
|
||||||
| null;
|
| null;
|
||||||
@ -51,143 +50,153 @@ export type TIssueOrderByOptions =
|
|||||||
|
|
||||||
export type TIssueTypeFilters = "active" | "backlog" | null;
|
export type TIssueTypeFilters = "active" | "backlog" | null;
|
||||||
|
|
||||||
export type TIssueExtraOptions = "show_empty_groups" | "sub_issue";
|
export type TIssueExtraOptions = "show_empty_groups" | "sub_issue";
|
||||||
|
|
||||||
export type TIssueParams =
|
export type TIssueParams =
|
||||||
| "priority"
|
| "priority"
|
||||||
| "state_group"
|
| "state_group"
|
||||||
| "state"
|
| "state"
|
||||||
| "assignees"
|
| "assignees"
|
||||||
| "mentions"
|
| "mentions"
|
||||||
| "created_by"
|
| "created_by"
|
||||||
| "subscriber"
|
| "subscriber"
|
||||||
| "labels"
|
| "labels"
|
||||||
| "cycle"
|
| "cycle"
|
||||||
| "module"
|
| "module"
|
||||||
| "start_date"
|
| "start_date"
|
||||||
| "target_date"
|
| "target_date"
|
||||||
| "project"
|
| "project"
|
||||||
| "group_by"
|
| "group_by"
|
||||||
| "sub_group_by"
|
| "sub_group_by"
|
||||||
| "order_by"
|
| "order_by"
|
||||||
| "type"
|
| "type"
|
||||||
| "sub_issue"
|
| "sub_issue"
|
||||||
| "show_empty_groups";
|
| "show_empty_groups"
|
||||||
|
| "cursor"
|
||||||
|
| "per_page";
|
||||||
|
|
||||||
export type TCalendarLayouts = "month" | "week";
|
export type TCalendarLayouts = "month" | "week";
|
||||||
|
|
||||||
export interface IIssueFilterOptions {
|
export interface IIssueFilterOptions {
|
||||||
assignees?: string[] | null;
|
assignees?: string[] | null;
|
||||||
mentions?: string[] | null;
|
mentions?: string[] | null;
|
||||||
created_by?: string[] | null;
|
created_by?: string[] | null;
|
||||||
labels?: string[] | null;
|
labels?: string[] | null;
|
||||||
priority?: string[] | null;
|
priority?: string[] | null;
|
||||||
project?: string[] | null;
|
cycle?: string[] | null;
|
||||||
cycle?: string[] | null;
|
module?: string[] | null;
|
||||||
module?: string[] | null;
|
project?: string[] | null;
|
||||||
start_date?: string[] | null;
|
start_date?: string[] | null;
|
||||||
state?: string[] | null;
|
state?: string[] | null;
|
||||||
state_group?: string[] | null;
|
state_group?: string[] | null;
|
||||||
subscriber?: string[] | null;
|
subscriber?: string[] | null;
|
||||||
target_date?: string[] | null;
|
target_date?: string[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IIssueDisplayFilterOptions {
|
export interface IIssueDisplayFilterOptions {
|
||||||
calendar?: {
|
calendar?: {
|
||||||
show_weekends?: boolean;
|
show_weekends?: boolean;
|
||||||
layout?: TCalendarLayouts;
|
layout?: TCalendarLayouts;
|
||||||
|
};
|
||||||
|
group_by?: TIssueGroupByOptions;
|
||||||
|
sub_group_by?: TIssueGroupByOptions;
|
||||||
|
layout?: TIssueLayouts;
|
||||||
|
order_by?: TIssueOrderByOptions;
|
||||||
|
show_empty_groups?: boolean;
|
||||||
|
sub_issue?: boolean;
|
||||||
|
type?: TIssueTypeFilters;
|
||||||
|
}
|
||||||
|
export interface IIssueDisplayProperties {
|
||||||
|
assignee?: boolean;
|
||||||
|
start_date?: boolean;
|
||||||
|
due_date?: boolean;
|
||||||
|
labels?: boolean;
|
||||||
|
key?: boolean;
|
||||||
|
priority?: boolean;
|
||||||
|
state?: boolean;
|
||||||
|
sub_issue_count?: boolean;
|
||||||
|
link?: boolean;
|
||||||
|
attachment_count?: boolean;
|
||||||
|
estimate?: boolean;
|
||||||
|
created_on?: boolean;
|
||||||
|
updated_on?: boolean;
|
||||||
|
modules?: boolean;
|
||||||
|
cycle?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TIssueKanbanFilters = {
|
||||||
|
group_by: string[];
|
||||||
|
sub_group_by: string[];
|
||||||
};
|
};
|
||||||
group_by?: TIssueGroupByOptions;
|
|
||||||
sub_group_by?: TIssueGroupByOptions;
|
|
||||||
layout?: TIssueLayouts;
|
|
||||||
order_by?: TIssueOrderByOptions;
|
|
||||||
show_empty_groups?: boolean;
|
|
||||||
sub_issue?: boolean;
|
|
||||||
type?: TIssueTypeFilters;
|
|
||||||
}
|
|
||||||
export interface IIssueDisplayProperties {
|
|
||||||
assignee?: boolean;
|
|
||||||
start_date?: boolean;
|
|
||||||
due_date?: boolean;
|
|
||||||
labels?: boolean;
|
|
||||||
key?: boolean;
|
|
||||||
priority?: boolean;
|
|
||||||
state?: boolean;
|
|
||||||
sub_issue_count?: boolean;
|
|
||||||
link?: boolean;
|
|
||||||
attachment_count?: boolean;
|
|
||||||
estimate?: boolean;
|
|
||||||
created_on?: boolean;
|
|
||||||
updated_on?: boolean;
|
|
||||||
modules?: boolean;
|
|
||||||
cycle?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TIssueKanbanFilters = {
|
export interface IIssueFilters {
|
||||||
group_by: string[];
|
filters: IIssueFilterOptions | undefined;
|
||||||
sub_group_by: string[];
|
displayFilters: IIssueDisplayFilterOptions | undefined;
|
||||||
};
|
displayProperties: IIssueDisplayProperties | undefined;
|
||||||
|
kanbanFilters: TIssueKanbanFilters | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IIssueFilters {
|
export interface IIssueFiltersResponse {
|
||||||
filters: IIssueFilterOptions | undefined;
|
filters: IIssueFilterOptions;
|
||||||
displayFilters: IIssueDisplayFilterOptions | undefined;
|
display_filters: IIssueDisplayFilterOptions;
|
||||||
displayProperties: IIssueDisplayProperties | undefined;
|
display_properties: IIssueDisplayProperties;
|
||||||
kanbanFilters: TIssueKanbanFilters | undefined;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export interface IIssueFiltersResponse {
|
export interface IWorkspaceIssueFilterOptions {
|
||||||
filters: IIssueFilterOptions;
|
assignees?: string[] | null;
|
||||||
display_filters: IIssueDisplayFilterOptions;
|
created_by?: string[] | null;
|
||||||
display_properties: IIssueDisplayProperties;
|
labels?: string[] | null;
|
||||||
}
|
priority?: string[] | null;
|
||||||
|
state_group?: string[] | null;
|
||||||
|
subscriber?: string[] | null;
|
||||||
|
start_date?: string[] | null;
|
||||||
|
target_date?: string[] | null;
|
||||||
|
project?: string[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IWorkspaceIssueFilterOptions {
|
export interface IWorkspaceGlobalViewDisplayFilterOptions {
|
||||||
assignees?: string[] | null;
|
order_by?: string | undefined;
|
||||||
created_by?: string[] | null;
|
type?: "active" | "backlog" | null;
|
||||||
labels?: string[] | null;
|
sub_issue?: boolean;
|
||||||
priority?: string[] | null;
|
layout?: TIssueViewOptions;
|
||||||
state_group?: string[] | null;
|
}
|
||||||
subscriber?: string[] | null;
|
|
||||||
start_date?: string[] | null;
|
|
||||||
target_date?: string[] | null;
|
|
||||||
project?: string[] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWorkspaceGlobalViewDisplayFilterOptions {
|
export interface IWorkspaceViewIssuesParams {
|
||||||
order_by?: string | undefined;
|
assignees?: string | undefined;
|
||||||
type?: "active" | "backlog" | null;
|
created_by?: string | undefined;
|
||||||
sub_issue?: boolean;
|
labels?: string | undefined;
|
||||||
layout?: TIssueViewOptions;
|
priority?: string | undefined;
|
||||||
}
|
start_date?: string | undefined;
|
||||||
|
state?: string | undefined;
|
||||||
|
state_group?: string | undefined;
|
||||||
|
subscriber?: string | undefined;
|
||||||
|
target_date?: string | undefined;
|
||||||
|
project?: string | undefined;
|
||||||
|
order_by?: string | undefined;
|
||||||
|
type?: "active" | "backlog" | undefined;
|
||||||
|
sub_issue?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IWorkspaceViewIssuesParams {
|
export interface IProjectViewProps {
|
||||||
assignees?: string | undefined;
|
display_filters: IIssueDisplayFilterOptions | undefined;
|
||||||
created_by?: string | undefined;
|
filters: IIssueFilterOptions;
|
||||||
labels?: string | undefined;
|
}
|
||||||
priority?: string | undefined;
|
|
||||||
start_date?: string | undefined;
|
|
||||||
state?: string | undefined;
|
|
||||||
state_group?: string | undefined;
|
|
||||||
subscriber?: string | undefined;
|
|
||||||
target_date?: string | undefined;
|
|
||||||
project?: string | undefined;
|
|
||||||
order_by?: string | undefined;
|
|
||||||
type?: "active" | "backlog" | undefined;
|
|
||||||
sub_issue?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IProjectViewProps {
|
export interface IWorkspaceViewProps {
|
||||||
display_filters: IIssueDisplayFilterOptions | undefined;
|
filters: IIssueFilterOptions;
|
||||||
filters: IIssueFilterOptions;
|
display_filters: IIssueDisplayFilterOptions | undefined;
|
||||||
}
|
display_properties: IIssueDisplayProperties;
|
||||||
|
}
|
||||||
|
export interface IWorkspaceGlobalViewProps {
|
||||||
|
filters: IWorkspaceIssueFilterOptions;
|
||||||
|
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
|
||||||
|
display_properties: IIssueDisplayProperties;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IWorkspaceViewProps {
|
export interface IssuePaginationOptions {
|
||||||
filters: IIssueFilterOptions;
|
canGroup: boolean;
|
||||||
display_filters: IIssueDisplayFilterOptions | undefined;
|
perPageCount: number;
|
||||||
display_properties: IIssueDisplayProperties;
|
greaterThanDate?: Date;
|
||||||
}
|
lessThanDate?: Date;
|
||||||
export interface IWorkspaceGlobalViewProps {
|
groupedBy?: TIssueGroupByOptions;
|
||||||
filters: IWorkspaceIssueFilterOptions;
|
}
|
||||||
display_filters: IWorkspaceIssueDisplayFilterOptions | undefined;
|
|
||||||
display_properties: IIssueDisplayProperties;
|
|
||||||
}
|
|
||||||
|
@ -427,3 +427,17 @@ export const groupReactionEmojis = (reactions: any) => {
|
|||||||
|
|
||||||
return _groupedEmojis;
|
return _groupedEmojis;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export enum IssueGroupByOptions {
|
||||||
|
"state" = "state_id",
|
||||||
|
"priority" = "priority",
|
||||||
|
"labels" = "labels__id",
|
||||||
|
"state_detail.group" = "state__group",
|
||||||
|
"assignees" = "assignees__id",
|
||||||
|
"cycle" = "cycle_id",
|
||||||
|
"module" = "modules__id",
|
||||||
|
"target_date" = "target_date",
|
||||||
|
"project" = "project_id",
|
||||||
|
"created_by" = "created_by",
|
||||||
|
}
|
||||||
|
@ -4,14 +4,21 @@ import {
|
|||||||
IIssueDisplayFilterOptions,
|
IIssueDisplayFilterOptions,
|
||||||
IIssueDisplayProperties,
|
IIssueDisplayProperties,
|
||||||
IIssueFilterOptions,
|
IIssueFilterOptions,
|
||||||
|
IssuePaginationOptions,
|
||||||
TIssue,
|
TIssue,
|
||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
|
TIssuesResponse,
|
||||||
TLoader,
|
TLoader,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { useCallback, useMemo } from "react";
|
import { useCallback, useMemo } from "react";
|
||||||
|
|
||||||
interface IssueActions {
|
interface IssueActions {
|
||||||
fetchIssues?: (projectId: string, loadType: TLoader) => Promise<TIssue[] | undefined>;
|
fetchIssues: (
|
||||||
|
loadType: TLoader,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
|
userViewId?: "assigned" | "created" | "subscribed"
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchNextIssues: () => Promise<TIssuesResponse | undefined>;
|
||||||
removeIssue: (projectId: string, issueId: string) => Promise<void>;
|
removeIssue: (projectId: string, issueId: string) => Promise<void>;
|
||||||
createIssue?: (projectId: string, data: Partial<TIssue>) => Promise<TIssue | undefined>;
|
createIssue?: (projectId: string, data: Partial<TIssue>) => Promise<TIssue | undefined>;
|
||||||
updateIssue?: (projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
updateIssue?: (projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
@ -29,25 +36,25 @@ export const useIssuesActions = (storeType: EIssuesStoreType): IssueActions => {
|
|||||||
const projectIssueActions = useProjectIssueActions();
|
const projectIssueActions = useProjectIssueActions();
|
||||||
const cycleIssueActions = useCycleIssueActions();
|
const cycleIssueActions = useCycleIssueActions();
|
||||||
const moduleIssueActions = useModuleIssueActions();
|
const moduleIssueActions = useModuleIssueActions();
|
||||||
const profileIssueActions = useProfileIssueActions();
|
|
||||||
const projectViewIssueActions = useProjectViewIssueActions();
|
const projectViewIssueActions = useProjectViewIssueActions();
|
||||||
|
const globalIssueActions = useGlobalIssueActions();
|
||||||
|
const profileIssueActions = useProfileIssueActions();
|
||||||
const draftIssueActions = useDraftIssueActions();
|
const draftIssueActions = useDraftIssueActions();
|
||||||
const archivedIssueActions = useArchivedIssueActions();
|
const archivedIssueActions = useArchivedIssueActions();
|
||||||
const globalIssueActions = useGlobalIssueActions();
|
|
||||||
|
|
||||||
switch (storeType) {
|
switch (storeType) {
|
||||||
case EIssuesStoreType.PROJECT_VIEW:
|
case EIssuesStoreType.PROJECT_VIEW:
|
||||||
return projectViewIssueActions;
|
return projectViewIssueActions;
|
||||||
case EIssuesStoreType.PROFILE:
|
case EIssuesStoreType.PROFILE:
|
||||||
return profileIssueActions;
|
return profileIssueActions;
|
||||||
case EIssuesStoreType.CYCLE:
|
|
||||||
return cycleIssueActions;
|
|
||||||
case EIssuesStoreType.MODULE:
|
|
||||||
return moduleIssueActions;
|
|
||||||
case EIssuesStoreType.ARCHIVED:
|
case EIssuesStoreType.ARCHIVED:
|
||||||
return archivedIssueActions;
|
return archivedIssueActions;
|
||||||
case EIssuesStoreType.DRAFT:
|
case EIssuesStoreType.DRAFT:
|
||||||
return draftIssueActions;
|
return draftIssueActions;
|
||||||
|
case EIssuesStoreType.CYCLE:
|
||||||
|
return cycleIssueActions;
|
||||||
|
case EIssuesStoreType.MODULE:
|
||||||
|
return moduleIssueActions;
|
||||||
case EIssuesStoreType.GLOBAL:
|
case EIssuesStoreType.GLOBAL:
|
||||||
return globalIssueActions;
|
return globalIssueActions;
|
||||||
case EIssuesStoreType.PROJECT:
|
case EIssuesStoreType.PROJECT:
|
||||||
@ -60,16 +67,21 @@ const useProjectIssueActions = () => {
|
|||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.PROJECT);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.PROJECT);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
router: { workspaceSlug },
|
router: { workspaceSlug, projectId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType);
|
return issues.fetchIssues(workspaceSlug.toString(), projectId.toString(), loadType, options);
|
||||||
},
|
},
|
||||||
[issues.fetchIssues, workspaceSlug]
|
[issues.fetchIssues, workspaceSlug, projectId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, projectId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
@ -114,13 +126,14 @@ const useProjectIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
archiveIssue,
|
archiveIssue,
|
||||||
updateFilters,
|
updateFilters,
|
||||||
}),
|
}),
|
||||||
[fetchIssues, createIssue, updateIssue, removeIssue, archiveIssue, updateFilters]
|
[fetchIssues, fetchNextIssues, createIssue, updateIssue, removeIssue, archiveIssue, updateFilters]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -128,16 +141,21 @@ const useCycleIssueActions = () => {
|
|||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.CYCLE);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.CYCLE);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
router: { workspaceSlug, cycleId },
|
router: { workspaceSlug, projectId, cycleId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
if (!cycleId || !workspaceSlug) return;
|
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType, cycleId);
|
return issues.fetchIssues(workspaceSlug.toString(), projectId.toString(), loadType, options, cycleId.toString());
|
||||||
},
|
},
|
||||||
[issues.fetchIssues, cycleId, workspaceSlug]
|
[issues.fetchIssues, workspaceSlug, projectId, cycleId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), projectId.toString(), cycleId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, projectId, cycleId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!cycleId || !workspaceSlug) return;
|
if (!cycleId || !workspaceSlug) return;
|
||||||
@ -147,17 +165,17 @@ const useCycleIssueActions = () => {
|
|||||||
);
|
);
|
||||||
const updateIssue = useCallback(
|
const updateIssue = useCallback(
|
||||||
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
if (!cycleId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.updateIssue(workspaceSlug, projectId, issueId, data, cycleId);
|
return await issues.updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
},
|
},
|
||||||
[issues.updateIssue, cycleId, workspaceSlug]
|
[issues.updateIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssue = useCallback(
|
const removeIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!cycleId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.removeIssue(workspaceSlug, projectId, issueId, cycleId);
|
return await issues.removeIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.removeIssue, cycleId, workspaceSlug]
|
[issues.removeIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssueFromView = useCallback(
|
const removeIssueFromView = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
@ -168,10 +186,10 @@ const useCycleIssueActions = () => {
|
|||||||
);
|
);
|
||||||
const archiveIssue = useCallback(
|
const archiveIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!cycleId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.archiveIssue(workspaceSlug, projectId, issueId, cycleId);
|
return await issues.archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.archiveIssue, cycleId, workspaceSlug]
|
[issues.archiveIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateFilters = useCallback(
|
const updateFilters = useCallback(
|
||||||
@ -189,6 +207,7 @@ const useCycleIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
@ -196,7 +215,16 @@ const useCycleIssueActions = () => {
|
|||||||
archiveIssue,
|
archiveIssue,
|
||||||
updateFilters,
|
updateFilters,
|
||||||
}),
|
}),
|
||||||
[fetchIssues, createIssue, updateIssue, removeIssue, removeIssueFromView, archiveIssue, updateFilters]
|
[
|
||||||
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
|
createIssue,
|
||||||
|
updateIssue,
|
||||||
|
removeIssue,
|
||||||
|
removeIssueFromView,
|
||||||
|
archiveIssue,
|
||||||
|
updateFilters,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -204,16 +232,21 @@ const useModuleIssueActions = () => {
|
|||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.MODULE);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.MODULE);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
router: { workspaceSlug, moduleId },
|
router: { workspaceSlug, projectId, moduleId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
if (!moduleId || !workspaceSlug) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType, moduleId);
|
return issues.fetchIssues(workspaceSlug.toString(), projectId.toString(), loadType, options, moduleId.toString());
|
||||||
},
|
},
|
||||||
[issues.fetchIssues, moduleId, workspaceSlug]
|
[issues.fetchIssues, workspaceSlug, projectId, moduleId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), projectId.toString(), moduleId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, projectId, moduleId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!moduleId || !workspaceSlug) return;
|
if (!moduleId || !workspaceSlug) return;
|
||||||
@ -223,17 +256,17 @@ const useModuleIssueActions = () => {
|
|||||||
);
|
);
|
||||||
const updateIssue = useCallback(
|
const updateIssue = useCallback(
|
||||||
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
if (!moduleId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.updateIssue(workspaceSlug, projectId, issueId, data, moduleId);
|
return await issues.updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
},
|
},
|
||||||
[issues.updateIssue, moduleId, workspaceSlug]
|
[issues.updateIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssue = useCallback(
|
const removeIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!moduleId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.removeIssue(workspaceSlug, projectId, issueId, moduleId);
|
return await issues.removeIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.removeIssue, moduleId, workspaceSlug]
|
[issues.removeIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssueFromView = useCallback(
|
const removeIssueFromView = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
@ -244,8 +277,8 @@ const useModuleIssueActions = () => {
|
|||||||
);
|
);
|
||||||
const archiveIssue = useCallback(
|
const archiveIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!moduleId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.archiveIssue(workspaceSlug, projectId, issueId, moduleId);
|
return await issues.archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.archiveIssue, moduleId, workspaceSlug]
|
[issues.archiveIssue, moduleId, workspaceSlug]
|
||||||
);
|
);
|
||||||
@ -265,6 +298,7 @@ const useModuleIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
@ -284,39 +318,44 @@ const useProfileIssueActions = () => {
|
|||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions, viewId?: "assigned" | "created" | "subscribed") => {
|
||||||
if (!userId || !workspaceSlug) return;
|
if (!workspaceSlug || !userId || !viewId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType, userId);
|
return issues.fetchIssues(workspaceSlug.toString(), userId.toString(), loadType, options, viewId);
|
||||||
},
|
},
|
||||||
[issues.fetchIssues, userId, workspaceSlug]
|
[issues.fetchIssues, workspaceSlug, userId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !userId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), userId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, userId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!userId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.createIssue(workspaceSlug, projectId, data, userId);
|
return await issues.createIssue(workspaceSlug, projectId, data);
|
||||||
},
|
},
|
||||||
[issues.createIssue, userId, workspaceSlug]
|
[issues.createIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const updateIssue = useCallback(
|
const updateIssue = useCallback(
|
||||||
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
if (!userId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.updateIssue(workspaceSlug, projectId, issueId, data, userId);
|
return await issues.updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
},
|
},
|
||||||
[issues.updateIssue, userId, workspaceSlug]
|
[issues.updateIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssue = useCallback(
|
const removeIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!userId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.removeIssue(workspaceSlug, projectId, issueId, userId);
|
return await issues.removeIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.removeIssue, userId, workspaceSlug]
|
[issues.removeIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const archiveIssue = useCallback(
|
const archiveIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!userId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.archiveIssue(workspaceSlug, projectId, issueId, userId);
|
return await issues.archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.archiveIssue, userId, workspaceSlug]
|
[issues.archiveIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateFilters = useCallback(
|
const updateFilters = useCallback(
|
||||||
@ -334,6 +373,7 @@ const useProfileIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
@ -348,43 +388,48 @@ const useProjectViewIssueActions = () => {
|
|||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.PROJECT_VIEW);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.PROJECT_VIEW);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
router: { workspaceSlug, viewId },
|
router: { workspaceSlug, projectId, viewId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
if (!viewId || !workspaceSlug) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType, viewId);
|
return issues.fetchIssues(workspaceSlug.toString(), projectId.toString(), loadType, options);
|
||||||
},
|
},
|
||||||
[issues.fetchIssues, viewId, workspaceSlug]
|
[issues.fetchIssues, workspaceSlug, projectId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, projectId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!viewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.createIssue(workspaceSlug, projectId, data, viewId);
|
return await issues.createIssue(workspaceSlug, projectId, data);
|
||||||
},
|
},
|
||||||
[issues.createIssue, viewId, workspaceSlug]
|
[issues.createIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const updateIssue = useCallback(
|
const updateIssue = useCallback(
|
||||||
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
if (!viewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.updateIssue(workspaceSlug, projectId, issueId, data, viewId);
|
return await issues.updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
},
|
},
|
||||||
[issues.updateIssue, viewId, workspaceSlug]
|
[issues.updateIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssue = useCallback(
|
const removeIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!viewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.removeIssue(workspaceSlug, projectId, issueId, viewId);
|
return await issues.removeIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.removeIssue, viewId, workspaceSlug]
|
[issues.removeIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const archiveIssue = useCallback(
|
const archiveIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!viewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.archiveIssue(workspaceSlug, projectId, issueId, viewId);
|
return await issues.archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.archiveIssue, viewId, workspaceSlug]
|
[issues.archiveIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateFilters = useCallback(
|
const updateFilters = useCallback(
|
||||||
@ -402,13 +447,14 @@ const useProjectViewIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
archiveIssue,
|
archiveIssue,
|
||||||
updateFilters,
|
updateFilters,
|
||||||
}),
|
}),
|
||||||
[fetchIssues, createIssue, updateIssue, removeIssue, archiveIssue, updateFilters]
|
[fetchIssues, fetchNextIssues, createIssue, updateIssue, removeIssue, archiveIssue, updateFilters]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -416,16 +462,21 @@ const useDraftIssueActions = () => {
|
|||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.DRAFT);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.DRAFT);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
router: { workspaceSlug },
|
router: { workspaceSlug, projectId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType);
|
return issues.fetchIssues(workspaceSlug.toString(), projectId.toString(), loadType, options);
|
||||||
},
|
},
|
||||||
[issues.fetchIssues, workspaceSlug]
|
[issues.fetchIssues, workspaceSlug, projectId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, projectId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
@ -463,6 +514,7 @@ const useDraftIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
@ -476,16 +528,21 @@ const useArchivedIssueActions = () => {
|
|||||||
const { issues, issuesFilter } = useIssues(EIssuesStoreType.ARCHIVED);
|
const { issues, issuesFilter } = useIssues(EIssuesStoreType.ARCHIVED);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
router: { workspaceSlug },
|
router: { workspaceSlug, projectId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
|
||||||
const fetchIssues = useCallback(
|
const fetchIssues = useCallback(
|
||||||
async (projectId: string, loadType: TLoader) => {
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
return await issues.fetchIssues(workspaceSlug, projectId, loadType);
|
return issues.fetchIssues(workspaceSlug.toString(), projectId.toString(), loadType, options);
|
||||||
},
|
},
|
||||||
[issues.fetchIssues]
|
[issues.fetchIssues, workspaceSlug, projectId]
|
||||||
);
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), projectId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, projectId]);
|
||||||
|
|
||||||
const removeIssue = useCallback(
|
const removeIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
@ -516,11 +573,12 @@ const useArchivedIssueActions = () => {
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
fetchIssues,
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
restoreIssue,
|
restoreIssue,
|
||||||
updateFilters,
|
updateFilters,
|
||||||
}),
|
}),
|
||||||
[fetchIssues, removeIssue, restoreIssue, updateFilters]
|
[fetchIssues, fetchNextIssues, removeIssue, restoreIssue, updateFilters]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -530,26 +588,38 @@ const useGlobalIssueActions = () => {
|
|||||||
const {
|
const {
|
||||||
router: { workspaceSlug, globalViewId },
|
router: { workspaceSlug, globalViewId },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
|
const fetchIssues = useCallback(
|
||||||
|
async (loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
|
if (!workspaceSlug || !globalViewId) return;
|
||||||
|
return issues.fetchIssues(workspaceSlug.toString(), globalViewId.toString(), loadType, options);
|
||||||
|
},
|
||||||
|
[issues.fetchIssues, workspaceSlug, globalViewId]
|
||||||
|
);
|
||||||
|
const fetchNextIssues = useCallback(async () => {
|
||||||
|
if (!workspaceSlug || !globalViewId) return;
|
||||||
|
return issues.fetchNextIssues(workspaceSlug.toString(), globalViewId.toString());
|
||||||
|
}, [issues.fetchIssues, workspaceSlug, globalViewId]);
|
||||||
|
|
||||||
const createIssue = useCallback(
|
const createIssue = useCallback(
|
||||||
async (projectId: string, data: Partial<TIssue>) => {
|
async (projectId: string, data: Partial<TIssue>) => {
|
||||||
if (!globalViewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.createIssue(workspaceSlug, projectId, data, globalViewId);
|
return await issues.createIssue(workspaceSlug, projectId, data);
|
||||||
},
|
},
|
||||||
[issues.createIssue, globalViewId, workspaceSlug]
|
[issues.createIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const updateIssue = useCallback(
|
const updateIssue = useCallback(
|
||||||
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
async (projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
if (!globalViewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.updateIssue(workspaceSlug, projectId, issueId, data, globalViewId);
|
return await issues.updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
},
|
},
|
||||||
[issues.updateIssue, globalViewId, workspaceSlug]
|
[issues.updateIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
const removeIssue = useCallback(
|
const removeIssue = useCallback(
|
||||||
async (projectId: string, issueId: string) => {
|
async (projectId: string, issueId: string) => {
|
||||||
if (!globalViewId || !workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
return await issues.removeIssue(workspaceSlug, projectId, issueId, globalViewId);
|
return await issues.removeIssue(workspaceSlug, projectId, issueId);
|
||||||
},
|
},
|
||||||
[issues.removeIssue, globalViewId, workspaceSlug]
|
[issues.removeIssue, workspaceSlug]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateFilters = useCallback(
|
const updateFilters = useCallback(
|
||||||
@ -566,6 +636,8 @@ const useGlobalIssueActions = () => {
|
|||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
fetchIssues,
|
||||||
|
fetchNextIssues,
|
||||||
createIssue,
|
createIssue,
|
||||||
updateIssue,
|
updateIssue,
|
||||||
removeIssue,
|
removeIssue,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// types
|
// types
|
||||||
import type { CycleDateCheckData, ICycle, TIssue } from "@plane/types";
|
import type { CycleDateCheckData, ICycle, TIssue, TIssuesResponse } from "@plane/types";
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
export class CycleService extends APIService {
|
export class CycleService extends APIService {
|
||||||
@ -46,20 +46,12 @@ export class CycleService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCycleIssues(workspaceSlug: string, projectId: string, cycleId: string): Promise<TIssue[]> {
|
async getCycleIssues(
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`)
|
|
||||||
.then((response) => response?.data)
|
|
||||||
.catch((error) => {
|
|
||||||
throw error?.response?.data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getCycleIssuesWithParams(
|
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
cycleId: string,
|
cycleId: string,
|
||||||
queries?: any
|
queries?: any
|
||||||
): Promise<TIssue[]> {
|
): Promise<TIssuesResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, {
|
||||||
params: queries,
|
params: queries,
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,14 @@
|
|||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// type
|
// type
|
||||||
import type { TIssue, IIssueDisplayProperties, TIssueLink, TIssueSubIssues, TIssueActivity } from "@plane/types";
|
import type {
|
||||||
|
TIssue,
|
||||||
|
IIssueDisplayProperties,
|
||||||
|
TIssueLink,
|
||||||
|
TIssueSubIssues,
|
||||||
|
TIssueActivity,
|
||||||
|
TIssuesResponse,
|
||||||
|
} from "@plane/types";
|
||||||
// helper
|
// helper
|
||||||
|
|
||||||
export class IssueService extends APIService {
|
export class IssueService extends APIService {
|
||||||
@ -10,7 +17,7 @@ export class IssueService extends APIService {
|
|||||||
super(API_BASE_URL);
|
super(API_BASE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createIssue(workspaceSlug: string, projectId: string, data: any): Promise<any> {
|
async createIssue(workspaceSlug: string, projectId: string, data: Partial<TIssue>): Promise<TIssue> {
|
||||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data)
|
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -18,7 +25,7 @@ export class IssueService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getIssues(workspaceSlug: string, projectId: string, queries?: any): Promise<TIssue[]> {
|
async getIssues(workspaceSlug: string, projectId: string, queries?: any): Promise<TIssuesResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/`, {
|
||||||
params: queries,
|
params: queries,
|
||||||
})
|
})
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// helpers
|
// helpers
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue, TIssuesResponse } from "@plane/types";
|
||||||
|
|
||||||
export class IssueDraftService extends APIService {
|
export class IssueDraftService extends APIService {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(API_BASE_URL);
|
super(API_BASE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDraftIssues(workspaceSlug: string, projectId: string, query?: any): Promise<TIssue[]> {
|
async getDraftIssues(workspaceSlug: string, projectId: string, query?: any): Promise<TIssuesResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/`, {
|
||||||
params: { ...query },
|
params: { ...query },
|
||||||
})
|
})
|
||||||
@ -18,7 +18,7 @@ export class IssueDraftService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async createDraftIssue(workspaceSlug: string, projectId: string, data: any): Promise<any> {
|
async createDraftIssue(workspaceSlug: string, projectId: string, data: any): Promise<TIssue> {
|
||||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/`, data)
|
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -26,7 +26,7 @@ export class IssueDraftService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateDraftIssue(workspaceSlug: string, projectId: string, issueId: string, data: any): Promise<any> {
|
async updateDraftIssue(workspaceSlug: string, projectId: string, issueId: string, data: any): Promise<void> {
|
||||||
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, data)
|
return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -34,7 +34,7 @@ export class IssueDraftService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteDraftIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<any> {
|
async deleteDraftIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<void> {
|
||||||
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`)
|
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -42,7 +42,7 @@ export class IssueDraftService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDraftIssueById(workspaceSlug: string, projectId: string, issueId: string, queries?: any): Promise<any> {
|
async getDraftIssueById(workspaceSlug: string, projectId: string, issueId: string, queries?: any): Promise<TIssue> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, {
|
||||||
params: queries,
|
params: queries,
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// types
|
// types
|
||||||
import type { IModule, TIssue, ILinkDetails, ModuleLink } from "@plane/types";
|
import type { IModule, ILinkDetails, ModuleLink, TIssuesResponse } from "@plane/types";
|
||||||
|
|
||||||
export class ModuleService extends APIService {
|
export class ModuleService extends APIService {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -70,7 +70,12 @@ export class ModuleService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getModuleIssues(workspaceSlug: string, projectId: string, moduleId: string, queries?: any): Promise<TIssue[]> {
|
async getModuleIssues(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
queries?: any
|
||||||
|
): Promise<TIssuesResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/`, {
|
||||||
params: queries,
|
params: queries,
|
||||||
})
|
})
|
||||||
@ -111,7 +116,7 @@ export class ModuleService extends APIService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
issueId: string
|
issueId: string
|
||||||
): Promise<any> {
|
): Promise<void> {
|
||||||
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
|
return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -124,14 +129,14 @@ export class ModuleService extends APIService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
issueIds: string[]
|
issueIds: string[]
|
||||||
): Promise<any> {
|
): Promise<void> {
|
||||||
const promiseDataUrls: any = [];
|
const promiseDataUrls: any = [];
|
||||||
issueIds.forEach((issueId) => {
|
issueIds.forEach((issueId) => {
|
||||||
promiseDataUrls.push(
|
promiseDataUrls.push(
|
||||||
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
|
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return await Promise.all(promiseDataUrls)
|
await Promise.all(promiseDataUrls)
|
||||||
.then((response) => response)
|
.then((response) => response)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
@ -143,14 +148,14 @@ export class ModuleService extends APIService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
issueId: string,
|
issueId: string,
|
||||||
moduleIds: string[]
|
moduleIds: string[]
|
||||||
): Promise<any> {
|
): Promise<void> {
|
||||||
const promiseDataUrls: any = [];
|
const promiseDataUrls: any = [];
|
||||||
moduleIds.forEach((moduleId) => {
|
moduleIds.forEach((moduleId) => {
|
||||||
promiseDataUrls.push(
|
promiseDataUrls.push(
|
||||||
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
|
this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/issues/${issueId}/`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return await Promise.all(promiseDataUrls)
|
await Promise.all(promiseDataUrls)
|
||||||
.then((response) => response)
|
.then((response) => response)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
|
@ -11,6 +11,7 @@ import type {
|
|||||||
IUserProfileProjectSegregation,
|
IUserProfileProjectSegregation,
|
||||||
IUserSettings,
|
IUserSettings,
|
||||||
IUserEmailNotificationSettings,
|
IUserEmailNotificationSettings,
|
||||||
|
TIssuesResponse,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ export class UserService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserProfileIssues(workspaceSlug: string, userId: string, params: any): Promise<TIssue[]> {
|
async getUserProfileIssues(workspaceSlug: string, userId: string, params: any): Promise<TIssuesResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/user-issues/${userId}/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/user-issues/${userId}/`, {
|
||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
|
@ -14,8 +14,8 @@ import {
|
|||||||
IWorkspaceBulkInviteFormData,
|
IWorkspaceBulkInviteFormData,
|
||||||
IWorkspaceViewProps,
|
IWorkspaceViewProps,
|
||||||
IUserProjectsRole,
|
IUserProjectsRole,
|
||||||
TIssue,
|
|
||||||
IWorkspaceView,
|
IWorkspaceView,
|
||||||
|
TIssuesResponse,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
|
|
||||||
export class WorkspaceService extends APIService {
|
export class WorkspaceService extends APIService {
|
||||||
@ -257,7 +257,7 @@ export class WorkspaceService extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getViewIssues(workspaceSlug: string, params: any): Promise<TIssue[]> {
|
async getViewIssues(workspaceSlug: string, params: any): Promise<TIssuesResponse> {
|
||||||
return this.get(`/api/workspaces/${workspaceSlug}/issues/`, {
|
return this.get(`/api/workspaces/${workspaceSlug}/issues/`, {
|
||||||
params,
|
params,
|
||||||
})
|
})
|
||||||
|
@ -14,20 +14,22 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface IArchivedIssuesFilter {
|
export interface IArchivedIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
//helper actions
|
||||||
filters: Record<string, IIssueFilters>; // Record defines projectId as key and IIssueFilters as value
|
getFilterParams: (
|
||||||
// computed
|
options: IssuePaginationOptions,
|
||||||
issueFilters: IIssueFilters | undefined;
|
cursor?: string
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -92,6 +94,22 @@ export class ArchivedIssuesFilter extends IssueFilterHelperStore implements IArc
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const _filters = this.handleIssuesLocalFilters.get(
|
const _filters = this.handleIssuesLocalFilters.get(
|
||||||
@ -150,7 +168,7 @@ export class ArchivedIssuesFilter extends IssueFilterHelperStore implements IArc
|
|||||||
});
|
});
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.archivedIssues.fetchIssues(
|
this.rootIssueStore.archivedIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
||||||
@ -193,7 +211,7 @@ export class ArchivedIssuesFilter extends IssueFilterHelperStore implements IArc
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.archivedIssues.fetchIssues(workspaceSlug, projectId, "mutation");
|
this.rootIssueStore.archivedIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
|
||||||
|
|
||||||
this.handleIssuesLocalFilters.set(EIssuesStoreType.ARCHIVED, type, workspaceSlug, projectId, undefined, {
|
this.handleIssuesLocalFilters.set(EIssuesStoreType.ARCHIVED, type, workspaceSlug, projectId, undefined, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,35 +1,36 @@
|
|||||||
import pull from "lodash/pull";
|
import pull from "lodash/pull";
|
||||||
import set from "lodash/set";
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
|
||||||
// base class
|
// base class
|
||||||
import { IssueArchiveService } from "services/issue";
|
import { TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse } from "@plane/types";
|
||||||
import { TIssue, TLoader, TGroupedIssues, TSubGroupedIssues, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
// services
|
// services
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { IArchivedIssuesFilter } from "./filter.store";
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
|
||||||
export interface IArchivedIssues {
|
export interface IArchivedIssues extends IBaseIssuesStore {
|
||||||
// observable
|
// observable
|
||||||
loader: TLoader;
|
|
||||||
issues: { [project_id: string]: string[] };
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<TIssue[]>;
|
fetchIssues: (
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader,
|
||||||
|
option: IssuePaginationOptions
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchIssuesWithExistingPagination: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchNextIssues: (workspaceSlug: string, projectId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
|
|
||||||
restoreIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
restoreIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
quickAddIssue: undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ArchivedIssues extends IssueHelperStore implements IArchivedIssues {
|
export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
|
||||||
loader: TLoader = "init-loader";
|
// filter store
|
||||||
issues: { [project_id: string]: string[] } = {};
|
issueFilterStore: IArchivedIssuesFilter;
|
||||||
// root store
|
|
||||||
rootIssueStore: IIssueRootStore;
|
|
||||||
// services
|
|
||||||
archivedIssueService;
|
|
||||||
|
|
||||||
//viewData
|
//viewData
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
@ -38,99 +39,73 @@ export class ArchivedIssues extends IssueHelperStore implements IArchivedIssues
|
|||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IArchivedIssuesFilter) {
|
||||||
super(_rootStore);
|
super(_rootStore, issueFilterStore, true);
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
|
||||||
loader: observable.ref,
|
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
removeIssue: action,
|
|
||||||
restoreIssue: action,
|
restoreIssue: action,
|
||||||
});
|
});
|
||||||
// root store
|
// filter store
|
||||||
this.rootIssueStore = _rootStore;
|
this.issueFilterStore = issueFilterStore;
|
||||||
// services
|
|
||||||
this.archivedIssueService = new IssueArchiveService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupedIssueIds() {
|
fetchIssues = async (
|
||||||
const projectId = this.rootIssueStore.projectId;
|
workspaceSlug: string,
|
||||||
if (!projectId) return undefined;
|
projectId: string,
|
||||||
|
loadType: TLoader = "init-loader",
|
||||||
const displayFilters = this.rootIssueStore?.archivedIssuesFilter?.issueFilters?.displayFilters;
|
options: IssuePaginationOptions
|
||||||
if (!displayFilters) return undefined;
|
) => {
|
||||||
|
|
||||||
const groupBy = displayFilters?.group_by;
|
|
||||||
const orderBy = displayFilters?.order_by;
|
|
||||||
const layout = displayFilters?.layout;
|
|
||||||
|
|
||||||
const archivedIssueIds = this.issues[projectId];
|
|
||||||
if (!archivedIssueIds) return undefined;
|
|
||||||
|
|
||||||
const _issues = this.rootIssueStore.issues.getIssuesByIds(archivedIssueIds, "archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined = undefined;
|
|
||||||
|
|
||||||
if (layout === "list" && orderBy) {
|
|
||||||
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, _issues);
|
|
||||||
else issues = this.unGroupedIssues(orderBy, _issues);
|
|
||||||
}
|
|
||||||
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
|
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
|
||||||
|
|
||||||
const params = this.rootIssueStore?.archivedIssuesFilter?.appliedFilters;
|
|
||||||
const response = await this.archivedIssueService.getArchivedIssues(workspaceSlug, projectId, params);
|
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
set(
|
this.loader = loadType;
|
||||||
this.issues,
|
|
||||||
[projectId],
|
|
||||||
response.map((issue: TIssue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
});
|
||||||
|
this.clear();
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(options);
|
||||||
|
const response = await this.issueArchiveService.getArchivedIssues(workspaceSlug, projectId, params);
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
this.onfetchIssues(response, options);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
try {
|
try {
|
||||||
await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
this.loader = "pagination";
|
||||||
|
|
||||||
runInAction(() => {
|
const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
|
||||||
pull(this.issues[projectId], issueId);
|
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||||
});
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fetchIssuesWithExistingPagination = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader = "mutation"
|
||||||
|
) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
|
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions);
|
||||||
|
};
|
||||||
|
|
||||||
restoreIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
restoreIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await this.archivedIssueService.restoreIssue(workspaceSlug, projectId, issueId);
|
const response = await this.issueArchiveService.restoreIssue(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.rootStore.issues.updateIssue(issueId, {
|
this.rootIssueStore.issues.updateIssue(issueId, {
|
||||||
archived_at: null,
|
archived_at: null,
|
||||||
});
|
});
|
||||||
pull(this.issues[projectId], issueId);
|
this.issues && pull(this.issues, issueId);
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
@ -138,6 +113,4 @@ export class ArchivedIssues extends IssueHelperStore implements IArchivedIssues
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
quickAddIssue: undefined;
|
|
||||||
}
|
}
|
||||||
|
@ -14,20 +14,22 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface ICycleIssuesFilter {
|
export interface ICycleIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
//helper actions
|
||||||
filters: Record<string, IIssueFilters>; // Record defines cycleId as key and IIssueFilters as value
|
getFilterParams: (
|
||||||
// computed
|
options: IssuePaginationOptions,
|
||||||
issueFilters: IIssueFilters | undefined;
|
cursor?: string
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -95,6 +97,22 @@ export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleI
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
fetchFilters = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||||
try {
|
try {
|
||||||
const _filters = await this.issueFilterService.fetchCycleIssueFilters(workspaceSlug, projectId, cycleId);
|
const _filters = await this.issueFilterService.fetchCycleIssueFilters(workspaceSlug, projectId, cycleId);
|
||||||
@ -161,7 +179,7 @@ export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleI
|
|||||||
|
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.cycleIssues.fetchIssues(
|
this.rootIssueStore.cycleIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation",
|
isEmpty(filteredFilters) ? "init-loader" : "mutation",
|
||||||
@ -205,7 +223,12 @@ export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleI
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.cycleIssues.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
this.rootIssueStore.cycleIssues.fetchIssuesWithExistingPagination(
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
"mutation",
|
||||||
|
cycleId
|
||||||
|
);
|
||||||
|
|
||||||
await this.issueFilterService.patchCycleIssueFilters(workspaceSlug, projectId, cycleId, {
|
await this.issueFilterService.patchCycleIssueFilters(workspaceSlug, projectId, cycleId, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,55 +1,43 @@
|
|||||||
import concat from "lodash/concat";
|
import concat from "lodash/concat";
|
||||||
import pull from "lodash/pull";
|
import pull from "lodash/pull";
|
||||||
import set from "lodash/set";
|
|
||||||
import uniq from "lodash/uniq";
|
import uniq from "lodash/uniq";
|
||||||
import update from "lodash/update";
|
import update from "lodash/update";
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
import { action, observable, makeObservable, runInAction } from "mobx";
|
||||||
// base class
|
// base class
|
||||||
// services
|
// services
|
||||||
import { CycleService } from "services/cycle.service";
|
import { CycleService } from "services/cycle.service";
|
||||||
import { IssueService } from "services/issue";
|
|
||||||
// types
|
// types
|
||||||
import { TIssue, TSubGroupedIssues, TGroupedIssues, TLoader, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
import { TIssue, TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse } from "@plane/types";
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
import { ICycleIssuesFilter } from "./filter.store";
|
||||||
|
|
||||||
export const ACTIVE_CYCLE_ISSUES = "ACTIVE_CYCLE_ISSUES";
|
export const ACTIVE_CYCLE_ISSUES = "ACTIVE_CYCLE_ISSUES";
|
||||||
|
|
||||||
export interface ICycleIssues {
|
export interface ICycleIssues extends IBaseIssuesStore {
|
||||||
// observable
|
|
||||||
loader: TLoader;
|
|
||||||
issues: { [cycle_id: string]: string[] };
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: (
|
fetchIssues: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
loadType: TLoader,
|
loadType: TLoader,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
cycleId: string
|
cycleId: string
|
||||||
) => Promise<TIssue[] | undefined>;
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
createIssue: (
|
fetchIssuesWithExistingPagination: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
data: Partial<TIssue>,
|
loadType: TLoader,
|
||||||
cycleId: string
|
cycleId: string
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
updateIssue: (
|
fetchNextIssues: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>, cycleId: string) => Promise<TIssue>;
|
||||||
issueId: string,
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
data: Partial<TIssue>,
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
cycleId: string
|
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue | undefined>;
|
||||||
) => Promise<void>;
|
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string, cycleId: string) => Promise<void>;
|
|
||||||
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string, cycleId: string) => Promise<void>;
|
|
||||||
quickAddIssue: (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
cycleId?: string | undefined
|
|
||||||
) => Promise<TIssue>;
|
|
||||||
addIssueToCycle: (
|
addIssueToCycle: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@ -66,106 +54,63 @@ export interface ICycleIssues {
|
|||||||
new_cycle_id: string;
|
new_cycle_id: string;
|
||||||
}
|
}
|
||||||
) => Promise<TIssue>;
|
) => Promise<TIssue>;
|
||||||
fetchActiveCycleIssues: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<TIssue[] | undefined>;
|
fetchActiveCycleIssues: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
cycleId: string
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
|
||||||
loader: TLoader = "init-loader";
|
cycleId: string | undefined = undefined;
|
||||||
issues: { [cycle_id: string]: string[] } = {};
|
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
enableQuickAdd: true,
|
enableQuickAdd: true,
|
||||||
enableIssueCreation: true,
|
enableIssueCreation: true,
|
||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
// root store
|
|
||||||
rootIssueStore: IIssueRootStore;
|
|
||||||
// service
|
// service
|
||||||
cycleService;
|
cycleService;
|
||||||
issueService;
|
// filter store
|
||||||
|
issueFilterStore;
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: ICycleIssuesFilter) {
|
||||||
super(_rootStore);
|
super(_rootStore, issueFilterStore);
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
// observable
|
||||||
loader: observable.ref,
|
cycleId: observable.ref,
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
|
||||||
updateIssue: action,
|
|
||||||
removeIssue: action,
|
|
||||||
archiveIssue: action,
|
|
||||||
quickAddIssue: action,
|
|
||||||
addIssueToCycle: action,
|
addIssueToCycle: action,
|
||||||
removeIssueFromCycle: action,
|
removeIssueFromCycle: action,
|
||||||
transferIssuesFromCycle: action,
|
transferIssuesFromCycle: action,
|
||||||
fetchActiveCycleIssues: action,
|
fetchActiveCycleIssues: action,
|
||||||
});
|
});
|
||||||
|
// service
|
||||||
this.rootIssueStore = _rootStore;
|
|
||||||
this.issueService = new IssueService();
|
|
||||||
this.cycleService = new CycleService();
|
this.cycleService = new CycleService();
|
||||||
}
|
// filter store
|
||||||
|
this.issueFilterStore = issueFilterStore;
|
||||||
get groupedIssueIds() {
|
|
||||||
const cycleId = this.rootIssueStore?.cycleId;
|
|
||||||
if (!cycleId) return undefined;
|
|
||||||
|
|
||||||
const displayFilters = this.rootIssueStore?.cycleIssuesFilter?.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 cycleIssueIds = this.issues[cycleId];
|
|
||||||
if (!cycleIssueIds) return;
|
|
||||||
|
|
||||||
const _issues = this.rootIssueStore.issues.getIssuesByIds(cycleIssueIds, "un-archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues = [];
|
|
||||||
|
|
||||||
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", "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 (
|
fetchIssues = async (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
loadType: TLoader = "init-loader",
|
loadType: TLoader,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
cycleId: string
|
cycleId: string
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
|
||||||
|
|
||||||
const params = this.rootIssueStore?.cycleIssuesFilter?.appliedFilters;
|
|
||||||
const response = await this.cycleService.getCycleIssuesWithParams(workspaceSlug, projectId, cycleId, params);
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
set(
|
this.loader = loadType;
|
||||||
this.issues,
|
|
||||||
[cycleId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
});
|
||||||
|
this.clear();
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
this.cycleId = cycleId;
|
||||||
|
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(options);
|
||||||
|
const response = await this.cycleService.getCycleIssues(workspaceSlug, projectId, cycleId, params);
|
||||||
|
|
||||||
|
this.onfetchIssues(response, options);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
@ -173,7 +118,33 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, cycleId: string) => {
|
fetchNextIssues = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
|
try {
|
||||||
|
this.loader = "pagination";
|
||||||
|
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
|
||||||
|
const response = await this.cycleService.getCycleIssues(workspaceSlug, projectId, cycleId, params);
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchIssuesWithExistingPagination = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader,
|
||||||
|
cycleId: string
|
||||||
|
) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
|
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions, cycleId);
|
||||||
|
};
|
||||||
|
|
||||||
|
override createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, cycleId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await this.rootIssueStore.projectIssues.createIssue(workspaceSlug, projectId, data);
|
const response = await this.rootIssueStore.projectIssues.createIssue(workspaceSlug, projectId, data);
|
||||||
await this.addIssueToCycle(workspaceSlug, projectId, cycleId, [response.id], false);
|
await this.addIssueToCycle(workspaceSlug, projectId, cycleId, [response.id], false);
|
||||||
@ -185,81 +156,6 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
cycleId: string
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string, cycleId: string) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
|
||||||
|
|
||||||
const issueIndex = this.issues[cycleId].findIndex((_issueId) => _issueId === issueId);
|
|
||||||
if (issueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[cycleId].splice(issueIndex, 1);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
archiveIssue = async (workspaceSlug: string, projectId: string, issueId: string, cycleId: string) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.archiveIssue(workspaceSlug, projectId, issueId);
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
pull(this.issues[cycleId], issueId);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quickAddIssue = async (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
cycleId: string | undefined = undefined
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
if (!cycleId) throw new Error("Cycle Id is required");
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[cycleId].push(data.id);
|
|
||||||
this.rootIssueStore.issues.addIssue([data]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data, cycleId);
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
|
||||||
|
|
||||||
const quickAddIssueIndex = this.issues[cycleId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[cycleId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootIssueStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
if (cycleId) this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
addIssueToCycle = async (
|
addIssueToCycle = async (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@ -275,17 +171,14 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
if (fetchAddedIssues) await this.rootIssueStore.issues.getIssues(workspaceSlug, projectId, issueIds);
|
if (fetchAddedIssues) await this.rootIssueStore.issues.getIssues(workspaceSlug, projectId, issueIds);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
update(this.issues, cycleId, (cycleIssueIds = []) => uniq(concat(cycleIssueIds, issueIds)));
|
this.cycleId === cycleId &&
|
||||||
|
update(this, "issues", (cycleIssueIds = []) => uniq(concat(cycleIssueIds, issueIds)));
|
||||||
});
|
});
|
||||||
|
|
||||||
issueIds.forEach((issueId) => {
|
issueIds.forEach((issueId) => {
|
||||||
const issueCycleId = this.rootIssueStore.issues.getIssueById(issueId)?.cycle_id;
|
this.rootIssueStore.issues.updateIssue(issueId, { cycle_id: cycleId });
|
||||||
if (issueCycleId && issueCycleId !== cycleId) {
|
|
||||||
runInAction(() => {
|
|
||||||
pull(this.issues[issueCycleId], issueId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.rootStore.issues.updateIssue(issueId, { cycle_id: cycleId });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -294,13 +187,12 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
|
|
||||||
removeIssueFromCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
removeIssueFromCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
|
await this.issueService.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
pull(this.issues[cycleId], issueId);
|
this.issues && this.cycleId === cycleId && pull(this.issues, issueId);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rootStore.issues.updateIssue(issueId, { cycle_id: null });
|
this.rootIssueStore.issues.updateIssue(issueId, { cycle_id: null });
|
||||||
|
|
||||||
await this.issueService.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -322,7 +214,8 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
cycleId as string,
|
cycleId as string,
|
||||||
payload
|
payload
|
||||||
);
|
);
|
||||||
await this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
this.paginationOptions &&
|
||||||
|
(await this.fetchIssues(workspaceSlug, projectId, "mutation", this.paginationOptions, cycleId));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -333,14 +226,14 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
fetchActiveCycleIssues = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
fetchActiveCycleIssues = async (workspaceSlug: string, projectId: string, cycleId: string) => {
|
||||||
try {
|
try {
|
||||||
const params = { priority: `urgent,high` };
|
const params = { priority: `urgent,high` };
|
||||||
const response = await this.cycleService.getCycleIssuesWithParams(workspaceSlug, projectId, cycleId, params);
|
const response = await this.cycleService.getCycleIssues(workspaceSlug, projectId, cycleId, params);
|
||||||
|
|
||||||
runInAction(() => {
|
// runInAction(() => {
|
||||||
set(this.issues, [ACTIVE_CYCLE_ISSUES], Object.keys(response));
|
// set(this.issues, , Object.keys(response));
|
||||||
this.loader = undefined;
|
// this.loader = undefined;
|
||||||
});
|
// });
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(Object.values(response));
|
// this.rootIssueStore.issues.addIssue(Object.values(response));
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -14,20 +14,22 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface IDraftIssuesFilter {
|
export interface IDraftIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
//helper actions
|
||||||
filters: Record<string, IIssueFilters>; // Record defines projectId as key and IIssueFilters as value
|
getFilterParams: (
|
||||||
// computed
|
options: IssuePaginationOptions,
|
||||||
issueFilters: IIssueFilters | undefined;
|
cursor?: string
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -92,6 +94,22 @@ export class DraftIssuesFilter extends IssueFilterHelperStore implements IDraftI
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const _filters = this.handleIssuesLocalFilters.get(EIssuesStoreType.DRAFT, workspaceSlug, projectId, undefined);
|
const _filters = this.handleIssuesLocalFilters.get(EIssuesStoreType.DRAFT, workspaceSlug, projectId, undefined);
|
||||||
@ -145,7 +163,7 @@ export class DraftIssuesFilter extends IssueFilterHelperStore implements IDraftI
|
|||||||
});
|
});
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.draftIssues.fetchIssues(
|
this.rootIssueStore.draftIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
||||||
@ -188,7 +206,7 @@ export class DraftIssuesFilter extends IssueFilterHelperStore implements IDraftI
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.draftIssues.fetchIssues(workspaceSlug, projectId, "mutation");
|
this.rootIssueStore.draftIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
|
||||||
|
|
||||||
this.handleIssuesLocalFilters.set(EIssuesStoreType.DRAFT, type, workspaceSlug, projectId, undefined, {
|
this.handleIssuesLocalFilters.set(EIssuesStoreType.DRAFT, type, workspaceSlug, projectId, undefined, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,178 +1,103 @@
|
|||||||
import concat from "lodash/concat";
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
import pull from "lodash/pull";
|
|
||||||
import set from "lodash/set";
|
|
||||||
import uniq from "lodash/uniq";
|
|
||||||
import update from "lodash/update";
|
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
|
||||||
// base class
|
// base class
|
||||||
// services
|
// services
|
||||||
import { IssueDraftService } from "services/issue/issue_draft.service";
|
|
||||||
// types
|
// types
|
||||||
import { TIssue, TLoader, TGroupedIssues, TSubGroupedIssues, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
import { TIssue, TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse } from "@plane/types";
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { IDraftIssuesFilter } from "./filter.store";
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
|
||||||
export interface IDraftIssues {
|
export interface IDraftIssues extends IBaseIssuesStore {
|
||||||
// observable
|
// observable
|
||||||
loader: TLoader;
|
|
||||||
issues: { [project_id: string]: string[] };
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<TIssue[]>;
|
fetchIssues: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader,
|
||||||
|
option: IssuePaginationOptions
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchIssuesWithExistingPagination: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
|
||||||
|
fetchNextIssues: (workspaceSlug: string, projectId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
||||||
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
|
||||||
quickAddIssue: undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DraftIssues extends IssueHelperStore implements IDraftIssues {
|
export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
|
||||||
loader: TLoader = "init-loader";
|
|
||||||
issues: { [project_id: string]: string[] } = {};
|
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
enableQuickAdd: false,
|
enableQuickAdd: false,
|
||||||
enableIssueCreation: true,
|
enableIssueCreation: true,
|
||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
// root store
|
// filter store
|
||||||
rootIssueStore: IIssueRootStore;
|
issueFilterStore: IDraftIssuesFilter;
|
||||||
// service
|
|
||||||
issueDraftService;
|
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IDraftIssuesFilter) {
|
||||||
super(_rootStore);
|
super(_rootStore, issueFilterStore);
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
|
||||||
loader: observable.ref,
|
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
createIssue: action,
|
||||||
updateIssue: action,
|
updateIssue: action,
|
||||||
removeIssue: action,
|
removeIssue: action,
|
||||||
});
|
});
|
||||||
// root store
|
// filter store
|
||||||
this.rootIssueStore = _rootStore;
|
this.issueFilterStore = issueFilterStore;
|
||||||
this.issueDraftService = new IssueDraftService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get getIssues() {
|
fetchIssues = async (
|
||||||
const projectId = this.rootIssueStore.projectId;
|
workspaceSlug: string,
|
||||||
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
|
projectId: string,
|
||||||
|
loadType: TLoader = "init-loader",
|
||||||
return this.issues[projectId];
|
options: IssuePaginationOptions
|
||||||
}
|
) => {
|
||||||
|
|
||||||
get groupedIssueIds() {
|
|
||||||
const projectId = this.rootIssueStore.projectId;
|
|
||||||
if (!projectId) return undefined;
|
|
||||||
|
|
||||||
const displayFilters = this.rootIssueStore?.draftIssuesFilter?.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 draftIssueIds = this.issues[projectId];
|
|
||||||
if (!draftIssueIds) return undefined;
|
|
||||||
|
|
||||||
const _issues = this.rootIssueStore.issues.getIssuesByIds(draftIssueIds, "un-archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
|
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
runInAction(() => {
|
||||||
|
this.loader = loadType;
|
||||||
const params = this.rootIssueStore?.draftIssuesFilter?.appliedFilters;
|
});
|
||||||
|
this.clear();
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(options);
|
||||||
const response = await this.issueDraftService.getDraftIssues(workspaceSlug, projectId, params);
|
const response = await this.issueDraftService.getDraftIssues(workspaceSlug, projectId, params);
|
||||||
|
|
||||||
runInAction(() => {
|
this.onfetchIssues(response, options);
|
||||||
set(
|
|
||||||
this.issues,
|
|
||||||
[projectId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => {
|
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
try {
|
try {
|
||||||
const response = await this.issueDraftService.createDraftIssue(workspaceSlug, projectId, data);
|
this.loader = "pagination";
|
||||||
|
|
||||||
runInAction(() => {
|
const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
|
||||||
update(this.issues, [projectId], (issueIds = []) => uniq(concat(issueIds, response.id)));
|
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.addIssue([response]);
|
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
|
fetchIssuesWithExistingPagination = async (
|
||||||
try {
|
workspaceSlug: string,
|
||||||
await this.issueDraftService.updateDraftIssue(workspaceSlug, projectId, issueId, data);
|
projectId: string,
|
||||||
|
loadType: TLoader = "mutation"
|
||||||
this.rootStore.issues.updateIssue(issueId, data);
|
) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
if (data.hasOwnProperty("is_draft") && data?.is_draft === false) {
|
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions);
|
||||||
runInAction(() => {
|
|
||||||
update(this.issues, [projectId], (issueIds = []) => {
|
|
||||||
if (issueIds.includes(issueId)) pull(issueIds, issueId);
|
|
||||||
return issueIds;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
createIssue = this.createDraftIssue;
|
||||||
try {
|
updateIssue = this.updateDraftIssue;
|
||||||
await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
update(this.issues, [projectId], (issueIds = []) => {
|
|
||||||
if (issueIds.includes(issueId)) pull(issueIds, issueId);
|
|
||||||
return issueIds;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quickAddIssue: undefined;
|
|
||||||
}
|
}
|
||||||
|
@ -1,72 +1,387 @@
|
|||||||
|
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
||||||
|
import update from "lodash/update";
|
||||||
|
import uniq from "lodash/uniq";
|
||||||
|
import concat from "lodash/concat";
|
||||||
|
import pull from "lodash/pull";
|
||||||
|
import orderBy from "lodash/orderBy";
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
import indexOf from "lodash/indexOf";
|
import indexOf from "lodash/indexOf";
|
||||||
import isEmpty from "lodash/isEmpty";
|
import isEmpty from "lodash/isEmpty";
|
||||||
import orderBy from "lodash/orderBy";
|
|
||||||
import values from "lodash/values";
|
import values from "lodash/values";
|
||||||
// types
|
// types
|
||||||
|
import {
|
||||||
|
TIssue,
|
||||||
|
TIssueMap,
|
||||||
|
TIssueGroupByOptions,
|
||||||
|
TIssueOrderByOptions,
|
||||||
|
TGroupedIssues,
|
||||||
|
TSubGroupedIssues,
|
||||||
|
TUnGroupedIssues,
|
||||||
|
TLoader,
|
||||||
|
IssuePaginationOptions,
|
||||||
|
TIssuesResponse,
|
||||||
|
} from "@plane/types";
|
||||||
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { IBaseIssueFilterStore } from "./issue-filter-helper.store";
|
||||||
// constants
|
// constants
|
||||||
import { ISSUE_PRIORITIES } from "constants/issue";
|
import { ISSUE_PRIORITIES } from "constants/issue";
|
||||||
import { STATE_GROUPS } from "constants/state";
|
import { STATE_GROUPS } from "constants/state";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { TIssue, TIssueMap, TIssueGroupByOptions, TIssueOrderByOptions } from "@plane/types";
|
// services
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IssueArchiveService, IssueDraftService, IssueService } from "services/issue";
|
||||||
|
|
||||||
export type TIssueDisplayFilterOptions = Exclude<TIssueGroupByOptions, null> | "target_date";
|
export type TIssueDisplayFilterOptions = Exclude<TIssueGroupByOptions, null> | "target_date";
|
||||||
|
|
||||||
export type TIssueHelperStore = {
|
export interface IBaseIssuesStore {
|
||||||
|
// observable
|
||||||
|
loader: TLoader;
|
||||||
|
|
||||||
|
issues: string[] | undefined;
|
||||||
|
|
||||||
|
nextCursor: string | undefined;
|
||||||
|
prevCursor: string | undefined;
|
||||||
|
issueCount: number | undefined;
|
||||||
|
pageCount: number | undefined;
|
||||||
|
|
||||||
|
groupedIssueCount: Record<string, number> | undefined;
|
||||||
|
|
||||||
|
// computed
|
||||||
|
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
||||||
|
|
||||||
|
//actions
|
||||||
|
removeIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<void>;
|
||||||
// helper methods
|
// helper methods
|
||||||
groupedIssues(
|
groupedIssues(
|
||||||
groupBy: TIssueDisplayFilterOptions,
|
groupBy: TIssueDisplayFilterOptions,
|
||||||
orderBy: TIssueOrderByOptions,
|
orderBy: TIssueOrderByOptions,
|
||||||
issues: TIssueMap,
|
issues: TIssueMap,
|
||||||
|
groupedIssueCount: Record<string, number>,
|
||||||
isCalendarIssues?: boolean
|
isCalendarIssues?: boolean
|
||||||
): { [group_id: string]: string[] };
|
): TGroupedIssues;
|
||||||
subGroupedIssues(
|
subGroupedIssues(
|
||||||
subGroupBy: TIssueDisplayFilterOptions,
|
subGroupBy: TIssueDisplayFilterOptions,
|
||||||
groupBy: TIssueDisplayFilterOptions,
|
groupBy: TIssueDisplayFilterOptions,
|
||||||
orderBy: TIssueOrderByOptions,
|
orderBy: TIssueOrderByOptions,
|
||||||
issues: TIssueMap
|
issues: TIssueMap,
|
||||||
): { [sub_group_id: string]: { [group_id: string]: string[] } };
|
groupedIssueCount: Record<string, number>
|
||||||
unGroupedIssues(orderBy: TIssueOrderByOptions, issues: TIssueMap): string[];
|
): TSubGroupedIssues;
|
||||||
|
unGroupedIssues(orderBy: TIssueOrderByOptions, issues: TIssueMap, count: number): TUnGroupedIssues;
|
||||||
issueDisplayFiltersDefaultData(groupBy: string | null): string[];
|
issueDisplayFiltersDefaultData(groupBy: string | null): string[];
|
||||||
issuesSortWithOrderBy(issueObject: TIssueMap, key: Partial<TIssueOrderByOptions>): TIssue[];
|
issuesSortWithOrderBy(issueObject: TIssueMap, key: Partial<TIssueOrderByOptions>): TIssue[];
|
||||||
getGroupArray(value: boolean | number | string | string[] | null, isDate?: boolean): string[];
|
getGroupArray(value: boolean | number | string | string[] | null, isDate?: boolean): string[];
|
||||||
};
|
}
|
||||||
|
|
||||||
const ISSUE_FILTER_DEFAULT_DATA: Record<TIssueDisplayFilterOptions, keyof TIssue> = {
|
const ISSUE_FILTER_DEFAULT_DATA: Record<TIssueDisplayFilterOptions, keyof TIssue> = {
|
||||||
project: "project_id",
|
project: "project_id",
|
||||||
cycle: "cycle_id",
|
|
||||||
module: "module_ids",
|
|
||||||
state: "state_id",
|
state: "state_id",
|
||||||
"state_detail.group": "state_group" as keyof TIssue, // state_detail.group is only being used for state_group display,
|
"state_detail.group": "state_group" as keyof TIssue, // state_detail.group is only being used for state_group display,
|
||||||
priority: "priority",
|
priority: "priority",
|
||||||
labels: "label_ids",
|
labels: "label_ids",
|
||||||
created_by: "created_by",
|
created_by: "created_by",
|
||||||
assignees: "assignee_ids",
|
assignees: "assignee_ids",
|
||||||
mentions: "assignee_ids",
|
|
||||||
target_date: "target_date",
|
target_date: "target_date",
|
||||||
|
cycle: "cycle_id",
|
||||||
|
module: "module_ids",
|
||||||
};
|
};
|
||||||
|
|
||||||
export class IssueHelperStore implements TIssueHelperStore {
|
export class BaseIssuesStore implements IBaseIssuesStore {
|
||||||
// root store
|
loader: TLoader = "init-loader";
|
||||||
rootStore;
|
issues: string[] | undefined = undefined;
|
||||||
|
groupedIssueCount: Record<string, number> | undefined = undefined;
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
nextCursor: string | undefined = undefined;
|
||||||
this.rootStore = _rootStore;
|
prevCursor: string | undefined = undefined;
|
||||||
|
|
||||||
|
issueCount: number | undefined = undefined;
|
||||||
|
pageCount: number | undefined = undefined;
|
||||||
|
|
||||||
|
paginationOptions: IssuePaginationOptions | undefined = undefined;
|
||||||
|
|
||||||
|
isArchived: boolean;
|
||||||
|
|
||||||
|
// services
|
||||||
|
issueService;
|
||||||
|
issueArchiveService;
|
||||||
|
issueDraftService;
|
||||||
|
// root store
|
||||||
|
rootIssueStore;
|
||||||
|
issueFilterStore;
|
||||||
|
|
||||||
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IBaseIssueFilterStore, isArchived = false) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// observable
|
||||||
|
loader: observable.ref,
|
||||||
|
groupedIssueCount: observable,
|
||||||
|
issues: observable,
|
||||||
|
|
||||||
|
nextCursor: observable.ref,
|
||||||
|
prevCursor: observable.ref,
|
||||||
|
issueCount: observable.ref,
|
||||||
|
pageCount: observable.ref,
|
||||||
|
|
||||||
|
paginationOptions: observable,
|
||||||
|
// computed
|
||||||
|
groupedIssueIds: computed,
|
||||||
|
// action
|
||||||
|
storePreviousPaginationValues: action.bound,
|
||||||
|
|
||||||
|
onfetchIssues: action.bound,
|
||||||
|
onfetchNexIssues: action.bound,
|
||||||
|
clear: action.bound,
|
||||||
|
|
||||||
|
createIssue: action,
|
||||||
|
updateIssue: action,
|
||||||
|
removeIssue: action,
|
||||||
|
archiveIssue: action,
|
||||||
|
quickAddIssue: action,
|
||||||
|
removeBulkIssues: action,
|
||||||
|
});
|
||||||
|
this.rootIssueStore = _rootStore;
|
||||||
|
this.issueFilterStore = issueFilterStore;
|
||||||
|
|
||||||
|
this.isArchived = isArchived;
|
||||||
|
|
||||||
|
this.issueService = new IssueService();
|
||||||
|
this.issueArchiveService = new IssueArchiveService();
|
||||||
|
this.issueDraftService = new IssueDraftService();
|
||||||
|
}
|
||||||
|
|
||||||
|
storePreviousPaginationValues = (issuesResponse: TIssuesResponse, options?: IssuePaginationOptions) => {
|
||||||
|
if (options) this.paginationOptions = options;
|
||||||
|
|
||||||
|
this.nextCursor = issuesResponse.next_cursor;
|
||||||
|
this.prevCursor = issuesResponse.prev_cursor;
|
||||||
|
|
||||||
|
this.issueCount = issuesResponse.count;
|
||||||
|
this.pageCount = issuesResponse.total_pages;
|
||||||
|
};
|
||||||
|
|
||||||
|
get groupedIssueIds() {
|
||||||
|
const displayFilters = this.issueFilterStore?.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;
|
||||||
|
|
||||||
|
if (!this.issues) return;
|
||||||
|
|
||||||
|
const _issues = this.rootIssueStore.issues.getIssuesByIds(
|
||||||
|
this.issues,
|
||||||
|
this.isArchived ? "archived" : "un-archived"
|
||||||
|
);
|
||||||
|
if (!_issues) return {};
|
||||||
|
|
||||||
|
let groupedIssues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues = {};
|
||||||
|
|
||||||
|
if (layout === "list" && orderBy) {
|
||||||
|
if (groupBy) groupedIssues = this.groupedIssues(groupBy, orderBy, _issues, this.groupedIssueCount);
|
||||||
|
else groupedIssues = this.unGroupedIssues(orderBy, _issues, this.issueCount);
|
||||||
|
} else if (layout === "kanban" && groupBy && orderBy) {
|
||||||
|
if (subGroupBy)
|
||||||
|
groupedIssues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, _issues, this.groupedIssueCount);
|
||||||
|
else groupedIssues = this.groupedIssues(groupBy, orderBy, _issues, this.groupedIssueCount);
|
||||||
|
} else if (layout === "calendar")
|
||||||
|
groupedIssues = this.groupedIssues("target_date", "target_date", _issues, this.groupedIssueCount, true);
|
||||||
|
else if (layout === "spreadsheet")
|
||||||
|
groupedIssues = this.unGroupedIssues(orderBy ?? "-created_at", _issues, this.issueCount);
|
||||||
|
else if (layout === "gantt_chart")
|
||||||
|
groupedIssues = this.unGroupedIssues(orderBy ?? "sort_order", _issues, this.issueCount);
|
||||||
|
|
||||||
|
return groupedIssues;
|
||||||
|
}
|
||||||
|
|
||||||
|
onfetchIssues(issuesResponse: TIssuesResponse, options: IssuePaginationOptions) {
|
||||||
|
const { issueList, groupedIssueCount } = this.processIssueResponse(issuesResponse);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues = issueList.map((issue) => issue.id);
|
||||||
|
this.groupedIssueCount = groupedIssueCount;
|
||||||
|
this.loader = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rootIssueStore.issues.addIssue(issueList);
|
||||||
|
|
||||||
|
this.storePreviousPaginationValues(issuesResponse, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
onfetchNexIssues(issuesResponse: TIssuesResponse) {
|
||||||
|
const { issueList, groupedIssueCount } = this.processIssueResponse(issuesResponse);
|
||||||
|
const newIssueIds = issueList.map((issue) => issue.id);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
update(this, "issues", (issueIds: string[] = []) => {
|
||||||
|
return uniq(concat(issueIds, newIssueIds));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.groupedIssueCount = groupedIssueCount;
|
||||||
|
this.loader = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rootIssueStore.issues.addIssue(issueList);
|
||||||
|
|
||||||
|
this.storePreviousPaginationValues(issuesResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
async createIssue(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
data: Partial<TIssue>,
|
||||||
|
id?: string,
|
||||||
|
shouldAddStore = true
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
|
||||||
|
|
||||||
|
if (shouldAddStore) this.addIssue(response);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateIssue(workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) {
|
||||||
|
const issueBeforeUpdate = { ...this.rootIssueStore.issues.getIssueById(issueId) };
|
||||||
|
try {
|
||||||
|
this.rootIssueStore.issues.updateIssue(issueId, data);
|
||||||
|
|
||||||
|
await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
|
||||||
|
} catch (error) {
|
||||||
|
this.rootIssueStore.issues.updateIssue(issueId, issueBeforeUpdate);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createDraftIssue(workspaceSlug: string, projectId: string, data: Partial<TIssue>) {
|
||||||
|
try {
|
||||||
|
const response = await this.issueDraftService.createDraftIssue(workspaceSlug, projectId, data);
|
||||||
|
|
||||||
|
this.addIssue(response);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDraftIssue(workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) {
|
||||||
|
const issueBeforeUpdate = { ...this.rootIssueStore.issues.getIssueById(issueId) };
|
||||||
|
try {
|
||||||
|
this.rootIssueStore.issues.updateIssue(issueId, data);
|
||||||
|
|
||||||
|
await this.issueDraftService.updateDraftIssue(workspaceSlug, projectId, issueId, data);
|
||||||
|
} catch (error) {
|
||||||
|
this.rootIssueStore.issues.updateIssue(issueId, issueBeforeUpdate);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeIssue(workspaceSlug: string, projectId: string, issueId: string) {
|
||||||
|
try {
|
||||||
|
await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
if (this.issues) pull(this.issues, issueId);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rootIssueStore.issues.removeIssue(issueId);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async archiveIssue(workspaceSlug: string, projectId: string, issueId: string) {
|
||||||
|
try {
|
||||||
|
const response = await this.issueArchiveService.archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.rootIssueStore.issues.updateIssue(issueId, {
|
||||||
|
archived_at: response.archived_at,
|
||||||
|
});
|
||||||
|
if (this.issues) pull(this.issues, issueId);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue) {
|
||||||
|
if (!this.issues) this.issues = [];
|
||||||
|
try {
|
||||||
|
this.addIssue(data);
|
||||||
|
|
||||||
|
const response = await this.createIssue(workspaceSlug, projectId, data);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
if (!this.issues) return;
|
||||||
|
const quickAddIssueIndex = this.issues.findIndex((_issueId) => _issueId === data.id);
|
||||||
|
if (quickAddIssueIndex >= 0)
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues!.splice(quickAddIssueIndex, 1);
|
||||||
|
this.rootIssueStore.issues.removeIssue(data.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeBulkIssues(workspaceSlug: string, projectId: string, issueIds: string[]) {
|
||||||
|
try {
|
||||||
|
if (!this.issues) return;
|
||||||
|
|
||||||
|
const response = await this.issueService.bulkDeleteIssues(workspaceSlug, projectId, { issue_ids: issueIds });
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
issueIds.forEach((issueId) => {
|
||||||
|
pull(this.issues!, issueId);
|
||||||
|
this.rootIssueStore.issues.removeIssue(issueId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addIssue(issue: TIssue) {
|
||||||
|
runInAction(() => {
|
||||||
|
if (!this.issues) this.issues = [];
|
||||||
|
this.issues.push(issue.id);
|
||||||
|
this.rootIssueStore.issues.addIssue([issue]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues = undefined;
|
||||||
|
this.groupedIssueCount = undefined;
|
||||||
|
this.groupedIssueCount = undefined;
|
||||||
|
|
||||||
|
this.nextCursor = undefined;
|
||||||
|
this.prevCursor = undefined;
|
||||||
|
|
||||||
|
this.issueCount = undefined;
|
||||||
|
this.pageCount = undefined;
|
||||||
|
|
||||||
|
this.paginationOptions = undefined;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedIssues = (
|
groupedIssues = (
|
||||||
groupBy: TIssueDisplayFilterOptions,
|
groupBy: TIssueDisplayFilterOptions,
|
||||||
orderBy: TIssueOrderByOptions,
|
orderBy: TIssueOrderByOptions,
|
||||||
issues: TIssueMap,
|
issues: TIssueMap,
|
||||||
|
groupedIssueCount: Record<string, number> | undefined,
|
||||||
isCalendarIssues: boolean = false
|
isCalendarIssues: boolean = false
|
||||||
) => {
|
) => {
|
||||||
const _issues: { [group_id: string]: string[] } = {};
|
const _issues: TGroupedIssues = {};
|
||||||
if (!groupBy) return _issues;
|
if (!groupBy || !groupedIssueCount) return _issues;
|
||||||
|
|
||||||
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
|
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
|
||||||
_issues[group] = [];
|
_issues[group] = { issueIds: [], issueCount: groupedIssueCount[group] };
|
||||||
});
|
});
|
||||||
|
|
||||||
const projectIssues = this.issuesSortWithOrderBy(issues, orderBy);
|
const projectIssues = this.issuesSortWithOrderBy(issues, orderBy);
|
||||||
@ -76,8 +391,8 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
let groupArray = [];
|
let groupArray = [];
|
||||||
|
|
||||||
if (groupBy === "state_detail.group") {
|
if (groupBy === "state_detail.group") {
|
||||||
// if groupBy state_detail.group is coming from the project level the we are using stateDetails from root store else we are looping through the stateMap
|
const state_group =
|
||||||
const state_group = (this.rootStore?.stateMap || {})?.[_issue?.state_id]?.group || "None";
|
this.rootIssueStore?.stateDetails?.find((_state) => _state.id === _issue?.state_id)?.group || "None";
|
||||||
groupArray = [state_group];
|
groupArray = [state_group];
|
||||||
} else {
|
} else {
|
||||||
const groupValue = get(_issue, ISSUE_FILTER_DEFAULT_DATA[groupBy]);
|
const groupValue = get(_issue, ISSUE_FILTER_DEFAULT_DATA[groupBy]);
|
||||||
@ -85,8 +400,8 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const group of groupArray) {
|
for (const group of groupArray) {
|
||||||
if (group && _issues[group]) _issues[group].push(_issue.id);
|
if (group && _issues[group]) _issues[group].issueIds.push(_issue.id);
|
||||||
else if (group) _issues[group] = [_issue.id];
|
else if (group) _issues[group].issueIds = [_issue.id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,15 +412,16 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
subGroupBy: TIssueDisplayFilterOptions,
|
subGroupBy: TIssueDisplayFilterOptions,
|
||||||
groupBy: TIssueDisplayFilterOptions,
|
groupBy: TIssueDisplayFilterOptions,
|
||||||
orderBy: TIssueOrderByOptions,
|
orderBy: TIssueOrderByOptions,
|
||||||
issues: TIssueMap
|
issues: TIssueMap,
|
||||||
|
groupedIssueCount: Record<string, number> | undefined
|
||||||
) => {
|
) => {
|
||||||
const _issues: { [sub_group_id: string]: { [group_id: string]: string[] } } = {};
|
const _issues: TSubGroupedIssues = {};
|
||||||
if (!subGroupBy || !groupBy) return _issues;
|
if (!subGroupBy || !groupBy || !groupedIssueCount) return _issues;
|
||||||
|
|
||||||
this.issueDisplayFiltersDefaultData(subGroupBy).forEach((sub_group: any) => {
|
this.issueDisplayFiltersDefaultData(subGroupBy).forEach((sub_group: any) => {
|
||||||
const groupByIssues: { [group_id: string]: string[] } = {};
|
const groupByIssues: TGroupedIssues = {};
|
||||||
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
|
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
|
||||||
groupByIssues[group] = [];
|
groupByIssues[group] = { issueIds: [], issueCount: groupedIssueCount[group] };
|
||||||
});
|
});
|
||||||
_issues[sub_group] = groupByIssues;
|
_issues[sub_group] = groupByIssues;
|
||||||
});
|
});
|
||||||
@ -117,8 +433,8 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
let subGroupArray = [];
|
let subGroupArray = [];
|
||||||
let groupArray = [];
|
let groupArray = [];
|
||||||
if (subGroupBy === "state_detail.group" || groupBy === "state_detail.group") {
|
if (subGroupBy === "state_detail.group" || groupBy === "state_detail.group") {
|
||||||
const state_group = (this.rootStore?.stateMap || {})?.[_issue?.state_id]?.group || "None";
|
const state_group =
|
||||||
|
this.rootIssueStore?.stateDetails?.find((_state) => _state.id === _issue?.state_id)?.group || "None";
|
||||||
subGroupArray = [state_group];
|
subGroupArray = [state_group];
|
||||||
groupArray = [state_group];
|
groupArray = [state_group];
|
||||||
} else {
|
} else {
|
||||||
@ -130,9 +446,10 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
|
|
||||||
for (const subGroup of subGroupArray) {
|
for (const subGroup of subGroupArray) {
|
||||||
for (const group of groupArray) {
|
for (const group of groupArray) {
|
||||||
if (subGroup && group && _issues?.[subGroup]?.[group]) _issues[subGroup][group].push(_issue.id);
|
if (subGroup && group && _issues?.[subGroup]?.[group]) _issues[subGroup][group].issueIds.push(_issue.id);
|
||||||
else if (subGroup && group && _issues[subGroup]) _issues[subGroup][group] = [_issue.id];
|
else if (subGroup && group && _issues[subGroup]) _issues[subGroup][group].issueIds = [_issue.id];
|
||||||
else if (subGroup && group) _issues[subGroup] = { [group]: [_issue.id] };
|
else if (subGroup && group)
|
||||||
|
_issues[subGroup] = { [group]: { issueIds: [_issue.id], issueCount: groupedIssueCount[group] } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,29 +457,28 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
return _issues;
|
return _issues;
|
||||||
};
|
};
|
||||||
|
|
||||||
unGroupedIssues = (orderBy: TIssueOrderByOptions, issues: TIssueMap) =>
|
unGroupedIssues = (orderBy: TIssueOrderByOptions, issues: TIssueMap, count: number | undefined) => {
|
||||||
this.issuesSortWithOrderBy(issues, orderBy).map((issue) => issue.id);
|
const issueIds = this.issuesSortWithOrderBy(issues, orderBy).map((issue) => issue.id);
|
||||||
|
|
||||||
|
return { "All Issues": { issueIds, issueCount: count || issueIds.length } };
|
||||||
|
};
|
||||||
|
|
||||||
issueDisplayFiltersDefaultData = (groupBy: string | null): string[] => {
|
issueDisplayFiltersDefaultData = (groupBy: string | null): string[] => {
|
||||||
switch (groupBy) {
|
switch (groupBy) {
|
||||||
case "state":
|
case "state":
|
||||||
return Object.keys(this.rootStore?.stateMap || {});
|
return Object.keys(this.rootIssueStore?.stateMap || {});
|
||||||
case "state_detail.group":
|
case "state_detail.group":
|
||||||
return Object.keys(STATE_GROUPS);
|
return Object.keys(STATE_GROUPS);
|
||||||
case "priority":
|
case "priority":
|
||||||
return ISSUE_PRIORITIES.map((i) => i.key);
|
return ISSUE_PRIORITIES.map((i) => i.key);
|
||||||
case "labels":
|
case "labels":
|
||||||
return Object.keys(this.rootStore?.labelMap || {});
|
return Object.keys(this.rootIssueStore?.labelMap || {});
|
||||||
case "created_by":
|
case "created_by":
|
||||||
return Object.keys(this.rootStore?.workSpaceMemberRolesMap || {});
|
return Object.keys(this.rootIssueStore?.workSpaceMemberRolesMap || {});
|
||||||
case "assignees":
|
case "assignees":
|
||||||
return Object.keys(this.rootStore?.workSpaceMemberRolesMap || {});
|
return Object.keys(this.rootIssueStore?.workSpaceMemberRolesMap || {});
|
||||||
case "project":
|
case "project":
|
||||||
return Object.keys(this.rootStore?.projectMap || {});
|
return Object.keys(this.rootIssueStore?.projectMap || {});
|
||||||
case "cycle":
|
|
||||||
return Object.keys(this.rootStore?.cycleMap || {});
|
|
||||||
case "module":
|
|
||||||
return Object.keys(this.rootStore?.moduleMap || {});
|
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -188,7 +504,7 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
|
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case "state_id":
|
case "state_id":
|
||||||
const stateMap = this.rootStore?.stateMap;
|
const stateMap = this.rootIssueStore?.stateMap;
|
||||||
if (!stateMap) break;
|
if (!stateMap) break;
|
||||||
for (const dataId of dataIdsArray) {
|
for (const dataId of dataIdsArray) {
|
||||||
const state = stateMap[dataId];
|
const state = stateMap[dataId];
|
||||||
@ -196,7 +512,7 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "label_ids":
|
case "label_ids":
|
||||||
const labelMap = this.rootStore?.labelMap;
|
const labelMap = this.rootIssueStore?.labelMap;
|
||||||
if (!labelMap) break;
|
if (!labelMap) break;
|
||||||
for (const dataId of dataIdsArray) {
|
for (const dataId of dataIdsArray) {
|
||||||
const label = labelMap[dataId];
|
const label = labelMap[dataId];
|
||||||
@ -204,7 +520,7 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "assignee_ids":
|
case "assignee_ids":
|
||||||
const memberMap = this.rootStore?.memberMap;
|
const memberMap = this.rootIssueStore?.memberMap;
|
||||||
if (!memberMap) break;
|
if (!memberMap) break;
|
||||||
for (const dataId of dataIdsArray) {
|
for (const dataId of dataIdsArray) {
|
||||||
const member = memberMap[dataId];
|
const member = memberMap[dataId];
|
||||||
@ -212,7 +528,7 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "module_ids":
|
case "module_ids":
|
||||||
const moduleMap = this.rootStore?.moduleMap;
|
const moduleMap = this.rootIssueStore?.moduleMap;
|
||||||
if (!moduleMap) break;
|
if (!moduleMap) break;
|
||||||
for (const dataId of dataIdsArray) {
|
for (const dataId of dataIdsArray) {
|
||||||
const _module = moduleMap[dataId];
|
const _module = moduleMap[dataId];
|
||||||
@ -220,7 +536,7 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cycle_id":
|
case "cycle_id":
|
||||||
const cycleMap = this.rootStore?.cycleMap;
|
const cycleMap = this.rootIssueStore?.cycleMap;
|
||||||
if (!cycleMap) break;
|
if (!cycleMap) break;
|
||||||
for (const dataId of dataIdsArray) {
|
for (const dataId of dataIdsArray) {
|
||||||
const cycle = cycleMap[dataId];
|
const cycle = cycleMap[dataId];
|
||||||
@ -233,10 +549,10 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Method is mainly used to filter out empty values in the beginning
|
* This Method is mainly used to filter out empty values in the begining
|
||||||
* @param key key of the value that is to be checked if empty
|
* @param key key of the value that is to be checked if empty
|
||||||
* @param object any object in which the key's value is to be checked
|
* @param object any object in which the key's value is to be checked
|
||||||
* @returns 1 if empty, 0 if not empty
|
* @returns 1 if emoty, 0 if not empty
|
||||||
*/
|
*/
|
||||||
getSortOrderToFilterEmptyValues(key: string, object: any) {
|
getSortOrderToFilterEmptyValues(key: string, object: any) {
|
||||||
const value = object?.[key];
|
const value = object?.[key];
|
||||||
@ -248,7 +564,7 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
|
|
||||||
issuesSortWithOrderBy = (issueObject: TIssueMap, key: Partial<TIssueOrderByOptions>): TIssue[] => {
|
issuesSortWithOrderBy = (issueObject: TIssueMap, key: Partial<TIssueOrderByOptions>): TIssue[] => {
|
||||||
let array = values(issueObject);
|
let array = values(issueObject);
|
||||||
array = orderBy(array, "created_at");
|
array = orderBy(array, "created_at", ["asc"]);
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "sort_order":
|
case "sort_order":
|
||||||
@ -395,4 +711,38 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
else if (isDate) return [renderFormattedPayloadDate(value) || "None"];
|
else if (isDate) return [renderFormattedPayloadDate(value) || "None"];
|
||||||
else return [value || "None"];
|
else return [value || "None"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processIssueResponse(issueResponse: TIssuesResponse): {
|
||||||
|
issueList: TIssue[];
|
||||||
|
groupedIssueCount: Record<string, number>;
|
||||||
|
} {
|
||||||
|
const issueResult = issueResponse?.results;
|
||||||
|
|
||||||
|
if (!issueResult)
|
||||||
|
return {
|
||||||
|
issueList: [],
|
||||||
|
groupedIssueCount: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(issueResult)) {
|
||||||
|
return {
|
||||||
|
issueList: issueResult,
|
||||||
|
groupedIssueCount: { "All Issues": issueResponse.count },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const issueList: TIssue[] = [];
|
||||||
|
const groupedIssueCount: Record<string, number> = {};
|
||||||
|
|
||||||
|
for (const groupId in issueResult) {
|
||||||
|
const groupIssueResult = issueResult[groupId];
|
||||||
|
|
||||||
|
if (!groupIssueResult) continue;
|
||||||
|
|
||||||
|
issueList.push(...groupIssueResult.results);
|
||||||
|
groupedIssueCount[groupId] = groupIssueResult.total_results;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { issueList, groupedIssueCount };
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,5 @@
|
|||||||
import isEmpty from "lodash/isEmpty";
|
import isEmpty from "lodash/isEmpty";
|
||||||
// types
|
// types
|
||||||
// constants
|
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
|
|
||||||
// lib
|
|
||||||
import { storage } from "lib/local-storage";
|
|
||||||
import {
|
import {
|
||||||
IIssueDisplayFilterOptions,
|
IIssueDisplayFilterOptions,
|
||||||
IIssueDisplayProperties,
|
IIssueDisplayProperties,
|
||||||
@ -14,6 +10,10 @@ import {
|
|||||||
TIssueParams,
|
TIssueParams,
|
||||||
TStaticViewTypes,
|
TStaticViewTypes,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
|
// constants
|
||||||
|
import { EIssueFilterType, EIssuesStoreType, IssueGroupByOptions } from "constants/issue";
|
||||||
|
// lib
|
||||||
|
import { storage } from "lib/local-storage";
|
||||||
|
|
||||||
interface ILocalStoreIssueFilters {
|
interface ILocalStoreIssueFilters {
|
||||||
key: EIssuesStoreType;
|
key: EIssuesStoreType;
|
||||||
@ -23,6 +23,14 @@ interface ILocalStoreIssueFilters {
|
|||||||
filters: IIssueFilters;
|
filters: IIssueFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IBaseIssueFilterStore {
|
||||||
|
// observables
|
||||||
|
filters: Record<string, IIssueFilters>;
|
||||||
|
//computed
|
||||||
|
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
||||||
|
issueFilters: IIssueFilters | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IIssueFilterHelperStore {
|
export interface IIssueFilterHelperStore {
|
||||||
computedIssueFilters(filters: IIssueFilters): IIssueFilters;
|
computedIssueFilters(filters: IIssueFilters): IIssueFilters;
|
||||||
computedFilteredParams(
|
computedFilteredParams(
|
||||||
@ -78,9 +86,11 @@ export class IssueFilterHelperStore implements IIssueFilterHelperStore {
|
|||||||
module: filters?.module || undefined,
|
module: filters?.module || undefined,
|
||||||
start_date: filters?.start_date || undefined,
|
start_date: filters?.start_date || undefined,
|
||||||
target_date: filters?.target_date || undefined,
|
target_date: filters?.target_date || undefined,
|
||||||
project: filters.project || undefined,
|
project: filters?.project || undefined,
|
||||||
subscriber: filters.subscriber || undefined,
|
subscriber: filters?.subscriber || undefined,
|
||||||
// display filters
|
// display filters
|
||||||
|
group_by: displayFilters?.group_by ? IssueGroupByOptions[displayFilters.group_by] : undefined,
|
||||||
|
order_by: displayFilters?.order_by || undefined,
|
||||||
type: displayFilters?.type || undefined,
|
type: displayFilters?.type || undefined,
|
||||||
sub_issue: displayFilters?.sub_issue ?? true,
|
sub_issue: displayFilters?.sub_issue ?? true,
|
||||||
};
|
};
|
||||||
|
@ -14,20 +14,22 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface IModuleIssuesFilter {
|
export interface IModuleIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
//helper actions
|
||||||
filters: Record<string, IIssueFilters>; // Record defines moduleId as key and IIssueFilters as value
|
getFilterParams: (
|
||||||
// computed
|
options: IssuePaginationOptions,
|
||||||
issueFilters: IIssueFilters | undefined;
|
cursor?: string
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -95,6 +97,22 @@ export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModul
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
fetchFilters = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||||
try {
|
try {
|
||||||
const _filters = await this.issueFilterService.fetchModuleIssueFilters(workspaceSlug, projectId, moduleId);
|
const _filters = await this.issueFilterService.fetchModuleIssueFilters(workspaceSlug, projectId, moduleId);
|
||||||
@ -160,7 +178,7 @@ export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModul
|
|||||||
});
|
});
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.moduleIssues.fetchIssues(
|
this.rootIssueStore.moduleIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation",
|
isEmpty(filteredFilters) ? "init-loader" : "mutation",
|
||||||
@ -204,7 +222,12 @@ export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModul
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.moduleIssues.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
|
this.rootIssueStore.moduleIssues.fetchIssuesWithExistingPagination(
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
"mutation",
|
||||||
|
moduleId
|
||||||
|
);
|
||||||
|
|
||||||
await this.issueFilterService.patchModuleIssueFilters(workspaceSlug, projectId, moduleId, {
|
await this.issueFilterService.patchModuleIssueFilters(workspaceSlug, projectId, moduleId, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,53 +1,41 @@
|
|||||||
import concat from "lodash/concat";
|
import concat from "lodash/concat";
|
||||||
import pull from "lodash/pull";
|
import pull from "lodash/pull";
|
||||||
import set from "lodash/set";
|
|
||||||
import uniq from "lodash/uniq";
|
import uniq from "lodash/uniq";
|
||||||
import update from "lodash/update";
|
import update from "lodash/update";
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
||||||
// base class
|
// base class
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
// services
|
// services
|
||||||
import { IssueService } from "services/issue";
|
|
||||||
import { ModuleService } from "services/module.service";
|
import { ModuleService } from "services/module.service";
|
||||||
// types
|
// types
|
||||||
import { TIssue, TLoader, TGroupedIssues, TSubGroupedIssues, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
import { TIssue, TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse } from "@plane/types";
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { IModuleIssuesFilter } from "./filter.store";
|
||||||
|
|
||||||
export interface IModuleIssues {
|
export interface IModuleIssues extends IBaseIssuesStore {
|
||||||
// observable
|
|
||||||
loader: TLoader;
|
|
||||||
issues: { [module_id: string]: string[] };
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: (
|
fetchIssues: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
loadType: TLoader,
|
loadType: TLoader,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
moduleId: string
|
moduleId: string
|
||||||
) => Promise<TIssue[] | undefined>;
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
createIssue: (
|
fetchIssuesWithExistingPagination: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
data: Partial<TIssue>,
|
loadType: TLoader,
|
||||||
moduleId: string
|
moduleId: string
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
updateIssue: (
|
fetchNextIssues: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>, moduleId: string) => Promise<TIssue>;
|
||||||
issueId: string,
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
data: Partial<TIssue>,
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
moduleId: string
|
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue | undefined>;
|
||||||
) => Promise<void>;
|
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string, moduleId: string) => Promise<void>;
|
|
||||||
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string, moduleId: string) => Promise<void>;
|
|
||||||
quickAddIssue: (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
moduleId?: string | undefined
|
|
||||||
) => Promise<TIssue | undefined>;
|
|
||||||
addIssuesToModule: (
|
addIssuesToModule: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@ -71,193 +59,99 @@ export interface IModuleIssues {
|
|||||||
removeIssueFromModule: (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => Promise<void>;
|
removeIssueFromModule: (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
|
||||||
loader: TLoader = "init-loader";
|
moduleId: string | undefined = undefined;
|
||||||
issues: { [module_id: string]: string[] } = {};
|
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
enableQuickAdd: true,
|
enableQuickAdd: true,
|
||||||
enableIssueCreation: true,
|
enableIssueCreation: true,
|
||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
// root store
|
|
||||||
rootIssueStore: IIssueRootStore;
|
|
||||||
// service
|
// service
|
||||||
moduleService;
|
moduleService;
|
||||||
issueService;
|
// filter store
|
||||||
|
issueFilterStore: IModuleIssuesFilter;
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IModuleIssuesFilter) {
|
||||||
super(_rootStore);
|
super(_rootStore, issueFilterStore);
|
||||||
|
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
// observable
|
||||||
loader: observable.ref,
|
moduleId: observable.ref,
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
|
||||||
updateIssue: action,
|
|
||||||
removeIssue: action,
|
|
||||||
archiveIssue: action,
|
|
||||||
quickAddIssue: action,
|
|
||||||
addIssuesToModule: action,
|
addIssuesToModule: action,
|
||||||
removeIssuesFromModule: action,
|
removeIssuesFromModule: action,
|
||||||
addModulesToIssue: action,
|
addModulesToIssue: action,
|
||||||
removeModulesFromIssue: action,
|
removeModulesFromIssue: action,
|
||||||
removeIssueFromModule: action,
|
removeIssueFromModule: action,
|
||||||
});
|
});
|
||||||
|
// filter store
|
||||||
this.rootIssueStore = _rootStore;
|
this.issueFilterStore = issueFilterStore;
|
||||||
this.issueService = new IssueService();
|
// service
|
||||||
this.moduleService = new ModuleService();
|
this.moduleService = new ModuleService();
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupedIssueIds() {
|
|
||||||
const moduleId = this.rootIssueStore?.moduleId;
|
|
||||||
if (!moduleId) return undefined;
|
|
||||||
|
|
||||||
const displayFilters = this.rootIssueStore?.moduleIssuesFilter?.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 moduleIssueIds = this.issues[moduleId];
|
|
||||||
if (!moduleIssueIds) return;
|
|
||||||
|
|
||||||
const _issues = this.rootIssueStore.issues.getIssuesByIds(moduleIssueIds, "un-archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues = [];
|
|
||||||
|
|
||||||
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", "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 (
|
fetchIssues = async (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
loadType: TLoader = "init-loader",
|
loadType: TLoader,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
moduleId: string
|
moduleId: string
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
|
||||||
|
|
||||||
const params = this.rootIssueStore?.moduleIssuesFilter?.appliedFilters;
|
|
||||||
const response = await this.moduleService.getModuleIssues(workspaceSlug, projectId, moduleId, params);
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
set(
|
this.loader = loadType;
|
||||||
this.issues,
|
|
||||||
[moduleId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
});
|
||||||
|
this.clear();
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
this.moduleId = moduleId;
|
||||||
|
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(options);
|
||||||
|
const response = await this.moduleService.getModuleIssues(workspaceSlug, projectId, moduleId, params);
|
||||||
|
|
||||||
|
this.onfetchIssues(response, options);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, moduleId: string) => {
|
fetchNextIssues = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
try {
|
try {
|
||||||
const response = await this.rootIssueStore.projectIssues.createIssue(workspaceSlug, projectId, data);
|
this.loader = "pagination";
|
||||||
await this.addIssuesToModule(workspaceSlug, projectId, moduleId, [response.id], false);
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
|
||||||
|
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
|
||||||
|
const response = await this.moduleService.getModuleIssues(workspaceSlug, projectId, moduleId, params);
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (
|
fetchIssuesWithExistingPagination = async (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
issueId: string,
|
loadType: TLoader,
|
||||||
data: Partial<TIssue>,
|
|
||||||
moduleId: string
|
moduleId: string
|
||||||
) => {
|
) => {
|
||||||
try {
|
if (!this.paginationOptions) return;
|
||||||
await this.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
|
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions, moduleId);
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleId: string) => {
|
override createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, moduleId: string) => {
|
||||||
try {
|
try {
|
||||||
await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
const response = await super.createIssue(workspaceSlug, projectId, data, moduleId, false);
|
||||||
|
await this.addIssuesToModule(workspaceSlug, projectId, moduleId, [response.id], false);
|
||||||
|
this.moduleId === moduleId && this.addIssue(response);
|
||||||
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
|
||||||
const issueIndex = this.issues[moduleId].findIndex((_issueId) => _issueId === issueId);
|
|
||||||
if (issueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[moduleId].splice(issueIndex, 1);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
archiveIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleId: string) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.archiveIssue(workspaceSlug, projectId, issueId);
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
pull(this.issues[moduleId], issueId);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quickAddIssue = async (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
moduleId: string | undefined = undefined
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
if (!moduleId) throw new Error("Module Id is required");
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[moduleId].push(data.id);
|
|
||||||
this.rootIssueStore.issues.addIssue([data]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data, moduleId);
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
|
||||||
|
|
||||||
const quickAddIssueIndex = this.issues[moduleId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[moduleId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootIssueStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -279,18 +173,20 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
|||||||
if (fetchAddedIssues) await this.rootIssueStore.issues.getIssues(workspaceSlug, projectId, issueIds);
|
if (fetchAddedIssues) await this.rootIssueStore.issues.getIssues(workspaceSlug, projectId, issueIds);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
update(this.issues, moduleId, (moduleIssueIds = []) => {
|
this.moduleId === moduleId &&
|
||||||
if (!moduleIssueIds) return [...issueIds];
|
update(this, "issues", (moduleIssueIds = []) => {
|
||||||
else return uniq(concat(moduleIssueIds, issueIds));
|
if (!moduleIssueIds) return [...issueIds];
|
||||||
});
|
else return uniq(concat(moduleIssueIds, issueIds));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
issueIds.forEach((issueId) => {
|
issueIds.forEach((issueId) => {
|
||||||
update(this.rootStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) => {
|
update(this.rootIssueStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) => {
|
||||||
if (issueModuleIds.includes(moduleId)) return issueModuleIds;
|
if (issueModuleIds.includes(moduleId)) return issueModuleIds;
|
||||||
else return uniq(concat(issueModuleIds, [moduleId]));
|
else return uniq(concat(issueModuleIds, [moduleId]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
@ -299,27 +195,29 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
|||||||
|
|
||||||
removeIssuesFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueIds: string[]) => {
|
removeIssuesFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
runInAction(() => {
|
|
||||||
issueIds.forEach((issueId) => {
|
|
||||||
pull(this.issues[moduleId], issueId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
issueIds.forEach((issueId) => {
|
|
||||||
update(this.rootStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) => {
|
|
||||||
if (issueModuleIds.includes(moduleId)) return pull(issueModuleIds, moduleId);
|
|
||||||
else return uniq(concat(issueModuleIds, [moduleId]));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await this.moduleService.removeIssuesFromModuleBulk(
|
const response = await this.moduleService.removeIssuesFromModuleBulk(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
moduleId,
|
moduleId,
|
||||||
issueIds
|
issueIds
|
||||||
);
|
);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.moduleId === moduleId &&
|
||||||
|
issueIds.forEach((issueId) => {
|
||||||
|
this.issues && pull(this.issues, issueId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
issueIds.forEach((issueId) => {
|
||||||
|
update(this.rootIssueStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) => {
|
||||||
|
if (issueModuleIds.includes(moduleId)) return pull(issueModuleIds, moduleId);
|
||||||
|
else return uniq(concat(issueModuleIds, [moduleId]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
@ -336,12 +234,13 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
|||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
moduleIds.forEach((moduleId) => {
|
moduleIds.forEach((moduleId) => {
|
||||||
update(this.issues, moduleId, (moduleIssueIds = []) => {
|
this.moduleId === moduleId &&
|
||||||
if (moduleIssueIds.includes(issueId)) return moduleIssueIds;
|
update(this, "issues", (moduleIssueIds = []) => {
|
||||||
else return uniq(concat(moduleIssueIds, [issueId]));
|
if (moduleIssueIds.includes(issueId)) return moduleIssueIds;
|
||||||
});
|
else return uniq(concat(moduleIssueIds, [issueId]));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
update(this.rootStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) =>
|
update(this.rootIssueStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) =>
|
||||||
uniq(concat(issueModuleIds, moduleIds))
|
uniq(concat(issueModuleIds, moduleIds))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -356,11 +255,12 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
|||||||
try {
|
try {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
moduleIds.forEach((moduleId) => {
|
moduleIds.forEach((moduleId) => {
|
||||||
update(this.issues, moduleId, (moduleIssueIds = []) => {
|
this.moduleId === moduleId &&
|
||||||
if (moduleIssueIds.includes(issueId)) return pull(moduleIssueIds, issueId);
|
update(this, "issues", (moduleIssueIds = []) => {
|
||||||
else return uniq(concat(moduleIssueIds, [issueId]));
|
if (moduleIssueIds.includes(issueId)) return pull(moduleIssueIds, issueId);
|
||||||
});
|
else return uniq(concat(moduleIssueIds, [issueId]));
|
||||||
update(this.rootStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) =>
|
});
|
||||||
|
update(this.rootIssueStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) =>
|
||||||
pull(issueModuleIds, moduleId)
|
pull(issueModuleIds, moduleId)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -382,8 +282,8 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
|||||||
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
pull(this.issues[moduleId], issueId);
|
this.issues && this.moduleId === this.moduleId && pull(this.issues, issueId);
|
||||||
update(this.rootStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) =>
|
update(this.rootIssueStore.issues.issuesMap, [issueId, "module_ids"], (issueModuleIds = []) =>
|
||||||
pull(issueModuleIds, moduleId)
|
pull(issueModuleIds, moduleId)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -14,21 +14,24 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface IProfileIssuesFilter {
|
export interface IProfileIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
// observables
|
||||||
userId: string;
|
userId: string;
|
||||||
filters: Record<string, IIssueFilters>; // Record defines userId as key and IIssueFilters as value
|
//helper actions
|
||||||
// computed
|
getFilterParams: (
|
||||||
issueFilters: IIssueFilters | undefined;
|
options: IssuePaginationOptions,
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
cursor?: string
|
||||||
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, userId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, userId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -96,6 +99,22 @@ export class ProfileIssuesFilter extends IssueFilterHelperStore implements IProf
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, userId: string) => {
|
fetchFilters = async (workspaceSlug: string, userId: string) => {
|
||||||
try {
|
try {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
@ -150,12 +169,10 @@ export class ProfileIssuesFilter extends IssueFilterHelperStore implements IProf
|
|||||||
|
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.profileIssues.fetchIssues(
|
this.rootIssueStore.profileIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
undefined,
|
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation",
|
|
||||||
userId,
|
userId,
|
||||||
this.rootIssueStore.profileIssues.currentView
|
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
||||||
);
|
);
|
||||||
|
|
||||||
this.handleIssuesLocalFilters.set(EIssuesStoreType.PROFILE, type, workspaceSlug, userId, undefined, {
|
this.handleIssuesLocalFilters.set(EIssuesStoreType.PROFILE, type, workspaceSlug, userId, undefined, {
|
||||||
@ -196,13 +213,7 @@ export class ProfileIssuesFilter extends IssueFilterHelperStore implements IProf
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.profileIssues.fetchIssues(
|
this.rootIssueStore.profileIssues.fetchIssuesWithExistingPagination(workspaceSlug, userId, "mutation");
|
||||||
workspaceSlug,
|
|
||||||
undefined,
|
|
||||||
"mutation",
|
|
||||||
userId,
|
|
||||||
this.rootIssueStore.profileIssues.currentView
|
|
||||||
);
|
|
||||||
|
|
||||||
this.handleIssuesLocalFilters.set(EIssuesStoreType.PROFILE, type, workspaceSlug, userId, undefined, {
|
this.handleIssuesLocalFilters.set(EIssuesStoreType.PROFILE, type, workspaceSlug, userId, undefined, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,123 +1,63 @@
|
|||||||
import pull from "lodash/pull";
|
|
||||||
import set from "lodash/set";
|
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
||||||
// base class
|
// base class
|
||||||
import { UserService } from "services/user.service";
|
import { UserService } from "services/user.service";
|
||||||
import { TIssue, TLoader, TGroupedIssues, TSubGroupedIssues, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
import { TIssue, TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse } from "@plane/types";
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
// services
|
// services
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { IProfileIssuesFilter } from "./filter.store";
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
|
||||||
interface IProfileIssueTabTypes {
|
export interface IProfileIssues extends IBaseIssuesStore {
|
||||||
[key: string]: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IProfileIssues {
|
|
||||||
// observable
|
// observable
|
||||||
loader: TLoader;
|
|
||||||
currentView: "assigned" | "created" | "subscribed";
|
currentView: "assigned" | "created" | "subscribed";
|
||||||
issues: { [userId: string]: IProfileIssueTabTypes };
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// actions
|
// actions
|
||||||
setViewId: (viewId: "assigned" | "created" | "subscribed") => void;
|
setViewId: (viewId: "assigned" | "created" | "subscribed") => void;
|
||||||
|
// action
|
||||||
fetchIssues: (
|
fetchIssues: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string | undefined,
|
|
||||||
loadType: TLoader,
|
|
||||||
userId: string,
|
userId: string,
|
||||||
view?: "assigned" | "created" | "subscribed"
|
loadType: TLoader,
|
||||||
) => Promise<TIssue[]>;
|
option: IssuePaginationOptions,
|
||||||
createIssue: (
|
view: "assigned" | "created" | "subscribed"
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchIssuesWithExistingPagination: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
userId: string,
|
||||||
data: Partial<TIssue>,
|
loadType: TLoader
|
||||||
userId: string
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
) => Promise<TIssue | undefined>;
|
fetchNextIssues: (workspaceSlug: string, userId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
updateIssue: (
|
|
||||||
workspaceSlug: string,
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
||||||
projectId: string,
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
issueId: string,
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
data: Partial<TIssue>,
|
|
||||||
userId: string
|
|
||||||
) => Promise<void>;
|
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string, userId: string) => Promise<void>;
|
|
||||||
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string, userId: string) => Promise<void>;
|
|
||||||
quickAddIssue: undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProfileIssues extends IssueHelperStore implements IProfileIssues {
|
export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
|
||||||
loader: TLoader = "init-loader";
|
|
||||||
currentView: "assigned" | "created" | "subscribed" = "assigned";
|
currentView: "assigned" | "created" | "subscribed" = "assigned";
|
||||||
issues: { [userId: string]: IProfileIssueTabTypes } = {};
|
// filter store
|
||||||
quickAddIssue = undefined;
|
issueFilterStore: IProfileIssuesFilter;
|
||||||
// root store
|
|
||||||
rootIssueStore: IIssueRootStore;
|
|
||||||
// services
|
// services
|
||||||
userService;
|
userService;
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IProfileIssuesFilter) {
|
||||||
super(_rootStore);
|
super(_rootStore, issueFilterStore);
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
// observable
|
||||||
loader: observable.ref,
|
|
||||||
currentView: observable.ref,
|
currentView: observable.ref,
|
||||||
issues: observable,
|
|
||||||
// computed
|
// computed
|
||||||
groupedIssueIds: computed,
|
|
||||||
viewFlags: computed,
|
viewFlags: computed,
|
||||||
// action
|
// action
|
||||||
setViewId: action.bound,
|
setViewId: action.bound,
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
|
||||||
updateIssue: action,
|
|
||||||
removeIssue: action,
|
|
||||||
archiveIssue: action,
|
|
||||||
});
|
});
|
||||||
// root store
|
// filter store
|
||||||
this.rootIssueStore = _rootStore;
|
this.issueFilterStore = issueFilterStore;
|
||||||
// services
|
// services
|
||||||
this.userService = new UserService();
|
this.userService = new UserService();
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupedIssueIds() {
|
|
||||||
const userId = this.rootIssueStore.userId;
|
|
||||||
const workspaceSlug = this.rootIssueStore.workspaceSlug;
|
|
||||||
const currentView = this.currentView;
|
|
||||||
if (!userId || !currentView || !workspaceSlug) return undefined;
|
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${currentView}`;
|
|
||||||
|
|
||||||
const displayFilters = this.rootIssueStore?.profileIssuesFilter?.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 userIssueIds = this.issues[userId]?.[uniqueViewId];
|
|
||||||
|
|
||||||
if (!userIssueIds) return;
|
|
||||||
|
|
||||||
const _issues = this.rootStore.issues.getIssuesByIds(userIssueIds, "un-archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
|
|
||||||
get viewFlags() {
|
get viewFlags() {
|
||||||
if (this.currentView === "subscribed")
|
if (this.currentView === "subscribed")
|
||||||
return {
|
return {
|
||||||
@ -138,20 +78,20 @@ export class ProfileIssues extends IssueHelperStore implements IProfileIssues {
|
|||||||
|
|
||||||
fetchIssues = async (
|
fetchIssues = async (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string | undefined,
|
|
||||||
loadType: TLoader = "init-loader",
|
|
||||||
userId: string,
|
userId: string,
|
||||||
view?: "assigned" | "created" | "subscribed"
|
loadType: TLoader,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
|
view: "assigned" | "created" | "subscribed"
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
runInAction(() => {
|
||||||
if (view) this.currentView = view;
|
this.loader = loadType;
|
||||||
|
});
|
||||||
|
this.clear();
|
||||||
|
|
||||||
if (!this.currentView) throw new Error("current tab view is required");
|
this.setViewId(view);
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${view}`;
|
let params = this.issueFilterStore?.getFilterParams(options);
|
||||||
|
|
||||||
let params: any = this.rootIssueStore?.profileIssuesFilter?.appliedFilters;
|
|
||||||
params = {
|
params = {
|
||||||
...params,
|
...params,
|
||||||
assignees: undefined,
|
assignees: undefined,
|
||||||
@ -164,17 +104,7 @@ export class ProfileIssues extends IssueHelperStore implements IProfileIssues {
|
|||||||
|
|
||||||
const response = await this.userService.getUserProfileIssues(workspaceSlug, userId, params);
|
const response = await this.userService.getUserProfileIssues(workspaceSlug, userId, params);
|
||||||
|
|
||||||
runInAction(() => {
|
this.onfetchIssues(response, options);
|
||||||
set(
|
|
||||||
this.issues,
|
|
||||||
[userId, uniqueViewId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
@ -182,73 +112,34 @@ export class ProfileIssues extends IssueHelperStore implements IProfileIssues {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, userId: string) => {
|
fetchNextIssues = async (workspaceSlug: string, userId: string) => {
|
||||||
|
if (!this.paginationOptions || !this.currentView) return;
|
||||||
try {
|
try {
|
||||||
const response = await this.rootIssueStore.projectIssues.createIssue(workspaceSlug, projectId, data);
|
this.loader = "pagination";
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${this.currentView}`;
|
let params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
|
||||||
|
params = {
|
||||||
|
...params,
|
||||||
|
assignees: undefined,
|
||||||
|
created_by: undefined,
|
||||||
|
subscriber: undefined,
|
||||||
|
};
|
||||||
|
if (this.currentView === "assigned") params = { ...params, assignees: userId };
|
||||||
|
else if (this.currentView === "created") params = { ...params, created_by: userId };
|
||||||
|
else if (this.currentView === "subscribed") params = { ...params, subscriber: userId };
|
||||||
|
|
||||||
runInAction(() => {
|
const response = await this.userService.getUserProfileIssues(workspaceSlug, userId, params);
|
||||||
this.issues[userId][uniqueViewId].push(response.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.addIssue([response]);
|
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (
|
fetchIssuesWithExistingPagination = async (workspaceSlug: string, userId: string, loadType: TLoader) => {
|
||||||
workspaceSlug: string,
|
if (!this.paginationOptions || !this.currentView) return;
|
||||||
projectId: string,
|
return await this.fetchIssues(workspaceSlug, userId, loadType, this.paginationOptions, this.currentView);
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
userId: string
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
this.rootStore.issues.updateIssue(issueId, data);
|
|
||||||
await this.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, data.id as keyof TIssue, data);
|
|
||||||
} catch (error) {
|
|
||||||
if (this.currentView) this.fetchIssues(workspaceSlug, undefined, "mutation", userId, this.currentView);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeIssue = async (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
userId: string | undefined = undefined
|
|
||||||
) => {
|
|
||||||
if (!userId) return;
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${this.currentView}`;
|
|
||||||
|
|
||||||
const issueIndex = this.issues[userId][uniqueViewId].findIndex((_issueId) => _issueId === issueId);
|
|
||||||
if (issueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[userId][uniqueViewId].splice(issueIndex, 1);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
archiveIssue = async (workspaceSlug: string, projectId: string, issueId: string, userId: string) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.archiveIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${this.currentView}`;
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
pull(this.issues[userId][uniqueViewId], issueId);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,20 +14,22 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface IProjectViewIssuesFilter {
|
export interface IProjectViewIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
//helper actions
|
||||||
filters: Record<string, IIssueFilters>; // Record defines viewId as key and IIssueFilters as value
|
getFilterParams: (
|
||||||
// computed
|
options: IssuePaginationOptions,
|
||||||
issueFilters: IIssueFilters | undefined;
|
cursor?: string
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -93,6 +95,22 @@ export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements I
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, projectId: string, viewId: string) => {
|
fetchFilters = async (workspaceSlug: string, projectId: string, viewId: string) => {
|
||||||
try {
|
try {
|
||||||
const _filters = await this.issueFilterService.getViewDetails(workspaceSlug, projectId, viewId);
|
const _filters = await this.issueFilterService.getViewDetails(workspaceSlug, projectId, viewId);
|
||||||
@ -159,11 +177,10 @@ export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements I
|
|||||||
|
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.projectViewIssues.fetchIssues(
|
this.rootIssueStore.projectViewIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation",
|
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
||||||
viewId
|
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case EIssueFilterType.DISPLAY_FILTERS:
|
case EIssueFilterType.DISPLAY_FILTERS:
|
||||||
@ -200,7 +217,11 @@ export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements I
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.projectViewIssues.fetchIssues(workspaceSlug, projectId, "mutation", viewId);
|
this.rootIssueStore.projectViewIssues.fetchIssuesWithExistingPagination(
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
"mutation"
|
||||||
|
);
|
||||||
|
|
||||||
await this.issueFilterService.patchView(workspaceSlug, projectId, viewId, {
|
await this.issueFilterService.patchView(workspaceSlug, projectId, viewId, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,230 +1,94 @@
|
|||||||
import pull from "lodash/pull";
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
import set from "lodash/set";
|
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
|
||||||
// base class
|
// base class
|
||||||
import { IssueService } from "services/issue/issue.service";
|
import { TIssue, TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse } from "@plane/types";
|
||||||
import { TIssue, TLoader, TGroupedIssues, TSubGroupedIssues, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
// services
|
// services
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
import { IProjectViewIssuesFilter } from "./filter.store";
|
||||||
|
|
||||||
export interface IProjectViewIssues {
|
export interface IProjectViewIssues extends IBaseIssuesStore {
|
||||||
// observable
|
|
||||||
loader: TLoader;
|
|
||||||
issues: { [view_id: string]: string[] };
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: (
|
fetchIssues: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
loadType: TLoader,
|
loadType: TLoader,
|
||||||
viewId: string
|
options: IssuePaginationOptions
|
||||||
) => Promise<TIssue[] | undefined>;
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
createIssue: (
|
fetchIssuesWithExistingPagination: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
data: Partial<TIssue>,
|
loadType: TLoader
|
||||||
viewId: string
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
) => Promise<TIssue | undefined>;
|
fetchNextIssues: (workspaceSlug: string, projectId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
updateIssue: (
|
|
||||||
workspaceSlug: string,
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
||||||
projectId: string,
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
issueId: string,
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
data: Partial<TIssue>,
|
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue | undefined>;
|
||||||
viewId: string
|
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
||||||
) => Promise<void>;
|
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string, viewId: string) => Promise<void>;
|
|
||||||
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string, viewId: string) => Promise<void>;
|
|
||||||
quickAddIssue: (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
viewId?: string | undefined
|
|
||||||
) => Promise<TIssue | undefined>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProjectViewIssues extends IssueHelperStore implements IProjectViewIssues {
|
export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIssues {
|
||||||
loader: TLoader = "init-loader";
|
|
||||||
issues: { [view_id: string]: string[] } = {};
|
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
enableQuickAdd: true,
|
enableQuickAdd: true,
|
||||||
enableIssueCreation: true,
|
enableIssueCreation: true,
|
||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
// root store
|
//filter store
|
||||||
rootIssueStore: IIssueRootStore;
|
issueFilterStore: IProjectViewIssuesFilter;
|
||||||
// services
|
|
||||||
issueService;
|
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IProjectViewIssuesFilter) {
|
||||||
super(_rootStore);
|
super(_rootStore, issueFilterStore);
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
|
||||||
loader: observable.ref,
|
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
|
||||||
updateIssue: action,
|
|
||||||
removeIssue: action,
|
|
||||||
archiveIssue: action,
|
|
||||||
quickAddIssue: action,
|
|
||||||
});
|
});
|
||||||
// root store
|
//filter store
|
||||||
this.rootIssueStore = _rootStore;
|
this.issueFilterStore = issueFilterStore;
|
||||||
// services
|
|
||||||
this.issueService = new IssueService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupedIssueIds() {
|
fetchIssues = async (
|
||||||
const viewId = this.rootStore?.viewId;
|
workspaceSlug: string,
|
||||||
if (!viewId) return undefined;
|
projectId: string,
|
||||||
|
loadType: TLoader,
|
||||||
const displayFilters = this.rootIssueStore?.projectViewIssuesFilter?.issueFilters?.displayFilters;
|
options: IssuePaginationOptions
|
||||||
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 viewIssueIds = this.issues[viewId];
|
|
||||||
if (!viewIssueIds) return;
|
|
||||||
|
|
||||||
const _issues = this.rootStore.issues.getIssuesByIds(viewIssueIds, "un-archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues = [];
|
|
||||||
|
|
||||||
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", "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", viewId: string) => {
|
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
runInAction(() => {
|
||||||
|
this.loader = loadType;
|
||||||
const params = this.rootIssueStore?.projectViewIssuesFilter?.appliedFilters;
|
});
|
||||||
|
this.clear();
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(options);
|
||||||
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||||
|
|
||||||
runInAction(() => {
|
this.onfetchIssues(response, options);
|
||||||
set(
|
|
||||||
this.issues,
|
|
||||||
[viewId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, viewId: string) => {
|
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
try {
|
try {
|
||||||
const response = await this.rootIssueStore.projectIssues.createIssue(workspaceSlug, projectId, data);
|
this.loader = "pagination";
|
||||||
|
|
||||||
runInAction(() => {
|
const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
|
||||||
this.issues[viewId].push(response.id);
|
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||||
});
|
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation", viewId);
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (
|
fetchIssuesWithExistingPagination = async (workspaceSlug: string, projectId: string, loadType: TLoader) => {
|
||||||
workspaceSlug: string,
|
if (!this.paginationOptions) return;
|
||||||
projectId: string,
|
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions);
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
viewId: string
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation", viewId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string, viewId: string) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
const issueIndex = this.issues[viewId].findIndex((_issueId) => _issueId === issueId);
|
|
||||||
if (issueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[viewId].splice(issueIndex, 1);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation", viewId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
archiveIssue = async (workspaceSlug: string, projectId: string, issueId: string, viewId: string) => {
|
|
||||||
try {
|
|
||||||
await this.rootIssueStore.projectIssues.archiveIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
pull(this.issues[viewId], issueId);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation", viewId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quickAddIssue = async (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
viewId: string | undefined = undefined
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
if (!viewId) throw new Error("View Id is required");
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[viewId].push(data.id);
|
|
||||||
this.rootIssueStore.issues.addIssue([data]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data, viewId);
|
|
||||||
|
|
||||||
const quickAddIssueIndex = this.issues[viewId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[viewId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootIssueStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
if (viewId) this.fetchIssues(workspaceSlug, projectId, "mutation", viewId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import pickBy from "lodash/pickBy";
|
|||||||
import set from "lodash/set";
|
import set from "lodash/set";
|
||||||
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
import { action, computed, makeObservable, observable, runInAction } from "mobx";
|
||||||
// base class
|
// base class
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
|
|
||||||
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
||||||
import { IssueFiltersService } from "services/issue_filter.service";
|
import { IssueFiltersService } from "services/issue_filter.service";
|
||||||
import {
|
import {
|
||||||
@ -14,20 +13,23 @@ import {
|
|||||||
TIssueKanbanFilters,
|
TIssueKanbanFilters,
|
||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
// constants
|
// constants
|
||||||
|
import { EIssueFilterType, EIssuesStoreType, IssueGroupByOptions } from "constants/issue";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// services
|
// services
|
||||||
|
|
||||||
export interface IProjectIssuesFilter {
|
export interface IProjectIssuesFilter extends IBaseIssueFilterStore {
|
||||||
// observables
|
//helper actions
|
||||||
filters: Record<string, IIssueFilters>; // Record defines projectId as key and IIssueFilters as value
|
getFilterParams: (
|
||||||
// computed
|
options: IssuePaginationOptions,
|
||||||
issueFilters: IIssueFilters | undefined;
|
cursor?: string
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
// action
|
// action
|
||||||
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -92,6 +94,22 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFilterParams = computedFn((options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.appliedFilters;
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
fetchFilters = async (workspaceSlug: string, projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const _filters = await this.issueFilterService.fetchProjectIssueFilters(workspaceSlug, projectId);
|
const _filters = await this.issueFilterService.fetchProjectIssueFilters(workspaceSlug, projectId);
|
||||||
@ -157,7 +175,7 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj
|
|||||||
|
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.projectIssues.fetchIssues(
|
this.rootIssueStore.projectIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
||||||
@ -200,7 +218,7 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.projectIssues.fetchIssues(workspaceSlug, projectId, "mutation");
|
this.rootIssueStore.projectIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
|
||||||
|
|
||||||
await this.issueFilterService.patchProjectIssueFilters(workspaceSlug, projectId, {
|
await this.issueFilterService.patchProjectIssueFilters(workspaceSlug, projectId, {
|
||||||
display_filters: _filters.displayFilters,
|
display_filters: _filters.displayFilters,
|
||||||
|
@ -1,123 +1,72 @@
|
|||||||
import concat from "lodash/concat";
|
|
||||||
import pull from "lodash/pull";
|
|
||||||
import set from "lodash/set";
|
|
||||||
import update from "lodash/update";
|
|
||||||
import { action, makeObservable, observable, runInAction, computed } from "mobx";
|
|
||||||
// base class
|
|
||||||
import { IssueService, IssueArchiveService } from "services/issue";
|
|
||||||
import { TIssue, TGroupedIssues, TSubGroupedIssues, TLoader, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
// services
|
// services
|
||||||
// types
|
// types
|
||||||
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
|
// base class
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { TLoader, ViewFlags, IssuePaginationOptions, TIssuesResponse, TIssue } from "@plane/types";
|
||||||
|
import { IProjectIssuesFilter } from "./filter.store";
|
||||||
|
|
||||||
export interface IProjectIssues {
|
export interface IProjectIssues extends IBaseIssuesStore {
|
||||||
// observable
|
|
||||||
loader: TLoader;
|
|
||||||
issues: Record<string, string[]>; // Record of project_id as key and issue_ids as value
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues | undefined;
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<TIssue[]>;
|
fetchIssues: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader,
|
||||||
|
option: IssuePaginationOptions
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchIssuesWithExistingPagination: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
loadType: TLoader
|
||||||
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
|
fetchNextIssues: (workspaceSlug: string, projectId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
|
|
||||||
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
||||||
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
|
||||||
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue>;
|
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue) => Promise<TIssue | undefined>;
|
||||||
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
export class ProjectIssues extends BaseIssuesStore implements IProjectIssues {
|
||||||
// observable
|
|
||||||
loader: TLoader = "init-loader";
|
|
||||||
issues: Record<string, string[]> = {};
|
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
enableQuickAdd: true,
|
enableQuickAdd: true,
|
||||||
enableIssueCreation: true,
|
enableIssueCreation: true,
|
||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
// root store
|
|
||||||
rootIssueStore: IIssueRootStore;
|
|
||||||
// services
|
|
||||||
issueService;
|
|
||||||
issueArchiveService;
|
|
||||||
|
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
// filter store
|
||||||
super(_rootStore);
|
issueFilterStore: IProjectIssuesFilter;
|
||||||
|
|
||||||
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IProjectIssuesFilter) {
|
||||||
|
super(_rootStore, issueFilterStore);
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
|
||||||
loader: observable.ref,
|
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
fetchNextIssues: action,
|
||||||
updateIssue: action,
|
fetchIssuesWithExistingPagination: action,
|
||||||
removeIssue: action,
|
|
||||||
archiveIssue: action,
|
|
||||||
removeBulkIssues: action,
|
|
||||||
quickAddIssue: action,
|
|
||||||
});
|
});
|
||||||
// root store
|
// filter store
|
||||||
this.rootIssueStore = _rootStore;
|
this.issueFilterStore = issueFilterStore;
|
||||||
// services
|
|
||||||
this.issueService = new IssueService();
|
|
||||||
this.issueArchiveService = new IssueArchiveService();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupedIssueIds() {
|
fetchIssues = async (
|
||||||
const projectId = this.rootStore?.projectId;
|
workspaceSlug: string,
|
||||||
if (!projectId) return undefined;
|
projectId: string,
|
||||||
|
loadType: TLoader = "init-loader",
|
||||||
const displayFilters = this.rootStore?.projectIssuesFilter?.issueFilters?.displayFilters;
|
options: IssuePaginationOptions
|
||||||
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 projectIssueIds = this.issues[projectId];
|
|
||||||
if (!projectIssueIds) return;
|
|
||||||
|
|
||||||
const _issues = this.rootStore.issues.getIssuesByIds(projectIssueIds, "un-archived");
|
|
||||||
if (!_issues) return [];
|
|
||||||
|
|
||||||
let issues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues = [];
|
|
||||||
|
|
||||||
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", "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 {
|
try {
|
||||||
this.loader = loadType;
|
runInAction(() => {
|
||||||
|
this.loader = loadType;
|
||||||
const params = this.rootStore?.projectIssuesFilter?.appliedFilters;
|
});
|
||||||
|
this.clear();
|
||||||
|
const params = this.issueFilterStore?.getFilterParams(options);
|
||||||
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||||
|
|
||||||
runInAction(() => {
|
this.onfetchIssues(response, options);
|
||||||
set(
|
|
||||||
this.issues,
|
|
||||||
[projectId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.addIssue(response);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
@ -125,102 +74,28 @@ export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => {
|
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
try {
|
try {
|
||||||
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
|
this.loader = "pagination";
|
||||||
|
|
||||||
runInAction(() => {
|
const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
|
||||||
update(this.issues, [projectId], (issueIds) => {
|
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
|
||||||
if (!issueIds) return [response.id];
|
|
||||||
return concat(issueIds, response.id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.addIssue([response]);
|
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
|
fetchIssuesWithExistingPagination = async (
|
||||||
try {
|
workspaceSlug: string,
|
||||||
this.rootStore.issues.updateIssue(issueId, data);
|
projectId: string,
|
||||||
|
loadType: TLoader = "mutation"
|
||||||
await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
|
) => {
|
||||||
} catch (error) {
|
if (!this.paginationOptions) return;
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions);
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
|
||||||
try {
|
|
||||||
await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
pull(this.issues[projectId], issueId);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.removeIssue(issueId);
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
archiveIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
|
|
||||||
try {
|
|
||||||
const response = await this.issueArchiveService.archiveIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.rootStore.issues.updateIssue(issueId, {
|
|
||||||
archived_at: response.archived_at,
|
|
||||||
});
|
|
||||||
pull(this.issues[projectId], issueId);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quickAddIssue = async (workspaceSlug: string, projectId: string, data: TIssue) => {
|
|
||||||
try {
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[projectId].push(data.id);
|
|
||||||
this.rootStore.issues.addIssue([data]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data);
|
|
||||||
|
|
||||||
const quickAddIssueIndex = this.issues[projectId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[projectId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeBulkIssues = async (workspaceSlug: string, projectId: string, issueIds: string[]) => {
|
|
||||||
try {
|
|
||||||
runInAction(() => {
|
|
||||||
issueIds.forEach((issueId) => {
|
|
||||||
pull(this.issues[projectId], issueId);
|
|
||||||
this.rootStore.issues.removeIssue(issueId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await this.issueService.bulkDeleteIssues(workspaceSlug, projectId, { issue_ids: issueIds });
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -184,28 +184,28 @@ export class IssueRootStore implements IIssueRootStore {
|
|||||||
this.issueDetail = new IssueDetail(this);
|
this.issueDetail = new IssueDetail(this);
|
||||||
|
|
||||||
this.workspaceIssuesFilter = new WorkspaceIssuesFilter(this);
|
this.workspaceIssuesFilter = new WorkspaceIssuesFilter(this);
|
||||||
this.workspaceIssues = new WorkspaceIssues(this);
|
this.workspaceIssues = new WorkspaceIssues(this, this.workspaceIssuesFilter);
|
||||||
|
|
||||||
this.profileIssuesFilter = new ProfileIssuesFilter(this);
|
this.profileIssuesFilter = new ProfileIssuesFilter(this);
|
||||||
this.profileIssues = new ProfileIssues(this);
|
this.profileIssues = new ProfileIssues(this, this.profileIssuesFilter);
|
||||||
|
|
||||||
this.projectIssuesFilter = new ProjectIssuesFilter(this);
|
this.projectIssuesFilter = new ProjectIssuesFilter(this);
|
||||||
this.projectIssues = new ProjectIssues(this);
|
this.projectIssues = new ProjectIssues(this, this.projectIssuesFilter);
|
||||||
|
|
||||||
this.cycleIssuesFilter = new CycleIssuesFilter(this);
|
this.cycleIssuesFilter = new CycleIssuesFilter(this);
|
||||||
this.cycleIssues = new CycleIssues(this);
|
this.cycleIssues = new CycleIssues(this, this.cycleIssuesFilter);
|
||||||
|
|
||||||
this.moduleIssuesFilter = new ModuleIssuesFilter(this);
|
this.moduleIssuesFilter = new ModuleIssuesFilter(this);
|
||||||
this.moduleIssues = new ModuleIssues(this);
|
this.moduleIssues = new ModuleIssues(this, this.moduleIssuesFilter);
|
||||||
|
|
||||||
this.projectViewIssuesFilter = new ProjectViewIssuesFilter(this);
|
this.projectViewIssuesFilter = new ProjectViewIssuesFilter(this);
|
||||||
this.projectViewIssues = new ProjectViewIssues(this);
|
this.projectViewIssues = new ProjectViewIssues(this, this.projectViewIssuesFilter);
|
||||||
|
|
||||||
this.archivedIssuesFilter = new ArchivedIssuesFilter(this);
|
this.archivedIssuesFilter = new ArchivedIssuesFilter(this);
|
||||||
this.archivedIssues = new ArchivedIssues(this);
|
this.archivedIssues = new ArchivedIssues(this, this.archivedIssuesFilter);
|
||||||
|
|
||||||
this.draftIssuesFilter = new DraftIssuesFilter(this);
|
this.draftIssuesFilter = new DraftIssuesFilter(this);
|
||||||
this.draftIssues = new DraftIssues(this);
|
this.draftIssues = new DraftIssues(this, this.draftIssuesFilter);
|
||||||
|
|
||||||
this.issueKanBanView = new IssueKanBanViewStore(this);
|
this.issueKanBanView = new IssueKanBanViewStore(this);
|
||||||
this.issueCalendarView = new CalendarStore();
|
this.issueCalendarView = new CalendarStore();
|
||||||
|
@ -15,21 +15,19 @@ import {
|
|||||||
IIssueFilters,
|
IIssueFilters,
|
||||||
TIssueParams,
|
TIssueParams,
|
||||||
TStaticViewTypes,
|
TStaticViewTypes,
|
||||||
|
IssuePaginationOptions,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
import { IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
import { IBaseIssueFilterStore, IssueFilterHelperStore } from "../helpers/issue-filter-helper.store";
|
||||||
// helpers
|
// helpers
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { computedFn } from "mobx-utils";
|
||||||
// constants
|
// constants
|
||||||
// services
|
// services
|
||||||
|
|
||||||
type TWorkspaceFilters = "all-issues" | "assigned" | "created" | "subscribed" | string;
|
type TWorkspaceFilters = "all-issues" | "assigned" | "created" | "subscribed" | string;
|
||||||
export interface IWorkspaceIssuesFilter {
|
|
||||||
// observables
|
export interface IWorkspaceIssuesFilter extends IBaseIssueFilterStore {
|
||||||
filters: Record<TWorkspaceFilters, IIssueFilters>; // Record defines viewId as key and IIssueFilters as value
|
|
||||||
// computed
|
|
||||||
issueFilters: IIssueFilters | undefined;
|
|
||||||
appliedFilters: Partial<Record<TIssueParams, string | boolean>> | undefined;
|
|
||||||
// fetch action
|
// fetch action
|
||||||
fetchFilters: (workspaceSlug: string, viewId: string) => Promise<void>;
|
fetchFilters: (workspaceSlug: string, viewId: string) => Promise<void>;
|
||||||
updateFilters: (
|
updateFilters: (
|
||||||
@ -42,6 +40,11 @@ export interface IWorkspaceIssuesFilter {
|
|||||||
//helper action
|
//helper action
|
||||||
getIssueFilters: (viewId: string | undefined) => IIssueFilters | undefined;
|
getIssueFilters: (viewId: string | undefined) => IIssueFilters | undefined;
|
||||||
getAppliedFilters: (viewId: string) => Partial<Record<TIssueParams, string | boolean>> | undefined;
|
getAppliedFilters: (viewId: string) => Partial<Record<TIssueParams, string | boolean>> | undefined;
|
||||||
|
getFilterParams: (
|
||||||
|
viewId: string,
|
||||||
|
options: IssuePaginationOptions,
|
||||||
|
cursor?: string
|
||||||
|
) => Partial<Record<TIssueParams, string | boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWorkspaceIssuesFilter {
|
export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWorkspaceIssuesFilter {
|
||||||
@ -63,9 +66,6 @@ export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWo
|
|||||||
// fetch actions
|
// fetch actions
|
||||||
fetchFilters: action,
|
fetchFilters: action,
|
||||||
updateFilters: action,
|
updateFilters: action,
|
||||||
// helper actions
|
|
||||||
getIssueFilters: action,
|
|
||||||
getAppliedFilters: action,
|
|
||||||
});
|
});
|
||||||
// root store
|
// root store
|
||||||
this.rootIssueStore = _rootStore;
|
this.rootIssueStore = _rootStore;
|
||||||
@ -102,6 +102,22 @@ export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWo
|
|||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getFilterParams = computedFn((viewId: string, options: IssuePaginationOptions, cursor: string | undefined) => {
|
||||||
|
const filterParams = this.getAppliedFilters(viewId);
|
||||||
|
|
||||||
|
const paginationOptions: Partial<Record<TIssueParams, string | boolean>> = {
|
||||||
|
...filterParams,
|
||||||
|
cursor: cursor ? cursor : `${options.perPageCount}:0:0`,
|
||||||
|
per_page: options.perPageCount.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.groupedBy) {
|
||||||
|
paginationOptions.group_by = options.groupedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return paginationOptions;
|
||||||
|
});
|
||||||
|
|
||||||
get issueFilters() {
|
get issueFilters() {
|
||||||
const viewId = this.rootIssueStore.globalViewId;
|
const viewId = this.rootIssueStore.globalViewId;
|
||||||
return this.getIssueFilters(viewId);
|
return this.getIssueFilters(viewId);
|
||||||
@ -182,7 +198,7 @@ export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWo
|
|||||||
});
|
});
|
||||||
const appliedFilters = _filters.filters || {};
|
const appliedFilters = _filters.filters || {};
|
||||||
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
const filteredFilters = pickBy(appliedFilters, (value) => value && isArray(value) && value.length > 0);
|
||||||
this.rootIssueStore.workspaceIssues.fetchIssues(
|
this.rootIssueStore.workspaceIssues.fetchIssuesWithExistingPagination(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
viewId,
|
viewId,
|
||||||
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
isEmpty(filteredFilters) ? "init-loader" : "mutation"
|
||||||
@ -222,7 +238,7 @@ export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWo
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (this.requiresServerUpdate(updatedDisplayFilters))
|
if (this.requiresServerUpdate(updatedDisplayFilters))
|
||||||
this.rootIssueStore.workspaceIssues.fetchIssues(workspaceSlug, viewId, "mutation");
|
this.rootIssueStore.workspaceIssues.fetchIssuesWithExistingPagination(workspaceSlug, viewId, "mutation");
|
||||||
|
|
||||||
if (["all-issues", "assigned", "created", "subscribed"].includes(viewId))
|
if (["all-issues", "assigned", "created", "subscribed"].includes(viewId))
|
||||||
this.handleIssuesLocalFilters.set(EIssuesStoreType.GLOBAL, type, workspaceSlug, undefined, viewId, {
|
this.handleIssuesLocalFilters.set(EIssuesStoreType.GLOBAL, type, workspaceSlug, undefined, viewId, {
|
||||||
|
@ -1,215 +1,93 @@
|
|||||||
import pull from "lodash/pull";
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
import set from "lodash/set";
|
|
||||||
import { action, observable, makeObservable, computed, runInAction } from "mobx";
|
|
||||||
// base class
|
// base class
|
||||||
import { IssueService, IssueArchiveService } from "services/issue";
|
|
||||||
import { WorkspaceService } from "services/workspace.service";
|
import { WorkspaceService } from "services/workspace.service";
|
||||||
import { TIssue, TLoader, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
import { IssuePaginationOptions, TIssue, TIssuesResponse, TLoader, TUnGroupedIssues, ViewFlags } from "@plane/types";
|
||||||
import { IssueHelperStore } from "../helpers/issue-helper.store";
|
|
||||||
// services
|
// services
|
||||||
// types
|
// types
|
||||||
import { IIssueRootStore } from "../root.store";
|
import { IIssueRootStore } from "../root.store";
|
||||||
|
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
|
||||||
|
import { IWorkspaceIssuesFilter } from "./filter.store";
|
||||||
|
|
||||||
export interface IWorkspaceIssues {
|
export interface IWorkspaceIssues extends IBaseIssuesStore {
|
||||||
// observable
|
// observable
|
||||||
loader: TLoader;
|
|
||||||
issues: { [viewId: string]: string[] };
|
|
||||||
viewFlags: ViewFlags;
|
viewFlags: ViewFlags;
|
||||||
// computed
|
|
||||||
groupedIssueIds: { dataViewId: string; issueIds: TUnGroupedIssues | undefined };
|
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: (workspaceSlug: string, viewId: string, loadType: TLoader) => Promise<TIssue[]>;
|
fetchIssues: (
|
||||||
createIssue: (
|
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
viewId: string,
|
||||||
data: Partial<TIssue>,
|
loadType: TLoader,
|
||||||
viewId: string
|
options: IssuePaginationOptions
|
||||||
) => Promise<TIssue | undefined>;
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
updateIssue: (
|
fetchIssuesWithExistingPagination: (
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
viewId: string,
|
||||||
issueId: string,
|
loadType: TLoader
|
||||||
data: Partial<TIssue>,
|
) => Promise<TIssuesResponse | undefined>;
|
||||||
viewId: string
|
fetchNextIssues: (workspaceSlug: string, viewId: string) => Promise<TIssuesResponse | undefined>;
|
||||||
) => Promise<void>;
|
createIssue: (workspaceSlug: string, projectId: string, data: Partial<TIssue>) => Promise<TIssue>;
|
||||||
removeIssue: (workspaceSlug: string, projectId: string, issueId: string, viewId: string) => Promise<void>;
|
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
archiveIssue: (
|
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
viewId?: string | undefined
|
|
||||||
) => Promise<void>;
|
|
||||||
quickAddIssue: undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkspaceIssues extends IssueHelperStore implements IWorkspaceIssues {
|
export class WorkspaceIssues extends BaseIssuesStore implements IWorkspaceIssues {
|
||||||
loader: TLoader = "init-loader";
|
|
||||||
issues: { [viewId: string]: string[] } = {};
|
|
||||||
viewFlags = {
|
viewFlags = {
|
||||||
enableQuickAdd: true,
|
enableQuickAdd: true,
|
||||||
enableIssueCreation: true,
|
enableIssueCreation: true,
|
||||||
enableInlineEditing: true,
|
enableInlineEditing: true,
|
||||||
};
|
};
|
||||||
// root store
|
|
||||||
rootIssueStore: IIssueRootStore;
|
|
||||||
// service
|
// service
|
||||||
workspaceService;
|
workspaceService;
|
||||||
issueService;
|
// filterStore
|
||||||
issueArchiveService;
|
issueFilterStore;
|
||||||
|
|
||||||
quickAddIssue = undefined;
|
constructor(_rootStore: IIssueRootStore, issueFilterStore: IWorkspaceIssuesFilter) {
|
||||||
|
super(_rootStore, issueFilterStore);
|
||||||
constructor(_rootStore: IIssueRootStore) {
|
|
||||||
super(_rootStore);
|
|
||||||
|
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observable
|
|
||||||
loader: observable.ref,
|
|
||||||
issues: observable,
|
|
||||||
// computed
|
|
||||||
groupedIssueIds: computed,
|
|
||||||
// action
|
// action
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
createIssue: action,
|
|
||||||
updateIssue: action,
|
|
||||||
removeIssue: action,
|
|
||||||
archiveIssue: action,
|
|
||||||
});
|
});
|
||||||
// root store
|
|
||||||
this.rootIssueStore = _rootStore;
|
|
||||||
// services
|
// services
|
||||||
this.workspaceService = new WorkspaceService();
|
this.workspaceService = new WorkspaceService();
|
||||||
this.issueService = new IssueService();
|
// filter store
|
||||||
this.issueArchiveService = new IssueArchiveService();
|
this.issueFilterStore = issueFilterStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupedIssueIds() {
|
fetchIssues = async (workspaceSlug: string, viewId: string, loadType: TLoader, options: IssuePaginationOptions) => {
|
||||||
const viewId = this.rootIssueStore.globalViewId;
|
|
||||||
const workspaceSlug = this.rootIssueStore.workspaceSlug;
|
|
||||||
if (!workspaceSlug || !viewId) return { dataViewId: "", issueIds: undefined };
|
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${viewId}`;
|
|
||||||
|
|
||||||
const displayFilters = this.rootIssueStore?.workspaceIssuesFilter?.filters?.[viewId]?.displayFilters;
|
|
||||||
if (!displayFilters) return { dataViewId: viewId, issueIds: undefined };
|
|
||||||
|
|
||||||
const orderBy = displayFilters?.order_by;
|
|
||||||
|
|
||||||
const viewIssueIds = this.issues[uniqueViewId];
|
|
||||||
|
|
||||||
if (!viewIssueIds) return { dataViewId: viewId, issueIds: undefined };
|
|
||||||
|
|
||||||
const _issues = this.rootStore.issues.getIssuesByIds(viewIssueIds, "un-archived");
|
|
||||||
if (!_issues) return { dataViewId: viewId, issueIds: [] };
|
|
||||||
|
|
||||||
let issueIds: TIssue | TUnGroupedIssues | undefined = undefined;
|
|
||||||
|
|
||||||
issueIds = this.unGroupedIssues(orderBy ?? "-created_at", _issues);
|
|
||||||
|
|
||||||
return { dataViewId: viewId, issueIds };
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchIssues = async (workspaceSlug: string, viewId: string, loadType: TLoader = "init-loader") => {
|
|
||||||
try {
|
try {
|
||||||
this.loader = loadType;
|
runInAction(() => {
|
||||||
|
this.loader = loadType;
|
||||||
const uniqueViewId = `${workspaceSlug}_${viewId}`;
|
});
|
||||||
|
this.clear();
|
||||||
const params = this.rootIssueStore?.workspaceIssuesFilter?.getAppliedFilters(viewId);
|
const params = this.issueFilterStore?.getFilterParams(viewId, options, undefined);
|
||||||
const response = await this.workspaceService.getViewIssues(workspaceSlug, params);
|
const response = await this.workspaceService.getViewIssues(workspaceSlug, params);
|
||||||
|
|
||||||
runInAction(() => {
|
this.onfetchIssues(response, options);
|
||||||
set(
|
|
||||||
this.issues,
|
|
||||||
[uniqueViewId],
|
|
||||||
response.map((issue) => issue.id)
|
|
||||||
);
|
|
||||||
this.loader = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootIssueStore.issues.addIssue(response);
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<TIssue>, viewId: string) => {
|
fetchNextIssues = async (workspaceSlug: string, viewId: string) => {
|
||||||
|
if (!this.paginationOptions) return;
|
||||||
try {
|
try {
|
||||||
const uniqueViewId = `${workspaceSlug}_${viewId}`;
|
this.loader = "pagination";
|
||||||
|
|
||||||
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
|
const params = this.issueFilterStore?.getFilterParams(viewId, this.paginationOptions, this.nextCursor);
|
||||||
|
const response = await this.workspaceService.getViewIssues(workspaceSlug, params);
|
||||||
runInAction(() => {
|
|
||||||
this.issues[uniqueViewId].push(response.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.addIssue([response]);
|
|
||||||
|
|
||||||
|
this.onfetchNexIssues(response);
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.loader = undefined;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateIssue = async (
|
fetchIssuesWithExistingPagination = async (workspaceSlug: string, viewId: string, loadType: TLoader) => {
|
||||||
workspaceSlug: string,
|
if (!this.paginationOptions) return;
|
||||||
projectId: string,
|
return await this.fetchIssues(workspaceSlug, viewId, loadType, this.paginationOptions);
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
viewId: string
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
this.rootStore.issues.updateIssue(issueId, data);
|
|
||||||
await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
|
|
||||||
} catch (error) {
|
|
||||||
if (viewId) this.fetchIssues(workspaceSlug, viewId, "mutation");
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string, viewId: string) => {
|
|
||||||
try {
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${viewId}`;
|
|
||||||
|
|
||||||
await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
const issueIndex = this.issues[uniqueViewId].findIndex((_issueId) => _issueId === issueId);
|
|
||||||
if (issueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[uniqueViewId].splice(issueIndex, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rootStore.issues.removeIssue(issueId);
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
archiveIssue = async (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
viewId: string | undefined = undefined
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
if (!viewId) throw new Error("View id is required");
|
|
||||||
|
|
||||||
const uniqueViewId = `${workspaceSlug}_${viewId}`;
|
|
||||||
|
|
||||||
const response = await this.issueArchiveService.archiveIssue(workspaceSlug, projectId, issueId);
|
|
||||||
|
|
||||||
runInAction(() => {
|
|
||||||
this.rootStore.issues.updateIssue(issueId, {
|
|
||||||
archived_at: response.archived_at,
|
|
||||||
});
|
|
||||||
pull(this.issues[uniqueViewId], issueId);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user