Fix: persist folder drag and drop moves

This commit is contained in:
MangoPig
2026-06-24 17:59:43 +01:00
parent a92e188f84
commit 9ddfa0c3c7
6 changed files with 578 additions and 6 deletions
@@ -58,6 +58,7 @@ type ProjectFoldersResponse = {
data?: {
folders?: PersistedProjectFolderRecord[];
renamedFolder?: PersistedProjectFolderRecord;
movedFolder?: PersistedProjectFolderRecord;
previousFolderId?: string;
};
error?: string;
@@ -574,9 +575,27 @@ export const ProjectSelector = (props: ProjectSelectorProps): JSX.Element => {
}
suppressTreeClickTemporarily();
setProjectTreeNodes((current) =>
moveTreeNode(current, nextDragState.draggedNodeId, nextDragState.dropTarget as ProjectDragTarget, projectTreeAdapter),
);
const currentNodes = projectTreeNodes();
const draggedLocation = findTreeNodeLocation(currentNodes, nextDragState.draggedNodeId, projectTreeAdapter);
const persistedParentId = nextDragState.dropTarget.parentId;
const canPersistMove = isUuidString(selectedProject().id);
const persistedParentLocation = persistedParentId
? findTreeNodeLocation(currentNodes, persistedParentId, projectTreeAdapter)
: null;
if (
canPersistMove &&
draggedLocation?.node.kind === "folder" &&
(persistedParentId === null || persistedParentLocation?.node.kind === "folder")
) {
void movePersistedFolder(draggedLocation.node.id, persistedParentId);
} else {
setProjectTreeNodes((current) =>
moveTreeNode(current, nextDragState.draggedNodeId, nextDragState.dropTarget as ProjectDragTarget, projectTreeAdapter),
);
}
setDragState(null);
};
@@ -732,6 +751,45 @@ export const ProjectSelector = (props: ProjectSelectorProps): JSX.Element => {
}
};
const movePersistedFolder = async (folderId: string, parentFolderId: string | null): Promise<void> => {
const projectId = selectedProject().id;
if (!folderId || !isUuidString(projectId)) {
return;
}
try {
const response = await fetch(`${resolveAPIBase()}/projects/${projectId}/folders/move`, {
method: "PATCH",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
folderId,
parentFolderId,
}),
});
const body = (await response.json()) as ProjectFoldersResponse;
if (!response.ok) {
throw new Error(body.message || "Failed to move project folder.");
}
setPersistedFolders(readPersistedFolders(body));
const previousFolderId = body.data?.previousFolderId;
const movedFolderId = body.data?.movedFolder?.id;
if (previousFolderId && movedFolderId && previousFolderId !== movedFolderId) {
setCollapsedFolderIds((current) =>
current.map((id) => (id === previousFolderId ? movedFolderId : id)),
);
}
} catch (error) {
console.error(error);
}
};
const submitPendingFolderRename = async (): Promise<void> => {
const draft = pendingFolderRename();
const name = pendingFolderRenameName().trim();