-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[WEB-2774] Chore: re-ordering functionality for entities in favorites. #6078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
0f641ec
12743b5
0a6cb1b
23b30d0
0bec7a1
a612ec7
b2a58a3
1b124c6
d1cc0e0
9535a4a
797a756
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,12 +3,16 @@ | |||||||||
| import { 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 { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview"; | ||||||||||
| import { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview"; | ||||||||||
|
|
||||||||||
| import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; | ||||||||||
| import uniqBy from "lodash/uniqBy"; | ||||||||||
| import { useParams } from "next/navigation"; | ||||||||||
| import { PenSquare, Star, MoreHorizontal, ChevronRight, GripVertical } from "lucide-react"; | ||||||||||
| import { Disclosure, Transition } from "@headlessui/react"; | ||||||||||
| import { createRoot } from "react-dom/client"; | ||||||||||
|
||||||||||
|
|
||||||||||
| // plane helpers | ||||||||||
| import { useOutsideClickDetector } from "@plane/helpers"; | ||||||||||
| // ui | ||||||||||
|
|
@@ -24,21 +28,23 @@ import { usePlatformOS } from "@/hooks/use-platform-os"; | |||||||||
| import { FavoriteRoot } from "./favorite-items"; | ||||||||||
| import { getDestinationStateSequence } from "./favorites.helpers"; | ||||||||||
| import { NewFavoriteFolder } from "./new-fav-folder"; | ||||||||||
| import { orderBy } from "lodash"; | ||||||||||
pushya22 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
|
|
||||||||||
| type Props = { | ||||||||||
| isLastChild: boolean; | ||||||||||
| favorite: IFavorite; | ||||||||||
| handleRemoveFromFavorites: (favorite: IFavorite) => void; | ||||||||||
| handleRemoveFromFavoritesFolder: (favoriteId: string) => void; | ||||||||||
| handleReorder: (favoriteId: string, sequence: number) => void; | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| export const FavoriteFolder: React.FC<Props> = (props) => { | ||||||||||
| const { favorite, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; | ||||||||||
| const { favorite, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder, handleReorder } = props; | ||||||||||
| // store hooks | ||||||||||
| const { sidebarCollapsed: isSidebarCollapsed } = useAppTheme(); | ||||||||||
|
|
||||||||||
| const { isMobile } = usePlatformOS(); | ||||||||||
| const { moveFavorite, getGroupedFavorites, groupedFavorites, moveFavoriteFolder } = useFavorite(); | ||||||||||
| const { getGroupedFavorites, groupedFavorites, moveFavoriteToFolder } = useFavorite(); | ||||||||||
| const { workspaceSlug } = useParams(); | ||||||||||
| // states | ||||||||||
| const [isMenuActive, setIsMenuActive] = useState(false); | ||||||||||
|
|
@@ -53,8 +59,8 @@ export const FavoriteFolder: React.FC<Props> = (props) => { | |||||||||
|
|
||||||||||
| !favorite.children && getGroupedFavorites(workspaceSlug.toString(), favorite.id); | ||||||||||
|
|
||||||||||
| const handleOnDrop = (source: string, destination: string) => { | ||||||||||
| moveFavorite(workspaceSlug.toString(), source, { | ||||||||||
| const handleMoveToFolder = (source: string, destination: string) => { | ||||||||||
| moveFavoriteToFolder(workspaceSlug.toString(), source, { | ||||||||||
| parent: destination, | ||||||||||
| }) | ||||||||||
| .then(() => { | ||||||||||
|
|
@@ -73,24 +79,6 @@ export const FavoriteFolder: React.FC<Props> = (props) => { | |||||||||
| }); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| const handleOnDropFolder = (payload: Partial<IFavorite>) => { | ||||||||||
| moveFavoriteFolder(workspaceSlug.toString(), favorite.id, payload) | ||||||||||
| .then(() => { | ||||||||||
| setToast({ | ||||||||||
| type: TOAST_TYPE.SUCCESS, | ||||||||||
| title: "Success!", | ||||||||||
| message: "Folder moved successfully.", | ||||||||||
| }); | ||||||||||
| }) | ||||||||||
| .catch(() => { | ||||||||||
| setToast({ | ||||||||||
| type: TOAST_TYPE.ERROR, | ||||||||||
| title: "Error!", | ||||||||||
| message: "Failed to move folder.", | ||||||||||
| }); | ||||||||||
| }); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| useEffect(() => { | ||||||||||
| const element = elementRef.current; | ||||||||||
|
|
||||||||||
|
|
@@ -101,22 +89,36 @@ export const FavoriteFolder: React.FC<Props> = (props) => { | |||||||||
| draggable({ | ||||||||||
| element, | ||||||||||
| getInitialData: () => initialData, | ||||||||||
| onDragStart: () => setIsDragging(true), | ||||||||||
| // onDragStart: () => setIsDragging(true), | ||||||||||
vamsikrishnamathala marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
| onGenerateDragPreview: ({ nativeSetDragImage }) =>{ | ||||||||||
| setCustomNativeDragPreview({ | ||||||||||
| getOffset: pointerOutsideOfPreview({ x: "0px", y: "0px" }), | ||||||||||
| render: ({ container }) => { | ||||||||||
| const root = createRoot(container); | ||||||||||
| root.render( | ||||||||||
| <div className="rounded flex gap-1 bg-custom-background-100 text-sm p-1 pr-2"> | ||||||||||
| <div className="size-5 grid place-items-center flex-shrink-0"> | ||||||||||
| <FavoriteFolderIcon /> | ||||||||||
| </div> | ||||||||||
| <p className="truncate text-sm font-medium text-custom-sidebar-text-200">{favorite.name}</p> | ||||||||||
| </div> | ||||||||||
| ); | ||||||||||
| return () => root.unmount(); | ||||||||||
| }, | ||||||||||
| nativeSetDragImage, | ||||||||||
| }); | ||||||||||
| }, | ||||||||||
| onDrop: (data) => { | ||||||||||
| setIsDraggedOver(false); | ||||||||||
| if (!data.location.current.dropTargets[0]) return; | ||||||||||
| const destinationData = data.location.current.dropTargets[0].data; | ||||||||||
|
|
||||||||||
| if (favorite.id && destinationData) { | ||||||||||
| const edge = extractClosestEdge(destinationData) || undefined; | ||||||||||
| const payload = { | ||||||||||
| id: favorite.id, | ||||||||||
| sequence: Math.round( | ||||||||||
| getDestinationStateSequence(groupedFavorites, destinationData.id as string, edge) || 0 | ||||||||||
| ), | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| handleOnDropFolder(payload); | ||||||||||
| const sequence = Math.round( | ||||||||||
| getDestinationStateSequence(groupedFavorites, destinationData.id as string, edge) || 0 | ||||||||||
| ); | ||||||||||
| handleReorder(favorite.id,sequence); | ||||||||||
| } | ||||||||||
| }, // canDrag: () => isDraggable, | ||||||||||
| }), | ||||||||||
|
|
@@ -128,10 +130,14 @@ export const FavoriteFolder: React.FC<Props> = (props) => { | |||||||||
| element, | ||||||||||
| allowedEdges: ["top", "bottom"], | ||||||||||
| }), | ||||||||||
| onDragEnter: (args) => { | ||||||||||
| setIsDragging(true); | ||||||||||
| setIsDraggedOver(true); | ||||||||||
| args.source.data.is_folder && setClosestEdge(extractClosestEdge(args.self.data)); | ||||||||||
| onDragEnter: ({source,self}) => { | ||||||||||
| const sourceId = source?.data?.id as string; | ||||||||||
| const destinationId = self?.data?.id as string | undefined; | ||||||||||
| if (groupedFavorites[sourceId].parent !== destinationId) { | ||||||||||
| setIsDraggedOver(true); | ||||||||||
| setIsDragging(true); | ||||||||||
| }; | ||||||||||
pushya22 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
| source.data.is_folder && setClosestEdge(extractClosestEdge(self.data)); | ||||||||||
| }, | ||||||||||
| onDragLeave: () => { | ||||||||||
| setIsDragging(false); | ||||||||||
|
|
@@ -146,16 +152,18 @@ export const FavoriteFolder: React.FC<Props> = (props) => { | |||||||||
| setIsDraggedOver(false); | ||||||||||
| const sourceId = source?.data?.id as string | undefined; | ||||||||||
| const destinationId = self?.data?.id as string | undefined; | ||||||||||
|
|
||||||||||
| if (source.data.is_folder) return; | ||||||||||
| if (sourceId === destinationId) return; | ||||||||||
| if (!sourceId || !destinationId) return; | ||||||||||
| if (groupedFavorites[sourceId].parent === destinationId) return; | ||||||||||
|
||||||||||
| if (!sourceId || !destinationId) return; | |
| if (groupedFavorites[sourceId].parent === destinationId) return; | |
| if (!sourceId || !destinationId) return; | |
| if (groupedFavorites[sourceId] && groupedFavorites[sourceId].parent === destinationId) return; |
pushya22 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,9 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import React, { FC, 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 { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { observer } from "mobx-react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // plane helpers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useOutsideClickDetector } from "@plane/helpers"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -19,66 +22,129 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useAppTheme } from "@/hooks/store"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useFavoriteItemDetails } from "@/hooks/use-favorite-item-details"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { createRoot } from "react-dom/client"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { DropIndicator } from "@plane/ui"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //constants | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getDestinationStateSequence } from "../favorites.helpers"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type Props = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workspaceSlug: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| favorite: IFavorite; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| favoriteMap: Record<string, IFavorite>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavorites: (favorite: IFavorite) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavoritesFolder: (favoriteId: string) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleReorder: (favoriteId: string, sequence: number) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const FavoriteRoot: FC<Props> = observer((props) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // props | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { workspaceSlug, favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workspaceSlug, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| favorite, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| favoriteMap, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavorites, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavoritesFolder, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleReorder, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // store hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { sidebarCollapsed } = useAppTheme(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { itemLink, itemIcon, itemTitle } = useFavoriteItemDetails(workspaceSlug, favorite); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //state | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isDragging, setIsDragging] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isMenuActive, setIsMenuActive] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [closestEdge, setClosestEdge] = useState<string | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isDraggedOver, setIsDraggedOver] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //ref | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const elementRef = useRef<HTMLDivElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const actionSectionRef = useRef<HTMLDivElement | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleQuickAction = (value: boolean) => setIsMenuActive(value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { itemLink, itemIcon, itemTitle } = useFavoriteItemDetails(workspaceSlug, favorite); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // drag and drop | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const element = elementRef.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!element) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const initialData = { id: favorite.id, type: favorite.parent ? 'CHILD' : 'NON_PARENT' }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return combine( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| draggable({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dragHandle: elementRef.current, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| canDrag: () => true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getInitialData: () => ({ id: favorite.id, type: "CHILD" }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getInitialData: () => initialData, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDragStart: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDragging(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDrop: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDrop: (data) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDraggedOver(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDragging(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!data.location.current.dropTargets[0]) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const destinationData = data.location.current.dropTargets[0].data; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (favorite.id && destinationData) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const edge = extractClosestEdge(destinationData) || undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sequence = Math.round( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getDestinationStateSequence(favoriteMap, destinationData.id as string, edge) || 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleReorder(favorite.id, sequence); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pushya22 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onGenerateDragPreview: ({ nativeSetDragImage }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setCustomNativeDragPreview({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getOffset: pointerOutsideOfPreview({ x: "0px", y: "0px" }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| render: ({ container }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const root = createRoot(container); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| root.render( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="rounded bg-custom-background-100 text-sm p-1 pr-2"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <FavoriteItemTitle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| href={itemLink} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| icon={itemIcon} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title={itemTitle} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isSidebarCollapsed={!!sidebarCollapsed} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return () => root.unmount(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nativeSetDragImage, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+83
to
+101
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add cleanup for drag preview root. The current implementation of the drag preview could potentially cause memory leaks if the component unmounts during a drag operation. Consider wrapping the root creation in a try-catch block and ensuring cleanup. onGenerateDragPreview: ({ nativeSetDragImage }) => {
+ let root: Root | null = null;
setCustomNativeDragPreview({
getOffset: pointerOutsideOfPreview({ x: "0px", y: "0px" }),
render: ({ container }) => {
- const root = createRoot(container);
+ try {
+ root = createRoot(container);
+ root.render(
- root.render(
<div className="rounded bg-custom-background-100 text-sm p-1 pr-2">
<FavoriteItemTitle
href={itemLink}
icon={itemIcon}
title={itemTitle}
isSidebarCollapsed={!!sidebarCollapsed}
/>
</div>
);
- return () => root.unmount();
+ return () => {
+ root?.unmount();
+ root = null;
+ };
+ } catch (error) {
+ console.error('Failed to create drag preview:', error);
+ return () => {};
+ }
},
nativeSetDragImage,
});
},📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| dropTargetForElements({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDragStart: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDragging(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDragEnter: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getData: ({ input, element }) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attachClosestEdge(initialData, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| input, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| element, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allowedEdges: ["top", "bottom"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDragEnter: (args) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDragging(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDraggedOver(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setClosestEdge(extractClosestEdge(args.self.data)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDragLeave: () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDragging(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDraggedOver(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setClosestEdge(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDrop: ({ source }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDrop: ({ self, source }) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDragging(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sourceId = source?.data?.id as string | undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!sourceId || !favoriteMap[sourceId].parent) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavoritesFolder(sourceId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsDraggedOver(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sourceId = source.data?.id as string | undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const destinationType = self.data?.type as string | undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sourceType = source.data?.type as string | undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!sourceId) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(destinationType === 'NON_PARENT'){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavoritesFolder(sourceId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -90,6 +156,7 @@ export const FavoriteRoot: FC<Props> = observer((props) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <FavoriteItemWrapper elementRef={elementRef} isMenuActive={isMenuActive} sidebarCollapsed={sidebarCollapsed}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <DropIndicator isVisible={isDraggedOver && closestEdge === "top"} classNames="absolute top-0" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {!sidebarCollapsed && <FavoriteItemDragHandle isDragging={isDragging} sort_order={favorite.sort_order} />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <FavoriteItemTitle href={itemLink} icon={itemIcon} title={itemTitle} isSidebarCollapsed={!!sidebarCollapsed} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {!sidebarCollapsed && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -101,6 +168,7 @@ export const FavoriteRoot: FC<Props> = observer((props) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavorites={handleRemoveFromFavorites} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <DropIndicator isVisible={isDraggedOver && closestEdge === "bottom"} classNames="absolute bottom-0" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </FavoriteItemWrapper> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Correct the import order according to coding standards
The static analysis tool indicates that
pointerOutsideOfPreviewimport should occur beforesetCustomNativeDragPreview. Please reorder the imports to comply with project conventions.Apply this diff to fix the import order:
📝 Committable suggestion
🧰 Tools
🪛 GitHub Check: lint-web
[failure] 7-7:
@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-previewimport should occur before import of@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview