From 985cfbe718204968d7eeabb3ad91cd311de464c7 Mon Sep 17 00:00:00 2001 From: rahulramesha Date: Tue, 7 May 2024 18:22:36 +0530 Subject: [PATCH 1/2] Gantt Drag and drop migration and enable Dnd in Modules and Cycles Gantt --- packages/types/src/module/module_filters.d.ts | 3 +- web/components/cycles/cycles-view.tsx | 2 +- .../cycles/gantt-chart/cycles-list-layout.tsx | 2 +- .../gantt-chart/chart/main-content.tsx | 18 ++- .../gantt-chart/sidebar/GanttDnDHOC.tsx | 104 +++++++++++++++ .../gantt-chart/sidebar/cycles/block.tsx | 14 +- .../gantt-chart/sidebar/cycles/sidebar.tsx | 116 ++++++---------- web/components/gantt-chart/sidebar/index.ts | 1 - .../gantt-chart/sidebar/issues/block.tsx | 16 +-- .../gantt-chart/sidebar/issues/sidebar.tsx | 124 ++++++------------ .../gantt-chart/sidebar/modules/block.tsx | 14 +- .../gantt-chart/sidebar/modules/sidebar.tsx | 116 ++++++---------- .../gantt-chart/sidebar/project-views.tsx | 105 --------------- web/components/gantt-chart/sidebar/utils.ts | 42 ++++++ web/components/modules/dropdowns/order-by.tsx | 45 ++++--- .../gantt-chart/modules-list-layout.tsx | 5 +- web/components/modules/module-view-header.tsx | 1 + web/constants/module.ts | 4 + web/helpers/cycle.helper.ts | 12 +- web/helpers/module.helper.ts | 1 + web/package.json | 4 +- web/store/cycle.store.ts | 6 +- yarn.lock | 8 +- 23 files changed, 354 insertions(+), 409 deletions(-) create mode 100644 web/components/gantt-chart/sidebar/GanttDnDHOC.tsx delete mode 100644 web/components/gantt-chart/sidebar/project-views.tsx create mode 100644 web/components/gantt-chart/sidebar/utils.ts diff --git a/packages/types/src/module/module_filters.d.ts b/packages/types/src/module/module_filters.d.ts index 297c8046cdc..e22ac152a5b 100644 --- a/packages/types/src/module/module_filters.d.ts +++ b/packages/types/src/module/module_filters.d.ts @@ -8,7 +8,8 @@ export type TModuleOrderByOptions = | "target_date" | "-target_date" | "created_at" - | "-created_at"; + | "-created_at" + | "sort_order"; export type TModuleLayoutOptions = "list" | "board" | "gantt"; diff --git a/web/components/cycles/cycles-view.tsx b/web/components/cycles/cycles-view.tsx index ddb45b5e52c..7f71892e991 100644 --- a/web/components/cycles/cycles-view.tsx +++ b/web/components/cycles/cycles-view.tsx @@ -26,7 +26,7 @@ export const CyclesView: FC = observer((props) => { const { getFilteredCycleIds, getFilteredCompletedCycleIds, loader } = useCycle(); const { searchQuery } = useCycleFilter(); // derived values - const filteredCycleIds = getFilteredCycleIds(projectId); + const filteredCycleIds = getFilteredCycleIds(projectId, layout === "gantt"); const filteredCompletedCycleIds = getFilteredCompletedCycleIds(projectId); if (loader || !filteredCycleIds) diff --git a/web/components/cycles/gantt-chart/cycles-list-layout.tsx b/web/components/cycles/gantt-chart/cycles-list-layout.tsx index 6d84f73f061..e4d85cf4bf8 100644 --- a/web/components/cycles/gantt-chart/cycles-list-layout.tsx +++ b/web/components/cycles/gantt-chart/cycles-list-layout.tsx @@ -61,7 +61,7 @@ export const CyclesListGanttChartView: FC = observer((props) => { enableBlockLeftResize={false} enableBlockRightResize={false} enableBlockMove={false} - enableReorder={false} + enableReorder /> ); diff --git a/web/components/gantt-chart/chart/main-content.tsx b/web/components/gantt-chart/chart/main-content.tsx index 99ea6c94e9a..2f5abc8863a 100644 --- a/web/components/gantt-chart/chart/main-content.tsx +++ b/web/components/gantt-chart/chart/main-content.tsx @@ -1,4 +1,6 @@ -import { useRef } from "react"; +import { useEffect, useRef } from "react"; +import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; +import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element"; import { observer } from "mobx-react"; // hooks // components @@ -62,6 +64,20 @@ export const GanttChartMainContent: React.FC = observer((props) => { const ganttContainerRef = useRef(null); // chart hook const { currentView, currentViewData } = useGanttChart(); + + // Enable Auto Scroll for Ganttlist + useEffect(() => { + const element = ganttContainerRef.current; + + if (!element) return; + + return combine( + autoScrollForElements({ + element, + getAllowedAxis: () => "vertical", + }) + ); + }, [ganttContainerRef?.current]); // handling scroll functionality const onScroll = (e: React.UIEvent) => { const { clientWidth, scrollLeft, scrollWidth } = e.currentTarget; diff --git a/web/components/gantt-chart/sidebar/GanttDnDHOC.tsx b/web/components/gantt-chart/sidebar/GanttDnDHOC.tsx new file mode 100644 index 00000000000..956a72b12e7 --- /dev/null +++ b/web/components/gantt-chart/sidebar/GanttDnDHOC.tsx @@ -0,0 +1,104 @@ +import { MutableRefObject, useEffect, useRef, useState } from "react"; +import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; +import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; +import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item"; +import { observer } from "mobx-react"; +import { DropIndicator } from "@plane/ui"; +import { highlightIssueOnDrop } from "@/components/issues/issue-layouts/kanban/utils"; +import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; + +type Props = { + id: string; + isLastChild: boolean; + isDragEnabled: boolean; + children: (isDragging: boolean, dragHandleRef: MutableRefObject) => JSX.Element; + onDrop: (draggingBlockId: string | undefined, droppedBlockId: string | undefined, dropAtEndOfList: boolean) => void; +}; + +export const GanttDnDHOC = observer((props: Props) => { + const { id, isLastChild, children, onDrop, isDragEnabled } = props; + // states + const [isDragging, setIsDragging] = useState(false); + const [instruction, setInstruction] = useState<"DRAG_OVER" | "DRAG_BELOW" | undefined>(undefined); + // refs + const blockRef = useRef(null); + const dragHandleRef = useRef(null); + + useEffect(() => { + const element = blockRef.current; + const dragHandleElement = dragHandleRef.current; + + if (!element) return; + + return combine( + draggable({ + element, + canDrag: () => isDragEnabled, + dragHandle: dragHandleElement ?? undefined, + getInitialData: () => ({ id }), + onDragStart: () => { + setIsDragging(true); + }, + onDrop: () => { + setIsDragging(false); + }, + }), + dropTargetForElements({ + element, + canDrop: ({ source }) => source?.data?.id !== id, + getData: ({ input, element }) => { + const data = { id }; + + // attach instruction for last in list + return attachInstruction(data, { + input, + element, + currentLevel: 0, + indentPerLevel: 0, + mode: isLastChild ? "last-in-group" : "standard", + }); + }, + onDrag: ({ self }) => { + const extractedInstruction = extractInstruction(self?.data)?.type; + // check if the highlight is to be shown above or below + setInstruction( + extractedInstruction + ? extractedInstruction === "reorder-below" && isLastChild + ? "DRAG_BELOW" + : "DRAG_OVER" + : undefined + ); + }, + onDragLeave: () => { + setInstruction(undefined); + }, + onDrop: ({ self, source }) => { + setInstruction(undefined); + const extractedInstruction = extractInstruction(self?.data)?.type; + const currentInstruction = extractedInstruction + ? extractedInstruction === "reorder-below" && isLastChild + ? "DRAG_BELOW" + : "DRAG_OVER" + : undefined; + if (!currentInstruction) return; + + const sourceId = source?.data?.id as string | undefined; + const destinationId = self?.data?.id as string | undefined; + + onDrop(sourceId, destinationId, currentInstruction === "DRAG_BELOW"); + highlightIssueOnDrop(source?.element?.id, false); + }, + }) + ); + }, [blockRef?.current, dragHandleRef?.current, isLastChild, onDrop]); + + useOutsideClickDetector(blockRef, () => blockRef?.current?.classList?.remove("highlight")); + + return ( +
+ + {children(isDragging, dragHandleRef)} + {isLastChild && } +
+ ); +}); diff --git a/web/components/gantt-chart/sidebar/cycles/block.tsx b/web/components/gantt-chart/sidebar/cycles/block.tsx index e9543e36728..1119e2e9ca9 100644 --- a/web/components/gantt-chart/sidebar/cycles/block.tsx +++ b/web/components/gantt-chart/sidebar/cycles/block.tsx @@ -1,4 +1,4 @@ -import { DraggableProvided, DraggableStateSnapshot } from "@hello-pangea/dnd"; +import { MutableRefObject } from "react"; import { observer } from "mobx-react"; import { MoreVertical } from "lucide-react"; // hooks @@ -16,12 +16,12 @@ import { findTotalDaysInRange } from "@/helpers/date-time.helper"; type Props = { block: IGanttBlock; enableReorder: boolean; - provided: DraggableProvided; - snapshot: DraggableStateSnapshot; + isDragging: boolean; + dragHandleRef: MutableRefObject; }; export const CyclesSidebarBlock: React.FC = observer((props) => { - const { block, enableReorder, provided, snapshot } = props; + const { block, enableReorder, isDragging, dragHandleRef } = props; // store hooks const { updateActiveBlockId, isBlockActive } = useGanttChart(); @@ -30,12 +30,10 @@ export const CyclesSidebarBlock: React.FC = observer((props) => { return (
updateActiveBlockId(block.id)} onMouseLeave={() => updateActiveBlockId(null)} - ref={provided.innerRef} - {...provided.draggableProps} >
= observer((props) => {