diff --git a/apps/remix-ide/src/app/files/workspaceFileProvider.js b/apps/remix-ide/src/app/files/workspaceFileProvider.js index 8f6b190668..5d7966afa4 100644 --- a/apps/remix-ide/src/app/files/workspaceFileProvider.js +++ b/apps/remix-ide/src/app/files/workspaceFileProvider.js @@ -81,16 +81,14 @@ class WorkspaceFileProvider extends FileProvider { } async createWorkspace (name) { - if (!name) name = 'default_workspace' - this.setWorkspace(name) - const workspacePath = 'browser/' + this.workspacesPath + '/' + name - const workspaceRootPath = 'browser/' + this.workspacesPath - const workspaceRootPathExists = await super.exists(workspaceRootPath) - const workspacePathExists = await super.exists(workspacePath) - - if (!workspaceRootPathExists) super.createDir(workspaceRootPath) - if (!workspacePathExists) super.createDir(workspacePath) - this.event.emit('createWorkspace', name) + try { + if (!name) name = 'default_workspace' + this.setWorkspace(name) + await super.createDir(name) + this.event.emit('createWorkspace', name) + } catch (e) { + throw new Error(e) + } } } diff --git a/libs/remix-ui/file-explorer/src/index.ts b/libs/remix-ui/file-explorer/src/index.ts index 7f375b8fb6..d6129e7e11 100644 --- a/libs/remix-ui/file-explorer/src/index.ts +++ b/libs/remix-ui/file-explorer/src/index.ts @@ -1 +1,2 @@ export * from './lib/file-explorer' +export * from './lib/types' 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 a758a25e7e..836adc7777 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -18,7 +18,7 @@ import './css/file-explorer.css' const queryParams = new QueryParams() export const FileExplorer = (props: FileExplorerProps) => { - const { name, registry, plugin, focusRoot, contextMenuItems, displayInput, externalUploads, removedContextMenuItems } = props + const { name, registry, plugin, focusRoot, contextMenuItems, displayInput, externalUploads, removedContextMenuItems, resetFocus } = props const [state, setState] = useState({ focusElement: [{ key: '', @@ -204,7 +204,7 @@ export const FileExplorer = (props: FileExplorerProps) => { setState(prevState => { return { ...prevState, focusElement: [{ key: '', type: 'folder' }] } }) - plugin.resetFocus(false) + resetFocus(false) } }, [focusRoot]) @@ -230,7 +230,6 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { if (externalUploads) { uploadFile(externalUploads) - plugin.resetUploadFile() } }, [externalUploads]) @@ -988,7 +987,7 @@ export const FileExplorer = (props: FileExplorerProps) => { setState(prevState => { return { ...prevState, expandPath } }) - plugin.resetFocus(true) + resetFocus(true) }}> void } export interface File { diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index ab26239d8c..48dd7c37a0 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -1,57 +1,37 @@ import React, { useState, useEffect, useRef, useReducer } from 'react' // eslint-disable-line -import { FileExplorer } from '@remix-ui/file-explorer' // eslint-disable-line +import { FileExplorer, MenuItems } from '@remix-ui/file-explorer' // eslint-disable-line import './remix-ui-workspace.css' import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line -import { Toaster } from '@remix-ui/toaster'// eslint-disable-line -import { MenuItems } from 'libs/remix-ui/file-explorer/src/lib/types' +import { Toaster } from '@remix-ui/toaster' // eslint-disable-line +import { WorkspaceProps, WorkspaceState, Modal } from './types' import { initWorkspace } from './actions/workspace' import { browserReducer, browserInitialState } from './reducers/workspace' -/* eslint-disable-next-line */ -export interface WorkspaceProps { - setWorkspace: ({ name: string, isLocalhost: boolean }, setEvent: boolean) => void, - createWorkspace: (name: string) => void, - renameWorkspace: (oldName: string, newName: string) => void - workspaceRenamed: ({ name: string }) => void, - workspaceCreated: ({ name: string }) => void, - workspaceDeleted: ({ name: string }) => void, - workspace: any // workspace provider, - browser: any // browser provider - localhost: any // localhost provider - fileManager : any - registry: any // registry - plugin: any // plugin call and resetFocus - request: any // api request, - workspaces: any, - registeredMenuItems: MenuItems // menu items - removedMenuItems: MenuItems - initialWorkspace: string -} +const canUpload = window.File || window.FileReader || window.FileList || window.Blob -var canUpload = window.File || window.FileReader || window.FileList || window.Blob -export const Workspace = (props: WorkspaceProps) => { +export function Workspace (props: WorkspaceProps) { const LOCALHOST = ' - connect to localhost - ' const NO_WORKSPACE = ' - none - ' - const [state, setState] = useState({ + const [state, setState] = useState({ workspaces: [], reset: false, hideRemixdExplorer: true, displayNewFile: false, externalUploads: null, uploadFileEvent: null, - modal: { - hide: true, - title: '', - message: null, - okLabel: '', - okFn: () => {}, - cancelLabel: '', - cancelFn: () => {}, - handleHide: null - }, loadingLocalhost: false, toasterMsg: '' }) + const [modal, setModal] = useState({ + hide: true, + title: '', + message: null, + okLabel: '', + okFn: () => {}, + cancelLabel: '', + cancelFn: () => {}, + handleHide: null + }) const [currentWorkspace, setCurrentWorkspace] = useState(NO_WORKSPACE) const [fs, dispatch] = useReducer(browserReducer, browserInitialState) @@ -63,36 +43,27 @@ export const Workspace = (props: WorkspaceProps) => { if (fs.browser.currentWorkspace) setCurrentWorkspace(fs.browser.currentWorkspace) }, [fs.browser.currentWorkspace]) - /* extends the parent 'plugin' with some function needed by the file explorer */ - props.plugin.resetFocus = (reset) => { - setState(prevState => { - return { ...prevState, reset } - }) - } - props.plugin.resetNewFile = () => { setState(prevState => { return { ...prevState, displayNewFile: !state.displayNewFile } }) } - props.plugin.resetUploadFile = () => {} - /* implement an external API, consumed by the parent */ - props.request.createWorkspace = () => { + props.plugin.request.createWorkspace = () => { return createWorkspace() } - props.request.setWorkspace = (workspaceName) => { + props.plugin.request.setWorkspace = (workspaceName) => { return setWorkspace(workspaceName) } - props.request.createNewFile = async () => { + props.plugin.request.createNewFile = async () => { if (!state.workspaces.length) await createNewWorkspace('default_workspace') props.plugin.resetNewFile() } - props.request.uploadFile = async (target) => { + props.plugin.request.uploadFile = async (target: EventTarget & HTMLInputElement) => { if (!state.workspaces.length) await createNewWorkspace('default_workspace') setState(prevState => { @@ -100,23 +71,23 @@ export const Workspace = (props: WorkspaceProps) => { }) } - props.request.getCurrentWorkspace = () => { - return { name: currentWorkspace, isLocalhost: currentWorkspace === LOCALHOST, absolutePath: `${props.workspace.workspacesPath}/${currentWorkspace}` } + props.plugin.request.getCurrentWorkspace = () => { + return { name: currentWorkspace, isLocalhost: currentWorkspace === LOCALHOST, absolutePath: `${props.plugin.workspace.workspacesPath}/${currentWorkspace}` } } const localhostDisconnect = () => { - if (currentWorkspace === LOCALHOST) setWorkspace(props.workspaces.length > 0 ? props.workspaces[0] : NO_WORKSPACE) + if (currentWorkspace === LOCALHOST) setWorkspace(props.plugin.workspaces.length > 0 ? props.plugin.workspaces[0] : NO_WORKSPACE) // This should be removed some time after refactoring: https://github.com/ethereum/remix-project/issues/1197 else { setWorkspace(currentWorkspace) // Useful to switch to last selcted workspace when remixd is disconnected - props.fileManager.setMode('browser') + props.plugin.fileManager.setMode('browser') } } const createNewWorkspace = async (workspaceName) => { try { - await props.fileManager.closeAllFiles() - await props.createWorkspace(workspaceName) + await props.plugin.fileManager.closeAllFiles() + await props.plugin.createWorkspace(workspaceName) await setWorkspace(workspaceName) toast('New default workspace has been created.') } catch (e) { @@ -134,20 +105,20 @@ export const Workspace = (props: WorkspaceProps) => { /* workspace creation, renaming and deletion */ const renameCurrentWorkspace = () => { - modal('Rename Current Workspace', renameModalMessage(), 'OK', onFinishRenameWorkspace, '', () => {}) + modalDialog('Rename Current Workspace', renameModalMessage(), 'OK', onFinishRenameWorkspace, '', () => {}) } const createWorkspace = () => { - modal('Create Workspace', createModalMessage(), 'OK', onFinishCreateWorkspace, '', () => {}) + modalDialog('Create Workspace', createModalMessage(), 'OK', onFinishCreateWorkspace, '', () => {}) } const deleteCurrentWorkspace = () => { - modal('Delete Current Workspace', 'Are you sure to delete the current workspace?', 'OK', onFinishDeleteWorkspace, '', () => {}) + modalDialog('Delete Current Workspace', 'Are you sure to delete the current workspace?', 'OK', onFinishDeleteWorkspace, '', () => {}) } const modalMessage = (title: string, body: string) => { setTimeout(() => { // wait for any previous modal a chance to close - modal(title, body, 'OK', () => {}, '', null) + modalDialog(title, body, 'OK', () => {}, '', null) }, 200) } @@ -160,9 +131,9 @@ export const Workspace = (props: WorkspaceProps) => { const workspaceName = workspaceRenameInput.current.value try { - await props.renameWorkspace(currentWorkspace, workspaceName) + await props.plugin.renameWorkspace(currentWorkspace, workspaceName) setWorkspace(workspaceName) - props.workspaceRenamed({ name: workspaceName }) + props.plugin.workspaceRenamed({ name: workspaceName }) } catch (e) { modalMessage('Rename Workspace', e.message) console.error(e) @@ -175,8 +146,8 @@ export const Workspace = (props: WorkspaceProps) => { const workspaceName = workspaceCreateInput.current.value try { - await props.fileManager.closeAllFiles() - await props.createWorkspace(workspaceName) + await props.plugin.fileManager.closeAllFiles() + await props.plugin.createWorkspace(workspaceName) await setWorkspace(workspaceName) } catch (e) { modalMessage('Create Workspace', e.message) @@ -185,12 +156,12 @@ export const Workspace = (props: WorkspaceProps) => { } const onFinishDeleteWorkspace = async () => { - await props.fileManager.closeAllFiles() - const workspacesPath = props.workspace.workspacesPath - props.browser.remove(workspacesPath + '/' + currentWorkspace) + await props.plugin.fileManager.closeAllFiles() + const workspacesPath = props.plugin.workspace.workspacesPath + props.plugin.browser.remove(workspacesPath + '/' + currentWorkspace) const name = currentWorkspace setWorkspace(NO_WORKSPACE) - props.workspaceDeleted({ name }) + props.plugin.workspaceDeleted({ name }) } /** ** ****/ @@ -201,15 +172,15 @@ export const Workspace = (props: WorkspaceProps) => { } const setWorkspace = async (name) => { - await props.fileManager.closeAllFiles() + await props.plugin.fileManager.closeAllFiles() if (name === LOCALHOST) { - props.workspace.clearWorkspace() + props.plugin.workspace.clearWorkspace() } else if (name === NO_WORKSPACE) { - props.workspace.clearWorkspace() + props.plugin.workspace.clearWorkspace() } else { - await props.workspace.setWorkspace(name) + await props.plugin.workspace.setWorkspace(name) } - await props.setWorkspace({ name, isLocalhost: name === LOCALHOST }, !(name === LOCALHOST || name === NO_WORKSPACE)) + await props.plugin.setWorkspace({ name, isLocalhost: name === LOCALHOST }, !(name === LOCALHOST || name === NO_WORKSPACE)) props.plugin.getWorkspaces() setState(prevState => { return { ...prevState, currentWorkspace: name } @@ -221,7 +192,7 @@ export const Workspace = (props: WorkspaceProps) => { // If 'connect to localhost' is clicked from home tab, mode is not 'localhost' // if (props.fileManager.mode === 'localhost') { await setWorkspace(NO_WORKSPACE) - props.fileManager.setMode('browser') + props.plugin.fileManager.setMode('browser') setState(prevState => { return { ...prevState, hideRemixdExplorer: true, loadingLocalhost: false } }) @@ -233,7 +204,7 @@ export const Workspace = (props: WorkspaceProps) => { // } }, show: () => { - props.fileManager.setMode('localhost') + props.plugin.fileManager.setMode('localhost') setState(prevState => { return { ...prevState, hideRemixdExplorer: false, loadingLocalhost: false } }) @@ -246,34 +217,21 @@ export const Workspace = (props: WorkspaceProps) => { } const handleHideModal = () => { - setState(prevState => { - return { ...prevState, modal: { ...state.modal, hide: true, message: null } } + setModal(prevModal => { + return { ...prevModal, hide: true, message: null } }) } - // eslint-disable-next-line no-undef - const modal = async (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel: string, cancelFn: () => void) => { - await setState(prevState => { - return { - ...prevState, - modal: { - ...prevState.modal, - hide: false, - message, - title, - okLabel, - okFn, - cancelLabel, - cancelFn, - handleHide: handleHideModal - } - } + + const modalDialog = async (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel: string, cancelFn: () => void) => { + await setModal(prevModal => { + return { ...prevModal, hide: false, message, title, okLabel, okFn, cancelLabel, cancelFn, handleHide: handleHideModal } }) } const createModalMessage = () => { return ( <> - { state.modal.message } + { modal.message } ) @@ -282,7 +240,7 @@ export const Workspace = (props: WorkspaceProps) => { const renameModalMessage = () => { return ( <> - { state.modal.message } + { modal.message } ) @@ -290,17 +248,8 @@ export const Workspace = (props: WorkspaceProps) => { return (
- { state.modal.message && - { (typeof state.modal.message !== 'string') && state.modal.message } + + { (typeof modal.message !== 'string') && modal.message } } @@ -364,15 +313,16 @@ export const Workspace = (props: WorkspaceProps) => { { state.hideRemixdExplorer && currentWorkspace && currentWorkspace !== NO_WORKSPACE && currentWorkspace !== LOCALHOST && }
@@ -382,13 +332,14 @@ export const Workspace = (props: WorkspaceProps) => { { !state.hideRemixdExplorer && } diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts new file mode 100644 index 0000000000..8b1364e406 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -0,0 +1,51 @@ +import { MenuItems } from '@remix-ui/file-explorer' + +export interface WorkspaceProps { + plugin: { + setWorkspace: ({ name: string, isLocalhost: boolean }, setEvent: boolean) => void, + createWorkspace: (name: string) => void, + renameWorkspace: (oldName: string, newName: string) => void + workspaceRenamed: ({ name: string }) => void, + workspaceCreated: ({ name: string }) => void, + workspaceDeleted: ({ name: string }) => void, + workspace: any // workspace provider, + browser: any // browser provider + localhost: any // localhost provider + fileManager : any + registry: any // registry + request: { + createWorkspace: () => void, + setWorkspace: (workspaceName: string) => void, + createNewFile: () => void, + uploadFile: (target: EventTarget & HTMLInputElement) => void, + getCurrentWorkspace: () => void + } // api request, + workspaces: any, + registeredMenuItems: MenuItems // menu items + removedMenuItems: MenuItems + initialWorkspace: string, + resetNewFile: () => void, + getWorkspaces: () => string[] + } +} +export interface WorkspaceState { + workspaces: string[] + reset: boolean + hideRemixdExplorer: boolean + displayNewFile: boolean + externalUploads: EventTarget & HTMLInputElement + uploadFileEvent: EventTarget & HTMLInputElement + loadingLocalhost: boolean + toasterMsg: string +} + +export interface Modal { + hide: boolean + title: string + message: string | JSX.Element + okLabel: string + okFn: () => void + cancelLabel: string + cancelFn: () => void + handleHide: () => void +}