diff --git a/libs/remix-lib/src/eventManager.ts b/libs/remix-lib/src/eventManager.ts index 7acff32cc2..1c3bdd760f 100644 --- a/libs/remix-lib/src/eventManager.ts +++ b/libs/remix-lib/src/eventManager.ts @@ -26,7 +26,7 @@ export class EventManager { obj = this.anonymous } for (const reg in this.registered[eventName]) { - if (this.registered[eventName][reg].obj === obj && this.registered[eventName][reg].func === func) { + if ((this.registered[eventName][reg].obj.toString() === obj.toString()) && (this.registered[eventName][reg].func.toString() === func.toString())) { this.registered[eventName].splice(reg, 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 d4184671ca..5b9d7bc062 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line -import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line +// import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line @@ -40,7 +40,6 @@ export const FileExplorer = (props: FileExplorerProps) => { isNew: false, lastEdit: '' }, - fileExternallyChanged: false, expandPath: [], modalOptions: { hide: true, @@ -95,14 +94,47 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { if (state.fileManager) { - props.filesProvider.event.register('fileAdded', fileAdded) + props.filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) + props.filesProvider.event.register('fileRenamedError', fileRenamedError) } }, [state.fileManager]) + useEffect(() => { + const { expandPath } = state + + if (expandPath && expandPath.length > 0) { + expandPath.map(async (path, index) => { + console.log('path ' + index + ' :', path) + const files = await resolveDirectory(path, state.files) + + setState(prevState => { + return { ...prevState, files } + }) + }) + if (props.filesProvider.event.registered.fileAdded) { + // unregister event to update state in callback + props.filesProvider.event.unregister('fileAdded', fileAdded) + } + props.filesProvider.event.register('fileAdded', fileAdded) + } + }, [state.expandPath]) + const resolveDirectory = async (folderPath, dir: File[]): Promise => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { - file.child = await fetchDirectoryContent(folderPath) + if (file.child) { + const newInput = file.child.filter(({ path }) => path === 'browser/blank') + + if (newInput.length === 1) { + const dirContent = await fetchDirectoryContent(folderPath) + + file.child = newInput[0].isDirectory ? [...newInput, ...dirContent] : [...dirContent, ...newInput] + } else { + file.child = await fetchDirectoryContent(folderPath) + } + } else { + file.child = await fetchDirectoryContent(folderPath) + } return file } else if (file.child) { file.child = await resolveDirectory(folderPath, file.child) @@ -413,32 +445,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - // props.files.event.register('fileExternallyChanged', (path, file) => { - // if (self._deps.config.get('currentFile') === path && self._deps.editor.currentContent() && self._deps.editor.currentContent() !== file.content) { - // if (this.files.isReadOnly(path)) return self._deps.editor.setText(file.content) - - // modalDialog(path + ' changed', remixdDialog(), - // { - // label: 'Replace by the new content', - // fn: () => { - // self._deps.editor.setText(file.content) - // } - // }, - // { - // label: 'Keep the content displayed in Remix', - // fn: () => {} - // } - // ) - // } - // }) - - // register to event of the file provider - // files.event.register('fileRemoved', fileRemoved) - // files.event.register('fileRenamed', fileRenamed) - // props.filesProvider.event.register('fileRenamedError', (error) => { - // // modalDialogCustom.alert(error) - // }) - const fileAdded = async (filePath: string) => { const pathArr = filePath.split('/') const hasChild = pathArr.length > 2 @@ -446,33 +452,23 @@ export const FileExplorer = (props: FileExplorerProps) => { if (hasChild) { const expandPath = pathArr.map((path, index) => { return [...pathArr.slice(0, index)].join('/') - }).filter(path => path && (path !== name)) + }).filter(path => path && (path !== props.name)) + const pathExist = state.files.findIndex(item => item.path === expandPath[0]) !== -1 - if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { + if (!pathExist) { const dir = buildTree(expandPath) - let files = [dir, ...state.files] + const files = [dir, ...state.files] - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) setState(prevState => { - return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] + + return { ...prevState, files, expandPath: uniquePaths } }) } else { - if (state.expandPath.findIndex(path => path === expandPath[expandPath.length - 1]) !== -1) return - const dir = state.files.find(item => item.path === expandPath[0]) - let files = [{ - ...dir, - child: [...(await fetchDirectoryContent(dir.path))] - }, ...state.files.filter(item => item.path !== expandPath[0])] - - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) - const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] - setState(prevState => { - return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } + const uniquePaths = [...new Set([...expandPath])] + + return { ...prevState, expandPath: uniquePaths } }) } } else { @@ -482,46 +478,32 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - // props.filesProvider.event.register('folderAdded', async (folderpath: string) => { - // const pathArr = folderpath.split('/') - // const hasChild = pathArr.length > 2 - - // if (hasChild) { - // const expandPath = pathArr.map((path, index) => { - // return [...pathArr.slice(0, index)].join('/') - // }).filter(path => path && (path !== name)) - - // if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { - // const dir = buildTree(expandPath) - // let files = [dir, ...state.files] - - // await Promise.all(expandPath.map(async path => { - // files = await resolveDirectory(path, files) - // })) - // setState(prevState => { - // return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } - // }) - // } else { - // if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return - // const dir = state.files.find(item => item.path === expandPath[0]) - // let files = [{ - // ...dir, - // child: [...(await fetchDirectoryContent(dir.path))] - // }, ...state.files.filter(item => item.path !== expandPath[0])] - - // await Promise.all(expandPath.map(async path => { - // files = await resolveDirectory(path, files) - // })) - // const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] - - // setState(prevState => { - // return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } - // }) - // } - // } else { - // addFolder(pathArr[0], folderpath) - // } - // }) + const fileExternallyChanged = (path: string, file: { content: string }) => { + const config = registry.get('config').api + + if (config.get('currentFile') === path && registry.editor.currentContent() && registry.editor.currentContent() !== file.content) { + if (filesProvider.isReadOnly(path)) return registry.editor.setText(file.content) + modal(path + ' changed', 'This file has been changed outside of Remix IDE.', { + label: 'Replace by the new content', + fn: () => { + registry.editor.setText(file.content) + } + }, { + label: 'Keep the content displayed in Remix', + fn: () => {} + }) + } + } + + // register to event of the file provider + // files.event.register('fileRemoved', fileRemoved) + // files.event.register('fileRenamed', fileRenamed) + const fileRenamedError = (error: string) => { + modal('File Renamed Failed', error, { + label: 'Close', + fn: () => {} + }, null) + } const uploadFile = (target) => { // TODO The file explorer is merely a view on the current state of @@ -738,17 +720,16 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } } else { - const files = await resolveDirectory(path, state.files) let expandPath = [] if (!state.expandPath.includes(path)) { - expandPath = [...state.expandPath, path] + expandPath = [...new Set([...state.expandPath, path])] } else { - expandPath = state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)) + expandPath = [...new Set(state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)))] } setState(prevState => { - return { ...prevState, focusElement: [{ key: path, type: 'folder' }], files, expandPath } + return { ...prevState, focusElement: [{ key: path, type: 'folder' }], expandPath } }) } } @@ -834,7 +815,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleNewFileInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name let files = await resolveDirectory(parentFolder, state.files) - const expandPath = [...state.expandPath, parentFolder] + const expandPath = [...new Set([...state.expandPath, parentFolder])] files = addEmptyFile(parentFolder, files) setState(prevState => { @@ -847,7 +828,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name else if ((parentFolder.indexOf('.sol') !== -1) || (parentFolder.indexOf('.js') !== -1)) parentFolder = extractParentFromKey(parentFolder) let files = await resolveDirectory(parentFolder, state.files) - const expandPath = [...state.expandPath, parentFolder] + const expandPath = [...new Set([...state.expandPath, parentFolder])] files = addEmptyFolder(parentFolder, state.files) setState(prevState => { @@ -863,11 +844,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - // warn if file changed outside of Remix - const remixdDialog = () => { - return
This file has been changed outside of Remix IDE.
- } - const label = (file: File) => { return (
{
{ @@ -958,7 +934,7 @@ export const FileExplorer = (props: FileExplorerProps) => { e.stopPropagation() handleContextMenuFile(e.pageX, e.pageY, file.path, e.target.textContent) }} - icon='fa fa-file' + icon='far fa-file' labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } /> { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) &&