chore: implemented drag and drop between dates for project issues, cycle, module, and project views for calendar layout (#2535)

This commit is contained in:
guru_sainath 2023-10-25 16:09:50 +05:30 committed by GitHub
parent cea39c758e
commit a6d741e784
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 492 additions and 63 deletions

View File

@ -29,10 +29,32 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
const issuesList = issues ? (issues as IIssueGroupedStructure)[renderDateFormat(date.date)] : null;
return (
<Droppable droppableId={renderDateFormat(date.date)}>
<>
<div className="w-full h-full relative flex flex-col bg-custom-background-90">
{/* header */}
<div
className={`text-xs text-right flex-shrink-0 py-1 px-2 ${
calendarLayout === "month" // if month layout, highlight current month days
? date.is_current_month
? "font-medium"
: "text-custom-text-300"
: "font-medium" // if week layout, highlight all days
} ${
date.date.getDay() === 0 || date.date.getDay() === 6
? "bg-custom-background-90"
: "bg-custom-background-100"
}`}
>
{date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "}
{date.date.getDate()}
</div>
{/* content */}
<div className="w-full h-full">
<Droppable droppableId={renderDateFormat(date.date)} isDropDisabled={false}>
{(provided, snapshot) => (
<div
className={`flex-grow p-2 space-y-1 w-full flex flex-col overflow-hidden ${
className={`h-full w-full overflow-y-auto select-none ${
snapshot.isDraggingOver || date.date.getDay() === 0 || date.date.getDay() === 6
? "bg-custom-background-90"
: "bg-custom-background-100"
@ -40,24 +62,13 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
{...provided.droppableProps}
ref={provided.innerRef}
>
<>
<div
className={`text-xs text-right ${
calendarLayout === "month" // if month layout, highlight current month days
? date.is_current_month
? "font-medium"
: "text-custom-text-300"
: "font-medium" // if week layout, highlight all days
}`}
>
{date.date.getDate() === 1 && MONTHS_LIST[date.date.getMonth() + 1].shortTitle + " "}
{date.date.getDate()}
</div>
<CalendarIssueBlocks issues={issuesList} quickActions={quickActions} />
{provided.placeholder}
</>
</div>
)}
</Droppable>
</div>
</div>
</>
);
});

View File

@ -17,10 +17,16 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
const { workspaceSlug } = router.query;
return (
<div className="space-y-2 h-full w-full overflow-y-auto p-0.5">
<>
{issues?.map((issue, index) => (
<Draggable key={issue.id} draggableId={issue.id} index={index}>
{(provided, snapshot) => (
<div
className="p-1 px-2"
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<Link href={`/${workspaceSlug?.toString()}/projects/${issue.project}/issues/${issue.id}`}>
<a
className={`group/calendar-block h-8 w-full shadow-custom-shadow-2xs rounded py-1.5 px-1 flex items-center gap-1.5 border-[0.5px] border-custom-border-100 ${
@ -28,9 +34,6 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
? "shadow-custom-shadow-rg bg-custom-background-90"
: "bg-custom-background-100 hover:bg-custom-background-90"
}`}
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<span
className="h-full w-0.5 rounded flex-shrink-0"
@ -50,9 +53,10 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
/> */}
</a>
</Link>
</div>
)}
</Draggable>
))}
</div>
</>
);
});

View File

@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue";
import { IIssue } from "types";
export const CycleCalendarLayout: React.FC = observer(() => {
const { cycleIssue: cycleIssueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore();
const {
cycleIssue: cycleIssueStore,
issueFilter: issueFilterStore,
issueDetail: issueDetailStore,
cycleIssueCalendarView: cycleIssueCalendarViewStore,
} = useMobxStore();
const router = useRouter();
const { workspaceSlug, cycleId } = router.query;
// TODO: add drag and drop functionality
const onDragEnd = (result: DropResult) => {
if (!result) return;
@ -26,7 +30,7 @@ export const CycleCalendarLayout: React.FC = observer(() => {
// return if dropped on the same date
if (result.destination.droppableId === result.source.droppableId) return;
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
cycleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
};
const issues = cycleIssueStore.getIssues;

View File

@ -15,12 +15,12 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
moduleIssue: moduleIssueStore,
issueFilter: issueFilterStore,
issueDetail: issueDetailStore,
moduleIssueCalendarView: moduleIssueCalendarViewStore,
} = useMobxStore();
const router = useRouter();
const { workspaceSlug, moduleId } = router.query;
// TODO: add drag and drop functionality
const onDragEnd = (result: DropResult) => {
if (!result) return;
@ -30,7 +30,7 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
// return if dropped on the same date
if (result.destination.droppableId === result.source.droppableId) return;
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
moduleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
};
const issues = moduleIssueStore.getIssues;

View File

@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue";
import { IIssue } from "types";
export const CalendarLayout: React.FC = observer(() => {
const { issue: issueStore, issueFilter: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore();
const {
issue: issueStore,
issueFilter: issueFilterStore,
issueDetail: issueDetailStore,
issueCalendarView: issueCalendarViewStore,
} = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
// TODO: add drag and drop functionality
const onDragEnd = (result: DropResult) => {
if (!result) return;
@ -26,7 +30,7 @@ export const CalendarLayout: React.FC = observer(() => {
// return if dropped on the same date
if (result.destination.droppableId === result.source.droppableId) return;
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
issueCalendarViewStore?.handleDragDrop(result.source, result.destination);
};
const issues = issueStore.getIssues;

View File

@ -15,12 +15,12 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => {
projectViewIssues: projectViewIssuesStore,
issueFilter: issueFilterStore,
issueDetail: issueDetailStore,
projectViewIssueCalendarView: projectViewIssueCalendarViewStore,
} = useMobxStore();
const router = useRouter();
const { workspaceSlug } = router.query;
// TODO: add drag and drop functionality
const onDragEnd = (result: DropResult) => {
if (!result) return;
@ -30,7 +30,7 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => {
// return if dropped on the same date
if (result.destination.droppableId === result.source.droppableId) return;
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
projectViewIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
};
const issues = projectViewIssuesStore.getIssues;

View File

@ -0,0 +1,89 @@
import { action, makeObservable, runInAction } from "mobx";
// types
import { RootStore } from "../root";
import { IIssueType } from "./cycle_issue.store";
export interface ICycleIssueCalendarViewStore {
// actions
handleDragDrop: (source: any, destination: any) => void;
}
export class CycleIssueCalendarViewStore implements ICycleIssueCalendarViewStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// actions
handleDragDrop: action,
});
this.rootStore = _rootStore;
}
handleDragDrop = async (source: any, destination: any) => {
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
const projectId = this.rootStore?.project?.projectId;
const cycleId = this.rootStore?.cycle?.cycleId;
const issueType: IIssueType | null = this.rootStore?.cycleIssue?.getIssueType;
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
const currentIssues: any = this.rootStore.cycleIssue.getIssues;
if (workspaceSlug && projectId && cycleId && issueType && issueLayout === "calendar" && currentIssues) {
// update issue payload
let updateIssue: any = {
workspaceSlug: workspaceSlug,
projectId: projectId,
};
const droppableSourceColumnId = source.droppableId;
const droppableDestinationColumnId = destination.droppableId;
if (droppableSourceColumnId === droppableDestinationColumnId) return;
if (droppableSourceColumnId != droppableDestinationColumnId) {
// horizontal
const _sourceIssues = currentIssues[droppableSourceColumnId];
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
const [removed] = _sourceIssues.splice(source.index, 1);
if (_destinationIssues && _destinationIssues.length > 0)
_destinationIssues.splice(destination.index, 0, {
...removed,
target_date: droppableDestinationColumnId,
});
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
currentIssues[droppableSourceColumnId] = _sourceIssues;
currentIssues[droppableDestinationColumnId] = _destinationIssues;
}
const reorderedIssues = {
...this.rootStore?.cycleIssue.issues,
[cycleId]: {
...this.rootStore?.cycleIssue.issues?.[cycleId],
[issueType]: {
...this.rootStore?.cycleIssue.issues?.[cycleId]?.[issueType],
[issueType]: currentIssues,
},
},
};
runInAction(() => {
this.rootStore.cycleIssue.issues = { ...reorderedIssues };
});
this.rootStore.issueDetail?.updateIssue(
updateIssue.workspaceSlug,
updateIssue.projectId,
updateIssue.issueId,
updateIssue
);
}
return;
};
}

View File

@ -1,4 +1,5 @@
export * from "./cycle_issue_filters.store";
export * from "./cycle_issue_kanban_view.store";
export * from "./cycle_issue_calendar_view.store";
export * from "./cycle_issue.store";
export * from "./cycles.store";

View File

@ -2,4 +2,5 @@ export * from "./issue_detail.store";
export * from "./issue_draft.store";
export * from "./issue_filters.store";
export * from "./issue_kanban_view.store";
export * from "./issue_calendar_view.store";
export * from "./issue.store";

View File

@ -0,0 +1,88 @@
import { action, makeObservable, runInAction } from "mobx";
// types
import { RootStore } from "../root";
import { IIssueType } from "./issue.store";
export interface IIssueCalendarViewStore {
// actions
handleDragDrop: (source: any, destination: any) => void;
}
export class IssueCalendarViewStore implements IIssueCalendarViewStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// actions
handleDragDrop: action,
});
this.rootStore = _rootStore;
}
handleDragDrop = async (source: any, destination: any) => {
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
const projectId = this.rootStore?.project?.projectId;
const issueType: IIssueType | null = this.rootStore?.issue?.getIssueType;
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
const currentIssues: any = this.rootStore.issue.getIssues;
if (workspaceSlug && projectId && issueType && issueLayout === "calendar" && currentIssues) {
// update issue payload
let updateIssue: any = {
workspaceSlug: workspaceSlug,
projectId: projectId,
};
const droppableSourceColumnId = source.droppableId;
const droppableDestinationColumnId = destination.droppableId;
if (droppableSourceColumnId === droppableDestinationColumnId) return;
// horizontal
if (droppableSourceColumnId != droppableDestinationColumnId) {
const _sourceIssues = currentIssues[droppableSourceColumnId];
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
const [removed] = _sourceIssues.splice(source.index, 1);
if (_destinationIssues && _destinationIssues.length > 0)
_destinationIssues.splice(destination.index, 0, {
...removed,
target_date: droppableDestinationColumnId,
});
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
currentIssues[droppableSourceColumnId] = _sourceIssues;
currentIssues[droppableDestinationColumnId] = _destinationIssues;
}
const reorderedIssues = {
...this.rootStore?.issue.issues,
[projectId]: {
...this.rootStore?.issue.issues?.[projectId],
[issueType]: {
...this.rootStore?.issue.issues?.[projectId]?.[issueType],
[issueType]: currentIssues,
},
},
};
runInAction(() => {
this.rootStore.issue.issues = { ...reorderedIssues };
});
this.rootStore.issueDetail?.updateIssue(
updateIssue.workspaceSlug,
updateIssue.projectId,
updateIssue.issueId,
updateIssue
);
}
return;
};
}

View File

@ -1,4 +1,5 @@
export * from "./module_filters.store";
export * from "./module_issue_kanban_view.store";
export * from "./module_issue_calendar_view.store";
export * from "./module_issue.store";
export * from "./modules.store";

View File

@ -0,0 +1,89 @@
import { action, makeObservable, runInAction } from "mobx";
// types
import { RootStore } from "../root";
import { IIssueType } from "./module_issue.store";
export interface IModuleIssueCalendarViewStore {
// actions
handleDragDrop: (source: any, destination: any) => void;
}
export class ModuleIssueCalendarViewStore implements IModuleIssueCalendarViewStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// actions
handleDragDrop: action,
});
this.rootStore = _rootStore;
}
handleDragDrop = async (source: any, destination: any) => {
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
const projectId = this.rootStore?.project?.projectId;
const moduleId = this.rootStore?.module?.moduleId;
const issueType: IIssueType | null = this.rootStore?.moduleIssue?.getIssueType;
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
const currentIssues: any = this.rootStore.moduleIssue.getIssues;
if (workspaceSlug && projectId && moduleId && issueType && issueLayout === "calendar" && currentIssues) {
// update issue payload
let updateIssue: any = {
workspaceSlug: workspaceSlug,
projectId: projectId,
};
const droppableSourceColumnId = source.droppableId;
const droppableDestinationColumnId = destination.droppableId;
if (droppableSourceColumnId === droppableDestinationColumnId) return;
if (droppableSourceColumnId != droppableDestinationColumnId) {
// horizontal
const _sourceIssues = currentIssues[droppableSourceColumnId];
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
const [removed] = _sourceIssues.splice(source.index, 1);
if (_destinationIssues && _destinationIssues.length > 0)
_destinationIssues.splice(destination.index, 0, {
...removed,
target_date: droppableDestinationColumnId,
});
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
currentIssues[droppableSourceColumnId] = _sourceIssues;
currentIssues[droppableDestinationColumnId] = _destinationIssues;
}
const reorderedIssues = {
...this.rootStore?.moduleIssue.issues,
[moduleId]: {
...this.rootStore?.moduleIssue.issues?.[moduleId],
[issueType]: {
...this.rootStore?.moduleIssue.issues?.[moduleId]?.[issueType],
[issueType]: currentIssues,
},
},
};
runInAction(() => {
this.rootStore.moduleIssue.issues = { ...reorderedIssues };
});
this.rootStore.issueDetail?.updateIssue(
updateIssue.workspaceSlug,
updateIssue.projectId,
updateIssue.issueId,
updateIssue
);
}
return;
};
}

View File

@ -1,3 +1,5 @@
export * from "./project_view_filters.store";
export * from "./project_view_issues.store";
export * from "./project_views.store";
export * from "./project_view_issue_calendar_view.store";

View File

@ -0,0 +1,89 @@
import { action, makeObservable, runInAction } from "mobx";
// types
import { RootStore } from "../root";
import { IIssueType } from "./project_view_issues.store";
export interface IProjectViewIssueCalendarViewStore {
// actions
handleDragDrop: (source: any, destination: any) => void;
}
export class ProjectViewIssueCalendarViewStore implements IProjectViewIssueCalendarViewStore {
// root store
rootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// actions
handleDragDrop: action,
});
this.rootStore = _rootStore;
}
handleDragDrop = async (source: any, destination: any) => {
const workspaceSlug = this.rootStore?.workspace?.workspaceSlug;
const projectId = this.rootStore?.project?.projectId;
const viewId = this.rootStore?.projectViews?.viewId;
const issueType: IIssueType | null = this.rootStore?.projectViewIssues?.getIssueType;
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
const currentIssues: any = this.rootStore.projectViewIssues.getIssues;
if (workspaceSlug && projectId && viewId && issueType && issueLayout === "calendar" && currentIssues) {
// update issue payload
let updateIssue: any = {
workspaceSlug: workspaceSlug,
projectId: projectId,
};
const droppableSourceColumnId = source.droppableId;
const droppableDestinationColumnId = destination.droppableId;
if (droppableSourceColumnId === droppableDestinationColumnId) return;
if (droppableSourceColumnId != droppableDestinationColumnId) {
// horizontal
const _sourceIssues = currentIssues[droppableSourceColumnId];
let _destinationIssues = currentIssues[droppableDestinationColumnId] || [];
const [removed] = _sourceIssues.splice(source.index, 1);
if (_destinationIssues && _destinationIssues.length > 0)
_destinationIssues.splice(destination.index, 0, {
...removed,
target_date: droppableDestinationColumnId,
});
else _destinationIssues = [..._destinationIssues, { ...removed, target_date: droppableDestinationColumnId }];
updateIssue = { ...updateIssue, issueId: removed?.id, target_date: droppableDestinationColumnId };
currentIssues[droppableSourceColumnId] = _sourceIssues;
currentIssues[droppableDestinationColumnId] = _destinationIssues;
}
const reorderedIssues = {
...this.rootStore?.projectViewIssues.viewIssues,
[viewId]: {
...this.rootStore?.projectViewIssues.viewIssues?.[viewId],
[issueType]: {
...this.rootStore?.projectViewIssues.viewIssues?.[viewId]?.[issueType],
[issueType]: currentIssues,
},
},
};
runInAction(() => {
this.rootStore.projectViewIssues.viewIssues = { ...reorderedIssues };
});
this.rootStore.issueDetail?.updateIssue(
updateIssue.workspaceSlug,
updateIssue.projectId,
updateIssue.issueId,
updateIssue
);
}
return;
};
}

View File

@ -6,10 +6,18 @@ import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
// types
import { RootStore } from "../root";
import { IIssueGroupWithSubGroupsStructure, IIssueGroupedStructure, IIssueUnGroupedStructure } from "store/issue";
import { IIssue, IIssueFilterOptions } from "types";
import { IBlockUpdateData } from "components/gantt-chart";
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
export type IIssueGroupWithSubGroupsStructure = {
[group_id: string]: {
[sub_group_id: string]: IIssue[];
};
};
export type IIssueUnGroupedStructure = IIssue[];
export interface IProjectViewIssuesStore {
// states
loader: boolean;
@ -37,6 +45,7 @@ export interface IProjectViewIssuesStore {
// computed
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
getIssueType: IIssueType | null;
}
export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
@ -75,6 +84,7 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
fetchViewIssues: action,
// computed
getIssueType: computed,
getIssues: computed,
});
@ -108,6 +118,26 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
return computedFilters;
};
get getIssueType() {
const groupedLayouts = ["kanban", "list", "calendar"];
const ungroupedLayouts = ["spreadsheet", "gantt_chart"];
const issueLayout = this.rootStore?.issueFilter?.userDisplayFilters?.layout || null;
const issueSubGroup = this.rootStore?.issueFilter?.userDisplayFilters?.sub_group_by || null;
if (!issueLayout) return null;
const _issueState = groupedLayouts.includes(issueLayout)
? issueSubGroup
? "groupWithSubGroups"
: "grouped"
: ungroupedLayouts.includes(issueLayout)
? "ungrouped"
: null;
return _issueState || null;
}
get getIssues() {
const viewId: string | null = this.rootStore.projectViews.viewId;
const issueType = this.rootStore.issue.getIssueType;

View File

@ -12,6 +12,8 @@ import {
IssueDetailStore,
IssueFilterStore,
IssueKanBanViewStore,
IIssueCalendarViewStore,
IssueCalendarViewStore,
IssueStore,
} from "store/issue";
import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace";
@ -24,6 +26,8 @@ import {
ModuleFilterStore,
ModuleIssueKanBanViewStore,
ModuleIssueStore,
IModuleIssueCalendarViewStore,
ModuleIssueCalendarViewStore,
ModuleStore,
} from "store/module";
import {
@ -33,6 +37,8 @@ import {
CycleStore,
ICycleIssueFilterStore,
ICycleIssueKanBanViewStore,
ICycleIssueCalendarViewStore,
CycleIssueCalendarViewStore,
ICycleIssueStore,
ICycleStore,
} from "store/cycle";
@ -43,6 +49,8 @@ import {
ProjectViewFiltersStore,
ProjectViewIssuesStore,
ProjectViewsStore,
IProjectViewIssueCalendarViewStore,
ProjectViewIssueCalendarViewStore,
} from "store/project-view";
import CalendarStore, { ICalendarStore } from "store/calendar.store";
import {
@ -95,19 +103,23 @@ export class RootStore {
moduleIssue: IModuleIssueStore;
moduleFilter: IModuleFilterStore;
moduleIssueKanBanView: IModuleIssueKanBanViewStore;
moduleIssueCalendarView: IModuleIssueCalendarViewStore;
cycle: ICycleStore;
cycleIssue: ICycleIssueStore;
cycleIssueFilter: ICycleIssueFilterStore;
cycleIssueKanBanView: ICycleIssueKanBanViewStore;
cycleIssueCalendarView: ICycleIssueCalendarViewStore;
projectViews: IProjectViewsStore;
projectViewIssues: IProjectViewIssuesStore;
projectViewFilters: IProjectViewFiltersStore;
projectViewIssueCalendarView: IProjectViewIssueCalendarViewStore;
issueFilter: IIssueFilterStore;
issueDetail: IIssueDetailStore;
issueKanBanView: IIssueKanBanViewStore;
issueCalendarView: IIssueCalendarViewStore;
draftIssuesStore: DraftIssuesStore;
calendar: ICalendarStore;
@ -145,20 +157,24 @@ export class RootStore {
this.moduleIssue = new ModuleIssueStore(this);
this.moduleFilter = new ModuleFilterStore(this);
this.moduleIssueKanBanView = new ModuleIssueKanBanViewStore(this);
this.moduleIssueCalendarView = new ModuleIssueCalendarViewStore(this);
this.cycle = new CycleStore(this);
this.cycleIssue = new CycleIssueStore(this);
this.cycleIssueFilter = new CycleIssueFilterStore(this);
this.cycleIssueKanBanView = new CycleIssueKanBanViewStore(this);
this.cycleIssueCalendarView = new CycleIssueCalendarViewStore(this);
this.projectViews = new ProjectViewsStore(this);
this.projectViewIssues = new ProjectViewIssuesStore(this);
this.projectViewFilters = new ProjectViewFiltersStore(this);
this.projectViewIssueCalendarView = new ProjectViewIssueCalendarViewStore(this);
this.issue = new IssueStore(this);
this.issueFilter = new IssueFilterStore(this);
this.issueDetail = new IssueDetailStore(this);
this.issueKanBanView = new IssueKanBanViewStore(this);
this.issueCalendarView = new IssueCalendarViewStore(this);
this.draftIssuesStore = new DraftIssuesStore(this);
this.calendar = new CalendarStore(this);