fix: Respect move policy in sidebar drag and drop (#13150)

Drop targets that reorder or reparent an item now require the `move`
ability on the dragged item, so no drop cursor or highlight appears
where the move would be rejected by the server.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-07-26 18:51:54 -04:00
committed by GitHub
co-authored by Claude
parent 17452bda5b
commit 053a3fd438
3 changed files with 12 additions and 10 deletions
@@ -23,7 +23,7 @@ import Text from "@shared/components/Text";
import usePolicy from "~/hooks/usePolicy";
function Collections() {
const { documents, auth, collections } = useStores();
const { documents, auth, collections, policies } = useStores();
const { t } = useTranslation();
const can = usePolicy(auth.team?.id);
const orderedCollections = collections.allActive;
@@ -46,10 +46,12 @@ function Collections() {
fractionalIndex(null, orderedCollections[0].index)
);
},
canDrop: (item) => item.id !== orderedCollections[0].id,
canDrop: (item) =>
item.id !== orderedCollections[0]?.id &&
!!policies.abilities(item.id).move,
collect: (monitor) => ({
isCollectionDropping: monitor.isOver(),
isDraggingAnyCollection: monitor.getItemType() === "collection",
isDraggingAnyCollection: monitor.canDrop(),
}),
});
@@ -58,7 +58,7 @@ function DraggableCollectionLink({
canDrop: (item) =>
collection.id !== item.id &&
(!belowCollection || item.id !== belowCollection.id) &&
policies.abilities(item.id)?.move,
!!policies.abilities(item.id).move,
collect: (monitor: DropTargetMonitor<Collection, Collection>) => ({
isCollectionDropping: monitor.isOver(),
isDraggingAnyCollection: monitor.canDrop(),
@@ -226,7 +226,7 @@ export function useDropToChangeCollection(
parentRef: React.RefObject<HTMLDivElement>
) {
const { t } = useTranslation();
const { documents, collections, dialogs } = useStores();
const { documents, collections, dialogs, policies } = useStores();
const can = usePolicy(collection);
const startHover = useHover(parentRef, expandNode);
@@ -281,7 +281,7 @@ export function useDropToChangeCollection(
}
}
},
canDrop: () => can.createDocument,
canDrop: (item) => can.createDocument && !!policies.abilities(item.id).move,
hover: (_, monitor) => {
if (
collection.hasDocuments &&
@@ -311,7 +311,7 @@ export function useDropToReparentDocument(
parentRef: React.RefObject<HTMLDivElement>
) {
const { t } = useTranslation();
const { documents, collections, dialogs } = useStores();
const { documents, collections, dialogs, policies } = useStores();
const hasChildDocuments = !!node?.children.length;
const document = node ? documents.get(node.id) : undefined;
const pathToNode = React.useMemo(
@@ -373,7 +373,7 @@ export function useDropToReparentDocument(
}
},
canDrop: (item) => {
if (!node || item.id === node.id) {
if (!node || item.id === node.id || !policies.abilities(item.id).move) {
return false;
}
@@ -425,7 +425,7 @@ export function useDropToReorderDocument(
}
) {
const { t } = useTranslation();
const { documents, collections, dialogs } = useStores();
const { documents, collections, dialogs, policies } = useStores();
const document = documents.get(node.id);
@@ -435,7 +435,7 @@ export function useDropToReorderDocument(
if (item.id === node.id || (document && !document.isActive)) {
return false;
}
return true;
return !!policies.abilities(item.id).move;
},
drop: async (item) => {
if (!collection?.isManualSort && item.collectionId === collection?.id) {