fix move folder/file bug
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user