diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 17bbc6ce48..578193c8e2 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -4,7 +4,6 @@ import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line import ReactDOM from 'react-dom' import { Workspace } from '@remix-ui/workspace' // eslint-disable-line -import { bufferToHex, keccakFromString } from 'ethereumjs-util' import { checkSpecialChars, checkSlash } from '../../lib/helper' const { RemixdHandle } = require('../files/remixd-handle.js') const { GitHandle } = require('../files/git-handle.js') @@ -12,8 +11,6 @@ const { HardhatHandle } = require('../files/hardhat-handle.js') const { SlitherHandle } = require('../files/slither-handle.js') const globalRegistry = require('../../global/registry') const examples = require('../editor/examples') -const GistHandler = require('../../lib/gist-handler') -const QueryParams = require('../../lib/query-params') const modalDialogCustom = require('../ui/modal-dialog-custom') /* Overview of APIs: @@ -67,7 +64,6 @@ module.exports = class Filepanel extends ViewPlugin { } render () { - this.on('editor', 'editorMounted', () => this.initWorkspace().then(() => this.getWorkspaces()).catch(console.error)) return this.el } @@ -149,73 +145,6 @@ module.exports = class Filepanel extends ViewPlugin { return this.workspaces } - async initWorkspace () { - this.renderComponent() - const queryParams = new QueryParams() - const gistHandler = new GistHandler() - const params = queryParams.get() - // get the file from gist - let loadedFromGist = false - if (params.gist) { - await this.processCreateWorkspace('gist-sample') - this.fileProviders.workspace.setWorkspace('gist-sample') - this.initialWorkspace = 'gist-sample' - loadedFromGist = gistHandler.loadFromGist(params, this._deps.fileManager) - } - if (loadedFromGist) return - - if (params.code || params.url) { - try { - await this.processCreateWorkspace('code-sample') - this.fileProviders.workspace.setWorkspace('code-sample') - let path = '' - let content = '' - if (params.code) { - var hash = bufferToHex(keccakFromString(params.code)) - path = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol' - content = atob(params.code) - await this.fileProviders.workspace.set(path, content) - } - if (params.url) { - const data = await this.call('contentImport', 'resolve', params.url) - path = data.cleanUrl - content = data.content - await this.fileProviders.workspace.set(path, content) - } - this.initialWorkspace = 'code-sample' - await this.fileManager.openFile(path) - } catch (e) { - console.error(e) - } - return - } - - const self = this - this.appManager.on('manager', 'pluginDeactivated', self.removePluginActions.bind(this)) - // insert example contracts if there are no files to show - return new Promise((resolve, reject) => { - this.fileProviders.browser.resolveDirectory('/', async (error, filesList) => { - if (error) return reject(error) - if (Object.keys(filesList).length === 0) { - await this.createWorkspace('default_workspace') - resolve('default_workspace') - } else { - this.fileProviders.browser.resolveDirectory('.workspaces', async (error, filesList) => { - if (error) return reject(error) - if (Object.keys(filesList).length > 0) { - const workspacePath = Object.keys(filesList)[0].split('/').filter(val => val) - const workspaceName = workspacePath[workspacePath.length - 1] - - this.fileProviders.workspace.setWorkspace(workspaceName) - return resolve(workspaceName) - } - return reject(new Error('Can\'t find available workspace.')) - }) - } - }) - }) - } - async createNewFile () { return await this.request.createNewFile() } diff --git a/libs/remix-ui/workspace/src/lib/actions/workspace.ts b/libs/remix-ui/workspace/src/lib/actions/workspace.ts index 2ad2ec9503..0f5aee08bd 100644 --- a/libs/remix-ui/workspace/src/lib/actions/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/actions/workspace.ts @@ -6,13 +6,55 @@ const QueryParams = require('../../../../../../apps/remix-ide/src/lib/query-para const examples = require('../../../../../../apps/remix-ide/src/app/editor/examples') let plugin -export const setCurrentWorkspace = (workspace: string) => { +const setCurrentWorkspace = (workspace: string) => { return { type: 'SET_CURRENT_WORKSPACE', payload: workspace } } +const processCreateWorkspace = async (name: string) => { + const workspaceProvider = plugin.fileProviders.workspace + const browserProvider = plugin.fileProviders.browser + const workspacePath = 'browser/' + workspaceProvider.workspacesPath + '/' + name + const workspaceRootPath = 'browser/' + workspaceProvider.workspacesPath + const workspaceRootPathExists = await browserProvider.exists(workspaceRootPath) + const workspacePathExists = await browserProvider.exists(workspacePath) + + if (!workspaceRootPathExists) browserProvider.createDir(workspaceRootPath) + if (!workspacePathExists) browserProvider.createDir(workspacePath) + workspaceProvider.setWorkspace(name) +} + +const createWorkspace = async (workspaceName: string, setDefaults = true) => { + if (!workspaceName) throw new Error('workspace name cannot be empty') + if (checkSpecialChars(workspaceName) || checkSlash(workspaceName)) throw new Error('special characters are not allowed') + if (await workspaceExists(workspaceName)) throw new Error('workspace already exists') + else { + const workspaceProvider = plugin.fileProviders.workspace + + await processCreateWorkspace(workspaceName) + if (setDefaults) { + // insert example contracts if there are no files to show + for (const file in examples) { + try { + await workspaceProvider.set(examples[file].name, examples[file].content) + } catch (error) { + console.error(error) + } + } + } + } +} + +const workspaceExists = async (name: string) => { + const workspaceProvider = plugin.fileProviders.workspace + const browserProvider = plugin.fileProviders.browser + const workspacePath = 'browser/' + workspaceProvider.workspacesPath + '/' + name + + return browserProvider.exists(workspacePath) +} + export const initWorkspace = (filePanelPlugin) => async (dispatch: React.Dispatch) => { plugin = filePanelPlugin const queryParams = new QueryParams() @@ -66,49 +108,24 @@ export const initWorkspace = (filePanelPlugin) => async (dispatch: React.Dispatc } }) }) - return dispatch(setCurrentWorkspace(initialWorkspace)) -} -const processCreateWorkspace = async (name: string) => { - const workspaceProvider = plugin.fileProviders.workspace - const browserProvider = plugin.fileProviders.browser - const workspacePath = 'browser/' + workspaceProvider.workspacesPath + '/' + name - const workspaceRootPath = 'browser/' + workspaceProvider.workspacesPath - const workspaceRootPathExists = await browserProvider.exists(workspaceRootPath) - const workspacePathExists = await browserProvider.exists(workspacePath) + // plugin.fileProviders.localhost.event.off('disconnected', localhostDisconnect) + // plugin.fileProviders.localhost.event.on('disconnected', localhostDisconnect) + // plugin.fileProviders.localhost.event.on('connected', () => { + // remixdExplorer.show() + // setWorkspace(LOCALHOST) + // }) - if (!workspaceRootPathExists) browserProvider.createDir(workspaceRootPath) - if (!workspacePathExists) browserProvider.createDir(workspacePath) - plugin.fileProviders.workspace.setWorkspace(name) -} + // plugin.fileProviders.localhost.event.on('disconnected', () => { + // remixdExplorer.hide() + // }) -const createWorkspace = async (workspaceName, setDefaults = true) => { - if (!workspaceName) throw new Error('name cannot be empty') - if (checkSpecialChars(workspaceName) || checkSlash(workspaceName)) throw new Error('special characters are not allowed') - if (await workspaceExists(workspaceName)) throw new Error('workspace already exists') - else { - const workspaceProvider = plugin.fileProviders.workspace + // plugin.fileProviders.localhost.event.on('loading', () => { + // remixdExplorer.loading() + // }) - await processCreateWorkspace(workspaceName) - workspaceProvider.setWorkspace(workspaceName) - plugin.workspaceName = workspaceName - if (setDefaults) { - // insert example contracts if there are no files to show - for (const file in examples) { - try { - await workspaceProvider.set(examples[file].name, examples[file].content) - } catch (error) { - console.error(error) - } - } - } - } -} - -const workspaceExists = async (name) => { - const workspaceProvider = plugin.fileProviders.workspace - const browserProvider = plugin.fileProviders.browser - const workspacePath = 'browser/' + workspaceProvider.workspacesPath + '/' + name - - return browserProvider.exists(workspacePath) + // plugin.fileProviders.workspace.event.on('createWorkspace', (name) => { + // createNewWorkspace(name) + // }) + return dispatch(setCurrentWorkspace(initialWorkspace)) } diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts index bb376b64c5..81a31899a2 100644 --- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts @@ -2,8 +2,17 @@ interface Action { type: string payload: Record | string } +interface State { + browser: { + currentWorkspace: string, + workspaces: string[], + isRequesting: boolean, + isSuccessful: boolean, + error: string + } +} -export const browserInitialState = { +export const browserInitialState: State = { browser: { currentWorkspace: '', workspaces: [], @@ -20,7 +29,8 @@ export const browserReducer = (state = browserInitialState, action: Action) => { ...state, browser: { ...state.browser, - currentWorkspace: typeof action.payload === 'string' ? action.payload : '' + currentWorkspace: typeof action.payload === 'string' ? action.payload : '', + workspaces: typeof action.payload === 'string' ? state.browser.workspaces.includes(action.payload) ? state.browser.workspaces : [...state.browser.workspaces, action.payload] : state.browser.workspaces } } } 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 a18d6426c5..df685d448b 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -32,6 +32,37 @@ var canUpload = window.File || window.FileReader || window.FileList || window.Bl export const Workspace = (props: WorkspaceProps) => { const LOCALHOST = ' - connect to localhost - ' const NO_WORKSPACE = ' - none - ' + const [state, setState] = useState({ + workspaces: [], + reset: false, + currentWorkspace: NO_WORKSPACE, + hideRemixdExplorer: true, + displayNewFile: false, + externalUploads: null, + uploadFileEvent: null, + modal: { + hide: true, + title: '', + message: null, + okLabel: '', + okFn: () => {}, + cancelLabel: '', + cancelFn: () => {}, + handleHide: null + }, + loadingLocalhost: false, + toasterMsg: '' + }) + const [currentWorkspace, setCurrentWorkspace] = useState('') + const [fs, dispatch] = useReducer(browserReducer, browserInitialState) + + useEffect(() => { + initWorkspace(props.plugin)(dispatch) + }, []) + + useEffect(() => { + 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) => { @@ -74,30 +105,6 @@ export const Workspace = (props: WorkspaceProps) => { return { name: state.currentWorkspace, isLocalhost: state.currentWorkspace === LOCALHOST, absolutePath: `${props.workspace.workspacesPath}/${state.currentWorkspace}` } } - useEffect(() => { - let getWorkspaces = async () => { - if (props.workspaces && Array.isArray(props.workspaces)) { - if (props.workspaces.length > 0 && state.currentWorkspace === NO_WORKSPACE) { - const currentWorkspace = props.workspace.getWorkspace() ? props.workspace.getWorkspace() : props.workspaces[0] - await props.workspace.setWorkspace(currentWorkspace) - setState(prevState => { - return { ...prevState, workspaces: props.workspaces, currentWorkspace } - }) - } else { - setState(prevState => { - return { ...prevState, workspaces: props.workspaces } - }) - } - } - } - - getWorkspaces() - - return () => { - getWorkspaces = async () => {} - } - }, [props.workspaces]) - const localhostDisconnect = () => { if (state.currentWorkspace === LOCALHOST) setWorkspace(props.workspaces.length > 0 ? props.workspaces[0] : NO_WORKSPACE) // This should be removed some time after refactoring: https://github.com/ethereum/remix-project/issues/1197 @@ -107,38 +114,6 @@ export const Workspace = (props: WorkspaceProps) => { } } - // useEffect(() => { - // props.localhost.event.off('disconnected', localhostDisconnect) - // props.localhost.event.on('disconnected', localhostDisconnect) - // props.localhost.event.on('connected', () => { - // remixdExplorer.show() - // setWorkspace(LOCALHOST) - // }) - - // props.localhost.event.on('disconnected', () => { - // remixdExplorer.hide() - // }) - - // props.localhost.event.on('loading', () => { - // remixdExplorer.loading() - // }) - - // props.workspace.event.on('createWorkspace', (name) => { - // createNewWorkspace(name) - // }) - - // if (props.initialWorkspace) { - // props.workspace.setWorkspace(props.initialWorkspace) - // setState(prevState => { - // return { ...prevState, currentWorkspace: props.initialWorkspace } - // }) - // } - // }, []) - - useEffect(() => { - initWorkspace(props.plugin)(dispatch) - }, []) - const createNewWorkspace = async (workspaceName) => { try { await props.fileManager.closeAllFiles() @@ -151,30 +126,6 @@ export const Workspace = (props: WorkspaceProps) => { } } - const [state, setState] = useState({ - workspaces: [], - reset: false, - currentWorkspace: NO_WORKSPACE, - hideRemixdExplorer: true, - displayNewFile: false, - externalUploads: null, - uploadFileEvent: null, - modal: { - hide: true, - title: '', - message: null, - okLabel: '', - okFn: () => {}, - cancelLabel: '', - cancelFn: () => {}, - handleHide: null - }, - loadingLocalhost: false, - toasterMsg: '' - }) - - const [fs, dispatch] = useReducer(browserReducer, browserInitialState) - const toast = (message: string) => { setState(prevState => { return { ...prevState, toasterMsg: message } @@ -395,9 +346,9 @@ export const Workspace = (props: WorkspaceProps) => { title='Delete'> - setWorkspace(e.target.value)} className="form-control custom-select"> { - state.workspaces + fs.browser.workspaces .map((folder, index) => { return })