[WEB-1004] feat: Pragmatic dnd implementation for Kanban (#4189)

* Pragmatic drag and drop implmentation of Kanban

* refactor pragmatic dnd implementation and fix bugs

* fix dnd for modules, cycles, draft and project views
This commit is contained in:
rahulramesha 2024-04-15 17:02:53 +05:30 committed by GitHub
parent 384624a21b
commit 7a21855ab6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 756 additions and 377 deletions

View file

@ -1,6 +1,8 @@
import { MutableRefObject } from "react";
import { Droppable } from "@hello-pangea/dnd";
// hooks
import { MutableRefObject, useEffect, useRef, useState } from "react";
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
//types
import {
TGroupedIssues,
TIssue,
@ -8,10 +10,14 @@ import {
IIssueMap,
TSubGroupedIssues,
TUnGroupedIssues,
TIssueGroupByOptions,
} from "@plane/types";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useProjectState } from "@/hooks/store";
//components
//types
import { KanbanDropLocation, getSourceFromDropPayload, getDestinationFromDropPayload } from "./utils";
import { KanbanIssueBlocksList, KanBanQuickAddIssueForm } from ".";
interface IKanbanGroup {
@ -20,8 +26,8 @@ interface IKanbanGroup {
peekIssueId?: string;
issueIds: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues;
displayProperties: IIssueDisplayProperties | undefined;
sub_group_by: string | null;
group_by: string | null;
sub_group_by: TIssueGroupByOptions | undefined;
group_by: TIssueGroupByOptions | undefined;
sub_group_id: string;
isDragDisabled: boolean;
updateIssue: ((projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined;
@ -38,7 +44,7 @@ interface IKanbanGroup {
canEditProperties: (projectId: string | undefined) => boolean;
groupByVisibilityToggle?: boolean;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
isDragStarted?: boolean;
handleOnDrop: (source: KanbanDropLocation, destination: KanbanDropLocation) => Promise<void>;
}
export const KanbanGroup = (props: IKanbanGroup) => {
@ -60,14 +66,53 @@ export const KanbanGroup = (props: IKanbanGroup) => {
quickAddCallback,
viewId,
scrollableContainerRef,
isDragStarted,
handleOnDrop,
} = props;
// hooks
const projectState = useProjectState();
const [isDraggingOverColumn, setIsDraggingOverColumn] = useState(false);
const columnRef = useRef<HTMLDivElement | null>(null);
// Enable Kanban Columns as Drop Targets
useEffect(() => {
const element = columnRef.current;
if (!element) return;
return combine(
dropTargetForElements({
element,
getData: () => ({ groupId, subGroupId: sub_group_id, columnId: `${groupId}__${sub_group_id}`, type: "COLUMN" }),
onDragEnter: () => {
setIsDraggingOverColumn(true);
},
onDragLeave: () => {
setIsDraggingOverColumn(false);
},
onDragStart: () => {
setIsDraggingOverColumn(true);
},
onDrop: (payload) => {
setIsDraggingOverColumn(false);
const source = getSourceFromDropPayload(payload);
const destination = getDestinationFromDropPayload(payload);
if (!source || !destination) return;
handleOnDrop(source, destination);
},
}),
autoScrollForElements({
element,
})
);
}, [columnRef?.current, groupId, sub_group_id, setIsDraggingOverColumn]);
const prePopulateQuickAddData = (
groupByKey: string | null,
subGroupByKey: string | null,
groupByKey: string | undefined,
subGroupByKey: string | undefined | null,
groupValue: string,
subGroupValue: string
) => {
@ -118,48 +163,43 @@ export const KanbanGroup = (props: IKanbanGroup) => {
};
return (
<div className={`relative w-full h-full transition-all`}>
<Droppable droppableId={`${groupId}__${sub_group_id}`}>
{(provided: any, snapshot: any) => (
<div
className={`relative h-full transition-all ${snapshot.isDraggingOver ? `bg-custom-background-80` : ``}`}
{...provided.droppableProps}
ref={provided.innerRef}
>
<KanbanIssueBlocksList
sub_group_id={sub_group_id}
columnId={groupId}
issuesMap={issuesMap}
peekIssueId={peekIssueId}
issueIds={(issueIds as TGroupedIssues)?.[groupId] || []}
displayProperties={displayProperties}
isDragDisabled={isDragDisabled}
updateIssue={updateIssue}
quickActions={quickActions}
canEditProperties={canEditProperties}
scrollableContainerRef={scrollableContainerRef}
isDragStarted={isDragStarted}
/>
<div
id={`${groupId}__${sub_group_id}`}
className={cn(
"relative h-full transition-all",
{ "bg-custom-background-80": isDraggingOverColumn },
{ "vertical-scrollbar scrollbar-md": !sub_group_by }
)}
ref={columnRef}
>
<KanbanIssueBlocksList
sub_group_id={sub_group_id}
columnId={groupId}
issuesMap={issuesMap}
peekIssueId={peekIssueId}
issueIds={(issueIds as TGroupedIssues)?.[groupId] || []}
displayProperties={displayProperties}
isDragDisabled={isDragDisabled}
updateIssue={updateIssue}
quickActions={quickActions}
canEditProperties={canEditProperties}
scrollableContainerRef={scrollableContainerRef}
/>
{provided.placeholder}
{enableQuickIssueCreate && !disableIssueCreation && (
<div className="w-full bg-custom-background-90 py-0.5 sticky bottom-0">
<KanBanQuickAddIssueForm
formKey="name"
groupId={groupId}
subGroupId={sub_group_id}
prePopulatedData={{
...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)),
}}
quickAddCallback={quickAddCallback}
viewId={viewId}
/>
</div>
)}
</div>
)}
</Droppable>
{enableQuickIssueCreate && !disableIssueCreation && (
<div className="w-full bg-custom-background-90 py-0.5 sticky bottom-0">
<KanBanQuickAddIssueForm
formKey="name"
groupId={groupId}
subGroupId={sub_group_id}
prePopulatedData={{
...(group_by && prePopulateQuickAddData(group_by, sub_group_by, groupId, sub_group_id)),
}}
quickAddCallback={quickAddCallback}
viewId={viewId}
/>
</div>
)}
</div>
);
};