Extract types

pull/1575/head
ioedeveloper 3 years ago
parent 9084e342ed
commit 1a51147266
  1. 18
      apps/remix-ide/src/app/files/workspaceFileProvider.js
  2. 1
      libs/remix-ui/file-explorer/src/index.ts
  3. 7
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
  4. 1
      libs/remix-ui/file-explorer/src/lib/types/index.ts
  5. 179
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  6. 51
      libs/remix-ui/workspace/src/lib/types/index.ts

@ -81,16 +81,14 @@ class WorkspaceFileProvider extends FileProvider {
} }
async createWorkspace (name) { async createWorkspace (name) {
if (!name) name = 'default_workspace' try {
this.setWorkspace(name) if (!name) name = 'default_workspace'
const workspacePath = 'browser/' + this.workspacesPath + '/' + name this.setWorkspace(name)
const workspaceRootPath = 'browser/' + this.workspacesPath await super.createDir(name)
const workspaceRootPathExists = await super.exists(workspaceRootPath) this.event.emit('createWorkspace', name)
const workspacePathExists = await super.exists(workspacePath) } catch (e) {
throw new Error(e)
if (!workspaceRootPathExists) super.createDir(workspaceRootPath) }
if (!workspacePathExists) super.createDir(workspacePath)
this.event.emit('createWorkspace', name)
} }
} }

@ -1 +1,2 @@
export * from './lib/file-explorer' export * from './lib/file-explorer'
export * from './lib/types'

@ -18,7 +18,7 @@ import './css/file-explorer.css'
const queryParams = new QueryParams() const queryParams = new QueryParams()
export const FileExplorer = (props: FileExplorerProps) => { 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({ const [state, setState] = useState({
focusElement: [{ focusElement: [{
key: '', key: '',
@ -204,7 +204,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
setState(prevState => { setState(prevState => {
return { ...prevState, focusElement: [{ key: '', type: 'folder' }] } return { ...prevState, focusElement: [{ key: '', type: 'folder' }] }
}) })
plugin.resetFocus(false) resetFocus(false)
} }
}, [focusRoot]) }, [focusRoot])
@ -230,7 +230,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
useEffect(() => { useEffect(() => {
if (externalUploads) { if (externalUploads) {
uploadFile(externalUploads) uploadFile(externalUploads)
plugin.resetUploadFile()
} }
}, [externalUploads]) }, [externalUploads])
@ -988,7 +987,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
setState(prevState => { setState(prevState => {
return { ...prevState, expandPath } return { ...prevState, expandPath }
}) })
plugin.resetFocus(true) resetFocus(true)
}}> }}>
<FileExplorerMenu <FileExplorerMenu
title={''} title={''}

@ -13,6 +13,7 @@ export interface FileExplorerProps {
removedContextMenuItems: MenuItems, removedContextMenuItems: MenuItems,
displayInput?: boolean, displayInput?: boolean,
externalUploads?: EventTarget & HTMLInputElement, externalUploads?: EventTarget & HTMLInputElement,
resetFocus?: (value: boolean) => void
} }
export interface File { export interface File {

@ -1,57 +1,37 @@
import React, { useState, useEffect, useRef, useReducer } from 'react' // eslint-disable-line 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 './remix-ui-workspace.css'
import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line
import { Toaster } from '@remix-ui/toaster'// eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
import { MenuItems } from 'libs/remix-ui/file-explorer/src/lib/types' import { WorkspaceProps, WorkspaceState, Modal } from './types'
import { initWorkspace } from './actions/workspace' import { initWorkspace } from './actions/workspace'
import { browserReducer, browserInitialState } from './reducers/workspace' import { browserReducer, browserInitialState } from './reducers/workspace'
/* eslint-disable-next-line */ const canUpload = window.File || window.FileReader || window.FileList || window.Blob
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
}
var canUpload = window.File || window.FileReader || window.FileList || window.Blob export function Workspace (props: WorkspaceProps) {
export const Workspace = (props: WorkspaceProps) => {
const LOCALHOST = ' - connect to localhost - ' const LOCALHOST = ' - connect to localhost - '
const NO_WORKSPACE = ' - none - ' const NO_WORKSPACE = ' - none - '
const [state, setState] = useState({ const [state, setState] = useState<WorkspaceState>({
workspaces: [], workspaces: [],
reset: false, reset: false,
hideRemixdExplorer: true, hideRemixdExplorer: true,
displayNewFile: false, displayNewFile: false,
externalUploads: null, externalUploads: null,
uploadFileEvent: null, uploadFileEvent: null,
modal: {
hide: true,
title: '',
message: null,
okLabel: '',
okFn: () => {},
cancelLabel: '',
cancelFn: () => {},
handleHide: null
},
loadingLocalhost: false, loadingLocalhost: false,
toasterMsg: '' toasterMsg: ''
}) })
const [modal, setModal] = useState<Modal>({
hide: true,
title: '',
message: null,
okLabel: '',
okFn: () => {},
cancelLabel: '',
cancelFn: () => {},
handleHide: null
})
const [currentWorkspace, setCurrentWorkspace] = useState<string>(NO_WORKSPACE) const [currentWorkspace, setCurrentWorkspace] = useState<string>(NO_WORKSPACE)
const [fs, dispatch] = useReducer(browserReducer, browserInitialState) const [fs, dispatch] = useReducer(browserReducer, browserInitialState)
@ -63,36 +43,27 @@ export const Workspace = (props: WorkspaceProps) => {
if (fs.browser.currentWorkspace) setCurrentWorkspace(fs.browser.currentWorkspace) if (fs.browser.currentWorkspace) setCurrentWorkspace(fs.browser.currentWorkspace)
}, [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 = () => { props.plugin.resetNewFile = () => {
setState(prevState => { setState(prevState => {
return { ...prevState, displayNewFile: !state.displayNewFile } return { ...prevState, displayNewFile: !state.displayNewFile }
}) })
} }
props.plugin.resetUploadFile = () => {}
/* implement an external API, consumed by the parent */ /* implement an external API, consumed by the parent */
props.request.createWorkspace = () => { props.plugin.request.createWorkspace = () => {
return createWorkspace() return createWorkspace()
} }
props.request.setWorkspace = (workspaceName) => { props.plugin.request.setWorkspace = (workspaceName) => {
return setWorkspace(workspaceName) return setWorkspace(workspaceName)
} }
props.request.createNewFile = async () => { props.plugin.request.createNewFile = async () => {
if (!state.workspaces.length) await createNewWorkspace('default_workspace') if (!state.workspaces.length) await createNewWorkspace('default_workspace')
props.plugin.resetNewFile() props.plugin.resetNewFile()
} }
props.request.uploadFile = async (target) => { props.plugin.request.uploadFile = async (target: EventTarget & HTMLInputElement) => {
if (!state.workspaces.length) await createNewWorkspace('default_workspace') if (!state.workspaces.length) await createNewWorkspace('default_workspace')
setState(prevState => { setState(prevState => {
@ -100,23 +71,23 @@ export const Workspace = (props: WorkspaceProps) => {
}) })
} }
props.request.getCurrentWorkspace = () => { props.plugin.request.getCurrentWorkspace = () => {
return { name: currentWorkspace, isLocalhost: currentWorkspace === LOCALHOST, absolutePath: `${props.workspace.workspacesPath}/${currentWorkspace}` } return { name: currentWorkspace, isLocalhost: currentWorkspace === LOCALHOST, absolutePath: `${props.plugin.workspace.workspacesPath}/${currentWorkspace}` }
} }
const localhostDisconnect = () => { 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 // This should be removed some time after refactoring: https://github.com/ethereum/remix-project/issues/1197
else { else {
setWorkspace(currentWorkspace) // Useful to switch to last selcted workspace when remixd is disconnected 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) => { const createNewWorkspace = async (workspaceName) => {
try { try {
await props.fileManager.closeAllFiles() await props.plugin.fileManager.closeAllFiles()
await props.createWorkspace(workspaceName) await props.plugin.createWorkspace(workspaceName)
await setWorkspace(workspaceName) await setWorkspace(workspaceName)
toast('New default workspace has been created.') toast('New default workspace has been created.')
} catch (e) { } catch (e) {
@ -134,20 +105,20 @@ export const Workspace = (props: WorkspaceProps) => {
/* workspace creation, renaming and deletion */ /* workspace creation, renaming and deletion */
const renameCurrentWorkspace = () => { const renameCurrentWorkspace = () => {
modal('Rename Current Workspace', renameModalMessage(), 'OK', onFinishRenameWorkspace, '', () => {}) modalDialog('Rename Current Workspace', renameModalMessage(), 'OK', onFinishRenameWorkspace, '', () => {})
} }
const createWorkspace = () => { const createWorkspace = () => {
modal('Create Workspace', createModalMessage(), 'OK', onFinishCreateWorkspace, '', () => {}) modalDialog('Create Workspace', createModalMessage(), 'OK', onFinishCreateWorkspace, '', () => {})
} }
const deleteCurrentWorkspace = () => { 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) => { const modalMessage = (title: string, body: string) => {
setTimeout(() => { // wait for any previous modal a chance to close setTimeout(() => { // wait for any previous modal a chance to close
modal(title, body, 'OK', () => {}, '', null) modalDialog(title, body, 'OK', () => {}, '', null)
}, 200) }, 200)
} }
@ -160,9 +131,9 @@ export const Workspace = (props: WorkspaceProps) => {
const workspaceName = workspaceRenameInput.current.value const workspaceName = workspaceRenameInput.current.value
try { try {
await props.renameWorkspace(currentWorkspace, workspaceName) await props.plugin.renameWorkspace(currentWorkspace, workspaceName)
setWorkspace(workspaceName) setWorkspace(workspaceName)
props.workspaceRenamed({ name: workspaceName }) props.plugin.workspaceRenamed({ name: workspaceName })
} catch (e) { } catch (e) {
modalMessage('Rename Workspace', e.message) modalMessage('Rename Workspace', e.message)
console.error(e) console.error(e)
@ -175,8 +146,8 @@ export const Workspace = (props: WorkspaceProps) => {
const workspaceName = workspaceCreateInput.current.value const workspaceName = workspaceCreateInput.current.value
try { try {
await props.fileManager.closeAllFiles() await props.plugin.fileManager.closeAllFiles()
await props.createWorkspace(workspaceName) await props.plugin.createWorkspace(workspaceName)
await setWorkspace(workspaceName) await setWorkspace(workspaceName)
} catch (e) { } catch (e) {
modalMessage('Create Workspace', e.message) modalMessage('Create Workspace', e.message)
@ -185,12 +156,12 @@ export const Workspace = (props: WorkspaceProps) => {
} }
const onFinishDeleteWorkspace = async () => { const onFinishDeleteWorkspace = async () => {
await props.fileManager.closeAllFiles() await props.plugin.fileManager.closeAllFiles()
const workspacesPath = props.workspace.workspacesPath const workspacesPath = props.plugin.workspace.workspacesPath
props.browser.remove(workspacesPath + '/' + currentWorkspace) props.plugin.browser.remove(workspacesPath + '/' + currentWorkspace)
const name = currentWorkspace const name = currentWorkspace
setWorkspace(NO_WORKSPACE) setWorkspace(NO_WORKSPACE)
props.workspaceDeleted({ name }) props.plugin.workspaceDeleted({ name })
} }
/** ** ****/ /** ** ****/
@ -201,15 +172,15 @@ export const Workspace = (props: WorkspaceProps) => {
} }
const setWorkspace = async (name) => { const setWorkspace = async (name) => {
await props.fileManager.closeAllFiles() await props.plugin.fileManager.closeAllFiles()
if (name === LOCALHOST) { if (name === LOCALHOST) {
props.workspace.clearWorkspace() props.plugin.workspace.clearWorkspace()
} else if (name === NO_WORKSPACE) { } else if (name === NO_WORKSPACE) {
props.workspace.clearWorkspace() props.plugin.workspace.clearWorkspace()
} else { } 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() props.plugin.getWorkspaces()
setState(prevState => { setState(prevState => {
return { ...prevState, currentWorkspace: name } 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 'connect to localhost' is clicked from home tab, mode is not 'localhost'
// if (props.fileManager.mode === 'localhost') { // if (props.fileManager.mode === 'localhost') {
await setWorkspace(NO_WORKSPACE) await setWorkspace(NO_WORKSPACE)
props.fileManager.setMode('browser') props.plugin.fileManager.setMode('browser')
setState(prevState => { setState(prevState => {
return { ...prevState, hideRemixdExplorer: true, loadingLocalhost: false } return { ...prevState, hideRemixdExplorer: true, loadingLocalhost: false }
}) })
@ -233,7 +204,7 @@ export const Workspace = (props: WorkspaceProps) => {
// } // }
}, },
show: () => { show: () => {
props.fileManager.setMode('localhost') props.plugin.fileManager.setMode('localhost')
setState(prevState => { setState(prevState => {
return { ...prevState, hideRemixdExplorer: false, loadingLocalhost: false } return { ...prevState, hideRemixdExplorer: false, loadingLocalhost: false }
}) })
@ -246,34 +217,21 @@ export const Workspace = (props: WorkspaceProps) => {
} }
const handleHideModal = () => { const handleHideModal = () => {
setState(prevState => { setModal(prevModal => {
return { ...prevState, modal: { ...state.modal, hide: true, message: null } } 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) => { const modalDialog = async (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel: string, cancelFn: () => void) => {
await setState(prevState => { await setModal(prevModal => {
return { return { ...prevModal, hide: false, message, title, okLabel, okFn, cancelLabel, cancelFn, handleHide: handleHideModal }
...prevState,
modal: {
...prevState.modal,
hide: false,
message,
title,
okLabel,
okFn,
cancelLabel,
cancelFn,
handleHide: handleHideModal
}
}
}) })
} }
const createModalMessage = () => { const createModalMessage = () => {
return ( return (
<> <>
<span>{ state.modal.message }</span> <span>{ modal.message }</span>
<input type="text" data-id="modalDialogCustomPromptTextCreate" defaultValue={`workspace_${Date.now()}`} ref={workspaceCreateInput} className="form-control" /> <input type="text" data-id="modalDialogCustomPromptTextCreate" defaultValue={`workspace_${Date.now()}`} ref={workspaceCreateInput} className="form-control" />
</> </>
) )
@ -282,7 +240,7 @@ export const Workspace = (props: WorkspaceProps) => {
const renameModalMessage = () => { const renameModalMessage = () => {
return ( return (
<> <>
<span>{ state.modal.message }</span> <span>{ modal.message }</span>
<input type="text" data-id="modalDialogCustomPromptTextRename" defaultValue={ currentWorkspace } ref={workspaceRenameInput} className="form-control" /> <input type="text" data-id="modalDialogCustomPromptTextRename" defaultValue={ currentWorkspace } ref={workspaceRenameInput} className="form-control" />
</> </>
) )
@ -290,17 +248,8 @@ export const Workspace = (props: WorkspaceProps) => {
return ( return (
<div className='remixui_container'> <div className='remixui_container'>
{ state.modal.message && <ModalDialog <ModalDialog id='workspacesModalDialog' {...modal}>
id='workspacesModalDialog' { (typeof modal.message !== 'string') && modal.message }
title={ state.modal.title }
message={ state.modal.message }
hide={ state.modal.hide }
okLabel={ state.modal.okLabel }
okFn={ state.modal.okFn }
cancelLabel={ state.modal.cancelLabel }
cancelFn={ state.modal.cancelFn }
handleHide={ handleHideModal }>
{ (typeof state.modal.message !== 'string') && state.modal.message }
</ModalDialog> </ModalDialog>
} }
<Toaster message={state.toasterMsg} /> <Toaster message={state.toasterMsg} />
@ -364,15 +313,16 @@ export const Workspace = (props: WorkspaceProps) => {
{ state.hideRemixdExplorer && currentWorkspace && currentWorkspace !== NO_WORKSPACE && currentWorkspace !== LOCALHOST && { state.hideRemixdExplorer && currentWorkspace && currentWorkspace !== NO_WORKSPACE && currentWorkspace !== LOCALHOST &&
<FileExplorer <FileExplorer
name={currentWorkspace} name={currentWorkspace}
registry={props.registry} registry={props.plugin.registry}
filesProvider={props.workspace} filesProvider={props.plugin.workspace}
menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']} menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']}
plugin={props.plugin} plugin={props.plugin}
focusRoot={state.reset} focusRoot={state.reset}
contextMenuItems={props.registeredMenuItems} contextMenuItems={props.plugin.registeredMenuItems}
removedContextMenuItems={props.removedMenuItems} removedContextMenuItems={props.plugin.removedMenuItems}
displayInput={state.displayNewFile} displayInput={state.displayNewFile}
externalUploads={state.uploadFileEvent} externalUploads={state.uploadFileEvent}
resetFocus={resetFocus}
/> />
} }
</div> </div>
@ -382,13 +332,14 @@ export const Workspace = (props: WorkspaceProps) => {
{ !state.hideRemixdExplorer && { !state.hideRemixdExplorer &&
<FileExplorer <FileExplorer
name='localhost' name='localhost'
registry={props.registry} registry={props.plugin.registry}
filesProvider={props.localhost} filesProvider={props.plugin.localhost}
menuItems={['createNewFile', 'createNewFolder']} menuItems={['createNewFile', 'createNewFolder']}
plugin={props.plugin} plugin={props.plugin}
focusRoot={state.reset} focusRoot={state.reset}
contextMenuItems={props.registeredMenuItems} contextMenuItems={props.plugin.registeredMenuItems}
removedContextMenuItems={props.removedMenuItems} removedContextMenuItems={props.plugin.removedMenuItems}
resetFocus={resetFocus}
/> />
} }
</div> </div>

@ -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
}
Loading…
Cancel
Save