🐛(front) improve drag-and-drop validation

Enhanced the drag-and-drop functionality by adding a check to prevent
dropping an item into its own children, ensuring a more intuitive user
experience. Updated the logic for determining if a folder has loaded
children based on the number of child folders and existing children.
Additionally, refined the conditions for allowing drops in the
ExplorerTree component, improving overall usability and consistency in
item management.
This commit is contained in:
Nathan Panchout
2025-05-05 10:08:32 +02:00
parent 24e6cb2c1b
commit 3eecb4de2a
4 changed files with 19 additions and 7 deletions
@@ -237,6 +237,11 @@ export const canDrop = (activeItem: Item, overItem: Item | TreeItem) => {
const activePathSegments = activePath.split(".");
const overPathSegments = overPath.split(".");
// Cannot drop an item into its children
if (overPath.startsWith(activePath)) {
return false;
}
if (activePathSegments.length === 1 && overPathSegments.length === 1) {
return activePathSegments[0] === overPathSegments[0];
}
@@ -97,14 +97,17 @@ export const ExplorerGrid = (props: ExplorerProps) => {
...folder,
children: children,
});
item.hasLoadedChildren = true;
item.hasLoadedChildren =
folder.numchild_folder !== undefined &&
folder.numchild_folder > 0 &&
children.length > 0;
return item;
} else {
const children = itemToTreeItem({
...folder,
children: [],
});
children.hasLoadedChildren = false;
return children;
}
});
@@ -21,6 +21,7 @@ import { ExplorerTreeNav } from "./nav/ExplorerTreeNav";
import { addItemsMovedToast } from "../toasts/addItemsMovedToast";
import { ExplorerTreeMoveConfirmationModal } from "./ExplorerTreeMoveConfirmationModal";
import { ExplorerSearchModal } from "../modals/search/ExplorerSearchModal";
import { canDrop } from "../ExplorerDndProvider";
export const ExplorerTree = () => {
const { t, i18n } = useTranslation();
@@ -237,15 +238,13 @@ export const ExplorerTree = () => {
}}
canDrop={(args) => {
const parent = args.parentNode?.data.value as Item | undefined;
const canDropOnParent = parent?.abilities.children_create ?? false;
const activeItem = args.dragNodes[0].data.value as Item;
const canDropActiveItem = activeItem.abilities.move;
const canDropItem = canDropOnParent && canDropActiveItem;
const canDropResult = parent ? canDrop(activeItem, parent) : true;
return (
args.index === 0 &&
args.parentNode?.willReceiveDrop === true &&
canDropItem
canDropResult
);
}}
renderNode={ExplorerTreeItem}
@@ -11,6 +11,7 @@ import { FileUploadMeta } from "../components/ExplorerInner";
import { ToasterItem } from "@/features/ui/components/toaster/Toaster";
import { addToast } from "@/features/ui/components/toaster/Toaster";
import { FileUploadToast } from "../components/toasts/FileUploadToast";
import { useQueryClient } from "@tanstack/react-query";
type FileUpload = FileWithPath & {
parentId?: string;
@@ -32,6 +33,7 @@ type Upload = {
const useUpload = ({ item }: { item: Item }) => {
const createFolder = useMutationCreateFolder();
const queryClient = useQueryClient();
/**
* TODO: Test.
@@ -129,6 +131,9 @@ const useUpload = ({ item }: { item: Item }) => {
},
{
onSuccess: async (createdFolder) => {
queryClient.invalidateQueries({
queryKey: ["items", parentItem.id],
});
folder.files.forEach((file) => {
file.parentId = createdFolder.id;
});
@@ -195,7 +200,7 @@ export const useUploadZone = ({ item }: { item: Item }) => {
<span className="material-icons">cloud_upload</span>
<span>
{t(
`explorer.actions.upload.toast${canUpload ? "_no_rights" : ""}`,
`explorer.actions.upload.toast${canUpload ? "" : "_no_rights"}`,
{
title: item?.title,
}