refactor: replace unstable tree view dnd hook

This commit is contained in:
2025-08-10 01:12:55 -06:00
parent c045e1dd30
commit d040b4c742

View File

@@ -20,9 +20,6 @@ import {
TreeItem, TreeItem,
useTreeViewApiRef useTreeViewApiRef
} from "@mui/x-tree-view"; } from "@mui/x-tree-view";
import {
unstable_useTreeViewDragAndDrop as useTreeViewDragAndDrop
} from "@mui/x-tree-view/internals";
import { RenameWorkflowDialog, RenameFolderDialog } from "./Dialogs"; import { RenameWorkflowDialog, RenameFolderDialog } from "./Dialogs";
function buildTree(workflows) { function buildTree(workflows) {
@@ -71,26 +68,28 @@ export default function WorkflowList({ onOpenWorkflow }) {
const [renameOpen, setRenameOpen] = useState(false); const [renameOpen, setRenameOpen] = useState(false);
const [renameFolderOpen, setRenameFolderOpen] = useState(false); const [renameFolderOpen, setRenameFolderOpen] = useState(false);
const apiRef = useTreeViewApiRef(); const apiRef = useTreeViewApiRef();
const [dragNode, setDragNode] = useState(null);
useTreeViewDragAndDrop(apiRef, { const handleDrop = async (target) => {
onItemDrop: async (params) => { if (!dragNode || !target.isFolder) return;
const source = nodeMap[params.dragItemId]; // Prevent dropping into itself or its descendants
const target = nodeMap[params.dropTargetId]; if (dragNode.path === target.path || target.path.startsWith(`${dragNode.path}/`)) {
if (source && target && !source.isFolder && target.isFolder) { setDragNode(null);
const newPath = `${target.path}/${source.fileName}`; return;
try {
await fetch("/api/storage/move_workflow", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: source.path, new_path: newPath })
});
loadTree();
} catch (err) {
console.error("Failed to move workflow:", err);
}
}
} }
}); const newPath = target.path ? `${target.path}/${dragNode.fileName}` : dragNode.fileName;
try {
await fetch("/api/storage/move_workflow", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ path: dragNode.path, new_path: newPath })
});
loadTree();
} catch (err) {
console.error("Failed to move workflow:", err);
}
setDragNode(null);
};
const loadTree = useCallback(async () => { const loadTree = useCallback(async () => {
try { try {
@@ -200,7 +199,18 @@ export default function WorkflowList({ onOpenWorkflow }) {
key={n.id} key={n.id}
itemId={n.id} itemId={n.id}
label={ label={
<Box sx={{ display: "flex", alignItems: "center" }}> <Box
sx={{ display: "flex", alignItems: "center" }}
draggable={!n.isFolder}
onDragStart={() => !n.isFolder && setDragNode(n)}
onDragOver={(e) => {
if (dragNode && n.isFolder) e.preventDefault();
}}
onDrop={(e) => {
e.preventDefault();
handleDrop(n);
}}
>
{n.isFolder ? ( {n.isFolder ? (
<FolderIcon sx={{ mr: 1, color: "#ffd54f" }} /> <FolderIcon sx={{ mr: 1, color: "#ffd54f" }} />
) : ( ) : (
@@ -276,7 +286,16 @@ export default function WorkflowList({ onOpenWorkflow }) {
</Button> </Button>
</Box> </Box>
</Box> </Box>
<Box sx={{ p: 2 }}> <Box
sx={{ p: 2 }}
onDragOver={(e) => {
if (dragNode) e.preventDefault();
}}
onDrop={(e) => {
e.preventDefault();
handleDrop({ path: "", isFolder: true });
}}
>
<SimpleTreeView <SimpleTreeView
sx={{ color: "#e6edf3" }} sx={{ color: "#e6edf3" }}
onNodeSelect={handleNodeSelect} onNodeSelect={handleNodeSelect}