From dc57090e52924c628234ab7bccdbaf69924d8189 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 24 Feb 2021 17:22:28 +0100 Subject: [PATCH] move workspace to a react component --- apps/remix-ide/src/app.js | 1 - apps/remix-ide/src/app/panels/file-panel.js | 352 +++----------- .../app/panels/styles/file-panel-styles.css | 59 --- libs/remix-ui/workspace/.babelrc | 4 + libs/remix-ui/workspace/.eslintrc | 19 + libs/remix-ui/workspace/README.md | 7 + libs/remix-ui/workspace/src/index.ts | 1 + .../workspace/src/lib/remix-ui-workspace.css | 40 +- .../workspace/src/lib/remix-ui-workspace.tsx | 432 ++++++++++++++++++ libs/remix-ui/workspace/tsconfig.json | 16 + libs/remix-ui/workspace/tsconfig.lib.json | 13 + nx.json | 3 + tsconfig.json | 7 +- workspace.json | 22 +- 14 files changed, 592 insertions(+), 384 deletions(-) delete mode 100644 apps/remix-ide/src/app/panels/styles/file-panel-styles.css create mode 100644 libs/remix-ui/workspace/.babelrc create mode 100644 libs/remix-ui/workspace/.eslintrc create mode 100644 libs/remix-ui/workspace/README.md create mode 100644 libs/remix-ui/workspace/src/index.ts rename apps/remix-ide/src/app/panels/styles/file-panel-styles.js => libs/remix-ui/workspace/src/lib/remix-ui-workspace.css (62%) create mode 100644 libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx create mode 100644 libs/remix-ui/workspace/tsconfig.json create mode 100644 libs/remix-ui/workspace/tsconfig.lib.json diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index f4f0f02eb0..52c194e04a 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -486,6 +486,5 @@ Please make a backup of your contracts and start using http://remix.ethereum.org migrateToWorkspace(fileManager) - filePanel.initWorkspace() if (params.embed) framingService.embed() } diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 7f9596b066..fd86d35ffa 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -3,10 +3,7 @@ import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line import ReactDOM from 'react-dom' -import { FileExplorer } from '@remix-ui/file-explorer' // eslint-disable-line -import './styles/file-panel-styles.css' -var ethutil = require('ethereumjs-util') -var yo = require('yo-yo') +import { Workspace } from '@remix-ui/workspace' // eslint-disable-line var EventManager = require('../../lib/events') var { RemixdHandle } = require('../files/remixd-handle.js') var { GitHandle } = require('../files/git-handle.js') @@ -14,9 +11,6 @@ var globalRegistry = require('../../global/registry') var examples = require('../editor/examples') var GistHandler = require('../../lib/gist-handler') var QueryParams = require('../../lib/query-params') -const modalDialog = require('../ui/modal-dialog-custom') - -var canUpload = window.File || window.FileReader || window.FileList || window.Blob /* Overview of APIs: @@ -51,328 +45,86 @@ const profile = { module.exports = class Filepanel extends ViewPlugin { constructor (appManager) { super(profile) + this.event = new EventManager() this._components = {} this._components.registry = globalRegistry this._deps = { fileProviders: this._components.registry.get('fileproviders').api, - fileManager: this._components.registry.get('filemanager').api, - config: this._components.registry.get('config').api - } - this.LOCALHOST = ' - connect to localhost - ' - this.NO_WORKSPACE = ' - none - ' - this.hideRemixdExplorer = true - this.remixdExplorer = { - hide: () => { - if (this.currentWorkspace === this.LOCALHOST) this.setWorkspace(this.NO_WORKSPACE) - this._deps.fileManager.setMode('browser') - this.hideRemixdExplorer = true - this.renderComponent() - }, - show: () => { - this._deps.fileManager.setMode('localhost') - this.hideRemixdExplorer = false - this.renderComponent() - } + fileManager: this._components.registry.get('filemanager').api } - this.reset = false - this.registeredMenuItems = [] - this.displayNewFile = false - this.uploadFileEvent = null - this.el = yo` -
-
- ` - + + this.el = document.createElement('div') + this.el.setAttribute('id', 'fileExplorerView') + this.remixdHandle = new RemixdHandle(this.remixdExplorer, this._deps.fileProviders.localhost, appManager) this.gitHandle = new GitHandle() - - this.event = new EventManager() - this._deps.fileProviders.localhost.event.register('connecting', (event) => { - }) - - this._deps.fileProviders.localhost.event.register('connected', (event) => { - this.remixdExplorer.show() - }) - - this._deps.fileProviders.localhost.event.register('errored', (event) => { - this.remixdExplorer.hide() - }) - - this._deps.fileProviders.localhost.event.register('closed', (event) => { - this.remixdExplorer.hide() - }) - - this.currentWorkspace = null - - const workspacesPath = this._deps.fileProviders.workspace.workspacesPath - this._deps.fileProviders.browser.resolveDirectory('/' + workspacesPath, (error, fileTree) => { - if (error) return console.error(error) - this.setWorkspace(Object.keys(fileTree)[0].replace(workspacesPath + '/', '')) - }) - this.renderComponent() - } - - async initWorkspace () { - const workspacesPath = this._deps.fileProviders.workspace.workspacesPath - const queryParams = new QueryParams() - const params = queryParams.get() - // get the file from gist - const gistHandler = new GistHandler() - const loadedFromGist = gistHandler.loadFromGist(params, this._deps.fileManager) - if (loadedFromGist) return - if (params.code) { - try { - await this._deps.fileManager.createWorkspace('code-sample') - var hash = ethutil.bufferToHex(ethutil.keccak(params.code)) - const fileName = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol' - const path = 'browser/' + workspacesPath + '/code-sample/' + fileName - await this._deps.fileManager.writeFile(path, atob(params.code)) - this.setWorkspace('code-sample') - await this._deps.fileManager.openFile(path) - } catch (e) { - console.error(e) - } - return - } - // insert example contracts if there are no files to show - this._deps.fileProviders.browser.resolveDirectory('/', async (error, filesList) => { - if (error) console.error(error) - if (Object.keys(filesList).length === 0) { - for (const file in examples) { - await this._deps.fileManager.writeFile('browser/' + workspacesPath + '/default_workspace/' + examples[file].name, examples[file].content) - } - this.setWorkspace('default_workspace') - } - }) - } - - async refreshWorkspacesList () { - if (!document.getElementById('workspacesSelect')) return - const workspaces = await this.getWorkspaces() - workspaces.push(this.LOCALHOST) - workspaces.push(this.NO_WORKSPACE) + + this.request = {} ReactDOM.render( - ( - workspaces - .map((folder) => { - return - })), document.getElementById('workspacesSelect') - ) - } - - resetFocus (value) { - this.reset = value - this.renderComponent() + + , this.el) } - createNewFile () { - this.displayNewFile = true - this.renderComponent() - } - - resetNewFile () { - this.displayNewFile = false - this.renderComponent() + render () { + return this.el } - uploadFile (target) { - this.uploadFileEvent = target - this.renderComponent() + async getCurrentWorkspace () { + return await this.request.getWorkspaces() } - resetUploadFile () { - this.uploadFileEvent = null - this.renderComponent() + async getWorkspaces () { + return await this.request.getWorkspaces() } - render () { - return this.el + async createNewFile () { + return await this.request.createNewFile() } - getWorkspaces () { - return new Promise((resolve, reject) => { - const workspacesPath = this._deps.fileProviders.workspace.workspacesPath - this._deps.fileProviders.browser.resolveDirectory('/' + workspacesPath, (error, items) => { - if (error) return reject(error) - resolve(Object.keys(items) - .filter((item) => items[item].isDirectory) - .map((folder) => folder.replace(workspacesPath + '/', ''))) - }) - }) - } + async uploadFile () { + return await this.request.uploadFile() + } - getCurrentWorkspace () { - return this.currentWorkspace + async createWorkspace () { + return await this.request.createWorkspace() } - async setWorkspace (name) { + /** these are called by the react component, action is already finished whent it's called */ + async setWorkspace (workspace) { this._deps.fileManager.removeTabsOf(this._deps.fileProviders.workspace) - this.currentWorkspace = name - if (name === this.LOCALHOST) { - this._deps.fileProviders.workspace.clearWorkspace() + if (workspace.isLocalhost) { this.call('manager', 'activatePlugin', 'remixd') - } else if (name === this.NO_WORKSPACE) { - this._deps.fileProviders.workspace.clearWorkspace() - } else { - this._deps.fileProviders.workspace.setWorkspace(name) - } - if (name !== this.LOCALHOST && await this.call('manager', 'isActive', 'remixd')) { + } else if (await this.call('manager', 'isActive', 'remixd')) { this.call('manager', 'deactivatePlugin', 'remixd') } - this.renderComponent() - this.emit('setWorkspace', { name }) + this.emit('setWorkspace', workspace) } - - /** - * - * @param item { id: string, name: string, type?: string[], path?: string[], extension?: string[], pattern?: string[] } - * @param callback (...args) => void - */ - registerContextMenuItem (item) { - if (!item) throw new Error('Invalid register context menu argument') - if (!item.name || !item.id) throw new Error('Item name and id is mandatory') - if (!item.type && !item.path && !item.extension && !item.pattern) throw new Error('Invalid file matching criteria provided') - - this.registeredMenuItems = [...this.registeredMenuItems, item] - this.renderComponent() - } - - renameWorkspace () { - modalDialog.prompt('Rename Workspace', 'Please choose a name for the workspace', this.currentWorkspace, async (value) => { - const workspacesPath = this._deps.fileProviders.workspace.workspacesPath - await this._deps.fileManager.rename('browser/' + workspacesPath + '/' + this.currentWorkspace, 'browser/' + workspacesPath + '/' + value) - this.setWorkspace(value) - this.emit('renameWorkspace', { name: value }) - }) + + renameWorkspace (workspace) { + this.emit('renameWorkspace', workspace) } - createWorkspace () { - return new Promise((resolve, reject) => { - const workspace = `workspace_${Date.now()}` - modalDialog.prompt('New Workspace', 'Please choose a name for the workspace', workspace, (value) => { - const workspacesPath = this._deps.fileProviders.workspace.workspacesPath - this._deps.fileProviders.browser.createDir(workspacesPath + '/' + value, async () => { - this.setWorkspace(value) - for (const file in examples) { - await this._deps.fileManager.writeFile(`${examples[file].name}`, examples[file].content) - } - resolve(value) - }) - }, () => reject(new Error('workspace creation rejected by user'))) - }) + deleteWorkspace (workspace) { + this.emit('deleteWorkspace', workspace) } - deleteCurrentWorkspace () { - if (!this.currentWorkspace) return - modalDialog.confirm('Delete Workspace', 'Please confirm workspace deletion', () => { - const workspacesPath = this._deps.fileProviders.workspace.workspacesPath - this._deps.fileProviders.browser.remove(workspacesPath + '/' + this.currentWorkspace) - const name = this.currentWorkspace - this.currentWorkspace = null - this.setWorkspace(this.NO_WORKSPACE) - this.renderComponent() - this.emit('deleteWorkspace', { name }) - }) - } - - renderComponent () { - ReactDOM.render( -
-
this.resetFocus(true)}> -
-
-
- - - { - e.stopPropagation() - this.createWorkspace() - }} - className='far fa-plus-square remixui_menuicon' - title='Create a new Workspace'> - - - - - -
-
-
-
-
-
- { this.hideRemixdExplorer && this.currentWorkspace && this.currentWorkspace !== this.NO_WORKSPACE && - - } -
-
- { !this.hideRemixdExplorer && - - } -
-
- { false && - } -
-
-
-
-
- , this.el) - setTimeout(() => { - this.refreshWorkspacesList() - }, 500) + createWorkspace (workspace) { + this.emit('createWorkspace', workspace) } + /** end section */ } diff --git a/apps/remix-ide/src/app/panels/styles/file-panel-styles.css b/apps/remix-ide/src/app/panels/styles/file-panel-styles.css deleted file mode 100644 index 8744e6a18d..0000000000 --- a/apps/remix-ide/src/app/panels/styles/file-panel-styles.css +++ /dev/null @@ -1,59 +0,0 @@ -.remixui_container { - display : flex; - flex-direction : row; - width : 100%; - height : 100%; - box-sizing : border-box; -} -.remixui_fileexplorer { - display : flex; - flex-direction : column; - position : relative; - width : 100%; - padding-left : 6px; - padding-top : 6px; -} -.remixui_fileExplorerTree { - cursor : default; -} -.remixui_gist { - padding : 10px; -} -.remixui_gist i { - cursor : pointer; -} -.remixui_gist i:hover { - color : orange; -} -.remixui_connectToLocalhost { - padding : 10px; -} -.remixui_connectToLocalhost i { - cursor : pointer; -} -.remixui_connectToLocalhost i:hover { - color : var(--secondary) -} -.remixui_uploadFile { - padding : 10px; -} -.remixui_uploadFile label:hover { - color : var(--secondary) -} -.remixui_uploadFile label { - cursor : pointer; -} -.remixui_treeview { - overflow-y : auto; -} -.remixui_dialog { - display: flex; - flex-direction: column; -} -.remixui_dialogParagraph { - margin-bottom: 2em; - word-break: break-word; -} -.remixui_menuicon { - padding-right : 10px; -} diff --git a/libs/remix-ui/workspace/.babelrc b/libs/remix-ui/workspace/.babelrc new file mode 100644 index 0000000000..09d67939cc --- /dev/null +++ b/libs/remix-ui/workspace/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@nrwl/react/babel"], + "plugins": [] +} diff --git a/libs/remix-ui/workspace/.eslintrc b/libs/remix-ui/workspace/.eslintrc new file mode 100644 index 0000000000..dae5c6feeb --- /dev/null +++ b/libs/remix-ui/workspace/.eslintrc @@ -0,0 +1,19 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "extends": "../../../.eslintrc", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 11, + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error" + } +} diff --git a/libs/remix-ui/workspace/README.md b/libs/remix-ui/workspace/README.md new file mode 100644 index 0000000000..61389a2bf8 --- /dev/null +++ b/libs/remix-ui/workspace/README.md @@ -0,0 +1,7 @@ +# remix-ui-workspace + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test remix-ui-workspace` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/remix-ui/workspace/src/index.ts b/libs/remix-ui/workspace/src/index.ts new file mode 100644 index 0000000000..b6c5ded2a1 --- /dev/null +++ b/libs/remix-ui/workspace/src/index.ts @@ -0,0 +1 @@ +export * from './lib/remix-ui-workspace'; diff --git a/apps/remix-ide/src/app/panels/styles/file-panel-styles.js b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.css similarity index 62% rename from apps/remix-ide/src/app/panels/styles/file-panel-styles.js rename to libs/remix-ui/workspace/src/lib/remix-ui-workspace.css index 4db78296b9..f190b84fac 100644 --- a/apps/remix-ide/src/app/panels/styles/file-panel-styles.js +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.css @@ -1,14 +1,11 @@ -var csjs = require('csjs-inject') - -var css = csjs` - .container { +.remixui_container { display : flex; flex-direction : row; width : 100%; height : 100%; box-sizing : border-box; } - .fileexplorer { + .remixui_fileexplorer { display : flex; flex-direction : column; position : relative; @@ -16,47 +13,48 @@ var css = csjs` padding-left : 6px; padding-top : 6px; } - .fileExplorerTree { + .remixui_fileExplorerTree { cursor : default; } - .gist { + .remixui_gist { padding : 10px; } - .gist i { + .remixui_gist i { cursor : pointer; } - .gist i:hover { + .remixui_gist i:hover { color : orange; } - .connectToLocalhost { + .remixui_connectToLocalhost { padding : 10px; } - .connectToLocalhost i { + .remixui_connectToLocalhost i { cursor : pointer; } - .connectToLocalhost i:hover { + .remixui_connectToLocalhost i:hover { color : var(--secondary) } - .uploadFile { + .remixui_uploadFile { padding : 10px; } - .uploadFile label:hover { + .remixui_uploadFile label:hover { color : var(--secondary) } - .uploadFile label { + .remixui_uploadFile label { cursor : pointer; } - .treeview { + .remixui_treeview { overflow-y : auto; } - .dialog { + .remixui_dialog { display: flex; flex-direction: column; } - .dialogParagraph { + .remixui_dialogParagraph { margin-bottom: 2em; word-break: break-word; } -` - -module.exports = css + .remixui_menuicon { + padding-right : 10px; + } + \ No newline at end of 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 new file mode 100644 index 0000000000..03ec84888f --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -0,0 +1,432 @@ +import React, { useState, useEffect } from 'react'; +import ethutil from 'ethereumjs-util' +import { FileExplorer } from '@remix-ui/file-explorer' // eslint-disable-line +import './remix-ui-workspace.css'; +import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line + +type CodeExamples = { + [key: string]: { name: string, content: string } +}; +/* eslint-disable-next-line */ +export interface WorkspaceProps { + setWorkspace: ({ name: string, isLocalhost: boolean }) => void, + renameWorkspace: ({ name: string }) => void, + createWorkspace: ({ name: string }) => void, + deleteWorkspace: ({ name: string }) => void, + workspace: any // workspace provider, + browser: any // browser provider + localhost: any // localhost provider + fileManager : any + examples: CodeExamples, + queryParams: any // URL parameters + gistHandler: any // handle load gist + registry: any // registry + plugin: any // plugin call and resetFocus + request: any // api request +} + +var canUpload = window.File || window.FileReader || window.FileList || window.Blob + +export const Workspace = (props: WorkspaceProps) => { + const LOCALHOST = ' - connect to localhost - ' + const NO_WORKSPACE = ' - none - ' + + props.request.createWorkspace = () => { + createWorkspace() + } + + props.request.getWorkspaces = () => { + return getWorkspaces() + } + + props.request.createNewFile = () => { + setState(prevState => { + return { ...prevState, displayNewFile: true } + }) + } + + props.request.uploadFile = (target) => { + setState(prevState => { + return { ...prevState, uploadFileEvent: target } + }) + } + + props.request.getCurrentWorkspace = () => { + return state.currentWorkspace + } + + useEffect(() => { + initWorkspace() + }, []) + + const handleHideCreateModal = () => { + setState(prevState => { + state.createModal.hide = true + return { ...prevState, ...state.createModal } + }) + } + + const handleHideDeleteModal = () => { + setState(prevState => { + state.deleteModal.hide = true + return { ...prevState, ...state.deleteModal } + }) + } + + const handleHideRenameModal = () => { + setState(prevState => { + state.renameModal.hide = true + return { ...prevState, ...state.renameModal } + }) + } + + const createWorkspace = () => { + setState(prevState => { + state.createModal.hide = false + return { ...prevState, ...state.createModal } + }) + } + + const renameCurrentWorkspace = () => { + setState(prevState => { + state.renameModal.hide = false + return { ...prevState, ...state.renameModal } + }) + } + + const deleteCurrentWorkspace = () => { + setState(prevState => { + state.deleteModal.hide = false + return { ...prevState, ...state.deleteModal } + }) + } + + const [state, setState] = useState({ + workspaces: [], + reset: false, + currentWorkspace: NO_WORKSPACE, + hideRemixdExplorer: true, + registeredMenuItems: [], + displayNewFile: false, + externalUploads: null, + uploadFileEvent: null, + renameModal: { + id: 'renameWorkspace', + hide: true, + title: 'Rename Workspace', + message: 'Please choose a name for the workspace', + ok: { + label: '', + fn: () => onFinishRenameWorkspace() + }, + cancel: { + label: '', + fn: () => {} + }, + handleHide: handleHideRenameModal + }, + deleteModal: { + id: 'deleteWorkspace', + hide: true, + title: 'Remove Workspace', + message: 'Please confirm workspace deletion', + ok: { + label: '', + fn: () => onFinishDeleteWorkspace() + }, + cancel: { + label: '', + fn: () => {} + }, + handleHide: handleHideDeleteModal + }, + createModal: { + id: 'createWorkspace', + hide: true, + title: 'Create Workspace', + message: 'Please choose a name for the workspace', + ok: { + label: '', + fn: () => onFinishCreateWorkspace() + }, + cancel: { + label: '', + fn: () => {} + }, + handleHide: handleHideCreateModal + } + }) + + let worspaceNewName // used for renaming and creation + + const onFinishRenameWorkspace = async () => { + const workspacesPath = props.workspace.workspacesPath + await props.fileManager.rename('browser/' + workspacesPath + '/' + state.currentWorkspace, 'browser/' + workspacesPath + '/' + worspaceNewName) + setWorkspace(worspaceNewName) + worspaceNewName = '' + props.renameWorkspace({ name: state.currentWorkspace }) + } + + const onFinishCreateWorkspace = async () => { + const workspacesPath = props.workspace.workspacesPath + props.browser.createDir(workspacesPath + '/' + worspaceNewName, async () => { + setWorkspace(worspaceNewName) + for (const file in props.examples) { + await props.fileManager.writeFile(`${props.examples[file].name}`, props.examples[file].content) + } + worspaceNewName = '' + props.createWorkspace({ name: state.currentWorkspace }) + }) + } + + const onFinishDeleteWorkspace = async () => { + const workspacesPath = props.workspace.workspacesPath + props.browser.remove(workspacesPath + '/' + state.currentWorkspace) + const name = state.currentWorkspace + setWorkspace(NO_WORKSPACE) + props.deleteWorkspace({ name }) + } + + const resetFocus = (reset) => { + /*setState(prevState => { + return { ...prevState, reset } + })*/ + } + + const setWorkspace = async (name) => { + if (name === LOCALHOST) { + props.workspace.clearWorkspace() + } else if (name === NO_WORKSPACE) { + props.workspace.clearWorkspace() + } else { + props.workspace.setWorkspace(name) + } + const workspaces = await getWorkspaces() + setState(prevState => { + return { ...prevState, workspaces, currentWorkspace: name } + }) + props.setWorkspace({ name, isLocalhost: name === LOCALHOST }) + } + + const initWorkspace = async () => { + const workspacesPath = props.workspace.workspacesPath + const params = props.queryParams.get() + // get the file from gist + const loadedFromGist = props.gistHandler.loadFromGist(params, props.fileManager) + if (loadedFromGist) return + if (params.code) { + try { + await props.fileManager.createWorkspace('code-sample') + var hash = ethutil.bufferToHex(ethutil.keccak(params.code)) + const fileName = 'contract-' + hash.replace('0x', '').substring(0, 10) + '.sol' + const path = 'browser/' + workspacesPath + '/code-sample/' + fileName + await props.fileManager.writeFile(path, atob(params.code)) + setWorkspace('code-sample') + await props.fileManager.openFile(path) + } catch (e) { + console.error(e) + } + return + } + // insert example contracts if there are no files to show + props.browser.resolveDirectory('/', async (error, filesList) => { + if (error) console.error(error) + if (Object.keys(filesList).length === 0) { + for (const file in props.examples) { + await props.fileManager.writeFile('browser/' + workspacesPath + '/default_workspace/' + props.examples[file].name, props.examples[file].content) + } + setWorkspace('default_workspace') + } else { + // we've already got some workspaces + const workspaces = await getWorkspaces() + if (workspaces.length) setWorkspace(workspaces[0]) + else setWorkspace(NO_WORKSPACE) + } + }) + } + + const getWorkspaces = (): any => { + return new Promise((resolve, reject) => { + const workspacesPath = props.workspace.workspacesPath + props.browser.resolveDirectory('/' + workspacesPath, (error, items) => { + if (error) return reject(error) + resolve(Object.keys(items) + .filter((item) => items[item].isDirectory) + .map((folder) => folder.replace(workspacesPath + '/', ''))) + }) + }) + } + + const remixdExplorer = { + hide: () => { + if (state.currentWorkspace === LOCALHOST) setWorkspace(NO_WORKSPACE) + props.fileManager.setMode('browser') + setState(prevState => { + return { ...prevState, hideRemixdExplorer: true } + }) + }, + show: () => { + props.fileManager.setMode('localhost') + setState(prevState => { + return { ...prevState, hideRemixdExplorer: false } + }) + } + } + + props.localhost.event.register('connecting', (event) => {}) + + props.localhost.event.register('connected', (event) => { + remixdExplorer.show() + }) + + props.localhost.event.register('errored', (event) => { + remixdExplorer.hide() + }) + + props.localhost.event.register('closed', (event) => { + remixdExplorer.hide() + }) + + props.plugin.resetFocus = () => { + setState(prevState => { + return { ...prevState, reset: true } + }) + } + + return ( +
+ + { worspaceNewName = e.target.value } }/> + + + { worspaceNewName = e.target.value } }/> + + + +
resetFocus(true)}> +
+
+
+ + + { + e.stopPropagation() + createWorkspace() + }} + className='far fa-plus-square remixui_menuicon' + title='Create a new Workspace'> + + + + + +
+
+
+
+
+
+ { state.hideRemixdExplorer && state.currentWorkspace && state.currentWorkspace !== NO_WORKSPACE && + + } +
+
+ { !state.hideRemixdExplorer && + + } +
+
+ { false && + } +
+
+
+
+
+ ); +}; + +export default Workspace; diff --git a/libs/remix-ui/workspace/tsconfig.json b/libs/remix-ui/workspace/tsconfig.json new file mode 100644 index 0000000000..6b65264565 --- /dev/null +++ b/libs/remix-ui/workspace/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/remix-ui/workspace/tsconfig.lib.json b/libs/remix-ui/workspace/tsconfig.lib.json new file mode 100644 index 0000000000..b560bc4dec --- /dev/null +++ b/libs/remix-ui/workspace/tsconfig.lib.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/nx.json b/nx.json index 2d9caab10b..5cf047d9cc 100644 --- a/nx.json +++ b/nx.json @@ -92,6 +92,9 @@ }, "debugger": { "tags": [] + }, + "remix-ui-workspace": { + "tags": [] } } } diff --git a/tsconfig.json b/tsconfig.json index 5a873c9f97..c2a383e9de 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,9 @@ "@remix-project/remix-astwalker": ["dist/libs/remix-astwalker/index.js"], "@remix-project/remix-debug": ["dist/libs/remix-debug/src/index.js"], "@remix-project/remix-lib": ["dist/libs/remix-lib/src/index.js"], - "@remix-project/remix-simulator": ["dist/libs/remix-simulator/src/index.js"], + "@remix-project/remix-simulator": [ + "dist/libs/remix-simulator/src/index.js" + ], "@remix-project/remix-solidity": ["dist/libs/remix-solidity/index.js"], "@remix-project/remix-tests": ["dist/libs/remix-tests/src/index.js"], "@remix-project/remix-url-resolver": [ @@ -35,7 +37,8 @@ "@remix-project/remix-solidity-ts": ["libs/remix-solidity/src/index.ts"], "@remix-ui/modal-dialog": ["libs/remix-ui/modal-dialog/src/index.ts"], "@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"], - "@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"] + "@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"], + "@remix-ui/workspace": ["libs/remix-ui/workspace/src/index.ts"] } }, "exclude": ["node_modules", "tmp"] diff --git a/workspace.json b/workspace.json index 3b1e4d5880..10793e13b3 100644 --- a/workspace.json +++ b/workspace.json @@ -347,7 +347,11 @@ "linter": "eslint", "config": "libs/remix-tests/.eslintrc", "tsConfig": ["libs/remix-tests/tsconfig.lib.json"], - "exclude": ["**/node_modules/**", "libs/remix-tests/tests/**/*", "**/dist/**"] + "exclude": [ + "**/node_modules/**", + "libs/remix-tests/tests/**/*", + "**/dist/**" + ] } }, "test": { @@ -705,6 +709,22 @@ } } } + }, + "remix-ui-workspace": { + "root": "libs/remix-ui/workspace", + "sourceRoot": "libs/remix-ui/workspace/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": ["libs/remix-ui/workspace/tsconfig.lib.json"], + "exclude": ["**/node_modules/**", "!libs/remix-ui/workspace/**/*"] + } + } + } } }, "cli": {