diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index e24680e91f..00ecb3b4e0 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -904,6 +904,57 @@ class FileManager extends Plugin { return exists } + + async moveFileIsAllowed (src: string, dest: string) { + try { + src = this.normalize(src) + dest = this.normalize(dest) + src = this.limitPluginScope(src) + dest = this.limitPluginScope(dest) + await this._handleExists(src, `Cannot move ${src}. Path does not exist.`) + await this._handleExists(dest, `Cannot move content into ${dest}. Path does not exist.`) + await this._handleIsFile(src, `Cannot move ${src}. Path is not a file.`) + await this._handleIsDir(dest, `Cannot move content into ${dest}. Path is not directory.`) + const fileName = helper.extractNameFromKey(src) + + if (await this.exists(dest + '/' + fileName)) { + return false + } + return true + } catch (e) { + console.log(e) + return false + } + } + + async moveDirIsAllowed (src: string, dest: string) { + try { + src = this.normalize(src) + dest = this.normalize(dest) + src = this.limitPluginScope(src) + dest = this.limitPluginScope(dest) + await this._handleExists(src, `Cannot move ${src}. Path does not exist.`) + await this._handleExists(dest, `Cannot move content into ${dest}. Path does not exist.`) + await this._handleIsDir(src, `Cannot move ${src}. Path is not directory.`) + await this._handleIsDir(dest, `Cannot move content into ${dest}. Path is not directory.`) + const dirName = helper.extractNameFromKey(src) + const provider = this.fileProviderOf(src) + + if (await this.exists(dest + '/' + dirName) || src === dest) { + return false + } + + if (provider.isSubDirectory(src, dest)) { + this.call('notification', 'toast', recursivePasteToastMsg()) + return false + } + return true + } catch (e) { + console.log(e) + return false + } + } + /** * Moves a file to a new folder * @param {string} src path of the source file @@ -954,7 +1005,13 @@ class FileManager extends Plugin { if (await this.exists(dest + '/' + dirName) || src === dest) { throw createError({ code: 'EEXIST', message: `Cannot move ${src}. Folder already exists at destination ${dest}` }) } - await this.copyDir(src, dest, dirName) + const provider = this.fileProviderOf(src) + + if (provider.isSubDirectory(src, dest)) { + this.call('notification', 'toast', recursivePasteToastMsg()) + return false + } + await this.inDepthCopy(src, dest, dirName) await this.remove(src) } catch (e) { diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index cdc270f480..0554b0ffa7 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -73,6 +73,7 @@ "filePanel.features": "Features", "filePanel.upgradeability": "Upgradeability", "filePanel.ok": "OK", + "filePanel.yes": "Yes", "filePanel.cancel": "Cancel", "filePanel.createNewWorkspace": "create a new workspace", "filePanel.connectToLocalhost": "connect to localhost", @@ -115,6 +116,8 @@ "filePanel.validationErrorMsg": "Special characters are not allowed", "filePanel.reservedKeyword": "Reserved Keyword", "filePanel.reservedKeywordMsg": "File name contains Remix reserved keywords. \"{content}\"", + "filePanel.moveFile": "Moving files", + "filePanel.moveFileMsg1": "Are you sure you want to move {src} to {dest}?", "filePanel.movingFileFailed": "Moving File Failed", "filePanel.movingFileFailedMsg": "Unexpected error while moving file: {src}", "filePanel.movingFolderFailed": "Moving Folder Failed", diff --git a/libs/remix-ui/drag-n-drop/src/lib/drag-n-drop.tsx b/libs/remix-ui/drag-n-drop/src/lib/drag-n-drop.tsx index 6d991d9663..6427dbed12 100644 --- a/libs/remix-ui/drag-n-drop/src/lib/drag-n-drop.tsx +++ b/libs/remix-ui/drag-n-drop/src/lib/drag-n-drop.tsx @@ -27,6 +27,11 @@ export const Draggable = (props: DraggableType) => { destination = props.file, context = useContext(MoveContext) + // delay timer + const [timer, setTimer] = useState() + // folder to open + const [folderToOpen, setFolderToOpen] = useState() + const handleDrop = (event: React.DragEvent) => { event.preventDefault() @@ -50,8 +55,15 @@ export const Draggable = (props: DraggableType) => { const handleDragover = (event: React.DragEvent) => { //Checks if the folder is opened event.preventDefault() - if (destination.isDirectory && !props.expandedPath.includes(destination.path)) { - props.handleClickFolder(destination.path, destination.type) + if (destination.isDirectory && !props.expandedPath.includes(destination.path) && folderToOpen !== destination.path && props.handleClickFolder) { + setFolderToOpen(destination.path) + timer && clearTimeout(timer) + setTimer( + setTimeout(() => { + props.handleClickFolder(destination.path, destination.type) + setFolderToOpen(null) + }, 600) + ) } } @@ -75,7 +87,12 @@ export const Draggable = (props: DraggableType) => { onDrop={(event) => { handleDrop(event) }} - onDragStart={() => { + onDragStart={(event) => { + if (destination && destination.path === '/'){ + event.preventDefault() + event.stopPropagation + } else + if (destination) { handleDrag() } diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index e34b9db417..9b8691319d 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -514,3 +514,16 @@ export const moveFolder = async (src: string, dest: string) => { dispatch(displayPopUp('Oops! An error ocurred while performing moveDir operation.' + error)) } } + +export const moveFileIsAllowed = async (src: string, dest: string) => { + const fileManager = plugin.fileManager + const isAllowed = await fileManager.moveFileIsAllowed(src, dest) + return isAllowed +} + +export const moveFolderIsAllowed = async (src: string, dest: string) => { + const fileManager = plugin.fileManager + const isAllowed = await fileManager.moveDirIsAllowed(src, dest) + return isAllowed +} + diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx index 998d432f16..a11b5ccf41 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx @@ -111,7 +111,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => return groupedActions.map((groupItem, groupIndex) => groupItem.map((item, index) => { key++ - const className = `remixui_liitem ${group !== item.group ? 'border-top' : ''}` + const className = `px-3 remixui_liitem ${group !== item.group ? 'border-top' : ''}` group = item.group if (item.name === 'Upload File') { return ( diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx index 7dcc5cdf16..89d777f6fd 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx @@ -67,12 +67,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { return ( <> - - - {props.title} - - - + {state.menuItems.map(({action, title, icon, placement}, index) => { if (action === 'uploadFile') { return ( @@ -83,7 +78,13 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { tooltipText={} key={`index-${action}-${placement}-${icon}`} > -