From fb9fbd99939bdc1398af7d2dd5c1e1c7a498a1c7 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 20 May 2021 11:28:13 +0100 Subject: [PATCH] Implement folder copy --- apps/remix-ide/src/app/files/fileManager.js | 41 +++++++++++++++++-- apps/remix-ide/src/lib/helper.js | 5 +++ .../file-explorer/src/lib/file-explorer.tsx | 15 +++++-- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/apps/remix-ide/src/app/files/fileManager.js b/apps/remix-ide/src/app/files/fileManager.js index 65b34c9b80..79664f5799 100644 --- a/apps/remix-ide/src/app/files/fileManager.js +++ b/apps/remix-ide/src/app/files/fileManager.js @@ -22,7 +22,7 @@ const profile = { icon: 'assets/img/fileManager.webp', permission: true, version: packageJson.version, - methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile'], + methods: ['file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir', 'readdir', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile'], kind: 'file-system' } const errorMsg = { @@ -213,7 +213,7 @@ class FileManager extends Plugin { * @param {string} dest path of the destrination file * @returns {void} */ - async copyFile (src, dest) { + async copyFile (src, dest, customName) { try { src = this.limitPluginScope(src) dest = this.limitPluginScope(dest) @@ -222,7 +222,7 @@ class FileManager extends Plugin { await this._handleExists(dest, `Cannot paste content into ${dest}. Path does not exist.`) await this._handleIsDir(dest, `Cannot paste content into ${dest}. Path is not directory.`) const content = await this.readFile(src) - const copiedFileName = `/Copy_${src.split('/')[src.split('/').length - 1]}` + const copiedFileName = customName ? '/' + customName : '/' + `Copy_${helper.extractNameFromKey(src)}` await this.writeFile(dest + copiedFileName, content) } catch (e) { @@ -230,6 +230,41 @@ class FileManager extends Plugin { } } + /** + * Upsert a directory with the content of the source directory + * @param {string} src path of the source dir + * @param {string} dest path of the destination dir + * @returns {void} + */ + async copyDir (src, dest) { + try { + src = this.limitPluginScope(src) + dest = this.limitPluginScope(dest) + await this._handleExists(src, `Cannot copy from ${src}. Path does not exist.`) + await this._handleIsDir(src, `Cannot copy from ${src}. Path is not a directory.`) + await this._handleExists(dest, `Cannot paste content into ${dest}. Path does not exist.`) + await this._handleIsDir(dest, `Cannot paste content into ${dest}. Path is not directory.`) + await this.inDepthCopy(src, dest) + } catch (e) { + throw new Error(e) + } + } + + async inDepthCopy (src, dest, count = 0) { + const content = await this.readdir(src) + const copiedFolderPath = count === 0 ? dest + '/' + `Copy_${helper.extractNameFromKey(src)}` : dest + '/' + helper.extractNameFromKey(src) + + await this.mkdir(copiedFolderPath) + + for (const [key, value] of Object.entries(content)) { + if (!value.isDirectory) { + await this.copyFile(key, copiedFolderPath, helper.extractNameFromKey(key)) + } else { + await this.inDepthCopy(key, copiedFolderPath, count + 1) + } + } + } + /** * Change the path of a file/directory * @param {string} oldPath current path of the file/directory diff --git a/apps/remix-ide/src/lib/helper.js b/apps/remix-ide/src/lib/helper.js index 2d8bb19cfb..b910dccfb3 100644 --- a/apps/remix-ide/src/lib/helper.js +++ b/apps/remix-ide/src/lib/helper.js @@ -106,6 +106,11 @@ module.exports = { paths = paths.filter((value) => value !== '').map((path) => path.replace(/^\/|\/$/g, '')) // remove first and last slash) if (paths.length === 1) return paths[0] return paths.join('/') + }, + extractNameFromKey (key) { + const keyPath = key.split('/') + + return keyPath[keyPath.length - 1] } } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 91e26e7ddb..a176909b94 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -423,6 +423,16 @@ export const FileExplorer = (props: FileExplorerProps) => { } } + const copyFolder = (src: string, dest: string) => { + const fileManager = state.fileManager + + try { + fileManager.copyDir(src, dest) + } catch (error) { + console.log('Oops! An error ocurred while performing copyDir operation.' + error) + } + } + const publishToGist = (path?: string, type?: string) => { modal('Create a public gist', `Are you sure you want to anonymously publish all your files in the ${name} workspace as a public gist on github.com?`, 'OK', () => toGist(path, type), 'Cancel', () => {}) } @@ -745,14 +755,13 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, copyElement: [{ key: path, type }] } }) setCanPaste(true) - // TODO: Reset toaster text after timeout. - toast('Copied to clipboard') + toast(`Copied to clipboard ${path}`) } const handlePasteClick = (dest: string, destType: string) => { dest = destType === 'file' ? extractParentFromKey(dest) || props.name : dest state.copyElement.map(({ key, type }) => { - type === 'file' ? copyFile(key, dest) : copyFile(key, dest) + type === 'file' ? copyFile(key, dest) : copyFolder(key, dest) }) setState(prevState => { return { ...prevState, copyElement: [] }