refactor: MobX store structure (#3228)

* query params from router as computed

* chore: setup workspace store and sub-stores

* chore: update router query store

* chore: update store types

* fix: pages store changes

* change observables and retain object reference

* fix build errors

* chore: changed the structure of workspace, project, cycle, module and pages

* fix: pages fixes

* fix: merge conflicts resolved

* chore: fixed workspace list

* chore: update workspace store accroding to the new response

* fix: adding page details to store

* fix: adding new contexts and providers

* dev: issues store and filters in new store

* dev: optimised the issue fetching in issue base store

* chore: project views id mapped

* update lodash set to directly run inside runInaction since it mutates the object

* fix: context changes

* code refactor kanban for better mainatinability

* optimize Kanban for performance

* chore: implemented hooks for all the created stores

* chore: removed bridge id

* css change and refactor

* chore: update cycle store structure

* chore: implement the new label root store

* chore: removed object structure

* chore: implement project view hook

* Kanban new store implementation for project issues

* fix project root for kanban

* feat: workspace and project members endpoint (#3092)

* fix: merge conflicts resolved

* issue properties optimization

* chore: user stores

* chore: create new store context and update hooks

* chore: setup inbox store and implement router store

* chore: initialize and implement project estimate store

* chore: initialize global view store

* kanban and list view optimization

* chore: use new cycle and module store. (#3172)

* chore: use new cycle and module store.

* chore: minor improvements.

* Revert "chore: merge develop"

This reverts commit 9d2e0e29e7370b55b48fc2fee4fd126093a6cc48, reversing
changes made to 9595493c42be3ea0ddd17b23a0b124555075c062.

* chore: implement useGlobalView hook

* refactor: projects & inbox store instances (#3179)

* refactor: projects & inbox store instances

* fix: formatting

* fix: action usage

* chore: implement useProjectState hook. (#3185)

* dev: issue, cycle store optimiation

* fix build for code

* dev: removed dummy variables

* dev: issue store

* fix: adding todos

* chore: removing legacy store

* dev: issues store types and typos

* chore: cycle module user properties

* fix legacy store deletion issues

* chore: change POST to PATCH

* fix issues rendering for project root

* chore: removed workspace details in workpsaceinvite

* chore: created models for display properties

* chore: setup member store and implement it everywhere

* refactor: module store (#3202)

* refactor: cycle store (#3192)

* refator: cycle store

* some more improvements.

* chore: implement useLabel hook. (#3190)

* refactor: inbox & project related stores. (#3193)

* refactor: inbox -> filter, issues, inoxes & project -> publish, projects store

* refactor: workspace-project-id name

* fix kanban dropdown overlapping issue

* fix kanban layout minor re rendering

* chore: implement useMember store everywhere

* chore: create and implement editor mention store

* chore: removed the issue view user property

* chore: created at id changed

* dev: segway intgegration (#3132)

* feat: implemented rabbitmq

* dev: initialize segway with queue setup

* dev: import refactors

* dev: create communication with the segway server

* dev: create new workers

* dev: create celery node queue for consuming messages from django

* dev: node to celery connection

* dev: setup segway and django connection

* dev: refactor the structure and add database integration to the app

* dev: add external id and source added

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>

* dev: github importer (#3205)

* dev: initiate github import

* dev: github importer all issues import

* dev: github comments and links for the imported issues

* dev: update controller to use logger and spread the resultData in getAllEntities

* dev: removed console log

* dev: update code structure and sync functions

* dev: updated retry logic when exception

* dev: add imported data as well

* dev: update logger and repo fetch

* dev: update jira integration to new structure

* dev: update migrations

* dev: update the reason field

* chore: workspace object id removed

* chore: view's creation fixed

* refactor: mobx store improvements. (#3213)

* fix: state and label errors

* chore: remove legacy code

* fix: branch build fix (#3214)

* branch build fix for release-* in case of space,backend,proxy

* fixes

* chore: update store names and types

* fix - file size limit not work on plane.settings.production (#3160)

* fix - file size limit not work on plane.settings.production

* fix - file size limit not work on plane.settings.production

* fix - file size limit not work on plane.settings.production, move to common.py

---------

Co-authored-by: luanduongtel4vn <hoangluan@tel4vn.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>

* style: instance admin email settings ui & ux update. (#3186)

* refactor: use-user-auth hook (#3215)

* refactor: use-user-auth hook

* fix: user store currentUserLoader

* refactor: project-view & application related stores (#3207)

* refactor: project-view & application related stores

* rename: projectViews -> projectViewIds

* fix: project-view favourite state in store

* chore: remove unnecessary hooks and contexts (#3217)

* chore: update issue assignee property component

* chore: bug fixes & improvement (#3218)

* chore: draft issue validation added to prevent saving empty or whitespace title

* chore: resolve scrolling issue in page empty state

* chore: kanban layout quick add issue improvement

* fix: bugs & improvements (#3189)

* fix: workspace invitation modal form values reset

* fix: profile sidebar avatar letter

* [refactor] Editor code refactoring (#3194)

* removed relative imports from editor core

* Update issue widget file paths and imports to use kebab case instead of camel case, to align with coding conventions and improve consistency.

* Update Tiptap core and extensions versions to 2.1.13 and Tiptap React version to 2.1.13. Update Tiptap table imports to use the new location in package @tiptap/pm/tables. Update AlertLabel component to use the new type definition for LucideIcon.

* updated lock file

* removed default exports from editor/core

* fixed injecting css into the core package itself

* seperated css code to have single source of origin wrt to the package

* removed default imports from document editor

* all instances using index as key while mapping fixed

* Update Lite Text Editor package.json to remove @plane/editor-types as a dependency.

Update Lite Text Editor index.ts to update the import of IMentionSuggestion and IMentionHighlight from @plane/editor-types to @plane/editor-core.

Update Lite Text Editor ui/index.tsx to update the import of UploadImage, DeleteImage, IMentionSuggestion, and RestoreImage from @plane/editor-types to @plane/editor-core.

Update Lite Text Editor ui/menus/fixed-menu/index.tsx to update the import of UploadImage from @plane/editor-types to @plane/editor-core.

Update turbo.json to remove @plane/editor-types#build as a dependency for @plane/lite-text-editor#build, @plane/rich-text-editor#build, and @plane/document-editor#build.

* Remove deprecated import and adjust tippy.js usage in the slash-commands.tsx file of the editor extensions package.

* Update dependencies in `rich-text-editor/package.json`, remove `@plane/editor-types` and add `@plane/editor-core` in `rich-text-editor/src/index.ts`, and update imports in `rich-text-editor/src/ui/extensions/index.tsx` and `rich-text-editor/src/ui/index.tsx` to use `@plane/editor-core` instead of `@plane/editor-types`.

* Update package.json dependencies and add new types for image deletion, upload, restore, mention highlight, mention suggestion, and slash command item.

* Update import statements in various files to use the new package "@plane/editor-core" instead of "@plane/editor-types".

* fixed document editor to follow conventions

* Refactor imports in the Rich Text Editor package to use relative paths instead of absolute paths.

- Updated imports in `index.ts`, `ui/index.tsx`, and `ui/menus/bubble-menu/index.tsx` to use relative paths.
- Updated `tsconfig.json` to include the `baseUrl` compiler option and adjust the `include` and `exclude` paths.

* Refactor Lite Text Editor code to use relative import paths instead of absolute import paths.

* Added LucideIconType to the exports in index.ts for use in other files.
Created a new file lucide-icon.ts which contains the type LucideIconType.
Updated the icon type in HeadingOneItem in menu-items/index.tsx to use LucideIconType.
Updated the Icon type in AlertLabel in alert-label.tsx to use LucideIconType.
Updated the Icon type in VerticalDropdownItemProps in vertical-dropdown-menu.tsx to use LucideIconType.
Updated the Icon type in BubbleMenuItem in fixed-menu/index.tsx to use LucideIconType.
Deleted the file tooltip.tsx since it is no longer used.
Updated the Icon type in BubbleMenuItem in bubble-menu/index.tsx to use LucideIconType.

* ♻️ refactor: simplify rendering logic in slash-commands.tsx

The rendering logic in the file "slash-commands.tsx" has been simplified. Previously, the code used inline positioning for the popup, but it has now been removed. Instead of appending the popup to the document body, it is now appended to the element with the ID "tiptap-container". The "flip" option has also been removed. These changes have improved the readability and maintainability of the code.

* fixed build errors caused due to core's internal imports

* regression: fixed pages not saving issue and not duplicating with proper content issue

* build: Update @tiptap dependencies

Updated the @tiptap dependencies in the package.json files of `document-editor`, `extensions`, and `rich-text-editor` packages to version 2.1.13.

* 🚑 fix: Correct appendTo selector in slash-commands.tsx

Update the `appendTo` function call in `slash-commands.tsx` to use the correct selector `#editor-container` instead of `#tiptap-container`. This ensures that the component is appended to the appropriate container in the editor extension.

Note: The commit message assumes that the change is a fix for an issue or error. If it's not a fix, please provide more context so that an appropriate commit type can be determined.

* style: email placeholder changed across the platform (#3206)

* style: email placeholder changed across the platform

* fix: placeholder text

* dev: updated new filter endpoints and restructured issue and issue filters store

* implement issues and replace useMobxStore

* remove all store legacy references

* dev: updated the orderby and subgroupby filters data

* dev:added projectId in issue filters for consistency

* fix more build errors

* dev: updated profile issues

* dev: removed store legacy

* dev: active cycle issues in the cycle issue store

* fix additional build errors and memoize issueActions in each layout component

* change store enums

* remove all useMobxStore references

* fix more build errors

* dev: reverted workspace invitation

* fix: build errors and warnings

* fix: optimistic update for instant operations (#3221)

* fix: update functions failed case

* fix: typo

* chore: revert back to optimistic update approach for all `update related actions` (#3219)

* fix: merge conflicts resolved

* chore: update memberMap logic in components

* add assignees to kanban groups and properties

* dev: migration fixes

* final bit of optimization on list view

* change all TODOs that are to be done before this release to FIXME

* change base Kanban TODOs that are to be done before this release to FIXME

* dev: add fields and expand for app serializers

* dev: issue detail store

* dev: update issue serializer to return object ids

* fix: Instance key added in settings and converted issues list api to arry instead of dict

* fix: removing segway files

* dev: control expand through query parameters

* revert: github importer

* Revert "dev: segway intgegration (#3132)"

This reverts commit 1cc18a09156d1790d114061dbac8c901e0f2754c.

* dev: remove migrations for segway

* dev: issue structure change and created workspacebasemodel

* dev: issue detail serializer

* fix: changed workspace dict

* dev: updated new issue structure

* chore: build fix

* dev: issue detail store refactor

* dev: created list endpoint for issue-relation

* dev: added issue attachments in issue detail store

* dev: added issue activity computed

* fix: build error

* chore: peek overview modal context added

* chore: build error fix

* dev: added sub_issues in issue details store

* dev: added complete issue serializer for sub issues

* dev: resolved type errors in issue root store

* dev: changed the issue relation structure

* chore: new global dropdowns

* chore: build error fix

* chore: cycle and module selection if disabled

* dev: removed unnecessary code from the workspace root

* chore: build error fix

* chore: issue relation remove endpoint

* fix: build error

* dev: typos and implemented issue relation store

* fix: yarn lock updated

* style: update the UI of all the dropdowns

* fix: state store fixes

* fix: key issue

* fix: state store console logs removed

* refactor: member dropdowns

* fix: moving types to packages

* fix: dropdown arrow positioning

* dev: removed logs

* style: label dropdown

* chore: restrict description notifications

* chore: description changes

* chore: update spreadsheet layout dropdowns

* fix: build errors

* chore: duplicate key change

* fix: ui bugs

* chore: relation activity change

* chore: comment activity changes

* chore: blocking issue removal

* chore: added project_id for relation

* chore: issue relation store and component

* chore: issue redirection issue in the issue realtion in detail page

* chore: created activity changed

* chore: issue links new store implementation on the issue detail

* chore: issue relation deletion acitivity changed

* chore: issue attachments new store implementation on the issue detail

* chore: workspace level issues

* fix: build errors

---------

Co-authored-by: rahulramesha <rahulramesham@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com>
Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Manish Gupta <59428681+mguptahub@users.noreply.github.com>
Co-authored-by: Hoang Luan <luandnh98@gmail.com>
Co-authored-by: luanduongtel4vn <hoangluan@tel4vn.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@plane.so>
This commit is contained in:
Aaryan Khandelwal 2024-01-02 18:12:55 +05:30 committed by GitHub
parent 1539340113
commit 804b7d8663
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
940 changed files with 26378 additions and 34411 deletions

View file

@ -1,53 +0,0 @@
export interface ICalendarHelpers {
// actions
handleDragDrop: (
source: any,
destination: any,
workspaceSlug: string,
projectId: string,
store: any,
issues: any,
issueWithIds: any,
viewId?: string | null
) => void;
}
export class CalendarHelpers implements ICalendarHelpers {
constructor() {}
handleDragDrop = async (
source: any,
destination: any,
workspaceSlug: string,
projectId: string,
store: any,
issues: any,
issueWithIds: any,
viewId: string | null = null // it can be moduleId, cycleId
) => {
if (issues && issueWithIds) {
const sourceColumnId = source?.droppableId || null;
const destinationColumnId = destination?.droppableId || null;
if (!workspaceSlug || !projectId || !sourceColumnId || !destinationColumnId) return;
if (sourceColumnId === destinationColumnId) return;
// horizontal
if (sourceColumnId != destinationColumnId) {
const sourceIssues = issueWithIds[sourceColumnId] || [];
const [removed] = sourceIssues.splice(source.index, 1);
const removedIssueDetail = issues[removed];
const updateIssue = {
id: removedIssueDetail?.id,
target_date: destinationColumnId,
};
if (viewId) return await store?.updateIssue(workspaceSlug, projectId, updateIssue.id, updateIssue, viewId);
else return await store?.updateIssue(workspaceSlug, projectId, updateIssue.id, updateIssue);
}
}
};
}

View file

@ -1,191 +0,0 @@
import { DraggableLocation } from "@hello-pangea/dnd";
import { IProjectIssuesStore } from "./project-issues/project/issue.store";
import { IModuleIssuesStore } from "./project-issues/module/issue.store";
import { ICycleIssuesStore } from "./project-issues/cycle/issue.store";
import { IViewIssuesStore } from "./project-issues/project-view/issue.store";
import { IProjectDraftIssuesStore } from "./project-issues/draft/issue.store";
import { IProfileIssuesStore } from "./profile/issue.store";
import { IGroupedIssues, IIssueResponse, ISubGroupedIssues, TUnGroupedIssues } from "./types";
import { IIssue } from "types";
export interface IKanBanHelpers {
// actions
handleDragDrop: (
source: DraggableLocation | null,
destination: DraggableLocation | null,
workspaceSlug: string,
projectId: string, // projectId for all views or user id in profile issues
store:
| IProjectIssuesStore
| IModuleIssuesStore
| ICycleIssuesStore
| IViewIssuesStore
| IProjectDraftIssuesStore
| IProfileIssuesStore,
subGroupBy: string | null,
groupBy: string | null,
issues: IIssueResponse | undefined,
issueWithIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined,
viewId?: string | null
) => Promise<IIssue | undefined>;
}
export class KanBanHelpers implements IKanBanHelpers {
constructor() {}
handleSortOrder = (destinationIssues: any, destinationIndex: any, issues: any) => {
const sortOrderDefaultValue = 65535;
let currentIssueState = {};
if (destinationIssues && destinationIssues.length > 0) {
if (destinationIndex === 0) {
const destinationIssueId = destinationIssues[destinationIndex];
currentIssueState = {
...currentIssueState,
sort_order: issues[destinationIssueId].sort_order - sortOrderDefaultValue,
};
} else if (destinationIndex === destinationIssues.length) {
const destinationIssueId = destinationIssues[destinationIndex - 1];
currentIssueState = {
...currentIssueState,
sort_order: issues[destinationIssueId].sort_order + sortOrderDefaultValue,
};
} else {
const destinationTopIssueId = destinationIssues[destinationIndex - 1];
const destinationBottomIssueId = destinationIssues[destinationIndex];
currentIssueState = {
...currentIssueState,
sort_order: (issues[destinationTopIssueId].sort_order + issues[destinationBottomIssueId].sort_order) / 2,
};
}
} else {
currentIssueState = {
...currentIssueState,
sort_order: sortOrderDefaultValue,
};
}
return currentIssueState;
};
handleDragDrop = async (
source: DraggableLocation | null,
destination: DraggableLocation | null,
workspaceSlug: string,
projectId: string, // projectId for all views or user id in profile issues
store:
| IProjectIssuesStore
| IModuleIssuesStore
| ICycleIssuesStore
| IViewIssuesStore
| IProjectDraftIssuesStore
| IProfileIssuesStore,
subGroupBy: string | null,
groupBy: string | null,
issues: IIssueResponse | undefined,
issueWithIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined,
viewId: string | null = null // it can be moduleId, cycleId
) => {
if (!issues || !issueWithIds || !source || !destination) return;
let updateIssue: any = {};
const sourceColumnId = (source?.droppableId && source?.droppableId.split("__")) || null;
const destinationColumnId = (destination?.droppableId && destination?.droppableId.split("__")) || null;
if (!sourceColumnId || !destinationColumnId) return;
const sourceGroupByColumnId = sourceColumnId[0] || null;
const destinationGroupByColumnId = destinationColumnId[0] || null;
const sourceSubGroupByColumnId = sourceColumnId[1] || null;
const destinationSubGroupByColumnId = destinationColumnId[1] || null;
if (
!workspaceSlug ||
!projectId ||
!groupBy ||
!sourceGroupByColumnId ||
!destinationGroupByColumnId ||
!sourceSubGroupByColumnId ||
!sourceGroupByColumnId
)
return;
if (destinationGroupByColumnId === "issue-trash-box") {
const sourceIssues: string[] = subGroupBy
? (issueWithIds as ISubGroupedIssues)[sourceSubGroupByColumnId][sourceGroupByColumnId]
: (issueWithIds as IGroupedIssues)[sourceGroupByColumnId];
const [removed] = sourceIssues.splice(source.index, 1);
if (removed) {
if (viewId) return await store?.removeIssue(workspaceSlug, projectId, removed, viewId);
else return await store?.removeIssue(workspaceSlug, projectId, removed);
}
} else {
const sourceIssues = subGroupBy
? (issueWithIds as ISubGroupedIssues)[sourceSubGroupByColumnId][sourceGroupByColumnId]
: (issueWithIds as IGroupedIssues)[sourceGroupByColumnId];
const destinationIssues = subGroupBy
? (issueWithIds as ISubGroupedIssues)[sourceSubGroupByColumnId][destinationGroupByColumnId]
: (issueWithIds as IGroupedIssues)[destinationGroupByColumnId];
const [removed] = sourceIssues.splice(source.index, 1);
const removedIssueDetail = issues[removed];
if (subGroupBy && sourceSubGroupByColumnId && destinationSubGroupByColumnId) {
updateIssue = {
id: removedIssueDetail?.id,
};
// for both horizontal and vertical dnd
updateIssue = {
...updateIssue,
...this.handleSortOrder(destinationIssues, destination.index, issues),
};
if (sourceSubGroupByColumnId === destinationSubGroupByColumnId) {
if (sourceGroupByColumnId != destinationGroupByColumnId) {
if (groupBy === "state") updateIssue = { ...updateIssue, state: destinationGroupByColumnId };
if (groupBy === "priority") updateIssue = { ...updateIssue, priority: destinationGroupByColumnId };
}
} else {
if (subGroupBy === "state")
updateIssue = {
...updateIssue,
state: destinationSubGroupByColumnId,
priority: destinationGroupByColumnId,
};
if (subGroupBy === "priority")
updateIssue = {
...updateIssue,
state: destinationGroupByColumnId,
priority: destinationSubGroupByColumnId,
};
}
} else {
updateIssue = {
id: removedIssueDetail?.id,
};
// for both horizontal and vertical dnd
updateIssue = {
...updateIssue,
...this.handleSortOrder(destinationIssues, destination.index, issues),
};
// for horizontal dnd
if (sourceColumnId != destinationColumnId) {
if (groupBy === "state") updateIssue = { ...updateIssue, state: destinationGroupByColumnId };
if (groupBy === "priority") updateIssue = { ...updateIssue, priority: destinationGroupByColumnId };
}
}
if (updateIssue && updateIssue?.id) {
if (viewId) return await store?.updateIssue(workspaceSlug, projectId, updateIssue.id, updateIssue, viewId);
else return await store?.updateIssue(workspaceSlug, projectId, updateIssue.id, updateIssue);
}
}
};
}

View file

@ -1,432 +0,0 @@
import { action, makeObservable, observable, runInAction } from "mobx";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { IssueFilterBaseStore } from "../project-issues/base-issue-filter.store";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
import { isNil } from "../project-issues/utils";
// services
import { WorkspaceService } from "services/workspace.service";
interface IIssuesDisplayOptions {
filters: IIssueFilterOptions;
}
type TIssueViewTypes = "all-issues" | "assigned" | "created" | "subscribed" | string;
interface IIssueViewOptions {
"all-issues": IIssuesDisplayOptions;
assigned: IIssuesDisplayOptions;
created: IIssuesDisplayOptions;
subscribed: IIssuesDisplayOptions;
[view_id: string]: IIssuesDisplayOptions;
}
interface IWorkspaceProperties {
filters: IIssueFilterOptions;
displayFilters: IIssueDisplayFilterOptions;
displayProperties: IIssueDisplayProperties;
}
export interface IGlobalIssuesFilterStore {
// observables
currentView: TIssueViewTypes;
workspaceProperties: { [workspaceId: string]: IWorkspaceProperties } | undefined;
workspaceViewFilters: { [workspaceId: string]: IIssueViewOptions } | undefined;
// computed
issueFilters: IWorkspaceProperties | undefined;
appliedFilters: TIssueParams[] | undefined;
// helpers
issueDisplayFilters: (workspaceId: string) => IIssuesDisplayOptions | undefined;
// actions
setCurrentView: (view: TIssueViewTypes) => void;
fetchWorkspaceProperties: (workspaceSlug: string) => Promise<IWorkspaceProperties>;
updateWorkspaceProperties: (
workspaceSlug: string,
type: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => Promise<IWorkspaceProperties>;
fetchWorkspaceViewFilters: (workspaceId: string, view: TIssueViewTypes) => Promise<IIssueFilterOptions>;
updateWorkspaceViewFilters: (workspaceId: string, filters: IIssueFilterOptions) => Promise<IIssueFilterOptions>;
fetchFilters: (workspaceSlug: string, view: TIssueViewTypes) => Promise<void>;
updateFilters: (
workspaceSlug: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => Promise<void>;
}
export class GlobalIssuesFilterStore extends IssueFilterBaseStore implements IGlobalIssuesFilterStore {
// observables
currentView: TIssueViewTypes = "all-issues";
workspaceProperties: { [workspaceId: string]: IWorkspaceProperties } | undefined = undefined;
workspaceViewFilters: { [workspaceId: string]: IIssueViewOptions } | undefined = undefined;
// root store
rootStore;
// service
workspaceService;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observables
currentView: observable.ref,
workspaceProperties: observable.ref,
workspaceViewFilters: observable.ref,
// computed
// actions
setCurrentView: action,
fetchWorkspaceProperties: action,
updateWorkspaceProperties: action,
fetchWorkspaceViewFilters: action,
updateWorkspaceViewFilters: action,
});
// root store
this.rootStore = _rootStore;
// services
this.workspaceService = new WorkspaceService();
}
// computed
// helpers
issueDisplayFilters = (workspaceId: string) => {
if (!workspaceId || !this.currentView) return undefined;
const filters: IWorkspaceProperties = {
filters: this.workspaceProperties?.[workspaceId]?.filters || {},
displayFilters: this.workspaceProperties?.[workspaceId]?.displayFilters || {},
displayProperties: this.workspaceProperties?.[workspaceId]?.displayProperties || {},
};
if (!["all-issues", "assigned", "created", "subscribed"].includes(this.currentView)) {
const viewFilters = this.workspaceViewFilters?.[workspaceId]?.[this.currentView];
if (viewFilters) {
filters.filters = { ...filters.filters, ...viewFilters?.filters };
}
}
return filters;
};
// actions
setCurrentView = (view: TIssueViewTypes) => {
this.currentView = view;
};
fetchWorkspaceProperties = async (workspaceSlug: string) => {
try {
let _filters: IWorkspaceProperties = {} as IWorkspaceProperties;
const filtersResponse = await this.workspaceService.workspaceMemberMe(workspaceSlug);
_filters = {
filters: { ...filtersResponse?.view_props?.filters } || null,
displayFilters: { ...filtersResponse?.view_props?.display_filters } || null,
displayProperties: { ...filtersResponse?.view_props?.display_properties } || null,
};
let filters: IIssueFilterOptions = {
assignees: _filters?.filters?.assignees || null,
mentions: _filters?.filters?.mentions || null,
created_by: _filters?.filters?.created_by || null,
labels: _filters?.filters?.labels || null,
priority: _filters?.filters?.priority || null,
project: _filters?.filters?.project || null,
start_date: _filters?.filters?.start_date || null,
state: _filters?.filters?.state || null,
state_group: _filters?.filters?.state_group || null,
subscriber: _filters?.filters?.subscriber || null,
target_date: _filters?.filters?.target_date || null,
};
const currentUserId = this.rootStore.user.currentUser?.id;
if (currentUserId && this.currentView === "assigned")
filters = {
...filters,
assignees: [currentUserId],
created_by: null,
subscriber: null,
};
if (currentUserId && this.currentView === "created")
filters = {
...filters,
assignees: null,
created_by: [currentUserId],
subscriber: null,
};
if (currentUserId && this.currentView === "subscribed")
filters = {
...filters,
assignees: null,
created_by: null,
subscriber: [currentUserId],
};
const displayFilters: IIssueDisplayFilterOptions = {
calendar: {
show_weekends: _filters?.displayFilters?.calendar?.show_weekends || false,
layout: _filters?.displayFilters?.calendar?.layout || "month",
},
group_by: _filters?.displayFilters?.group_by || null,
sub_group_by: _filters?.displayFilters?.sub_group_by || null,
layout: _filters?.displayFilters?.layout || "list",
order_by: _filters?.displayFilters?.order_by || "-created_at",
show_empty_groups: _filters?.displayFilters?.show_empty_groups || false,
start_target_date: _filters?.displayFilters?.start_target_date || false,
sub_issue: _filters?.displayFilters?.sub_issue || false,
type: _filters?.displayFilters?.type || null,
};
const displayProperties: IIssueDisplayProperties = {
assignee: _filters?.displayProperties?.assignee || false,
start_date: _filters?.displayProperties?.start_date || false,
due_date: _filters?.displayProperties?.due_date || false,
labels: _filters?.displayProperties?.labels || false,
key: _filters?.displayProperties?.key || false,
priority: _filters?.displayProperties?.priority || false,
state: _filters?.displayProperties?.state || false,
sub_issue_count: _filters?.displayProperties?.sub_issue_count || false,
link: _filters?.displayProperties?.link || false,
attachment_count: _filters?.displayProperties?.attachment_count || false,
estimate: _filters?.displayProperties?.estimate || false,
created_on: _filters?.displayProperties?.created_on || false,
updated_on: _filters?.displayProperties?.updated_on || false,
};
const issueFilters: IWorkspaceProperties = {
filters: filters,
displayFilters: displayFilters,
displayProperties: displayProperties,
};
let _workspaceProperties = { ...this.workspaceProperties };
if (!_workspaceProperties) _workspaceProperties = {};
if (!_workspaceProperties[workspaceSlug])
_workspaceProperties[workspaceSlug] = {
filters: {},
displayFilters: {},
displayProperties: {},
};
_workspaceProperties[workspaceSlug] = { ...issueFilters };
runInAction(() => {
this.workspaceProperties = _workspaceProperties;
});
return issueFilters;
} catch (error) {
throw error;
}
};
updateWorkspaceProperties = async (
workspaceSlug: string,
type: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => {
try {
let _workspaceProperties = { ...this.workspaceProperties };
if (!_workspaceProperties) _workspaceProperties = {};
if (!_workspaceProperties[workspaceSlug])
_workspaceProperties[workspaceSlug] = { filters: {}, displayFilters: {}, displayProperties: {} };
const _filters = {
filters: { ..._workspaceProperties[workspaceSlug].filters },
displayFilters: { ..._workspaceProperties[workspaceSlug].displayFilters },
displayProperties: { ..._workspaceProperties[workspaceSlug].displayProperties },
};
switch (type) {
case EFilterType.FILTERS:
_filters.filters = { ..._filters.filters, ...(filters as IIssueFilterOptions) };
break;
case EFilterType.DISPLAY_FILTERS:
_filters.displayFilters = { ..._filters.displayFilters, ...(filters as IIssueDisplayFilterOptions) };
break;
case EFilterType.DISPLAY_PROPERTIES:
_filters.displayProperties = { ..._filters.displayProperties, ...(filters as IIssueDisplayProperties) };
break;
}
_workspaceProperties[workspaceSlug] = {
..._workspaceProperties[workspaceSlug],
filters: _filters?.filters,
displayFilters: _filters?.displayFilters,
displayProperties: _filters?.displayProperties,
};
runInAction(() => {
this.workspaceProperties = _workspaceProperties;
});
await this.workspaceService.updateWorkspaceView(workspaceSlug, {
view_props: {
filters: _filters.filters,
display_filters: _filters.displayFilters,
display_properties: _filters.displayProperties,
},
});
return _filters;
} catch (error) {
this.fetchWorkspaceProperties(workspaceSlug);
throw error;
}
};
fetchWorkspaceViewFilters = async (workspaceSlug: string, view: TIssueViewTypes) => {
try {
let _workspaceViewFilters = { ...this.workspaceViewFilters };
if (!_workspaceViewFilters) _workspaceViewFilters = {};
if (!_workspaceViewFilters[workspaceSlug]) _workspaceViewFilters[workspaceSlug] = {} as IIssueViewOptions;
if (!_workspaceViewFilters[workspaceSlug][view]) _workspaceViewFilters[workspaceSlug][view] = { filters: {} };
const filtersResponse = await this.workspaceService.getViewDetails(workspaceSlug, view);
const _filters: IIssueFilterOptions = {
assignees: filtersResponse?.query_data?.filters?.assignees || null,
mentions: filtersResponse?.query_data?.filters?.mentions || null,
created_by: filtersResponse?.query_data?.filters?.created_by || null,
labels: filtersResponse?.query_data?.filters?.labels || null,
priority: filtersResponse?.query_data?.filters?.priority || null,
project: filtersResponse?.query_data?.filters?.project || null,
start_date: filtersResponse?.query_data?.filters?.start_date || null,
state: filtersResponse?.query_data?.filters?.state || null,
state_group: filtersResponse?.query_data?.filters?.state_group || null,
subscriber: filtersResponse?.query_data?.filters?.subscriber || null,
target_date: filtersResponse?.query_data?.filters?.target_date || null,
};
_workspaceViewFilters[workspaceSlug][view].filters = { ..._filters };
runInAction(() => {
this.workspaceViewFilters = _workspaceViewFilters;
});
return _filters;
} catch (error) {
throw error;
}
};
updateWorkspaceViewFilters = async (workspaceSlug: string, filters: IIssueFilterOptions) => {
try {
let _workspaceViewFilters = { ...this.workspaceViewFilters };
if (!_workspaceViewFilters) _workspaceViewFilters = {};
if (!_workspaceViewFilters[workspaceSlug]) _workspaceViewFilters[workspaceSlug] = {} as IIssueViewOptions;
if (!_workspaceViewFilters[workspaceSlug][this.currentView])
_workspaceViewFilters[workspaceSlug][this.currentView] = { filters: {} };
const _filters = {
filters: { ..._workspaceViewFilters[workspaceSlug][this.currentView].filters, ...filters },
};
_workspaceViewFilters[workspaceSlug][this.currentView] = {
..._workspaceViewFilters[workspaceSlug][this.currentView],
filters: _filters?.filters,
};
runInAction(() => {
this.workspaceViewFilters = _workspaceViewFilters;
});
await this.workspaceService.updateView(workspaceSlug, this.currentView, {
query_data: {
filters: _filters.filters,
} as any,
});
return _filters.filters;
} catch (error) {
this.fetchWorkspaceViewFilters(workspaceSlug, this.currentView);
throw error;
}
};
get issueFilters() {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
if (!workspaceSlug) return undefined;
const displayFilters = this.issueDisplayFilters(workspaceSlug);
const _filters: IWorkspaceProperties = {
filters: displayFilters?.filters || {},
displayFilters: displayFilters?.displayFilters || {},
displayProperties: displayFilters?.displayProperties || {},
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
project: userFilters?.filters?.project || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
sub_issue: false,
};
const filteredParams = handleIssueQueryParamsByLayout("spreadsheet", "my_issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
return filteredRouteParams;
}
fetchFilters = async (workspaceSlug: string, view: TIssueViewTypes) => {
try {
await this.fetchWorkspaceProperties(workspaceSlug);
if (!["all-issues", "assigned", "created", "subscribed"].includes(view))
await this.fetchWorkspaceViewFilters(workspaceSlug, view);
return;
} catch (error) {
throw Error;
}
};
updateFilters = async (
workspaceSlug: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => {
try {
switch (filterType) {
case EFilterType.FILTERS:
if (["all-issues", "assigned", "created", "subscribed"].includes(this.currentView))
await this.updateWorkspaceProperties(workspaceSlug, filterType, filters as IIssueDisplayFilterOptions);
else await this.updateWorkspaceViewFilters(workspaceSlug, filters as IIssueFilterOptions);
break;
case EFilterType.DISPLAY_FILTERS:
await this.updateWorkspaceProperties(workspaceSlug, filterType, filters as IIssueDisplayFilterOptions);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.updateWorkspaceProperties(workspaceSlug, filterType, filters as IIssueDisplayProperties);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,224 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { WorkspaceService } from "services/workspace.service";
import { IssueService } from "services/issue";
// types
import { IIssue } from "types/issues";
import { IIssueResponse, TLoader, TUnGroupedIssues, ViewFlags } from "../types";
import { RootStore } from "store/root";
import isEmpty from "lodash/isEmpty";
export interface IGlobalIssuesStore {
// observable
loader: TLoader;
issues: { [workspace_view: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: TUnGroupedIssues | undefined;
// actions
fetchIssues: (workspaceSlug: string, workspaceViewId: string, loadType: TLoader) => Promise<IIssueResponse>;
createIssue: (
workspaceSlug: string,
projectId: string,
data: Partial<IIssue>,
workspaceViewId?: string | undefined
) => Promise<IIssue | undefined>;
updateIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<IIssue>,
workspaceViewId?: string | undefined
) => Promise<IIssue | undefined>;
removeIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
workspaceViewId?: string | undefined
) => Promise<IIssue | undefined>;
viewFlags: ViewFlags;
}
export class GlobalIssuesStore extends IssueBaseStore implements IGlobalIssuesStore {
loader: TLoader = "init-loader";
issues: { [workspace_view: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
workspaceService;
issueService;
//viewData
viewFlags = {
enableQuickAdd: true,
enableIssueCreation: true,
enableInlineEditing: true,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
});
this.rootStore = _rootStore;
this.workspaceService = new WorkspaceService();
this.issueService = new IssueService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const currentView = this.rootStore.workspaceGlobalIssuesFilter?.currentView;
if (!workspaceSlug || currentView === "") return;
const userFilters = this.rootStore?.workspaceGlobalIssuesFilter?.issueFilters?.filters;
if (!isEmpty(userFilters)) this.fetchIssues(workspaceSlug, currentView, "mutation");
});
}
get getIssues() {
const currentView = this.rootStore.workspaceGlobalIssuesFilter?.currentView;
if (currentView === "" || !this.issues || !this.issues[currentView]) return undefined;
return this.issues[currentView];
}
get getIssuesIds() {
const currentView = this.rootStore.workspaceGlobalIssuesFilter?.currentView;
const displayFilters = this.rootStore?.workspaceGlobalIssuesFilter?.issueFilters?.displayFilters;
if (!displayFilters) return undefined;
const orderBy = displayFilters?.order_by;
if (currentView === "" || !this.issues || !this.issues[currentView]) return undefined;
let issues: IIssueResponse | TUnGroupedIssues | undefined = undefined;
issues = this.unGroupedIssues(orderBy ?? "-created_at", this.issues[currentView]);
return issues;
}
fetchIssues = async (workspaceSlug: string, workspaceViewId: string, loadType: TLoader = "init-loader") => {
try {
this.loader = loadType;
const params = this.rootStore?.workspaceGlobalIssuesFilter?.appliedFilters;
const response = await this.workspaceService.getViewIssues(workspaceSlug, params);
const _issues = { ...this.issues, [workspaceViewId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
createIssue = async (
workspaceSlug: string,
projectId: string,
data: Partial<IIssue>,
workspaceViewId: string | undefined = undefined
) => {
if (!workspaceViewId) return;
try {
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[workspaceViewId]) _issues[workspaceViewId] = {};
_issues[workspaceViewId] = { ..._issues[workspaceViewId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, workspaceViewId, "mutation");
throw error;
}
};
updateIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<IIssue>,
workspaceViewId: string | undefined = undefined
) => {
if (!workspaceViewId) return;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[workspaceViewId]) _issues[workspaceViewId] = {};
_issues[workspaceViewId][issueId] = { ..._issues[workspaceViewId][issueId], ...data };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
runInAction(() => {
_issues = { ...this.issues };
_issues[workspaceViewId][issueId] = { ..._issues[workspaceViewId][issueId], ...response };
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, workspaceViewId, "mutation");
throw error;
}
};
removeIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
workspaceViewId: string | undefined = undefined
) => {
if (!workspaceViewId) return;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[workspaceViewId]) _issues[workspaceViewId] = {};
delete _issues?.[workspaceViewId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, workspaceViewId, "mutation");
throw error;
}
};
}

View file

@ -1,48 +0,0 @@
/** project issues and issue-filters starts */
// helpers
export * from "./base-issue-calendar-helper.store";
export * from "./base-issue-kanban-helper.store";
// issue and filter helpers
export * from "./project-issues/base-issue.store";
export * from "./project-issues/base-issue-filter.store";
// project display filters and display properties
export * from "./project-issues/issue-filters.store";
// project issues and filters
export * from "./project-issues/project/issue.store";
export * from "./project-issues/project/filter.store";
// module issues and filters
export * from "./project-issues/module/issue.store";
export * from "./project-issues/module/filter.store";
// cycle
export * from "./project-issues/cycle/issue.store";
export * from "./project-issues/cycle/filter.store";
// project views
export * from "./project-issues/project-view/issue.store";
export * from "./project-issues/project-view/filter.store";
// archived
export * from "./project-issues/archived/issue.store";
export * from "./project-issues/archived/filter.store";
// draft
export * from "./project-issues/draft/issue.store";
export * from "./project-issues/draft/filter.store";
/** project issues and issue-filters ends */
/** profile issues and issue-filters starts */
export * from "./profile/issue.store";
export * from "./profile/filter.store";
/** profile issues and issue-filters ends */
/** global issues and issue-filters starts */
export * from "./global/issue.store";
export * from "./global/filter.store";
/** global issues and issue-filters ends */

View file

@ -1,341 +0,0 @@
import { action, makeObservable, observable, runInAction } from "mobx";
import isEmpty from "lodash/isEmpty";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
import { IssueFilterBaseStore } from "../project-issues/base-issue-filter.store";
import { isNil } from "../project-issues/utils";
interface IProjectIssuesFiltersOptions {
filters: IIssueFilterOptions;
displayFilters: IIssueDisplayFilterOptions;
}
interface IProjectIssuesDisplayOptions {
filters: IIssueFilterOptions;
displayFilters: IIssueDisplayFilterOptions;
displayProperties: IIssueDisplayProperties;
}
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface IProfileIssuesFilterStore {
// observables
projectIssueFilters: { [workspaceId: string]: IProjectIssuesDisplayOptions } | undefined;
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// helpers
issueDisplayFilters: (workspaceId: string) => IProjectIssuesDisplayOptions | undefined;
// actions
fetchDisplayFilters: (workspaceSlug: string) => Promise<IProjectIssuesFiltersOptions>;
updateDisplayFilters: (
workspaceSlug: string,
type: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
) => Promise<IProjectIssuesFiltersOptions>;
fetchDisplayProperties: (workspaceSlug: string) => Promise<IIssueDisplayProperties>;
updateDisplayProperties: (
workspaceSlug: string,
properties: IIssueDisplayProperties
) => Promise<IIssueDisplayProperties>;
fetchFilters: (workspaceSlug: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => Promise<void>;
}
export class ProfileIssuesFilterStore extends IssueFilterBaseStore implements IProfileIssuesFilterStore {
// observables
projectIssueFilters: { [projectId: string]: IProjectIssuesDisplayOptions } | undefined = undefined;
// root store
rootStore;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observables
projectIssueFilters: observable.ref,
// computed
// actions
fetchDisplayFilters: action,
updateDisplayFilters: action,
fetchDisplayProperties: action,
updateDisplayProperties: action,
});
// root store
this.rootStore = _rootStore;
}
// computed
// helpers
issueDisplayFilters = (workspaceId: string) => {
if (!workspaceId) return undefined;
return this.projectIssueFilters?.[workspaceId] || undefined;
};
// actions
fetchDisplayFilters = async (workspaceSlug: string) => {
try {
const filters: IIssueFilterOptions = {
assignees: null,
mentions: null,
created_by: null,
labels: null,
priority: null,
project: null,
start_date: null,
state: null,
state_group: null,
subscriber: null,
target_date: null,
};
const displayFilters: IIssueDisplayFilterOptions = {
calendar: {
show_weekends: false,
layout: "month",
},
group_by: "state_detail.group",
sub_group_by: null,
layout: "list",
order_by: "-created_at",
show_empty_groups: false,
start_target_date: false,
sub_issue: false,
type: null,
};
const issueFilters: IProjectIssuesFiltersOptions = {
filters: filters,
displayFilters: displayFilters,
};
let _projectIssueFilters = this.projectIssueFilters;
if (!_projectIssueFilters) _projectIssueFilters = {};
if (!_projectIssueFilters[workspaceSlug]) {
_projectIssueFilters[workspaceSlug] = { displayProperties: {} } as IProjectIssuesDisplayOptions;
}
if (
isEmpty(_projectIssueFilters[workspaceSlug].filters) ||
isEmpty(_projectIssueFilters[workspaceSlug].displayFilters)
) {
_projectIssueFilters[workspaceSlug] = {
..._projectIssueFilters[workspaceSlug],
...issueFilters,
};
}
runInAction(() => {
this.projectIssueFilters = _projectIssueFilters;
});
return issueFilters;
} catch (error) {
throw error;
}
};
updateDisplayFilters = async (
workspaceSlug: string,
type: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
) => {
try {
let _projectIssueFilters = { ...this.projectIssueFilters };
if (!_projectIssueFilters) _projectIssueFilters = {};
if (!_projectIssueFilters[workspaceSlug])
_projectIssueFilters[workspaceSlug] = { filters: {}, displayFilters: {}, displayProperties: {} };
const _filters = {
filters: { ..._projectIssueFilters[workspaceSlug].filters },
displayFilters: { ..._projectIssueFilters[workspaceSlug].displayFilters },
};
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
else if (type === EFilterType.DISPLAY_FILTERS)
_filters.displayFilters = { ..._filters.displayFilters, ...filters };
// set sub_group_by to null if group_by is set to null
if (_filters.displayFilters.group_by === null) _filters.displayFilters.sub_group_by = null;
// set sub_group_by to null if layout is switched to kanban group_by and sub_group_by are same
if (
_filters.displayFilters.layout === "kanban" &&
_filters.displayFilters.group_by === _filters.displayFilters.sub_group_by
)
_filters.displayFilters.sub_group_by = null;
// set group_by to state if layout is switched to kanban and group_by is null
if (_filters.displayFilters.layout === "kanban" && _filters.displayFilters.group_by === null)
_filters.displayFilters.group_by = "state";
_projectIssueFilters[workspaceSlug] = {
filters: _filters.filters,
displayFilters: _filters.displayFilters,
displayProperties: _projectIssueFilters[workspaceSlug].displayProperties,
};
runInAction(() => {
this.projectIssueFilters = _projectIssueFilters;
});
return _filters;
} catch (error) {
throw error;
}
};
fetchDisplayProperties = async (workspaceSlug: string) => {
try {
const displayProperties: IIssueDisplayProperties = {
assignee: true,
start_date: true,
due_date: true,
labels: true,
key: true,
priority: true,
state: false,
sub_issue_count: true,
link: true,
attachment_count: false,
estimate: false,
created_on: false,
updated_on: false,
};
let _projectIssueFilters = { ...this.projectIssueFilters };
if (!_projectIssueFilters) _projectIssueFilters = {};
if (!_projectIssueFilters[workspaceSlug]) {
_projectIssueFilters[workspaceSlug] = { filters: {}, displayFilters: {} } as IProjectIssuesDisplayOptions;
}
if (isEmpty(_projectIssueFilters[workspaceSlug].displayProperties)) {
_projectIssueFilters[workspaceSlug] = {
..._projectIssueFilters[workspaceSlug],
displayProperties: displayProperties,
};
}
runInAction(() => {
this.projectIssueFilters = _projectIssueFilters;
});
return displayProperties;
} catch (error) {
throw error;
}
};
updateDisplayProperties = async (workspaceSlug: string, properties: IIssueDisplayProperties) => {
try {
let _issueFilters = { ...this.projectIssueFilters };
if (!_issueFilters) _issueFilters = {};
if (!_issueFilters[workspaceSlug])
_issueFilters[workspaceSlug] = { filters: {}, displayFilters: {}, displayProperties: {} };
const updatedDisplayProperties = { ..._issueFilters[workspaceSlug].displayProperties, ...properties };
_issueFilters[workspaceSlug] = { ..._issueFilters[workspaceSlug], displayProperties: updatedDisplayProperties };
runInAction(() => {
this.projectIssueFilters = _issueFilters;
});
return properties;
} catch (error) {
throw error;
}
};
get issueFilters() {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
if (!workspaceSlug) return undefined;
const displayFilters = this.issueDisplayFilters(workspaceSlug);
const _filters: IProjectIssuesFilters = {
filters: displayFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "profile_issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
return filteredRouteParams;
}
fetchFilters = async (workspaceSlug: string) => {
try {
await this.fetchDisplayFilters(workspaceSlug);
await this.fetchDisplayProperties(workspaceSlug);
return;
} catch (error) {
throw Error;
}
};
updateFilters = async (
workspaceSlug: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => {
try {
switch (filterType) {
case EFilterType.FILTERS:
await this.updateDisplayFilters(workspaceSlug, filterType, filters as IIssueFilterOptions);
break;
case EFilterType.DISPLAY_FILTERS:
await this.updateDisplayFilters(workspaceSlug, filterType, filters as IIssueDisplayFilterOptions);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.updateDisplayProperties(workspaceSlug, filters as IIssueDisplayProperties);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,334 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { UserService } from "services/user.service";
// types
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../types";
import { RootStore } from "store/root";
import { IIssue } from "types";
interface IProfileIssueTabTypes {
assigned: IIssueResponse;
created: IIssueResponse;
subscribed: IIssueResponse;
}
export interface IProfileIssuesStore {
// observable
loader: TLoader;
issues: { [user_id: string]: IProfileIssueTabTypes } | undefined;
currentUserId: string | null;
currentUserIssueTab: "assigned" | "created" | "subscribed" | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (
workspaceSlug: string,
userId: string,
loadType: TLoader,
id?: string | undefined,
type?: "assigned" | "created" | "subscribed"
) => Promise<IIssueResponse>;
createIssue: (workspaceSlug: string, userId: string, data: Partial<IIssue>) => Promise<IIssue | undefined>;
updateIssue: (
workspaceSlug: string,
userId: string,
issueId: string,
data: Partial<IIssue>
) => Promise<IIssue | undefined>;
removeIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
userId?: string
) => Promise<IIssue | undefined>;
quickAddIssue: (workspaceSlug: string, userId: string, data: IIssue) => Promise<IIssue | undefined>;
viewFlags: ViewFlags;
}
export class ProfileIssuesStore extends IssueBaseStore implements IProfileIssuesStore {
loader: TLoader = "init-loader";
issues: { [user_id: string]: IProfileIssueTabTypes } | undefined = undefined;
currentUserId: string | null = null;
currentUserIssueTab: "assigned" | "created" | "subscribed" | undefined = undefined;
// root store
rootStore;
// service
userService;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
currentUserId: observable.ref,
currentUserIssueTab: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
viewFlags: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
quickAddIssue: action,
});
this.rootStore = _rootStore;
this.userService = new UserService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
if (!workspaceSlug || !this.currentUserId || !this.currentUserIssueTab) return;
const userFilters = this.rootStore?.workspaceProfileIssuesFilter?.issueFilters?.filters;
if (userFilters) {
this.fetchIssues(workspaceSlug, this.currentUserId, "mutation", this.currentUserIssueTab);
}
});
}
get getIssues() {
if (!this.currentUserId || !this.currentUserIssueTab || !this.issues || !this.issues[this.currentUserId])
return undefined;
return this.issues[this.currentUserId][this.currentUserIssueTab];
}
get getIssuesIds() {
const currentUserId = this.currentUserId;
const displayFilters = this.rootStore?.workspaceProfileIssuesFilter?.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 (!currentUserId || !this.currentUserIssueTab || !this.issues || !this.issues[currentUserId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[currentUserId][this.currentUserIssueTab]);
else issues = this.unGroupedIssues(orderBy, this.issues[currentUserId][this.currentUserIssueTab]);
} else if (layout === "kanban" && groupBy && orderBy) {
if (subGroupBy)
issues = this.subGroupedIssues(
subGroupBy,
groupBy,
orderBy,
this.issues[currentUserId][this.currentUserIssueTab]
);
else issues = this.groupedIssues(groupBy, orderBy, this.issues[currentUserId][this.currentUserIssueTab]);
}
return issues;
}
get viewFlags() {
if (this.currentUserIssueTab === "subscribed") {
return {
enableQuickAdd: false,
enableIssueCreation: false,
enableInlineEditing: true,
};
}
return {
enableQuickAdd: false,
enableIssueCreation: true,
enableInlineEditing: true,
};
}
fetchIssues = async (
workspaceSlug: string,
userId: string,
loadType: TLoader = "init-loader",
id?: string | undefined,
type?: "assigned" | "created" | "subscribed"
) => {
try {
this.loader = loadType;
this.currentUserId = userId;
if (type) this.currentUserIssueTab = type;
let params: any = this.rootStore?.workspaceProfileIssuesFilter?.appliedFilters;
params = {
...params,
assignees: undefined,
created_by: undefined,
subscriber: undefined,
};
if (this.currentUserIssueTab === "assigned")
params = params ? { ...params, assignees: userId } : { assignees: userId };
else if (this.currentUserIssueTab === "created")
params = params ? { ...params, created_by: userId } : { created_by: userId };
else if (this.currentUserIssueTab === "subscribed")
params = params ? { ...params, subscriber: userId } : { subscriber: userId };
const response = await this.userService.getUserProfileIssues(workspaceSlug, userId, params);
if (!this.currentUserIssueTab) return;
const _issues: any = {
...this.issues,
[userId]: {
...this.issues?.[userId],
...{ [this.currentUserIssueTab]: response },
},
};
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return _issues;
} catch (error) {
this.loader = undefined;
throw error;
}
};
createIssue = async (workspaceSlug: string, userId: string, data: Partial<IIssue>) => {
try {
const projectId = data.project;
if (!projectId) return;
let response = {} as IIssue;
response = await this.rootStore.projectIssues.createIssue(workspaceSlug, projectId, data);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[userId]) _issues[userId] = { assigned: {}, created: {}, subscribed: {} };
_issues[userId] = { ..._issues[userId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
if (this.currentUserIssueTab) this.fetchIssues(workspaceSlug, userId, "mutation", this.currentUserIssueTab);
throw error;
}
};
updateIssue = async (workspaceSlug: string, userId: string, issueId: string, data: Partial<IIssue>) => {
try {
const projectId = data.project;
const moduleId = data.module_id;
const cycleId = data.cycle_id;
if (!projectId || !this.currentUserIssueTab) return;
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[userId]) _issues[userId] = { assigned: {}, created: {}, subscribed: {} };
_issues[userId][this.currentUserIssueTab][issueId] = {
..._issues[userId][this.currentUserIssueTab][issueId],
...data,
};
runInAction(() => {
this.issues = _issues;
});
let response = data as IIssue | undefined;
response = await this.rootStore.projectIssues.updateIssue(
workspaceSlug,
projectId,
data.id as keyof IIssue,
data
);
if (moduleId)
response = await this.rootStore.moduleIssues.updateIssue(
workspaceSlug,
projectId,
response.id as keyof IIssue,
response,
moduleId
);
if (cycleId)
response = await this.rootStore.cycleIssues.updateIssue(
workspaceSlug,
projectId,
data.id as keyof IIssue,
data,
cycleId
);
return response;
} catch (error) {
if (this.currentUserIssueTab) this.fetchIssues(workspaceSlug, userId, "mutation", this.currentUserIssueTab);
throw error;
}
};
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string, userId?: string) => {
if (!userId) return;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[userId]) _issues[userId] = { assigned: {}, created: {}, subscribed: {} };
if (this.currentUserIssueTab) delete _issues?.[userId]?.[this.currentUserIssueTab]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.rootStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
if (this.currentUserIssueTab) this.fetchIssues(workspaceSlug, userId, "mutation", this.currentUserIssueTab);
throw error;
}
};
quickAddIssue = async (workspaceSlug: string, userId: string, data: IIssue) => {
try {
const projectId = data.project;
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[userId]) _issues[userId] = { assigned: {}, created: {}, subscribed: {} };
_issues[userId] = { ..._issues[userId], ...{ [data.id as keyof IIssue]: data } };
runInAction(() => {
this.issues = _issues;
});
const response = await this.rootStore.projectIssues.createIssue(workspaceSlug, projectId, data);
if (this.issues && this.currentUserIssueTab) {
delete this.issues[userId][this.currentUserIssueTab][data.id as keyof IIssue];
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[userId]) _issues[userId] = { assigned: {}, created: {}, subscribed: {} };
_issues[userId] = { ..._issues[userId], ...{ [response.id as keyof IIssue]: response } };
runInAction(() => {
this.issues = _issues;
});
}
return response;
} catch (error) {
if (this.currentUserIssueTab) this.fetchIssues(workspaceSlug, userId, "mutation", this.currentUserIssueTab);
throw error;
}
};
}

View file

@ -1,145 +0,0 @@
import { computed, makeObservable } from "mobx";
// base class
import { IssueFilterBaseStore } from "store/issues";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { isNil } from "../utils";
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface IProjectArchivedIssuesFilterStore {
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// action
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => Promise<void>;
}
export class ProjectArchivedIssuesFilterStore
extends IssueFilterBaseStore
implements IProjectArchivedIssuesFilterStore
{
// root store
rootStore;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// computed
issueFilters: computed,
appliedFilters: computed,
});
// root store
this.rootStore = _rootStore;
}
get issueFilters() {
const projectId = this.rootStore.project.projectId;
if (!projectId) return undefined;
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
const _filters: IProjectIssuesFilters = {
filters: displayFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
return filteredRouteParams;
}
fetchFilters = async (workspaceSlug: string, projectId: string) => {
try {
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
return;
} catch (error) {
throw Error;
}
};
updateFilters = async (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => {
try {
switch (filterType) {
case EFilterType.FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueFilterOptions
);
break;
case EFilterType.DISPLAY_FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueDisplayFilterOptions
);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.rootStore.issuesFilter.updateDisplayProperties(
workspaceSlug,
projectId,
filters as IIssueDisplayProperties
);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,158 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { IssueArchiveService } from "services/issue";
// types
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../../types";
import { RootStore } from "store/root";
export interface IProjectArchivedIssuesStore {
// observable
loader: TLoader;
issues: { [project_id: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<IIssueResponse>;
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
removeIssueFromArchived: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
quickAddIssue: undefined;
viewFlags: ViewFlags;
}
export class ProjectArchivedIssuesStore extends IssueBaseStore implements IProjectArchivedIssuesStore {
loader: TLoader = "init-loader";
issues: { [project_id: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
archivedIssueService;
//viewData
viewFlags = {
enableQuickAdd: false,
enableIssueCreation: false,
enableInlineEditing: true,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
removeIssue: action,
removeIssueFromArchived: action,
});
this.rootStore = _rootStore;
this.archivedIssueService = new IssueArchiveService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const projectId = this.rootStore.project.projectId;
const hasPermissionToCurrentProject = this.rootStore.user.hasPermissionToCurrentProject;
if (!workspaceSlug || !projectId || !hasPermissionToCurrentProject) return;
const userFilters = this.rootStore?.projectArchivedIssuesFilter?.issueFilters?.filters;
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation");
});
}
get getIssues() {
const projectId = this.rootStore?.project.projectId;
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
return this.issues[projectId];
}
get getIssuesIds() {
const projectId = this.rootStore?.project.projectId;
const displayFilters = this.rootStore?.projectArchivedIssuesFilter?.issueFilters?.displayFilters;
if (!displayFilters) return undefined;
const groupBy = displayFilters?.group_by;
const orderBy = displayFilters?.order_by;
const layout = displayFilters?.layout;
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
else issues = this.unGroupedIssues(orderBy, this.issues[projectId]);
}
return issues;
}
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
try {
this.loader = loadType;
const params = this.rootStore?.projectArchivedIssuesFilter?.appliedFilters;
const response = await this.archivedIssueService.getArchivedIssues(workspaceSlug, projectId, params);
const _issues = { ...this.issues, [projectId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
delete _issues?.[projectId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.archivedIssueService.deleteArchivedIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;
}
};
removeIssueFromArchived = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
delete _issues?.[projectId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.archivedIssueService.unarchiveIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
throw error;
}
};
quickAddIssue: undefined;
}

View file

@ -1,29 +0,0 @@
// types
import { RootStore } from "store/root";
export interface IIssueFilterBaseStore {
// helper methods
computedFilter(filters: any, filteredParams: any): any;
}
export class IssueFilterBaseStore implements IIssueFilterBaseStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
// root store
this.rootStore = _rootStore;
}
// helper methods
computedFilter = (filters: any, filteredParams: any) => {
const computedFilters: any = {};
Object.keys(filters).map((key) => {
if (filters[key] != undefined && filteredParams.includes(key))
computedFilters[key] =
typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(",");
});
return computedFilters;
};
}

View file

@ -1,207 +0,0 @@
import sortBy from "lodash/sortBy";
import get from "lodash/get";
import indexOf from "lodash/indexOf";
import reverse from "lodash/reverse";
import values from "lodash/values";
// types
import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
import { RootStore } from "store/root";
import { IIssueResponse } from "../types";
// constants
import { ISSUE_PRIORITIES, ISSUE_STATE_GROUPS } from "constants/issue";
// helpers
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
export interface IIssueBaseStore {
groupedIssues(
groupBy: TIssueGroupByOptions,
orderBy: TIssueOrderByOptions,
issues: IIssueResponse,
isCalendarIssues?: boolean
): { [group_id: string]: string[] };
subGroupedIssues(
subGroupBy: TIssueGroupByOptions,
groupBy: TIssueGroupByOptions,
orderBy: TIssueOrderByOptions,
issues: IIssueResponse
): { [sub_group_id: string]: { [group_id: string]: string[] } };
unGroupedIssues(orderBy: TIssueOrderByOptions, issues: IIssueResponse): string[];
issueDisplayFiltersDefaultData(groupBy: string | null): string[];
issuesSortWithOrderBy(issueObject: IIssueResponse, key: Partial<TIssueOrderByOptions>): IIssue[];
getGroupArray(value: string[] | string | null, isDate?: boolean): string[];
}
export class IssueBaseStore implements IIssueBaseStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
this.rootStore = _rootStore;
}
groupedIssues = (
groupBy: TIssueGroupByOptions,
orderBy: TIssueOrderByOptions,
issues: IIssueResponse,
isCalendarIssues: boolean = false
) => {
const _issues: { [group_id: string]: string[] } = {};
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
_issues[group] = [];
});
const projectIssues = this.issuesSortWithOrderBy(issues, orderBy);
for (const issue in projectIssues) {
const _issue = projectIssues[issue];
const groupArray = this.getGroupArray(get(_issue, groupBy as keyof IIssue), isCalendarIssues);
for (const group of groupArray) {
if (group && _issues[group]) _issues[group].push(_issue.id);
else if (group) _issues[group] = [_issue.id];
}
}
return _issues;
};
subGroupedIssues = (
subGroupBy: TIssueGroupByOptions,
groupBy: TIssueGroupByOptions,
orderBy: TIssueOrderByOptions,
issues: IIssueResponse
) => {
const _issues: { [sub_group_id: string]: { [group_id: string]: string[] } } = {};
this.issueDisplayFiltersDefaultData(subGroupBy).forEach((sub_group: any) => {
const groupByIssues: { [group_id: string]: string[] } = {};
this.issueDisplayFiltersDefaultData(groupBy).forEach((group) => {
groupByIssues[group] = [];
});
_issues[sub_group] = groupByIssues;
});
const projectIssues = this.issuesSortWithOrderBy(issues, orderBy);
for (const issue in projectIssues) {
const _issue = projectIssues[issue];
const subGroupArray = this.getGroupArray(get(_issue, subGroupBy as keyof IIssue));
const groupArray = this.getGroupArray(get(_issue, groupBy as keyof IIssue));
for (const subGroup of subGroupArray) {
for (const group of groupArray) {
if (subGroup && group && _issues?.[subGroup]?.[group]) _issues[subGroup][group].push(_issue.id);
else if (subGroup && group && _issues[subGroup]) _issues[subGroup][group] = [_issue.id];
else if (subGroup && group) _issues[subGroup] = { [group]: [_issue.id] };
}
}
}
return _issues;
};
unGroupedIssues = (orderBy: TIssueOrderByOptions, issues: IIssueResponse) =>
this.issuesSortWithOrderBy(issues, orderBy).map((issue) => issue.id);
issueDisplayFiltersDefaultData = (groupBy: string | null): string[] => {
switch (groupBy) {
case "state":
return this.rootStore?.projectState.projectStateIds();
case "state_detail.group":
return ISSUE_STATE_GROUPS.map((i) => i.key);
case "priority":
return ISSUE_PRIORITIES.map((i) => i.key);
case "labels":
return this.rootStore?.projectLabel?.projectLabelIds(true);
case "created_by":
return this.rootStore?.projectMember?.projectMemberIds(true);
case "assignees":
return this.rootStore?.projectMember?.projectMemberIds(true);
case "project":
return this.rootStore?.project?.workspaceProjectIds();
default:
return [];
}
};
issuesSortWithOrderBy = (issueObject: IIssueResponse, key: Partial<TIssueOrderByOptions>): IIssue[] => {
let array = values(issueObject);
array = reverse(sortBy(array, "created_at"));
switch (key) {
case "sort_order":
return reverse(sortBy(array, "sort_order"));
case "state__name": {
return reverse(sortBy(array, "state"));
}
case "-state__name": {
return sortBy(array, "state");
}
//dates
case "created_at":
return sortBy(array, "created_at");
case "-created_at":
return reverse(sortBy(array, "created_at"));
case "updated_at":
return sortBy(array, "updated_at");
case "-updated_at":
return reverse(sortBy(array, "updated_at"));
case "start_date":
return sortBy(array, "start_date");
case "-start_date":
return reverse(sortBy(array, "start_date"));
case "target_date":
return sortBy(array, "target_date");
case "-target_date":
return reverse(sortBy(array, "target_date"));
//custom
case "priority": {
const sortArray = ISSUE_PRIORITIES.map((i) => i.key);
return reverse(sortBy(array, (_issue: IIssue) => indexOf(sortArray, _issue.priority)));
}
case "-priority": {
const sortArray = ISSUE_PRIORITIES.map((i) => i.key);
return sortBy(array, (_issue: IIssue) => indexOf(sortArray, _issue.priority));
}
//number
case "attachment_count":
return sortBy(array, "attachment_count");
case "-attachment_count":
return reverse(sortBy(array, "attachment_count"));
case "estimate_point":
return sortBy(array, "estimate_point");
case "-estimate_point":
return reverse(sortBy(array, "estimate_point"));
case "link_count":
return sortBy(array, "link_count");
case "-link_count":
return reverse(sortBy(array, "link_count"));
case "sub_issues_count":
return sortBy(array, "sub_issues_count");
case "-sub_issues_count":
return reverse(sortBy(array, "sub_issues_count"));
//Array
case "labels__name":
return reverse(sortBy(array, "labels"));
case "-labels__name":
return sortBy(array, "labels");
case "assignees__first_name":
return reverse(sortBy(array, "assignees"));
case "-assignees__first_name":
return sortBy(array, "assignees");
default:
return array;
}
};
getGroupArray(value: string[] | string | null, isDate: boolean = false) {
if (Array.isArray(value)) {
if (value.length) return value;
else return ["None"];
} else if (isDate) return [renderFormattedPayloadDate(value ?? "") || "None"];
else return [value || "None"];
}
}

View file

@ -1,258 +0,0 @@
import { observable, action, computed, makeObservable, runInAction } from "mobx";
// base class
import { IssueFilterBaseStore } from "store/issues";
// services
import { ProjectService, ProjectMemberService } from "services/project";
import { IssueService } from "services/issue";
import { CycleService } from "services/cycle.service";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { isNil } from "../utils";
interface ICycleIssuesFilterOptions {
filters: IIssueFilterOptions;
}
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface ICycleIssuesFilterStore {
// observable
loader: boolean;
filters: { [cycleId: string]: ICycleIssuesFilterOptions } | undefined;
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// actions
fetchCycleFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<IIssueFilterOptions>;
updateCycleFilters: (
workspaceSlug: string,
projectId: string,
cycleId: string,
type: EFilterType,
filters: IIssueFilterOptions
) => Promise<ICycleIssuesFilterOptions>;
fetchFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
cycleId?: string | undefined
) => Promise<void>;
}
export class CycleIssuesFilterStore extends IssueFilterBaseStore implements ICycleIssuesFilterStore {
// observables
loader: boolean = false;
filters: { [projectId: string]: ICycleIssuesFilterOptions } | undefined = undefined;
// root store
rootStore;
// services
projectService;
projectMemberService;
issueService;
cycleService;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observables
loader: observable.ref,
filters: observable.ref,
// computed
issueFilters: computed,
appliedFilters: computed,
// actions
fetchCycleFilters: action,
updateCycleFilters: action,
fetchFilters: action,
updateFilters: action,
});
this.rootStore = _rootStore;
this.projectService = new ProjectService();
this.projectMemberService = new ProjectMemberService();
this.issueService = new IssueService();
this.cycleService = new CycleService();
}
get issueFilters() {
const projectId = this.rootStore.project.projectId;
const cycleId = this.rootStore.cycle.cycleId;
if (!projectId || !cycleId) return undefined;
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
const cycleFilters = this.filters?.[cycleId];
const _filters: IProjectIssuesFilters = {
filters: cycleFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
return filteredRouteParams;
}
fetchCycleFilters = async (workspaceSlug: string, projectId: string, cycleId: string) => {
try {
const cycleFilters = await this.cycleService.getCycleDetails(workspaceSlug, projectId, cycleId);
const filters: IIssueFilterOptions = {
assignees: cycleFilters?.view_props?.filters?.assignees || null,
mentions: cycleFilters?.view_props?.filters?.mentions || null,
created_by: cycleFilters?.view_props?.filters?.created_by || null,
labels: cycleFilters?.view_props?.filters?.labels || null,
priority: cycleFilters?.view_props?.filters?.priority || null,
project: cycleFilters?.view_props?.filters?.project || null,
start_date: cycleFilters?.view_props?.filters?.start_date || null,
state: cycleFilters?.view_props?.filters?.state || null,
state_group: cycleFilters?.view_props?.filters?.state_group || null,
subscriber: cycleFilters?.view_props?.filters?.subscriber || null,
target_date: cycleFilters?.view_props?.filters?.target_date || null,
};
const issueFilters: ICycleIssuesFilterOptions = {
filters: filters,
};
let _filters = { ...this.filters };
if (!_filters) _filters = {};
if (!_filters[cycleId]) _filters[cycleId] = { filters: {} };
_filters[cycleId] = issueFilters;
runInAction(() => {
this.filters = _filters;
});
return filters;
} catch (error) {
console.log("error in fetchCycleFilters", error);
throw error;
}
};
updateCycleFilters = async (
workspaceSlug: string,
projectId: string,
cycleId: string,
type: EFilterType,
filters: IIssueFilterOptions
) => {
try {
let _cycleIssueFilters = { ...this.filters };
if (!_cycleIssueFilters) _cycleIssueFilters = {};
if (!_cycleIssueFilters[cycleId]) _cycleIssueFilters[cycleId] = { filters: {} };
const _filters = { filters: { ..._cycleIssueFilters[cycleId].filters } };
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
_cycleIssueFilters[cycleId] = { filters: _filters.filters };
runInAction(() => {
this.filters = _cycleIssueFilters;
});
await this.cycleService.patchCycle(workspaceSlug, projectId, cycleId, {
view_props: { filters: _filters.filters },
});
return _filters;
} catch (error) {
this.fetchFilters(workspaceSlug, projectId, cycleId);
throw error;
}
};
fetchFilters = async (workspaceSlug: string, projectId: string, cycleId: string) => {
try {
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
await this.fetchCycleFilters(workspaceSlug, projectId, cycleId);
return;
} catch (error) {
console.log("error in cycleFetchFilters", error);
throw error;
}
};
updateFilters = async (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
cycleId?: string | undefined
) => {
try {
if (!cycleId) throw new Error();
switch (filterType) {
case EFilterType.FILTERS:
await this.updateCycleFilters(workspaceSlug, projectId, cycleId, filterType, filters as IIssueFilterOptions);
break;
case EFilterType.DISPLAY_FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueDisplayFilterOptions
);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.rootStore.issuesFilter.updateDisplayProperties(
workspaceSlug,
projectId,
filters as IIssueDisplayProperties
);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,396 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { IssueService } from "services/issue";
import { CycleService } from "services/cycle.service";
// types
import { TIssueGroupByOptions } from "types";
import { IIssue } from "types/issues";
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../../types";
import { RootStore } from "store/root";
export interface ICycleIssuesStore {
// observable
loader: TLoader;
issues: { [cycle_id: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (
workspaceSlug: string,
projectId: string,
loadType: TLoader,
cycleId?: string | undefined
) => Promise<IIssueResponse | undefined>;
createIssue: (
workspaceSlug: string,
projectId: string,
data: Partial<IIssue>,
cycleId?: string | undefined
) => Promise<IIssue | undefined>;
updateIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<IIssue>,
cycleId?: string | undefined
) => Promise<IIssue | undefined>;
removeIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
cycleId?: string | undefined
) => Promise<IIssue | undefined>;
quickAddIssue: (
workspaceSlug: string,
projectId: string,
data: IIssue,
cycleId?: string | undefined
) => Promise<IIssue | undefined>;
addIssueToCycle: (
workspaceSlug: string,
cycleId: string,
issueIds: string[],
fetchAfterAddition?: boolean,
projectId?: string
) => Promise<IIssue>;
removeIssueFromCycle: (
workspaceSlug: string,
projectId: string,
cycleId: string,
issueId: string,
issueBridgeId: string
) => Promise<IIssue>;
transferIssuesFromCycle: (
workspaceSlug: string,
projectId: string,
cycleId: string,
payload: {
new_cycle_id: string;
}
) => Promise<IIssue>;
viewFlags: ViewFlags;
}
export class CycleIssuesStore extends IssueBaseStore implements ICycleIssuesStore {
loader: TLoader = "init-loader";
issues: { [cycle_id: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
cycleService;
issueService;
//viewData
viewFlags = {
enableQuickAdd: true,
enableIssueCreation: true,
enableInlineEditing: true,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
quickAddIssue: action,
addIssueToCycle: action,
removeIssueFromCycle: action,
transferIssuesFromCycle: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
this.cycleService = new CycleService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const projectId = this.rootStore.project.projectId;
const cycleId = this.rootStore.cycle.cycleId;
const hasPermissionToCurrentProject = this.rootStore.user.hasPermissionToCurrentProject;
if (!workspaceSlug || !projectId || !hasPermissionToCurrentProject || !cycleId) return;
const userFilters = this.rootStore?.cycleIssuesFilter?.issueFilters?.filters;
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
});
}
get getIssues() {
const cycleId = this.rootStore?.cycle?.cycleId;
if (!cycleId || !this.issues || !this.issues[cycleId]) return undefined;
return this.issues[cycleId];
}
get getIssuesIds() {
const cycleId = this.rootStore?.cycle?.cycleId;
const displayFilters = this.rootStore?.cycleIssuesFilter?.issueFilters?.displayFilters;
const subGroupBy = displayFilters?.sub_group_by;
const groupBy = displayFilters?.group_by;
const orderBy = displayFilters?.order_by;
const layout = displayFilters?.layout;
if (!cycleId || !this.issues || !this.issues[cycleId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[cycleId]);
else issues = this.unGroupedIssues(orderBy, this.issues[cycleId]);
} else if (layout === "kanban" && groupBy && orderBy) {
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, this.issues[cycleId]);
else issues = this.groupedIssues(groupBy, orderBy, this.issues[cycleId]);
} else if (layout === "calendar")
issues = this.groupedIssues("target_date" as TIssueGroupByOptions, "target_date", this.issues[cycleId], true);
else if (layout === "spreadsheet") issues = this.unGroupedIssues(orderBy ?? "-created_at", this.issues[cycleId]);
else if (layout === "gantt_chart") issues = this.unGroupedIssues(orderBy ?? "sort_order", this.issues[cycleId]);
return issues;
}
fetchIssues = async (
workspaceSlug: string,
projectId: string,
loadType: TLoader = "init-loader",
cycleId: string | undefined = undefined
) => {
if (!cycleId) return undefined;
try {
this.loader = loadType;
const params = this.rootStore?.cycleIssuesFilter?.appliedFilters;
const response = await this.cycleService.getCycleIssuesWithParams(workspaceSlug, projectId, cycleId, params);
const _issues = { ...this.issues, [cycleId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
createIssue = async (
workspaceSlug: string,
projectId: string,
data: Partial<IIssue>,
cycleId: string | undefined = undefined
) => {
if (!cycleId) return undefined;
try {
const response = await this.rootStore.projectIssues.createIssue(workspaceSlug, projectId, data);
const issueToCycle = await this.addIssueToCycle(workspaceSlug, cycleId, [response.id], false);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[cycleId]) _issues[cycleId] = {};
_issues[cycleId] = { ..._issues[cycleId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return issueToCycle;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
throw error;
}
};
updateIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<IIssue>,
cycleId: string | undefined = undefined
) => {
if (!cycleId) return undefined;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[cycleId]) _issues[cycleId] = {};
_issues[cycleId][issueId] = { ..._issues[cycleId][issueId], ...data };
runInAction(() => {
this.issues = _issues;
});
const response = await this.rootStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
runInAction(() => {
_issues = { ...this.issues };
_issues[cycleId][issueId] = { ..._issues[cycleId][issueId], ...response };
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
throw error;
}
};
removeIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
cycleId: string | undefined = undefined
) => {
if (!cycleId) return undefined;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[cycleId]) _issues[cycleId] = {};
delete _issues?.[cycleId]?.[issueId];
_issues[cycleId] = { ..._issues[cycleId] };
runInAction(() => {
this.issues = _issues;
});
const response = await this.rootStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
throw error;
}
};
quickAddIssue = async (
workspaceSlug: string,
projectId: string,
data: IIssue,
cycleId: string | undefined = undefined
) => {
if (!cycleId) return;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[cycleId]) _issues[cycleId] = {};
_issues[cycleId] = { ..._issues[cycleId], ...{ [data.id as keyof IIssue]: data } };
runInAction(() => {
this.issues = _issues;
});
const response = await this.createIssue(workspaceSlug, projectId, data, cycleId);
if (this.issues) {
delete this.issues[cycleId][data.id as keyof IIssue];
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[cycleId]) _issues[cycleId] = {};
_issues[cycleId] = { ..._issues[cycleId], ...{ [response.id as keyof IIssue]: response } };
runInAction(() => {
this.issues = _issues;
});
}
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
throw error;
}
};
addIssueToCycle = async (
workspaceSlug: string,
cycleId: string,
issueIds: string[],
fetchAfterAddition = true,
projectId?: string
) => {
const activeProjectId = this.rootStore.project.projectId;
if (!activeProjectId && !projectId) return;
const projectIdToUpdate: string = projectId || activeProjectId || "";
try {
const issueToCycle = await this.issueService.addIssueToCycle(workspaceSlug, projectIdToUpdate, cycleId, {
issues: issueIds,
});
if (fetchAfterAddition) this.fetchIssues(workspaceSlug, projectIdToUpdate, "mutation", cycleId);
return issueToCycle;
} catch (error) {
this.fetchIssues(workspaceSlug, projectIdToUpdate, "mutation", cycleId);
throw error;
}
};
removeIssueFromCycle = async (
workspaceSlug: string,
projectId: string,
cycleId: string,
issueId: string,
issueBridgeId: string
) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[cycleId]) _issues[cycleId] = {};
delete _issues?.[cycleId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueBridgeId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
throw error;
}
};
transferIssuesFromCycle = async (
workspaceSlug: string,
projectId: string,
cycleId: string,
payload: {
new_cycle_id: string;
}
) => {
try {
const response = await this.cycleService.transferIssues(
workspaceSlug as string,
projectId as string,
cycleId as string,
payload
);
await this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
throw error;
}
};
}

View file

@ -1,142 +0,0 @@
import { computed, makeObservable } from "mobx";
// base class
import { IssueFilterBaseStore } from "store/issues";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { isNil } from "../utils";
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface IProjectDraftIssuesFilterStore {
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// action
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => Promise<void>;
}
export class ProjectDraftIssuesFilterStore extends IssueFilterBaseStore implements IProjectDraftIssuesFilterStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// computed
issueFilters: computed,
appliedFilters: computed,
});
// root store
this.rootStore = _rootStore;
}
get issueFilters() {
const projectId = this.rootStore.project.projectId;
if (!projectId) return undefined;
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
const _filters: IProjectIssuesFilters = {
filters: displayFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
return filteredRouteParams;
}
fetchFilters = async (workspaceSlug: string, projectId: string) => {
try {
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
return;
} catch (error) {
throw Error;
}
};
updateFilters = async (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => {
try {
switch (filterType) {
case EFilterType.FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueFilterOptions
);
break;
case EFilterType.DISPLAY_FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueDisplayFilterOptions
);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.rootStore.issuesFilter.updateDisplayProperties(
workspaceSlug,
projectId,
filters as IIssueDisplayProperties
);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,195 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { IssueDraftService } from "services/issue/issue_draft.service";
// types
import { IIssue } from "types/issues";
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../../types";
import { RootStore } from "store/root";
export interface IProjectDraftIssuesStore {
// observable
loader: TLoader;
issues: { [project_id: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<IIssueResponse>;
createIssue: (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => Promise<IIssue>;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => Promise<IIssue>;
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<IIssue>;
quickAddIssue: undefined;
viewFlags: ViewFlags;
}
export class ProjectDraftIssuesStore extends IssueBaseStore implements IProjectDraftIssuesStore {
loader: TLoader = "init-loader";
issues: { [project_id: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
issueDraftService;
//viewData
viewFlags = {
enableQuickAdd: false,
enableIssueCreation: true,
enableInlineEditing: false,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
});
this.rootStore = _rootStore;
this.issueDraftService = new IssueDraftService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const projectId = this.rootStore.project.projectId;
const hasPermissionToCurrentProject = this.rootStore.user.hasPermissionToCurrentProject;
if (!workspaceSlug || !projectId || !hasPermissionToCurrentProject) return;
const userFilters = this.rootStore?.projectDraftIssuesFilter?.issueFilters?.filters;
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation");
});
}
get getIssues() {
const projectId = this.rootStore?.project.projectId;
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
return this.issues[projectId];
}
get getIssuesIds() {
const projectId = this.rootStore?.project.projectId;
const displayFilters = this.rootStore?.projectDraftIssuesFilter?.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 (!projectId || !this.issues || !this.issues[projectId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
else issues = this.unGroupedIssues(orderBy, this.issues[projectId]);
} else if (layout === "kanban" && groupBy && orderBy) {
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, this.issues[projectId]);
else issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
}
return issues;
}
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
try {
this.loader = loadType;
const params = this.rootStore?.projectDraftIssuesFilter?.appliedFilters;
const response = await this.issueDraftService.getDraftIssues(workspaceSlug, projectId, params);
const _issues = { ...this.issues, [projectId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => {
try {
const response = await this.issueDraftService.createDraftIssue(workspaceSlug, projectId, data);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId][issueId] = { ..._issues[projectId][issueId], ...data };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueDraftService.updateDraftIssue(workspaceSlug, projectId, issueId, data);
runInAction(() => {
_issues = { ...this.issues };
_issues[projectId][issueId] = { ..._issues[projectId][issueId], ...response };
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
delete _issues?.[projectId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueDraftService.deleteDraftIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
quickAddIssue: undefined;
}

View file

@ -1,252 +0,0 @@
import { action, makeObservable, observable, runInAction } from "mobx";
// services
import { IssueService } from "services/issue";
import { ProjectMemberService, ProjectService } from "services/project";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "types";
import { EFilterType } from "store/issues/types";
interface IProjectIssuesFiltersOptions {
filters: IIssueFilterOptions;
displayFilters: IIssueDisplayFilterOptions;
}
interface IProjectIssuesDisplayOptions {
filters: IIssueFilterOptions;
displayFilters: IIssueDisplayFilterOptions;
displayProperties: IIssueDisplayProperties;
}
export interface IIssuesFilterStore {
// observables
projectIssueFilters: { [projectId: string]: IProjectIssuesDisplayOptions } | undefined;
// computed
// helpers
issueDisplayFilters: (projectId: string) => IProjectIssuesDisplayOptions | undefined;
// actions
fetchDisplayFilters: (workspaceSlug: string, projectId: string) => Promise<IProjectIssuesFiltersOptions>;
updateDisplayFilters: (
workspaceSlug: string,
projectId: string,
type: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
) => Promise<IProjectIssuesFiltersOptions>;
fetchDisplayProperties: (workspaceSlug: string, projectId: string) => Promise<IIssueDisplayProperties>;
updateDisplayProperties: (
workspaceSlug: string,
projectId: string,
properties: IIssueDisplayProperties
) => Promise<IIssueDisplayProperties>;
}
export class IssuesFilterStore implements IIssuesFilterStore {
// observables
projectIssueFilters: { [projectId: string]: IProjectIssuesDisplayOptions } | undefined = undefined;
// root store
rootStore;
// services
projectMemberService;
projectService;
issueService;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// observables
projectIssueFilters: observable.ref,
// computed
// actions
fetchDisplayFilters: action,
updateDisplayFilters: action,
fetchDisplayProperties: action,
updateDisplayProperties: action,
});
// root store
this.rootStore = _rootStore;
// services
this.projectMemberService = new ProjectMemberService();
this.projectService = new ProjectService();
this.issueService = new IssueService();
}
// computed
// helpers
issueDisplayFilters = (projectId: string) => {
if (!projectId) return undefined;
return this.projectIssueFilters?.[projectId] || undefined;
};
// actions
fetchDisplayFilters = async (workspaceSlug: string, projectId: string) => {
try {
const _filters = await this.projectMemberService.projectMemberMe(workspaceSlug, projectId);
const filters: IIssueFilterOptions = {
assignees: _filters?.view_props?.filters?.assignees || null,
mentions: _filters?.view_props?.filters?.mentions || null,
created_by: _filters?.view_props?.filters?.created_by || null,
labels: _filters?.view_props?.filters?.labels || null,
priority: _filters?.view_props?.filters?.priority || null,
project: _filters?.view_props?.filters?.project || null,
start_date: _filters?.view_props?.filters?.start_date || null,
state: _filters?.view_props?.filters?.state || null,
state_group: _filters?.view_props?.filters?.state_group || null,
subscriber: _filters?.view_props?.filters?.subscriber || null,
target_date: _filters?.view_props?.filters?.target_date || null,
};
const displayFilters: IIssueDisplayFilterOptions = {
calendar: {
show_weekends: _filters?.view_props?.display_filters?.calendar?.show_weekends || false,
layout: _filters?.view_props?.display_filters?.calendar?.layout || "month",
},
group_by: _filters?.view_props?.display_filters?.group_by || null,
sub_group_by: _filters?.view_props?.display_filters?.sub_group_by || null,
layout: _filters?.view_props?.display_filters?.layout || "list",
order_by: _filters?.view_props?.display_filters?.order_by || "-created_at",
show_empty_groups: _filters?.view_props?.display_filters?.show_empty_groups || false,
start_target_date: _filters?.view_props?.display_filters?.start_target_date || false,
sub_issue: _filters?.view_props?.display_filters?.sub_issue || false,
type: _filters?.view_props?.display_filters?.type || null,
};
const issueFilters: IProjectIssuesFiltersOptions = {
filters: filters,
displayFilters: displayFilters,
};
let _projectIssueFilters = this.projectIssueFilters;
if (!_projectIssueFilters) _projectIssueFilters = {};
if (!_projectIssueFilters[projectId])
_projectIssueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
_projectIssueFilters[projectId] = {
..._projectIssueFilters[projectId],
...issueFilters,
};
runInAction(() => {
this.projectIssueFilters = _projectIssueFilters;
});
return issueFilters;
} catch (error) {
throw error;
}
};
updateDisplayFilters = async (
workspaceSlug: string,
projectId: string,
type: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions
) => {
try {
let _projectIssueFilters = { ...this.projectIssueFilters };
if (!_projectIssueFilters) _projectIssueFilters = {};
if (!_projectIssueFilters[projectId])
_projectIssueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
const _filters = {
filters: { ..._projectIssueFilters[projectId].filters },
displayFilters: { ..._projectIssueFilters[projectId].displayFilters },
};
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
else if (type === EFilterType.DISPLAY_FILTERS)
_filters.displayFilters = { ..._filters.displayFilters, ...filters };
// set sub_group_by to null if group_by is set to null
if (_filters.displayFilters.group_by === null) _filters.displayFilters.sub_group_by = null;
// set sub_group_by to null if layout is switched to kanban group_by and sub_group_by are same
if (
_filters.displayFilters.layout === "kanban" &&
_filters.displayFilters.group_by === _filters.displayFilters.sub_group_by
)
_filters.displayFilters.sub_group_by = null;
// set group_by to state if layout is switched to kanban and group_by is null
if (_filters.displayFilters.layout === "kanban" && _filters.displayFilters.group_by === null)
_filters.displayFilters.group_by = "state";
_projectIssueFilters[projectId] = {
filters: _filters.filters,
displayFilters: _filters.displayFilters,
displayProperties: _projectIssueFilters[projectId].displayProperties,
};
runInAction(() => {
this.projectIssueFilters = _projectIssueFilters;
});
await this.projectService.setProjectView(workspaceSlug, projectId, {
view_props: { filters: _filters.filters, display_filters: _filters.displayFilters },
});
return _filters;
} catch (error) {
this.fetchDisplayFilters(workspaceSlug, projectId);
throw error;
}
};
fetchDisplayProperties = async (workspaceSlug: string, projectId: string) => {
try {
const _issueDisplayProperties = await this.issueService.getIssueDisplayProperties(workspaceSlug, projectId);
const displayProperties: IIssueDisplayProperties = {
assignee: _issueDisplayProperties?.properties?.assignee || false,
start_date: _issueDisplayProperties?.properties?.start_date || false,
due_date: _issueDisplayProperties?.properties?.due_date || false,
labels: _issueDisplayProperties?.properties?.labels || false,
key: _issueDisplayProperties?.properties?.key || false,
priority: _issueDisplayProperties?.properties?.priority || false,
state: _issueDisplayProperties?.properties?.state || false,
sub_issue_count: _issueDisplayProperties?.properties?.sub_issue_count || false,
link: _issueDisplayProperties?.properties?.link || false,
attachment_count: _issueDisplayProperties?.properties?.attachment_count || false,
estimate: _issueDisplayProperties?.properties?.estimate || false,
created_on: _issueDisplayProperties?.properties?.created_on || false,
updated_on: _issueDisplayProperties?.properties?.updated_on || false,
};
let _projectIssueFilters = { ...this.projectIssueFilters };
if (!_projectIssueFilters) _projectIssueFilters = {};
if (!_projectIssueFilters[projectId])
_projectIssueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
_projectIssueFilters[projectId] = { ..._projectIssueFilters[projectId], displayProperties: displayProperties };
runInAction(() => {
this.projectIssueFilters = _projectIssueFilters;
});
return displayProperties;
} catch (error) {
throw error;
}
};
updateDisplayProperties = async (workspaceSlug: string, projectId: string, properties: IIssueDisplayProperties) => {
try {
let _issueFilters = { ...this.projectIssueFilters };
if (!_issueFilters) _issueFilters = {};
if (!_issueFilters[projectId])
_issueFilters[projectId] = { filters: {}, displayFilters: {}, displayProperties: {} };
const updatedDisplayProperties = { ..._issueFilters[projectId].displayProperties, ...properties };
_issueFilters[projectId] = { ..._issueFilters[projectId], displayProperties: updatedDisplayProperties };
runInAction(() => {
this.projectIssueFilters = _issueFilters;
});
await this.issueService.updateIssueDisplayProperties(workspaceSlug, projectId, updatedDisplayProperties);
return properties;
} catch (error) {
this.fetchDisplayProperties(workspaceSlug, projectId);
throw error;
}
};
}

View file

@ -1,266 +0,0 @@
import { observable, action, computed, makeObservable, runInAction } from "mobx";
// base class
import { IssueFilterBaseStore } from "store/issues";
// services
import { ProjectService, ProjectMemberService } from "services/project";
import { IssueService } from "services/issue";
import { ModuleService } from "services/module.service";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { isNil } from "../utils";
interface IModuleIssuesFilterOptions {
filters: IIssueFilterOptions;
}
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface IModuleIssuesFilterStore {
// observable
loader: boolean;
filters: { [moduleId: string]: IModuleIssuesFilterOptions } | undefined;
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// actions
fetchModuleFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<IIssueFilterOptions>;
updateModuleFilters: (
workspaceSlug: string,
projectId: string,
moduleId: string,
type: EFilterType,
filters: IIssueFilterOptions
) => Promise<IModuleIssuesFilterOptions | undefined>;
fetchFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
moduleId?: string | undefined
) => Promise<void>;
}
export class ModuleIssuesFilterStore extends IssueFilterBaseStore implements IModuleIssuesFilterStore {
// observables
loader: boolean = false;
filters: { [projectId: string]: IModuleIssuesFilterOptions } | undefined = undefined;
// root store
rootStore;
// services
projectService;
projectMemberService;
issueService;
moduleService;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observables
loader: observable.ref,
filters: observable.ref,
// computed
issueFilters: computed,
appliedFilters: computed,
// actions
fetchModuleFilters: action,
updateModuleFilters: action,
fetchFilters: action,
updateFilters: action,
});
this.rootStore = _rootStore;
this.projectService = new ProjectService();
this.projectMemberService = new ProjectMemberService();
this.issueService = new IssueService();
this.moduleService = new ModuleService();
}
get issueFilters() {
const projectId = this.rootStore.project.projectId;
const moduleId = this.rootStore.module.moduleId;
if (!projectId || !moduleId) return undefined;
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
const moduleFilters = this.filters?.[moduleId];
const _filters: IProjectIssuesFilters = {
filters: moduleFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
return filteredRouteParams;
}
fetchModuleFilters = async (workspaceSlug: string, projectId: string, moduleId: string) => {
try {
const moduleFilters = await this.moduleService.getModuleDetails(workspaceSlug, projectId, moduleId);
const filters: IIssueFilterOptions = {
assignees: moduleFilters?.view_props?.filters?.assignees || null,
mentions: moduleFilters?.view_props?.filters?.mentions || null,
created_by: moduleFilters?.view_props?.filters?.created_by || null,
labels: moduleFilters?.view_props?.filters?.labels || null,
priority: moduleFilters?.view_props?.filters?.priority || null,
project: moduleFilters?.view_props?.filters?.project || null,
start_date: moduleFilters?.view_props?.filters?.start_date || null,
state: moduleFilters?.view_props?.filters?.state || null,
state_group: moduleFilters?.view_props?.filters?.state_group || null,
subscriber: moduleFilters?.view_props?.filters?.subscriber || null,
target_date: moduleFilters?.view_props?.filters?.target_date || null,
};
const issueFilters: IModuleIssuesFilterOptions = {
filters: filters,
};
let _filters = { ...this.filters };
if (!_filters) _filters = {};
if (!_filters[moduleId]) _filters[moduleId] = { filters: {} };
_filters[moduleId] = issueFilters;
runInAction(() => {
this.filters = _filters;
});
return filters;
} catch (error) {
console.log("error in moduleFetchFilters", error);
throw error;
}
};
updateModuleFilters = async (
workspaceSlug: string,
projectId: string,
moduleId: string,
type: EFilterType,
filters: IIssueFilterOptions
) => {
if (!moduleId) return;
try {
let _moduleIssueFilters = { ...this.filters };
if (!_moduleIssueFilters) _moduleIssueFilters = {};
if (!_moduleIssueFilters[moduleId]) _moduleIssueFilters[moduleId] = { filters: {} };
const _filters = { filters: { ..._moduleIssueFilters[moduleId].filters } };
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
_moduleIssueFilters[moduleId] = { filters: _filters.filters };
runInAction(() => {
this.filters = _moduleIssueFilters;
});
await this.moduleService.patchModule(workspaceSlug, projectId, moduleId, {
view_props: { filters: _filters.filters },
});
return _filters;
} catch (error) {
this.fetchFilters(workspaceSlug, projectId, moduleId);
throw error;
}
};
fetchFilters = async (workspaceSlug: string, projectId: string, moduleId: string) => {
try {
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
await this.fetchModuleFilters(workspaceSlug, projectId, moduleId);
return;
} catch (error) {
console.log("error in projectFetchFilters", error);
throw error;
}
};
updateFilters = async (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
moduleId?: string | undefined
) => {
try {
if (!moduleId) throw new Error();
switch (filterType) {
case EFilterType.FILTERS:
await this.updateModuleFilters(
workspaceSlug,
projectId,
moduleId,
filterType,
filters as IIssueFilterOptions
);
break;
case EFilterType.DISPLAY_FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueDisplayFilterOptions
);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.rootStore.issuesFilter.updateDisplayProperties(
workspaceSlug,
projectId,
filters as IIssueDisplayProperties
);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,371 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { IssueService } from "services/issue";
import { ModuleService } from "services/module.service";
// types
import { TIssueGroupByOptions } from "types";
import { IIssue } from "types/issues";
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../../types";
import { RootStore } from "store/root";
export interface IModuleIssuesStore {
// observable
loader: TLoader;
issues: { [module_id: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (
workspaceSlug: string,
projectId: string,
loadType: TLoader,
moduleId?: string | undefined
) => Promise<IIssueResponse | undefined>;
createIssue: (
workspaceSlug: string,
projectId: string,
data: Partial<IIssue>,
moduleId?: string | undefined
) => Promise<IIssue | undefined>;
updateIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<IIssue>,
moduleId?: string | undefined
) => Promise<IIssue | undefined>;
removeIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
moduleId?: string | undefined
) => Promise<IIssue | undefined>;
quickAddIssue: (
workspaceSlug: string,
projectId: string,
data: IIssue,
moduleId?: string | undefined
) => Promise<IIssue | undefined>;
addIssueToModule: (
workspaceSlug: string,
moduleId: string,
issueIds: string[],
fetchAfterAddition?: boolean,
projectId?: string
) => Promise<any>;
removeIssueFromModule: (
workspaceSlug: string,
projectId: string,
moduleId: string,
issueId: string,
issueBridgeId: string
) => Promise<IIssue>;
viewFlags: ViewFlags;
}
export class ModuleIssuesStore extends IssueBaseStore implements IModuleIssuesStore {
loader: TLoader = "init-loader";
issues: { [module_id: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
moduleService;
issueService;
//viewData
viewFlags = {
enableQuickAdd: true,
enableIssueCreation: true,
enableInlineEditing: true,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
quickAddIssue: action,
addIssueToModule: action,
removeIssueFromModule: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
this.moduleService = new ModuleService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const projectId = this.rootStore.project.projectId;
const moduleId = this.rootStore.module.moduleId;
const hasPermissionToCurrentProject = this.rootStore.user.hasPermissionToCurrentProject;
if (!workspaceSlug || !projectId || !hasPermissionToCurrentProject || !moduleId) return;
const userFilters = this.rootStore?.moduleIssuesFilter?.issueFilters?.filters;
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
});
}
get getIssues() {
const moduleId = this.rootStore?.module?.moduleId;
if (!moduleId || !this.issues || !this.issues[moduleId]) return undefined;
return this.issues[moduleId];
}
get getIssuesIds() {
const moduleId = this.rootStore?.module?.moduleId;
const displayFilters = this.rootStore?.moduleIssuesFilter?.issueFilters?.displayFilters;
const subGroupBy = displayFilters?.sub_group_by;
const groupBy = displayFilters?.group_by;
const orderBy = displayFilters?.order_by;
const layout = displayFilters?.layout;
if (!moduleId || !this.issues || !this.issues[moduleId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[moduleId]);
else issues = this.unGroupedIssues(orderBy, this.issues[moduleId]);
} else if (layout === "kanban" && groupBy && orderBy) {
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, this.issues[moduleId]);
else issues = this.groupedIssues(groupBy, orderBy, this.issues[moduleId]);
} else if (layout === "calendar")
issues = this.groupedIssues("target_date" as TIssueGroupByOptions, "target_date", this.issues[moduleId], true);
else if (layout === "spreadsheet") issues = this.unGroupedIssues(orderBy ?? "-created_at", this.issues[moduleId]);
else if (layout === "gantt_chart") issues = this.unGroupedIssues(orderBy ?? "sort_order", this.issues[moduleId]);
return issues;
}
fetchIssues = async (
workspaceSlug: string,
projectId: string,
loadType: TLoader = "init-loader",
moduleId: string | undefined = undefined
) => {
if (!moduleId) return undefined;
try {
this.loader = loadType;
const params = this.rootStore?.moduleIssuesFilter?.appliedFilters;
const response = await this.moduleService.getModuleIssues(workspaceSlug, projectId, moduleId, params);
const _issues = { ...this.issues, [moduleId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
createIssue = async (
workspaceSlug: string,
projectId: string,
data: Partial<IIssue>,
moduleId: string | undefined = undefined
) => {
if (!moduleId) return undefined;
try {
const response = await this.rootStore.projectIssues.createIssue(workspaceSlug, projectId, data);
await this.addIssueToModule(workspaceSlug, moduleId, [response.id], false);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[moduleId]) _issues[moduleId] = {};
_issues[moduleId] = { ..._issues[moduleId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
throw error;
}
};
updateIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<IIssue>,
moduleId: string | undefined = undefined
) => {
if (!moduleId) return undefined;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[moduleId]) _issues[moduleId] = {};
_issues[moduleId][issueId] = { ..._issues[moduleId][issueId], ...data };
runInAction(() => {
this.issues = _issues;
});
const response = await this.rootStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data);
runInAction(() => {
_issues = { ...this.issues };
_issues[moduleId][issueId] = { ..._issues[moduleId][issueId], ...response };
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
throw error;
}
};
removeIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
moduleId: string | undefined = undefined
) => {
if (!moduleId) return undefined;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[moduleId]) _issues[moduleId] = {};
delete _issues?.[moduleId]?.[issueId];
_issues[moduleId] = { ..._issues[moduleId] };
runInAction(() => {
this.issues = _issues;
});
const response = await this.rootStore.projectIssues.removeIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
throw error;
}
};
quickAddIssue = async (
workspaceSlug: string,
projectId: string,
data: IIssue,
moduleId: string | undefined = undefined
) => {
if (!moduleId) return undefined;
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[moduleId]) _issues[moduleId] = {};
_issues[moduleId] = { ..._issues[moduleId], ...{ [data.id as keyof IIssue]: data } };
runInAction(() => {
this.issues = _issues;
});
const response = await this.createIssue(workspaceSlug, projectId, data, moduleId);
if (this.issues && response) {
delete this.issues[moduleId][data.id as keyof IIssue];
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[moduleId]) _issues[moduleId] = {};
_issues[moduleId] = { ..._issues[moduleId], ...{ [response.id as keyof IIssue]: response } };
runInAction(() => {
this.issues = _issues;
});
}
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
throw error;
}
};
addIssueToModule = async (
workspaceSlug: string,
moduleId: string,
issueIds: string[],
fetchAfterAddition = true,
projectId?: string
) => {
const activeProjectId = this.rootStore.project.projectId;
if (!activeProjectId && !projectId) return;
const projectIdToUpdate: string = projectId || activeProjectId || "";
try {
const issueToModule = await this.moduleService.addIssuesToModule(workspaceSlug, projectIdToUpdate, moduleId, {
issues: issueIds,
});
if (fetchAfterAddition) this.fetchIssues(workspaceSlug, projectIdToUpdate, "mutation", moduleId);
return issueToModule;
} catch (error) {
this.fetchIssues(workspaceSlug, projectIdToUpdate, "mutation", moduleId);
throw error;
}
};
removeIssueFromModule = async (
workspaceSlug: string,
projectId: string,
moduleId: string,
issueId: string,
issueBridgeId: string
) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[moduleId]) _issues[moduleId] = {};
delete _issues?.[moduleId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.moduleService.removeIssueFromModule(
workspaceSlug,
projectId,
moduleId,
issueBridgeId
);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation", moduleId);
throw error;
}
};
}

View file

@ -1,260 +0,0 @@
import { observable, action, computed, makeObservable, runInAction } from "mobx";
// base class
import { IssueFilterBaseStore } from "store/issues";
// services
import { ProjectService, ProjectMemberService } from "services/project";
import { IssueService } from "services/issue";
import { ViewService } from "services/view.service";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { isNil } from "../utils";
interface IViewIssuesFilterOptions {
filters: IIssueFilterOptions;
}
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface IViewIssuesFilterStore {
// observable
loader: boolean;
filters: { [view_id: string]: IViewIssuesFilterOptions } | undefined;
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// actions
fetchViewFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise<IIssueFilterOptions>;
updateViewFilters: (
workspaceSlug: string,
projectId: string,
viewId: string,
type: EFilterType,
filters: IIssueFilterOptions
) => Promise<IViewIssuesFilterOptions | undefined>;
fetchFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
viewId?: string | undefined
) => Promise<void>;
}
export class ViewIssuesFilterStore extends IssueFilterBaseStore implements IViewIssuesFilterStore {
// observables
loader: boolean = false;
filters: { [projectId: string]: IViewIssuesFilterOptions } | undefined = undefined;
// root store
rootStore;
// services
projectService;
projectMemberService;
issueService;
viewService;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observables
loader: observable.ref,
filters: observable.ref,
// computed
issueFilters: computed,
appliedFilters: computed,
// actions
fetchViewFilters: action,
updateViewFilters: action,
fetchFilters: action,
updateFilters: action,
});
this.rootStore = _rootStore;
this.projectService = new ProjectService();
this.projectMemberService = new ProjectMemberService();
this.issueService = new IssueService();
this.viewService = new ViewService();
}
get issueFilters() {
const projectId = this.rootStore.project.projectId;
const viewId = this.rootStore.projectViews.viewId;
if (!projectId || !viewId) return undefined;
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
const viewFilters = this.filters?.[viewId];
const _filters: IProjectIssuesFilters = {
filters: viewFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
return filteredRouteParams;
}
fetchViewFilters = async (workspaceSlug: string, projectId: string, viewId: string) => {
try {
const viewFilters = await this.viewService.getViewDetails(workspaceSlug, projectId, viewId);
const filters: IIssueFilterOptions = {
assignees: viewFilters?.query_data?.assignees || null,
mentions: viewFilters?.query_data?.mentions || null,
created_by: viewFilters?.query_data?.created_by || null,
labels: viewFilters?.query_data?.labels || null,
priority: viewFilters?.query_data?.priority || null,
project: viewFilters?.query_data?.project || null,
start_date: viewFilters?.query_data?.start_date || null,
state: viewFilters?.query_data?.state || null,
state_group: viewFilters?.query_data?.state_group || null,
subscriber: viewFilters?.query_data?.subscriber || null,
target_date: viewFilters?.query_data?.target_date || null,
};
const issueFilters: IViewIssuesFilterOptions = {
filters: filters,
};
let _filters = { ...this.filters };
if (!_filters) _filters = {};
if (!_filters[viewId]) _filters[viewId] = { filters: {} };
_filters[viewId] = issueFilters;
runInAction(() => {
this.filters = _filters;
});
return filters;
} catch (error) {
console.log("error in viewFetchFilters", error);
throw error;
}
};
updateViewFilters = async (
workspaceSlug: string,
projectId: string,
viewId: string,
type: EFilterType,
filters: IIssueFilterOptions
) => {
if (!viewId) return;
try {
let _moduleIssueFilters = { ...this.filters };
if (!_moduleIssueFilters) _moduleIssueFilters = {};
if (!_moduleIssueFilters[viewId]) _moduleIssueFilters[viewId] = { filters: {} };
const _filters = { filters: { ..._moduleIssueFilters[viewId].filters } };
if (type === EFilterType.FILTERS) _filters.filters = { ..._filters.filters, ...filters };
_moduleIssueFilters[viewId] = { filters: _filters.filters };
runInAction(() => {
this.filters = _moduleIssueFilters;
});
await this.viewService.patchView(workspaceSlug, projectId, viewId, {
query_data: { ..._filters.filters },
});
return _filters;
} catch (error) {
this.fetchFilters(workspaceSlug, projectId, viewId);
throw error;
}
};
fetchFilters = async (workspaceSlug: string, projectId: string, viewId: string) => {
try {
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
await this.fetchViewFilters(workspaceSlug, projectId, viewId);
return;
} catch (error) {
console.log("error in viewFetchFilters", error);
throw error;
}
};
updateFilters = async (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties,
viewId?: string | undefined
) => {
try {
if (!viewId) throw new Error();
switch (filterType) {
case EFilterType.FILTERS:
await this.updateViewFilters(workspaceSlug, projectId, viewId, filterType, filters as IIssueFilterOptions);
break;
case EFilterType.DISPLAY_FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueDisplayFilterOptions
);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.rootStore.issuesFilter.updateDisplayProperties(
workspaceSlug,
projectId,
filters as IIssueDisplayProperties
);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,231 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { IssueService } from "services/issue/issue.service";
// types
import { TIssueGroupByOptions } from "types";
import { IIssue } from "types/issues";
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../../types";
import { RootStore } from "store/root";
export interface IViewIssuesStore {
// observable
loader: TLoader;
issues: { [view_id: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<IIssueResponse>;
createIssue: (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => Promise<IIssue>;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => Promise<IIssue>;
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<IIssue>;
quickAddIssue: (workspaceSlug: string, projectId: string, data: IIssue) => Promise<IIssue>;
viewFlags: ViewFlags;
}
export class ViewIssuesStore extends IssueBaseStore implements IViewIssuesStore {
loader: TLoader = "init-loader";
issues: { [view_id: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
issueService;
//viewData
viewFlags = {
enableQuickAdd: true,
enableIssueCreation: true,
enableInlineEditing: true,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
quickAddIssue: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const projectId = this.rootStore.project.projectId;
const hasPermissionToCurrentProject = this.rootStore.user.hasPermissionToCurrentProject;
if (!workspaceSlug || !projectId || !hasPermissionToCurrentProject) return;
const userFilters = this.rootStore?.viewIssuesFilter?.issueFilters?.filters;
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation");
});
}
get getIssues() {
const projectId = this.rootStore?.project.projectId;
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
return this.issues[projectId];
}
get getIssuesIds() {
const projectId = this.rootStore?.project.projectId;
const displayFilters = this.rootStore?.viewIssuesFilter?.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 (!projectId || !this.issues || !this.issues[projectId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
else issues = this.unGroupedIssues(orderBy, this.issues[projectId]);
} else if (layout === "kanban" && groupBy && orderBy) {
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, this.issues[projectId]);
else issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
} else if (layout === "calendar")
issues = this.groupedIssues("target_date" as TIssueGroupByOptions, "target_date", this.issues[projectId], true);
else if (layout === "spreadsheet") issues = this.unGroupedIssues(orderBy ?? "-created_at", this.issues[projectId]);
else if (layout === "gantt_chart") issues = this.unGroupedIssues(orderBy ?? "sort_order", this.issues[projectId]);
return issues;
}
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
try {
this.loader = loadType;
const params = this.rootStore?.viewIssuesFilter?.appliedFilters;
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
const _issues = { ...this.issues, [projectId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => {
try {
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId][issueId] = { ..._issues[projectId][issueId], ...data };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
runInAction(() => {
_issues = { ...this.issues };
_issues[projectId][issueId] = { ..._issues[projectId][issueId], ...response };
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
delete _issues?.[projectId]?.[issueId];
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
quickAddIssue = async (workspaceSlug: string, projectId: string, data: IIssue) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [data.id as keyof IIssue]: data } };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
if (this.issues) {
delete this.issues[projectId][data.id as keyof IIssue];
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [response.id as keyof IIssue]: response } };
runInAction(() => {
this.issues = _issues;
});
}
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
}

View file

@ -1,145 +0,0 @@
import { computed, makeObservable } from "mobx";
// base class
import { IssueFilterBaseStore } from "store/issues";
// helpers
import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
// types
import { RootStore } from "store/root";
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueParams } from "types";
import { EFilterType } from "store/issues/types";
import { isNil } from "../utils";
interface IProjectIssuesFilters {
filters: IIssueFilterOptions | undefined;
displayFilters: IIssueDisplayFilterOptions | undefined;
displayProperties: IIssueDisplayProperties | undefined;
}
export interface IProjectIssuesFilterStore {
// computed
issueFilters: IProjectIssuesFilters | undefined;
appliedFilters: TIssueParams[] | undefined;
// action
fetchFilters: (workspaceSlug: string, projectId: string) => Promise<void>;
updateFilters: (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => Promise<void>;
}
export class ProjectIssuesFilterStore extends IssueFilterBaseStore implements IProjectIssuesFilterStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// computed
issueFilters: computed,
appliedFilters: computed,
});
// root store
this.rootStore = _rootStore;
}
get issueFilters() {
const projectId = this.rootStore.project.projectId;
if (!projectId) return undefined;
const displayFilters = this.rootStore.issuesFilter.issueDisplayFilters(projectId);
const _filters: IProjectIssuesFilters = {
filters: displayFilters?.filters,
displayFilters: displayFilters?.displayFilters,
displayProperties: displayFilters?.displayProperties,
};
return _filters;
}
get appliedFilters() {
const userFilters = this.issueFilters;
if (!userFilters) return undefined;
let filteredRouteParams: any = {
priority: userFilters?.filters?.priority || undefined,
state_group: userFilters?.filters?.state_group || undefined,
state: userFilters?.filters?.state || undefined,
assignees: userFilters?.filters?.assignees || undefined,
mentions: userFilters?.filters?.mentions || undefined,
created_by: userFilters?.filters?.created_by || undefined,
labels: userFilters?.filters?.labels || undefined,
start_date: userFilters?.filters?.start_date || undefined,
target_date: userFilters?.filters?.target_date || undefined,
type: userFilters?.displayFilters?.type || undefined,
sub_issue: isNil(userFilters?.displayFilters?.sub_issue) ? true : userFilters?.displayFilters?.sub_issue,
show_empty_groups: isNil(userFilters?.displayFilters?.show_empty_groups)
? true
: userFilters?.displayFilters?.show_empty_groups,
start_target_date: isNil(userFilters?.displayFilters?.start_target_date)
? true
: userFilters?.displayFilters?.start_target_date,
};
const filteredParams = handleIssueQueryParamsByLayout(userFilters?.displayFilters?.layout, "issues");
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
if (userFilters?.displayFilters?.layout === "calendar") filteredRouteParams.group_by = "target_date";
if (userFilters?.displayFilters?.layout === "gantt_chart") filteredRouteParams.start_target_date = true;
return filteredRouteParams;
}
fetchFilters = async (workspaceSlug: string, projectId: string) => {
try {
await this.rootStore.issuesFilter.fetchDisplayFilters(workspaceSlug, projectId);
await this.rootStore.issuesFilter.fetchDisplayProperties(workspaceSlug, projectId);
return;
} catch (error) {
throw Error;
}
};
updateFilters = async (
workspaceSlug: string,
projectId: string,
filterType: EFilterType,
filters: IIssueFilterOptions | IIssueDisplayFilterOptions | IIssueDisplayProperties
) => {
try {
switch (filterType) {
case EFilterType.FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueFilterOptions
);
break;
case EFilterType.DISPLAY_FILTERS:
await this.rootStore.issuesFilter.updateDisplayFilters(
workspaceSlug,
projectId,
filterType,
filters as IIssueDisplayFilterOptions
);
break;
case EFilterType.DISPLAY_PROPERTIES:
await this.rootStore.issuesFilter.updateDisplayProperties(
workspaceSlug,
projectId,
filters as IIssueDisplayProperties
);
break;
}
return;
} catch (error) {
throw error;
}
};
}

View file

@ -1,232 +0,0 @@
import { action, observable, makeObservable, computed, runInAction, autorun } from "mobx";
// base class
import { IssueBaseStore } from "store/issues";
// services
import { IssueService } from "services/issue/issue.service";
// types
import { TIssueGroupByOptions } from "types";
import { IIssue } from "types/issues";
import { IIssueResponse, TLoader, IGroupedIssues, ISubGroupedIssues, TUnGroupedIssues, ViewFlags } from "../../types";
import { RootStore } from "store/root";
export interface IProjectIssuesStore {
// observable
loader: TLoader;
issues: { [project_id: string]: IIssueResponse } | undefined;
// computed
getIssues: IIssueResponse | undefined;
getIssuesIds: IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined;
// actions
fetchIssues: (workspaceSlug: string, projectId: string, loadType: TLoader) => Promise<IIssueResponse>;
createIssue: (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => Promise<IIssue>;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => Promise<IIssue>;
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<IIssue>;
quickAddIssue: (workspaceSlug: string, projectId: string, data: IIssue) => Promise<IIssue>;
viewFlags: ViewFlags;
}
export class ProjectIssuesStore extends IssueBaseStore implements IProjectIssuesStore {
loader: TLoader = "init-loader";
issues: { [project_id: string]: IIssueResponse } | undefined = undefined;
// root store
rootStore;
// service
issueService;
//viewData
viewFlags = {
enableQuickAdd: true,
enableIssueCreation: true,
enableInlineEditing: true,
};
constructor(_rootStore: RootStore) {
super(_rootStore);
makeObservable(this, {
// observable
loader: observable.ref,
issues: observable.ref,
// computed
getIssues: computed,
getIssuesIds: computed,
// action
fetchIssues: action,
createIssue: action,
updateIssue: action,
removeIssue: action,
quickAddIssue: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueService();
autorun(() => {
const workspaceSlug = this.rootStore.workspace.workspaceSlug;
const projectId = this.rootStore.project.projectId;
const hasPermissionToCurrentProject = this.rootStore.user.hasPermissionToCurrentProject;
if (!workspaceSlug || !projectId || !hasPermissionToCurrentProject) return;
const userFilters = this.rootStore?.projectIssuesFilter?.issueFilters?.filters;
if (userFilters) this.fetchIssues(workspaceSlug, projectId, "mutation");
});
}
get getIssues() {
const projectId = this.rootStore?.project.projectId;
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
return this.issues[projectId];
}
get getIssuesIds() {
const projectId = this.rootStore?.project.projectId;
const displayFilters = this.rootStore?.projectIssuesFilter?.issueFilters?.displayFilters;
if (!displayFilters) return undefined;
const subGroupBy = displayFilters?.sub_group_by;
const groupBy = displayFilters?.group_by;
const orderBy = displayFilters?.order_by;
const layout = displayFilters?.layout;
if (!projectId || !this.issues || !this.issues[projectId]) return undefined;
let issues: IIssueResponse | IGroupedIssues | ISubGroupedIssues | TUnGroupedIssues | undefined = undefined;
if (layout === "list" && orderBy) {
if (groupBy) issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
else issues = this.unGroupedIssues(orderBy, this.issues[projectId]);
} else if (layout === "kanban" && groupBy && orderBy) {
if (subGroupBy) issues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, this.issues[projectId]);
else issues = this.groupedIssues(groupBy, orderBy, this.issues[projectId]);
} else if (layout === "calendar")
issues = this.groupedIssues("target_date" as TIssueGroupByOptions, "target_date", this.issues[projectId], true);
else if (layout === "spreadsheet") issues = this.unGroupedIssues(orderBy ?? "-created_at", this.issues[projectId]);
else if (layout === "gantt_chart") issues = this.unGroupedIssues(orderBy ?? "sort_order", this.issues[projectId]);
return issues;
}
fetchIssues = async (workspaceSlug: string, projectId: string, loadType: TLoader = "init-loader") => {
try {
this.loader = loadType;
const params = this.rootStore?.projectIssuesFilter?.appliedFilters;
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
const _issues = { ...this.issues, [projectId]: { ...response } };
runInAction(() => {
this.issues = _issues;
this.loader = undefined;
});
return response;
} catch (error) {
console.error(error);
this.loader = undefined;
throw error;
}
};
createIssue = async (workspaceSlug: string, projectId: string, data: Partial<IIssue>) => {
try {
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
let _issues = this.issues;
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [response.id]: response } };
runInAction(() => {
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
updateIssue = async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<IIssue>) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId][issueId] = { ..._issues[projectId][issueId], ...data };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.patchIssue(workspaceSlug, projectId, issueId, data);
runInAction(() => {
_issues = { ...this.issues };
_issues[projectId][issueId] = { ..._issues[projectId][issueId], ...response };
this.issues = _issues;
});
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
removeIssue = async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
delete _issues?.[projectId]?.[issueId];
_issues[projectId] = { ..._issues[projectId] };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.deleteIssue(workspaceSlug, projectId, issueId);
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
quickAddIssue = async (workspaceSlug: string, projectId: string, data: IIssue) => {
try {
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [data.id as keyof IIssue]: data } };
runInAction(() => {
this.issues = _issues;
});
const response = await this.issueService.createIssue(workspaceSlug, projectId, data);
if (this.issues) {
delete this.issues[projectId][data.id as keyof IIssue];
let _issues = { ...this.issues };
if (!_issues) _issues = {};
if (!_issues[projectId]) _issues[projectId] = {};
_issues[projectId] = { ..._issues[projectId], ...{ [response.id as keyof IIssue]: response } };
runInAction(() => {
this.issues = _issues;
});
}
return response;
} catch (error) {
this.fetchIssues(workspaceSlug, projectId, "mutation");
throw error;
}
};
}

View file

@ -1,5 +0,0 @@
export const isNil = (value: any) => {
if (value === undefined || value === null) return true;
return false;
};

View file

@ -1,33 +0,0 @@
import { IIssue } from "types";
// issue filters
export enum EFilterType {
FILTERS = "filters",
DISPLAY_FILTERS = "display_filters",
DISPLAY_PROPERTIES = "display_properties",
}
// issues
export interface IGroupedIssues {
[group_id: string]: string[];
}
export interface ISubGroupedIssues {
[sub_grouped_id: string]: {
[group_id: string]: string[];
};
}
export type TUnGroupedIssues = string[];
export interface IIssueResponse {
[issue_id: string]: IIssue;
}
export type TLoader = "init-loader" | "mutation" | undefined;
export interface ViewFlags {
enableQuickAdd: boolean;
enableIssueCreation: boolean;
enableInlineEditing: boolean;
}