-
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 2 commits
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,17 @@ | |||||||||
| 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 { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview"; | ||||||||||
| import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview"; | ||||||||||
|
|
||||||||||
| import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; | ||||||||||
| import orderBy from "lodash/orderBy"; | ||||||||||
| import uniqBy from "lodash/uniqBy"; | ||||||||||
| import { useParams } from "next/navigation"; | ||||||||||
| import { createRoot } from "react-dom/client"; | ||||||||||
| import { PenSquare, Star, MoreHorizontal, ChevronRight, GripVertical } from "lucide-react"; | ||||||||||
| import { Disclosure, Transition } from "@headlessui/react"; | ||||||||||
|
|
||||||||||
| // plane helpers | ||||||||||
| import { useOutsideClickDetector } from "@plane/helpers"; | ||||||||||
| // ui | ||||||||||
|
|
@@ -30,15 +35,16 @@ type Props = { | |||||||||
| 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); | ||||||||||
|
|
@@ -51,10 +57,10 @@ export const FavoriteFolder: React.FC<Props> = (props) => { | |||||||||
| const actionSectionRef = useRef<HTMLDivElement | null>(null); | ||||||||||
| const elementRef = useRef<HTMLDivElement | null>(null); | ||||||||||
|
|
||||||||||
| !favorite.children && getGroupedFavorites(workspaceSlug.toString(), favorite.id); | ||||||||||
| if(!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
|
||||||||||
| if(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,12 +3,17 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 { pointerOutsideOfPreview } from "@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { observer } from "mobx-react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // plane helpers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { createRoot } from "react-dom/client"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useOutsideClickDetector } from "@plane/helpers"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ui | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IFavorite } from "@plane/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // components | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { DropIndicator } from "@plane/ui"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FavoriteItemDragHandle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FavoriteItemQuickAction, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -19,66 +24,126 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useAppTheme } from "@/hooks/store"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useFavoriteItemDetails } from "@/hooks/use-favorite-item-details"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| //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; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!sourceId) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(destinationType === 'NON_PARENT'){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRemoveFromFavoritesFolder(sourceId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -90,6 +155,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 +167,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
Add error handling for grouped favorites fetch
The conditional fetch should include error handling to gracefully handle failures.