fix move folder/file bug

This commit is contained in:
Weixuan Fu
2024-02-26 21:30:55 +08:00
parent 6663acca54
commit a5662f9ea3
9 changed files with 228 additions and 78 deletions
+1
View File
@@ -6,6 +6,7 @@ from aiohttp import web
import json
import uuid
from pathlib import Path
from .twoway_sync_folder_service import *
@server.PromptServer.instance.routes.post('/workspace/create_workflow_file')
async def create_workflow_file(request):
+66
View File
@@ -0,0 +1,66 @@
import asyncio
import shutil
from aiohttp import web
import os
from pathlib import Path
import server
@server.PromptServer.instance.routes.post('/workspace/folder/create')
async def create_folder(request):
reqJson = await request.json()
data = await asyncio.to_thread(create_folder_sync, reqJson)
return web.json_response(data, content_type='application/json')
def create_folder_sync(reqJson):
folder_path = reqJson.get('path')
try:
Path(folder_path).mkdir(parents=True, exist_ok=True)
return {"success": True}
except Exception as e:
return {"success": False, "error": str(e)}
@server.PromptServer.instance.routes.post('/workspace/folder/delete')
async def delete_folder(request):
reqJson = await request.json()
data = await asyncio.to_thread(delete_folder_sync, reqJson)
return web.json_response(data, content_type='application/json')
def delete_folder_sync(reqJson):
folder_path = reqJson.get('path')
try:
shutil.rmtree(folder_path)
return {"success": True}
except Exception as e:
return {"success": False, "error": str(e)}
@server.PromptServer.instance.routes.post('/workspace/folder/rename')
async def rename_folder(request):
reqJson = await request.json()
data = await asyncio.to_thread(rename_folder_sync, reqJson)
return web.json_response(data, content_type='application/json')
def rename_folder_sync(reqJson):
current_path = reqJson.get('absPath')
new_name = reqJson.get('newName')
try:
new_path = Path(current_path).parent / new_name
Path(current_path).rename(new_path)
return {"success": True}
except Exception as e:
return {"success": False, "error": str(e)}
@server.PromptServer.instance.routes.post('/workspace/folder/move')
async def move_folder(request):
reqJson = await request.json()
data = await asyncio.to_thread(move_folder_sync, reqJson)
return web.json_response(data, content_type='application/json')
def move_folder_sync(reqJson):
print("🍻Move folder:", reqJson)
current_path = reqJson.get('folder')
new_path = reqJson.get('newParentPath')
try:
shutil.move(current_path, new_path)
return {"success": True}
except Exception as e:
return {"success": False, "error": str(e)}
@@ -75,6 +75,10 @@ export default memo(function FilesListFolderItem({ folder }: Props) {
setIsActive(false);
};
useEffect(() => {
if (!isCollapsed) {
console.log("folder.unisCollapse", folder);
}
if (!!folder.isCollapse === isCollapsed) return;
foldersTable?.update(folder.id, {
isCollapse: isCollapsed,
+2 -6
View File
@@ -1,8 +1,5 @@
import { updateFile } from "../Api";
import {
COMFYSPACE_TRACKING_FIELD_NAME,
LEGACY_COMFYSPACE_TRACKING_FIELD_NAME,
} from "../const";
import { COMFYSPACE_TRACKING_FIELD_NAME } from "../const";
import { userSettingsTable } from "../db-tables/WorkspaceDB";
import { indexdb } from "../db-tables/indexdb";
import { Workflow } from "../types/dbTypes";
@@ -181,11 +178,10 @@ export async function scanLocalFiles(
"Content-Type": "application/json",
},
body: JSON.stringify({
path,
path: sanitizeAbsPath(path),
}),
});
const result = await response.json();
console.log("scanLocalNewFiles", result);
return result;
} catch (error) {
console.error("Error scan local new files:", error);
+110
View File
@@ -0,0 +1,110 @@
import { userSettingsTable } from "../db-tables/WorkspaceDB";
import { Folder } from "../types/dbTypes";
import { sanitizeAbsPath, sanitizeRelPath } from "../utils/OsPathUtils";
export namespace TwowayFolderSyncAPI {
export async function genFolderRelPath({
parentFolderID,
name,
}: {
parentFolderID: string | null;
name: string;
}): Promise<string> {
return sanitizeRelPath(`${parentFolderID ?? ""}/${name}`);
}
export async function genFolderAbsPath({
parentFolderID,
name,
}: Folder): Promise<string> {
const myWorkflowsDir =
await userSettingsTable?.getSetting("myWorkflowsDir");
const absPath = sanitizeAbsPath(
`${myWorkflowsDir}/${parentFolderID ?? ""}/${name}`,
);
return absPath;
}
export async function genAbsPathByRelPath(relPath: string): Promise<string> {
const myWorkflowsDir =
await userSettingsTable?.getSetting("myWorkflowsDir");
const absPath = sanitizeAbsPath(`${myWorkflowsDir}/${relPath}`);
return absPath;
}
export async function createFolder(folder: Folder) {
console.log("🥳savecreateFolder", folder);
const abs = await genFolderAbsPath(folder);
await fetch("/workspace/folder/create", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
path: abs,
}),
});
}
export async function moveFolder(
folderToBeMoved: string,
newParentPath: string,
) {
console.log("🥳moveFolder", folderToBeMoved, newParentPath);
const absPath = await genAbsPathByRelPath(folderToBeMoved);
const absNewParentPath = await genAbsPathByRelPath(newParentPath);
const resp = await fetch("/workspace/folder/move", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
folder: absPath,
newParentPath: absNewParentPath,
}),
});
const result = await resp.json();
if (result.error) {
alert("Failed to move folder: " + result.error);
}
return;
}
export async function deleteFolder(folder: Folder) {
const absPath = await genFolderAbsPath(folder);
try {
const response = await fetch("/workspace/folder/delete", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
path: absPath,
}),
});
const result = await response.text();
return result;
} catch (error) {
console.error("Error deleting file:", error);
}
}
export async function renameFolder(
folderRelPath: string,
newName: string,
): Promise<void> {
const oldAbsPath = await genAbsPathByRelPath(folderRelPath);
try {
const response = await fetch("/workspace/folder/rename", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
absPath: oldAbsPath,
newName: newName,
}),
});
const result = await response.json();
if (result.error) {
alert("Failed to rename folder: " + result.error);
}
} catch (error) {
console.error("Error renaming file:", error);
}
}
}
+1
View File
@@ -33,6 +33,7 @@ export async function deleteJsonFileMyWorkflows(workflow: Workflow) {
return;
}
const file_path = await generateFilePath(workflow);
console.log("deleteJsonFileMyWorkflows", file_path);
file_path != null && deleteFile(file_path);
}
+17 -65
View File
@@ -1,11 +1,12 @@
import { deleteLocalDiskFolder } from "../Api";
import { workflowsTable } from "./WorkspaceDB";
import { userSettingsTable, workflowsTable } from "./WorkspaceDB";
import { EFlowOperationType, Folder } from "../types/dbTypes";
import { validateOrSaveAllJsonFileMyWorkflows } from "../utils";
import { v4 as uuidv4 } from "uuid";
import { TableBase } from "./TableBase";
import { indexdb } from "./indexdb";
import { generateFolderPath } from "./DiskFileUtils";
import { TwowayFolderSyncAPI } from "../apis/TwowaySyncFolderApi";
export class FoldersTable extends TableBase<Folder> {
static readonly TABLE_NAME = "folders";
@@ -37,10 +38,23 @@ export class FoldersTable extends TableBase<Folder> {
};
await indexdb.folders.add(folder);
this.saveDiskDB();
if (await userSettingsTable?.getSetting("twoWaySync")) {
await TwowayFolderSyncAPI.createFolder(folder);
}
return folder;
}
public async update(id: string, input: Partial<Folder>) {
const twoWaySyncEnabled = await userSettingsTable?.getSetting("twoWaySync");
if (twoWaySyncEnabled) {
if ("parentFolderID" in input) {
await TwowayFolderSyncAPI.moveFolder(id, input["parentFolderID"] ?? "");
}
if ("name" in input) {
await TwowayFolderSyncAPI.renameFolder(id, input["name"] ?? "");
}
return null;
}
const folder = await this.get(id);
if (folder == null) {
return null;
@@ -75,8 +89,7 @@ export class FoldersTable extends TableBase<Folder> {
id: string,
flowOperationType: EFlowOperationType = EFlowOperationType.DELETE,
) {
const folderPath = await generateFolderPath(id);
const folder = await indexdb.folders.get(id);
/**
* When deleting a folder, if there are files in the folder
* Breadth traverse all nested folders, find all files, move to root directory or delete as needed.
@@ -115,7 +128,7 @@ export class FoldersTable extends TableBase<Folder> {
}
}
folderPath && (await deleteLocalDiskFolder(folderPath));
folder && (await TwowayFolderSyncAPI.deleteFolder(folder));
this.saveDiskDB();
}
@@ -138,65 +151,4 @@ export class FoldersTable extends TableBase<Folder> {
}
return newFlowName;
}
public async genRelativePath(id: string): Promise<string | null> {
let currentFolderId: string | null | undefined = id;
const pathSegments: string[] = [];
while (currentFolderId != null) {
const folder = await this.get(currentFolderId);
if (!folder) {
console.error(`Folder with ID <${currentFolderId}> not found`);
return null;
}
// Prepend the current folder name to the path segments
pathSegments.unshift(folder.name);
// Move up to the parent folder for the next iteration
currentFolderId = folder.parentFolderID;
}
return pathSegments.join("/");
}
// given a relative path, create the folder structure if not exist, and return the folder
public async putWithRelativePath(
relativePath: string,
): Promise<Folder | null> {
console.log("putWithRelativePath", relativePath);
if (relativePath === "") {
// root folder
return null;
}
const pathSegments = relativePath.split("/");
let parentFolderID: string | null = null;
let folder: Folder | null = null;
for (const name of pathSegments) {
if (name === "") {
console.warn('Invalid folder name "" in path', relativePath);
continue;
}
folder =
(await indexdb.folders
.where({ name })
.filter((f) => {
return f.parentFolderID == parentFolderID;
})
.first()) ?? null;
if (folder == null) {
const newFolder = await this.add({
name,
parentFolderID,
updateTime: Date.now(),
type: "folder",
});
folder = (await this.get(newFolder.id)) ?? null;
}
if (folder == null) {
console.error("Failed to create folder", name);
throw new Error("Failed to create folder");
}
parentFolderID = folder.id;
}
return folder;
}
}
+18 -3
View File
@@ -184,11 +184,12 @@ export class WorkflowsTable extends TableBase<Workflow> {
const twoWaySyncEnabled =
await userSettingsTable?.getSetting("twoWaySync");
// renamed file or moved file folder
await deleteJsonFileMyWorkflows(before);
if (twoWaySyncEnabled) {
await TwowaySyncAPI.saveWorkflow(after);
await TwowaySyncAPI.deleteWorkflow(before);
} else {
await saveJsonFileMyWorkflows(after);
await deleteJsonFileMyWorkflows(before);
}
return;
}
@@ -237,8 +238,15 @@ export class WorkflowsTable extends TableBase<Workflow> {
public async deleteFlow(id: string) {
const workflow = await this.get(id);
if (workflow) {
deleteJsonFileMyWorkflows({ ...workflow });
const twoWaySyncEnabled =
await userSettingsTable?.getSetting("twoWaySync");
if (twoWaySyncEnabled) {
await TwowaySyncAPI.deleteWorkflow(workflow);
} else {
deleteJsonFileMyWorkflows({ ...workflow });
}
}
//add to IndexDB
await indexdb.workflows.delete(id);
@@ -248,7 +256,14 @@ export class WorkflowsTable extends TableBase<Workflow> {
public async batchDeleteFlow(ids: string[]) {
const workflowList = (await indexdb.workflows.bulkGet(ids)) as Workflow[];
for (const flow of workflowList) {
flow && (await deleteJsonFileMyWorkflows(flow));
if (!flow) return;
const twoWaySyncEnabled =
await userSettingsTable?.getSetting("twoWaySync");
if (twoWaySyncEnabled) {
await TwowaySyncAPI.deleteWorkflow(flow);
} else {
deleteJsonFileMyWorkflows({ ...flow });
}
}
await indexdb.workflows.bulkDelete(ids);
this.saveDiskDB();
+9 -4
View File
@@ -1,3 +1,4 @@
import { ESortTypes } from "../RecentFilesDrawer/types";
import {
ScanLocalFile,
ScanLocalFolder,
@@ -6,10 +7,12 @@ import {
import { isFolder, userSettingsTable } from "../db-tables/WorkspaceDB";
import { indexdb } from "../db-tables/indexdb";
import { Folder, Workflow } from "../types/dbTypes";
import { sortFileItem } from "../utils";
import { sanitizeAbsPath } from "./OsPathUtils";
export async function scanMyWorkflowsDir(
parentFolderID: string | null,
sortBy?: ESortTypes,
): Promise<(Workflow | Folder)[]> {
const myWorkflowsDir = await userSettingsTable?.getSetting("myWorkflowsDir");
if (myWorkflowsDir == null || myWorkflowsDir === "") {
@@ -30,9 +33,9 @@ export async function scanMyWorkflowsDir(
if (scanFileIsFolder(file)) {
// is folder
const folder: Folder = {
id: file.name,
id: relPath,
name: file.name,
parentFolderID: relPath,
parentFolderID: parentRelPath,
type: "folder",
createTime: Date.now(),
updateTime: Date.now(),
@@ -49,7 +52,8 @@ export async function scanMyWorkflowsDir(
...existingWorkflow,
id: file.id,
filePath: absPath,
json: "{}", //we don't need to load json data for file list display
lastSavedJson: file.json ?? "{}",
json: file.json ?? "{}",
name: fileName.replace(".json", ""),
parentFolderID: parentRelPath,
};
@@ -61,7 +65,8 @@ export async function scanMyWorkflowsDir(
indexdb.workflows.bulkPut(
result.filter((item) => !isFolder(item)) as Workflow[],
);
return result.filter((item) => item != null) as (Workflow | Folder)[];
const all = result.filter((item) => item != null) as (Workflow | Folder)[];
return sortFileItem(all, sortBy ?? ESortTypes.RECENTLY_MODIFIED);
}
function scanFileIsFolder(
scanFile: ScanLocalFile | ScanLocalFolder,