forked from github/plane
chore: implemented drag and drop between dates for project issues, cycle, module, and project views for calendar layout (#2535)
This commit is contained in:
parent
cea39c758e
commit
a6d741e784
@ -29,10 +29,32 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
|||||||
const issuesList = issues ? (issues as IIssueGroupedStructure)[renderDateFormat(date.date)] : null;
|
const issuesList = issues ? (issues as IIssueGroupedStructure)[renderDateFormat(date.date)] : null;
|
||||||
|
|
||||||
return (
|
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) => (
|
{(provided, snapshot) => (
|
||||||
<div
|
<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
|
snapshot.isDraggingOver || date.date.getDay() === 0 || date.date.getDay() === 6
|
||||||
? "bg-custom-background-90"
|
? "bg-custom-background-90"
|
||||||
: "bg-custom-background-100"
|
: "bg-custom-background-100"
|
||||||
@ -40,24 +62,13 @@ export const CalendarDayTile: React.FC<Props> = observer((props) => {
|
|||||||
{...provided.droppableProps}
|
{...provided.droppableProps}
|
||||||
ref={provided.innerRef}
|
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} />
|
<CalendarIssueBlocks issues={issuesList} quickActions={quickActions} />
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
</>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -17,10 +17,16 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2 h-full w-full overflow-y-auto p-0.5">
|
<>
|
||||||
{issues?.map((issue, index) => (
|
{issues?.map((issue, index) => (
|
||||||
<Draggable key={issue.id} draggableId={issue.id} index={index}>
|
<Draggable key={issue.id} draggableId={issue.id} index={index}>
|
||||||
{(provided, snapshot) => (
|
{(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}`}>
|
<Link href={`/${workspaceSlug?.toString()}/projects/${issue.project}/issues/${issue.id}`}>
|
||||||
<a
|
<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 ${
|
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"
|
? "shadow-custom-shadow-rg bg-custom-background-90"
|
||||||
: "bg-custom-background-100 hover:bg-custom-background-90"
|
: "bg-custom-background-100 hover:bg-custom-background-90"
|
||||||
}`}
|
}`}
|
||||||
{...provided.draggableProps}
|
|
||||||
{...provided.dragHandleProps}
|
|
||||||
ref={provided.innerRef}
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="h-full w-0.5 rounded flex-shrink-0"
|
className="h-full w-0.5 rounded flex-shrink-0"
|
||||||
@ -50,9 +53,10 @@ export const CalendarIssueBlocks: React.FC<Props> = observer((props) => {
|
|||||||
/> */}
|
/> */}
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
))}
|
))}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue";
|
|||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
|
|
||||||
export const CycleCalendarLayout: React.FC = observer(() => {
|
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 router = useRouter();
|
||||||
const { workspaceSlug, cycleId } = router.query;
|
const { workspaceSlug, cycleId } = router.query;
|
||||||
|
|
||||||
// TODO: add drag and drop functionality
|
|
||||||
const onDragEnd = (result: DropResult) => {
|
const onDragEnd = (result: DropResult) => {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
@ -26,7 +30,7 @@ export const CycleCalendarLayout: React.FC = observer(() => {
|
|||||||
// return if dropped on the same date
|
// return if dropped on the same date
|
||||||
if (result.destination.droppableId === result.source.droppableId) return;
|
if (result.destination.droppableId === result.source.droppableId) return;
|
||||||
|
|
||||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
cycleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||||
};
|
};
|
||||||
|
|
||||||
const issues = cycleIssueStore.getIssues;
|
const issues = cycleIssueStore.getIssues;
|
||||||
|
@ -15,12 +15,12 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
|
|||||||
moduleIssue: moduleIssueStore,
|
moduleIssue: moduleIssueStore,
|
||||||
issueFilter: issueFilterStore,
|
issueFilter: issueFilterStore,
|
||||||
issueDetail: issueDetailStore,
|
issueDetail: issueDetailStore,
|
||||||
|
moduleIssueCalendarView: moduleIssueCalendarViewStore,
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, moduleId } = router.query;
|
const { workspaceSlug, moduleId } = router.query;
|
||||||
|
|
||||||
// TODO: add drag and drop functionality
|
|
||||||
const onDragEnd = (result: DropResult) => {
|
const onDragEnd = (result: DropResult) => {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export const ModuleCalendarLayout: React.FC = observer(() => {
|
|||||||
// return if dropped on the same date
|
// return if dropped on the same date
|
||||||
if (result.destination.droppableId === result.source.droppableId) return;
|
if (result.destination.droppableId === result.source.droppableId) return;
|
||||||
|
|
||||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
moduleIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||||
};
|
};
|
||||||
|
|
||||||
const issues = moduleIssueStore.getIssues;
|
const issues = moduleIssueStore.getIssues;
|
||||||
|
@ -11,12 +11,16 @@ import { IIssueGroupedStructure } from "store/issue";
|
|||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
|
|
||||||
export const CalendarLayout: React.FC = observer(() => {
|
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 router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
// TODO: add drag and drop functionality
|
|
||||||
const onDragEnd = (result: DropResult) => {
|
const onDragEnd = (result: DropResult) => {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
@ -26,7 +30,7 @@ export const CalendarLayout: React.FC = observer(() => {
|
|||||||
// return if dropped on the same date
|
// return if dropped on the same date
|
||||||
if (result.destination.droppableId === result.source.droppableId) return;
|
if (result.destination.droppableId === result.source.droppableId) return;
|
||||||
|
|
||||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
issueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||||
};
|
};
|
||||||
|
|
||||||
const issues = issueStore.getIssues;
|
const issues = issueStore.getIssues;
|
||||||
|
@ -15,12 +15,12 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => {
|
|||||||
projectViewIssues: projectViewIssuesStore,
|
projectViewIssues: projectViewIssuesStore,
|
||||||
issueFilter: issueFilterStore,
|
issueFilter: issueFilterStore,
|
||||||
issueDetail: issueDetailStore,
|
issueDetail: issueDetailStore,
|
||||||
|
projectViewIssueCalendarView: projectViewIssueCalendarViewStore,
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
// TODO: add drag and drop functionality
|
|
||||||
const onDragEnd = (result: DropResult) => {
|
const onDragEnd = (result: DropResult) => {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export const ProjectViewCalendarLayout: React.FC = observer(() => {
|
|||||||
// return if dropped on the same date
|
// return if dropped on the same date
|
||||||
if (result.destination.droppableId === result.source.droppableId) return;
|
if (result.destination.droppableId === result.source.droppableId) return;
|
||||||
|
|
||||||
// issueKanBanViewStore?.handleDragDrop(result.source, result.destination);
|
projectViewIssueCalendarViewStore?.handleDragDrop(result.source, result.destination);
|
||||||
};
|
};
|
||||||
|
|
||||||
const issues = projectViewIssuesStore.getIssues;
|
const issues = projectViewIssuesStore.getIssues;
|
||||||
|
89
web/store/cycle/cycle_issue_calendar_view.store.ts
Normal file
89
web/store/cycle/cycle_issue_calendar_view.store.ts
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
export * from "./cycle_issue_filters.store";
|
export * from "./cycle_issue_filters.store";
|
||||||
export * from "./cycle_issue_kanban_view.store";
|
export * from "./cycle_issue_kanban_view.store";
|
||||||
|
export * from "./cycle_issue_calendar_view.store";
|
||||||
export * from "./cycle_issue.store";
|
export * from "./cycle_issue.store";
|
||||||
export * from "./cycles.store";
|
export * from "./cycles.store";
|
||||||
|
@ -2,4 +2,5 @@ export * from "./issue_detail.store";
|
|||||||
export * from "./issue_draft.store";
|
export * from "./issue_draft.store";
|
||||||
export * from "./issue_filters.store";
|
export * from "./issue_filters.store";
|
||||||
export * from "./issue_kanban_view.store";
|
export * from "./issue_kanban_view.store";
|
||||||
|
export * from "./issue_calendar_view.store";
|
||||||
export * from "./issue.store";
|
export * from "./issue.store";
|
||||||
|
88
web/store/issue/issue_calendar_view.store.ts
Normal file
88
web/store/issue/issue_calendar_view.store.ts
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
export * from "./module_filters.store";
|
export * from "./module_filters.store";
|
||||||
export * from "./module_issue_kanban_view.store";
|
export * from "./module_issue_kanban_view.store";
|
||||||
|
export * from "./module_issue_calendar_view.store";
|
||||||
export * from "./module_issue.store";
|
export * from "./module_issue.store";
|
||||||
export * from "./modules.store";
|
export * from "./modules.store";
|
||||||
|
89
web/store/module/module_issue_calendar_view.store.ts
Normal file
89
web/store/module/module_issue_calendar_view.store.ts
Normal 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;
|
||||||
|
};
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
export * from "./project_view_filters.store";
|
export * from "./project_view_filters.store";
|
||||||
export * from "./project_view_issues.store";
|
export * from "./project_view_issues.store";
|
||||||
export * from "./project_views.store";
|
export * from "./project_views.store";
|
||||||
|
|
||||||
|
export * from "./project_view_issue_calendar_view.store";
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
@ -6,10 +6,18 @@ import { handleIssueQueryParamsByLayout } from "helpers/issue.helper";
|
|||||||
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "../root";
|
import { RootStore } from "../root";
|
||||||
import { IIssueGroupWithSubGroupsStructure, IIssueGroupedStructure, IIssueUnGroupedStructure } from "store/issue";
|
|
||||||
import { IIssue, IIssueFilterOptions } from "types";
|
import { IIssue, IIssueFilterOptions } from "types";
|
||||||
import { IBlockUpdateData } from "components/gantt-chart";
|
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 {
|
export interface IProjectViewIssuesStore {
|
||||||
// states
|
// states
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
@ -37,6 +45,7 @@ export interface IProjectViewIssuesStore {
|
|||||||
|
|
||||||
// computed
|
// computed
|
||||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||||
|
getIssueType: IIssueType | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
||||||
@ -75,6 +84,7 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
|||||||
fetchViewIssues: action,
|
fetchViewIssues: action,
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
|
getIssueType: computed,
|
||||||
getIssues: computed,
|
getIssues: computed,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -108,6 +118,26 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
|||||||
return computedFilters;
|
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() {
|
get getIssues() {
|
||||||
const viewId: string | null = this.rootStore.projectViews.viewId;
|
const viewId: string | null = this.rootStore.projectViews.viewId;
|
||||||
const issueType = this.rootStore.issue.getIssueType;
|
const issueType = this.rootStore.issue.getIssueType;
|
||||||
|
@ -12,6 +12,8 @@ import {
|
|||||||
IssueDetailStore,
|
IssueDetailStore,
|
||||||
IssueFilterStore,
|
IssueFilterStore,
|
||||||
IssueKanBanViewStore,
|
IssueKanBanViewStore,
|
||||||
|
IIssueCalendarViewStore,
|
||||||
|
IssueCalendarViewStore,
|
||||||
IssueStore,
|
IssueStore,
|
||||||
} from "store/issue";
|
} from "store/issue";
|
||||||
import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace";
|
import { IWorkspaceFilterStore, IWorkspaceStore, WorkspaceFilterStore, WorkspaceStore } from "store/workspace";
|
||||||
@ -24,6 +26,8 @@ import {
|
|||||||
ModuleFilterStore,
|
ModuleFilterStore,
|
||||||
ModuleIssueKanBanViewStore,
|
ModuleIssueKanBanViewStore,
|
||||||
ModuleIssueStore,
|
ModuleIssueStore,
|
||||||
|
IModuleIssueCalendarViewStore,
|
||||||
|
ModuleIssueCalendarViewStore,
|
||||||
ModuleStore,
|
ModuleStore,
|
||||||
} from "store/module";
|
} from "store/module";
|
||||||
import {
|
import {
|
||||||
@ -33,6 +37,8 @@ import {
|
|||||||
CycleStore,
|
CycleStore,
|
||||||
ICycleIssueFilterStore,
|
ICycleIssueFilterStore,
|
||||||
ICycleIssueKanBanViewStore,
|
ICycleIssueKanBanViewStore,
|
||||||
|
ICycleIssueCalendarViewStore,
|
||||||
|
CycleIssueCalendarViewStore,
|
||||||
ICycleIssueStore,
|
ICycleIssueStore,
|
||||||
ICycleStore,
|
ICycleStore,
|
||||||
} from "store/cycle";
|
} from "store/cycle";
|
||||||
@ -43,6 +49,8 @@ import {
|
|||||||
ProjectViewFiltersStore,
|
ProjectViewFiltersStore,
|
||||||
ProjectViewIssuesStore,
|
ProjectViewIssuesStore,
|
||||||
ProjectViewsStore,
|
ProjectViewsStore,
|
||||||
|
IProjectViewIssueCalendarViewStore,
|
||||||
|
ProjectViewIssueCalendarViewStore,
|
||||||
} from "store/project-view";
|
} from "store/project-view";
|
||||||
import CalendarStore, { ICalendarStore } from "store/calendar.store";
|
import CalendarStore, { ICalendarStore } from "store/calendar.store";
|
||||||
import {
|
import {
|
||||||
@ -95,19 +103,23 @@ export class RootStore {
|
|||||||
moduleIssue: IModuleIssueStore;
|
moduleIssue: IModuleIssueStore;
|
||||||
moduleFilter: IModuleFilterStore;
|
moduleFilter: IModuleFilterStore;
|
||||||
moduleIssueKanBanView: IModuleIssueKanBanViewStore;
|
moduleIssueKanBanView: IModuleIssueKanBanViewStore;
|
||||||
|
moduleIssueCalendarView: IModuleIssueCalendarViewStore;
|
||||||
|
|
||||||
cycle: ICycleStore;
|
cycle: ICycleStore;
|
||||||
cycleIssue: ICycleIssueStore;
|
cycleIssue: ICycleIssueStore;
|
||||||
cycleIssueFilter: ICycleIssueFilterStore;
|
cycleIssueFilter: ICycleIssueFilterStore;
|
||||||
cycleIssueKanBanView: ICycleIssueKanBanViewStore;
|
cycleIssueKanBanView: ICycleIssueKanBanViewStore;
|
||||||
|
cycleIssueCalendarView: ICycleIssueCalendarViewStore;
|
||||||
|
|
||||||
projectViews: IProjectViewsStore;
|
projectViews: IProjectViewsStore;
|
||||||
projectViewIssues: IProjectViewIssuesStore;
|
projectViewIssues: IProjectViewIssuesStore;
|
||||||
projectViewFilters: IProjectViewFiltersStore;
|
projectViewFilters: IProjectViewFiltersStore;
|
||||||
|
projectViewIssueCalendarView: IProjectViewIssueCalendarViewStore;
|
||||||
|
|
||||||
issueFilter: IIssueFilterStore;
|
issueFilter: IIssueFilterStore;
|
||||||
issueDetail: IIssueDetailStore;
|
issueDetail: IIssueDetailStore;
|
||||||
issueKanBanView: IIssueKanBanViewStore;
|
issueKanBanView: IIssueKanBanViewStore;
|
||||||
|
issueCalendarView: IIssueCalendarViewStore;
|
||||||
draftIssuesStore: DraftIssuesStore;
|
draftIssuesStore: DraftIssuesStore;
|
||||||
|
|
||||||
calendar: ICalendarStore;
|
calendar: ICalendarStore;
|
||||||
@ -145,20 +157,24 @@ export class RootStore {
|
|||||||
this.moduleIssue = new ModuleIssueStore(this);
|
this.moduleIssue = new ModuleIssueStore(this);
|
||||||
this.moduleFilter = new ModuleFilterStore(this);
|
this.moduleFilter = new ModuleFilterStore(this);
|
||||||
this.moduleIssueKanBanView = new ModuleIssueKanBanViewStore(this);
|
this.moduleIssueKanBanView = new ModuleIssueKanBanViewStore(this);
|
||||||
|
this.moduleIssueCalendarView = new ModuleIssueCalendarViewStore(this);
|
||||||
|
|
||||||
this.cycle = new CycleStore(this);
|
this.cycle = new CycleStore(this);
|
||||||
this.cycleIssue = new CycleIssueStore(this);
|
this.cycleIssue = new CycleIssueStore(this);
|
||||||
this.cycleIssueFilter = new CycleIssueFilterStore(this);
|
this.cycleIssueFilter = new CycleIssueFilterStore(this);
|
||||||
this.cycleIssueKanBanView = new CycleIssueKanBanViewStore(this);
|
this.cycleIssueKanBanView = new CycleIssueKanBanViewStore(this);
|
||||||
|
this.cycleIssueCalendarView = new CycleIssueCalendarViewStore(this);
|
||||||
|
|
||||||
this.projectViews = new ProjectViewsStore(this);
|
this.projectViews = new ProjectViewsStore(this);
|
||||||
this.projectViewIssues = new ProjectViewIssuesStore(this);
|
this.projectViewIssues = new ProjectViewIssuesStore(this);
|
||||||
this.projectViewFilters = new ProjectViewFiltersStore(this);
|
this.projectViewFilters = new ProjectViewFiltersStore(this);
|
||||||
|
this.projectViewIssueCalendarView = new ProjectViewIssueCalendarViewStore(this);
|
||||||
|
|
||||||
this.issue = new IssueStore(this);
|
this.issue = new IssueStore(this);
|
||||||
this.issueFilter = new IssueFilterStore(this);
|
this.issueFilter = new IssueFilterStore(this);
|
||||||
this.issueDetail = new IssueDetailStore(this);
|
this.issueDetail = new IssueDetailStore(this);
|
||||||
this.issueKanBanView = new IssueKanBanViewStore(this);
|
this.issueKanBanView = new IssueKanBanViewStore(this);
|
||||||
|
this.issueCalendarView = new IssueCalendarViewStore(this);
|
||||||
this.draftIssuesStore = new DraftIssuesStore(this);
|
this.draftIssuesStore = new DraftIssuesStore(this);
|
||||||
|
|
||||||
this.calendar = new CalendarStore(this);
|
this.calendar = new CalendarStore(this);
|
||||||
|
Loading…
Reference in New Issue
Block a user