diff --git a/package-lock.json b/package-lock.json index f291a48dfe..f32c87ee4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1778,9 +1778,9 @@ "integrity": "sha512-ePDxG9UuU9Kobk90ZUjtmDW8IT9U7aRb1/Rl9683MRNM+ur0ocHL2v7TPH2ajTiVSBUFbbeW8vKIt9jrb0JIAA==" }, "@remixproject/engine": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@remixproject/engine/-/engine-0.2.0.tgz", - "integrity": "sha512-J8UqkQSANp6hKMP5G4/rMYf6j0RJdBYSm4mfkwkpRAZi2/01nPjuBmgbaQ4tFNcwCOjdAMp24ySAKaCj0ciPDA==" + "version": "0.2.0-alpha.4", + "resolved": "https://registry.npmjs.org/@remixproject/engine/-/engine-0.2.0-alpha.4.tgz", + "integrity": "sha512-AY6HaF7Y4fR1oOdz60B2zt+gGftaT5fZWSl5ka7UuDHZUzeouNMx4O1+Uk4376Mv+M3vdmpGFo6KgfsZj6wSJw==" }, "@resolver-engine/core": { "version": "0.3.3", @@ -6737,8 +6737,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -6756,13 +6755,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6775,18 +6772,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -6889,8 +6883,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -6900,7 +6893,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6913,20 +6905,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6943,7 +6932,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -7024,8 +7012,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -7035,7 +7022,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -7111,8 +7097,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -7142,7 +7127,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7160,7 +7144,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7199,13 +7182,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -17777,7 +17758,7 @@ "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.27", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" }, "dependencies": { "debug": { diff --git a/package.json b/package.json index c07ddc0bfc..9339c0d1ad 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "yo-yoify": "^3.7.3" }, "dependencies": { - "@remixproject/engine": "^0.2.0", + "@remixproject/engine": "^0.2.0-alpha.4", "http-server": "^0.11.1", "remixd": "0.1.8-alpha.10", "standard": "^8.5.0" diff --git a/src/app.js b/src/app.js index 547527beb7..6af62bb3bc 100644 --- a/src/app.js +++ b/src/app.js @@ -35,12 +35,14 @@ const DebuggerTab = require('./app/tabs/debugger-tab') const TestTab = require('./app/tabs/test-tab') const FilePanel = require('./app/panels/file-panel') const Editor = require('./app/editor/editor') - +const Terminal = require('./app/panels/terminal') +const ContextualListener = require('./app/editor/contextualListener') import { basicLogo } from './app/ui/svgLogo' import { RunTab, makeUdapp } from './app/udapp' import PanelsResize from './lib/panels-resize' +import { Engine } from '@remixproject/engine' import { RemixAppManager } from './remixAppManager' import { FramingService } from './framingService' import { MainView } from './app/panels/main-view' @@ -229,12 +231,14 @@ Please make a backup of your contracts and start using http://remix.ethereum.org // APP_MANAGER const appManager = new RemixAppManager({}) + const engine = new Engine(appManager) + await engine.onload() const workspace = appManager.pluginLoader.get() // SERVICES - // ----------------- import content servive ---------------------------- + // ----------------- import content servive ------------------------ const contentImport = new CompilerImport() - // ----------------- theme servive ---------------------------- + // ----------------- theme servive --------------------------------- const themeModule = new ThemeModule(registry) registry.put({api: themeModule, name: 'themeModule'}) themeModule.initTheme(() => { @@ -247,6 +251,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const editor = new Editor({}, themeModule) // wrapper around ace editor registry.put({api: editor, name: 'editor'}) editor.event.register('requiringToSaveCurrentfile', () => fileManager.saveCurrentFile()) + // ----------------- fileManager servive ---------------------------- const fileManager = new FileManager(editor) registry.put({api: fileManager, name: 'filemanager'}) @@ -254,20 +259,38 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const blockchain = new Blockchain(registry.get('config').api) const pluginUdapp = new PluginUDapp(blockchain) - // ----------------- compilation metadata generation servive ---------------------------- + // ----------------- compilation metadata generation servive --------- const compilerMetadataGenerator = new CompilerMetadata(blockchain, fileManager, registry.get('config').api) // ----------------- compilation result service (can keep track of compilation results) ---------------------------- const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name) registry.put({api: compilersArtefacts, name: 'compilersartefacts'}) - const {eventsDecoder, txlistener} = makeUdapp(blockchain, compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl)) - // ----------------- network service (resolve network id / name) ---------------------------- + // ----------------- network service (resolve network id / name) ----- const networkModule = new NetworkModule(blockchain) - // ----------------- convert offset to line/column service ---------------------------- - var offsetToLineColumnConverter = new OffsetToLineColumnConverter() + // ----------------- convert offset to line/column service ----------- + const offsetToLineColumnConverter = new OffsetToLineColumnConverter() registry.put({api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter'}) - appManager.register([ + // -------------------Terminal---------------------------------------- + + const terminal = new Terminal( + { appManager, blockchain }, + { + getPosition: (event) => { + var limitUp = 36 + var limitDown = 20 + var height = window.innerHeight + var newpos = (event.pageY < limitUp) ? limitUp : event.pageY + newpos = (newpos < height - limitDown) ? newpos : height - limitDown + return height - newpos + } + } + ) + makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl)) + + const contextualListener = new ContextualListener({editor}) + + engine.register([ contentImport, themeModule, editor, @@ -275,24 +298,24 @@ Please make a backup of your contracts and start using http://remix.ethereum.org compilerMetadataGenerator, compilersArtefacts, networkModule, - offsetToLineColumnConverter + offsetToLineColumnConverter, + contextualListener, + terminal ]) // LAYOUT & SYSTEM VIEWS const appPanel = new MainPanel() - const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder, blockchain) + const mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal) registry.put({ api: mainview, name: 'mainview' }) - appManager.register([ - appPanel - ]) + engine.register(appPanel) // those views depend on app_manager const menuicons = new VerticalIcons(appManager) const landingPage = new LandingPage(appManager, menuicons) const sidePanel = new SidePanel(appManager, menuicons) const hiddenPanel = new HiddenPanel() - const pluginManagerComponent = new PluginManagerComponent(appManager) + const pluginManagerComponent = new PluginManagerComponent(appManager, engine) const filePanel = new FilePanel(appManager) let settings = new SettingsTab( registry.get('config').api, @@ -306,7 +329,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org self._view.sidepanel.appendChild(sidePanel.render()) document.body.appendChild(hiddenPanel.render()) // Hidden Panel is display none, it can be directly on body - appManager.register([ + engine.register([ menuicons, landingPage, sidePanel, @@ -344,7 +367,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org new Renderer() ) - appManager.register([ + engine.register([ compileTab, run, debug, @@ -354,17 +377,17 @@ Please make a backup of your contracts and start using http://remix.ethereum.org ]) try { - appManager.register(await appManager.registeredPlugins()) + engine.register(await appManager.registeredPlugins()) } catch (e) { console.log('couldn\'t register iframe plugins', e.message) } - await appManager.activate(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter']) - await appManager.activate(['mainPanel']) - await appManager.activate(['menuicons', 'home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings']) + await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter']) + await appManager.activatePlugin(['mainPanel', 'menuicons']) + await appManager.activatePlugin(['home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings', 'contextualListener', 'terminal']) // Set workspace after initial activation - if (Array.isArray(workspace)) await appManager.activate(workspace) + if (Array.isArray(workspace)) await appManager.activatePlugin(workspace) // Load and start the service who manager layout and frame const framingService = new FramingService(sidePanel, menuicons, mainview, this._components.resizeFeature) @@ -390,6 +413,6 @@ Please make a backup of your contracts and start using http://remix.ethereum.org } if (isElectron()) { - appManager.activate(['remixd']) + appManager.activatePlugin('remixd') } } diff --git a/src/app/components/hidden-panel.js b/src/app/components/hidden-panel.js index a76c521f0e..73c6fb26e6 100644 --- a/src/app/components/hidden-panel.js +++ b/src/app/components/hidden-panel.js @@ -13,7 +13,8 @@ const profile = { name: 'hiddenPanel', displayName: 'Hidden Panel', description: '', - version: packageJson.version + version: packageJson.version, + methods: [] } export class HiddenPanel extends AbstractPanel { diff --git a/src/app/components/local-plugin.js b/src/app/components/local-plugin.js index bcd2929236..f71e10d7bb 100644 --- a/src/app/components/local-plugin.js +++ b/src/app/components/local-plugin.js @@ -9,10 +9,9 @@ const defaultProfile = { } module.exports = class LocalPlugin { - /** * Open a modal to create a local plugin - * @param {PluginApi[]} plugins The list of the plugins in the store + * @param {Profile[]} plugins The list of the plugins in the store * @returns {Promise<{api: any, profile: any}>} A promise with the new plugin profile */ open (plugins) { @@ -26,7 +25,7 @@ module.exports = class LocalPlugin { reject(err) } } - modalDialog('Local Plugin', this.form(plugins), + modalDialog('Local Plugin', this.form(), { fn: () => onValidation() }, { fn: () => resolve() } ) diff --git a/src/app/components/main-panel.js b/src/app/components/main-panel.js index def2acc62e..082ccb61c5 100644 --- a/src/app/components/main-panel.js +++ b/src/app/components/main-panel.js @@ -20,8 +20,8 @@ const profile = { } export class MainPanel extends AbstractPanel { - constructor (options) { - super(profile, options) + constructor () { + super(profile) } render () { diff --git a/src/app/components/panel.js b/src/app/components/panel.js index fcbecbc397..bd1d59d176 100644 --- a/src/app/components/panel.js +++ b/src/app/components/panel.js @@ -1,7 +1,7 @@ import { EventEmitter } from 'events' const csjs = require('csjs-inject') const yo = require('yo-yo') -const { HostPlugin } = require('@remixproject/engine') +import { HostPlugin } from '@remixproject/engine' const css = csjs` .plugins { @@ -28,7 +28,7 @@ const css = csjs` /** Abstract class used for hosting the view of a plugin */ export class AbstractPanel extends HostPlugin { - constructor (profile, opts) { + constructor (profile) { super(profile) this.events = new EventEmitter() this.contents = {} diff --git a/src/app/components/plugin-manager-component.js b/src/app/components/plugin-manager-component.js index 2c7f06615d..2b95d250e7 100644 --- a/src/app/components/plugin-manager-component.js +++ b/src/app/components/plugin-manager-component.js @@ -72,7 +72,7 @@ const profile = { class PluginManagerComponent extends ViewPlugin { - constructor (appManager) { + constructor (appManager, engine) { super(profile) this.event = new EventEmitter() this.appManager = appManager @@ -85,37 +85,46 @@ class PluginManagerComponent extends ViewPlugin { this.appManager.event.on('activate', () => { this.reRender() }) this.appManager.event.on('deactivate', () => { this.reRender() }) this.appManager.event.on('added', () => { this.reRender() }) + this.engine = engine } - renderItem (name) { - const api = this.appManager.getOne(name) - if (!api) return - const isActive = this.appManager.isActive(name) - const displayName = (api.profile.displayName) ? api.profile.displayName : name + isActive (name) { + return this.appManager.actives.includes(name) + } + + renderItem (profile) { + const displayName = (profile.displayName) ? profile.displayName : profile.name // Check version of the plugin let versionWarning // Alpha - if (api.profile.version && api.profile.version.match(/\b(\w*alpha\w*)\b/g)) { + if (profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) { versionWarning = yo`alpha` } // Beta - if (api.profile.version && api.profile.version.match(/\b(\w*beta\w*)\b/g)) { + if (profile.version && profile.version.match(/\b(\w*beta\w*)\b/g)) { versionWarning = yo`beta` } - const activationButton = isActive + const activationButton = this.isActive(profile.name) ? yo` - ` + + ` : yo` - ` return yo` -
+
${displayName} @@ -123,7 +132,7 @@ class PluginManagerComponent extends ViewPlugin {
${activationButton}
-

${api.profile.description}

+

${profile.description}

` } @@ -141,10 +150,9 @@ class PluginManagerComponent extends ViewPlugin { if (this.appManager.getIds().includes(profile.name)) { throw new Error('This name has already been used') } - const plugin = profile.type === 'iframe' ? new IframePlugin(profile) : new WebsocketPlugin(profile) - this.appManager.registerOne(plugin) - this.appManager.activateOne(profile.name) + this.engine.register(plugin) + this.appManager.activatePlugin(plugin.name) } catch (err) { // TODO : Use an alert to handle this error instead of a console.log console.log(`Cannot create Plugin : ${err.message}`) @@ -154,25 +162,25 @@ class PluginManagerComponent extends ViewPlugin { render () { // Filtering helpers - const isFiltered = (api) => (api.profile.displayName ? api.profile.displayName : api.name).toLowerCase().includes(this.filter) - const isNotRequired = ({profile}) => !this.appManager.isRequired(profile.name) - const isNotHome = ({profile}) => profile.name !== 'home' - const sortByName = (a, b) => { - const nameA = ((a.profile.displayName) ? a.profile.displayName : a.profile.name).toUpperCase() - const nameB = ((b.profile.displayName) ? b.profile.displayName : b.profile.name).toUpperCase() + const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(this.filter) + const isNotRequired = (profile) => !this.appManager.isRequired(profile.name) + const isNotHome = (profile) => profile.name !== 'home' + const sortByName = (profileA, profileB) => { + const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase() + const nameB = ((profileB.displayName) ? profileB.displayName : profileB.name).toUpperCase() return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0 } // Filter all active and inactive modules that are not required - const { actives, inactives } = this.appManager.getAll() + const {actives, inactives} = this.appManager.getAll() .filter(isFiltered) .filter(isNotRequired) .filter(isNotHome) .sort(sortByName) - .reduce(({actives, inactives}, api) => { - return this.appManager.isActive(api.name) - ? { actives: [...actives, api.name], inactives } - : { inactives: [...inactives, api.name], actives } + .reduce(({actives, inactives}, profile) => { + return this.isActive(profile.name) + ? { actives: [...actives, profile], inactives } + : { inactives: [...inactives, profile], actives } }, { actives: [], inactives: [] }) const activeTile = actives.length !== 0 @@ -203,11 +211,11 @@ class PluginManagerComponent extends ViewPlugin {
${activeTile}
- ${actives.map(name => this.renderItem(name))} + ${actives.map(profile => this.renderItem(profile))}
${inactiveTile}
- ${inactives.map(name => this.renderItem(name))} + ${inactives.map(profile => this.renderItem(profile))}
${settings} diff --git a/src/app/components/side-panel.js b/src/app/components/side-panel.js index ac110c3a82..a4a5e23245 100644 --- a/src/app/components/side-panel.js +++ b/src/app/components/side-panel.js @@ -48,10 +48,6 @@ const css = csjs` } ` -const options = { - default: true -} - const sidePanel = { name: 'sidePanel', displayName: 'Side Panel', @@ -64,9 +60,10 @@ const sidePanel = { export class SidePanel extends AbstractPanel { constructor (appManager, verticalIcons) { - super(sidePanel, options) + super(sidePanel) this.appManager = appManager - this.header = this.renderHeader() + this.header = yo`
` + this.renderHeader() this.verticalIcons = verticalIcons // Toggle content @@ -107,18 +104,18 @@ export class SidePanel extends AbstractPanel { * Display content and update the header * @param {String} name The name of the plugin to display */ - showContent (name) { + async showContent (name) { super.showContent(name) - yo.update(this.header, this.renderHeader()) + this.renderHeader() } /** The header of the side panel */ - renderHeader () { + async renderHeader () { let name = ' - ' let docLink = '' let versionWarning if (this.active) { - const { profile } = this.appManager.getOne(this.active) + const profile = await this.appManager.getProfile(this.active) name = profile.displayName ? profile.displayName : profile.name docLink = profile.documentation ? yo`` : '' if (profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) { @@ -130,13 +127,14 @@ export class SidePanel extends AbstractPanel { } } - return yo` + const header = yo`
${name}
${docLink} ${versionWarning}
` + yo.update(this.header, header) } render () { diff --git a/src/app/files/fileManager.js b/src/app/files/fileManager.js index 4ec3095bf2..a4518ce2f3 100644 --- a/src/app/files/fileManager.js +++ b/src/app/files/fileManager.js @@ -9,6 +9,7 @@ const toaster = require('../ui/tooltip') const modalDialogCustom = require('../ui/modal-dialog-custom') const helper = require('../../lib/helper.js') import { Plugin } from '@remixproject/engine' +import { isNative } from '../../remixAppManager.js' import * as packageJson from '../../../package.json' /* @@ -172,7 +173,7 @@ class FileManager extends Plugin { toaster.hide() } if (this.currentRequest) { - if (this.currentRequest.isFromNative) { + if (isNative(this.currentRequest.from)) { this._setFileInternal(path, content) return } diff --git a/src/app/panels/main-view.js b/src/app/panels/main-view.js index c1f981ab94..6e9e2a4f54 100644 --- a/src/app/panels/main-view.js +++ b/src/app/panels/main-view.js @@ -1,11 +1,9 @@ var yo = require('yo-yo') var EventManager = require('../../lib/events') -var Terminal = require('./terminal') var globalRegistry = require('../../global/registry') var { TabProxy } = require('./tab-proxy.js') -var ContextualListener = require('../editor/contextualListener') var ContextView = require('../editor/contextView') var csjs = require('csjs-inject') @@ -20,7 +18,7 @@ var css = csjs` ` export class MainView { - constructor (editor, mainPanel, fileManager, appManager, txListener, eventsDecoder, blockchain) { + constructor (contextualListener, editor, mainPanel, fileManager, appManager, terminal) { var self = this self.event = new EventManager() self._view = {} @@ -29,9 +27,9 @@ export class MainView { self.editor = editor self.fileManager = fileManager self.mainPanel = mainPanel - self.txListener = txListener - self.eventsDecoder = eventsDecoder - self.blockchain = blockchain + self.txListener = globalRegistry.get('txlistener').api + self._components.terminal = terminal + self._components.contextualListener = contextualListener this.appManager = appManager this.init() } @@ -88,32 +86,10 @@ export class MainView { } } - var contextualListener = new ContextualListener({editor: self.editor}) - this.appManager.registerOne(contextualListener) - this.appManager.activate('contextualListener') - - var contextView = new ContextView({contextualListener, editor: self.editor}) + const contextView = new ContextView({contextualListener: self._components.contextualListener, editor: self.editor}) - self._components.contextualListener = contextualListener self._components.contextView = contextView - self._components.terminal = new Terminal({ - appManager: this.appManager, - eventsDecoder: this.eventsDecoder, - txListener: this.txListener, - blockchain: this.blockchain - }, - { - getPosition: (event) => { - var limitUp = 36 - var limitDown = 20 - var height = window.innerHeight - var newpos = (event.pageY < limitUp) ? limitUp : event.pageY - newpos = (newpos < height - limitDown) ? newpos : height - limitDown - return height - newpos - } - }) - self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta)) if (self.txListener) { self._components.terminal.event.register('listenOnNetWork', (listenOnNetWork) => { diff --git a/src/app/panels/tab-proxy.js b/src/app/panels/tab-proxy.js index d69dbd7e96..52c597c2df 100644 --- a/src/app/panels/tab-proxy.js +++ b/src/app/panels/tab-proxy.js @@ -49,25 +49,24 @@ export class TabProxy { }) }) - appManager.event.on('activate', (name) => { - const { profile } = appManager.getOne(name) - if (profile.location === 'mainPanel') { + appManager.event.on('activate', ({ name, location, displayName, icon }) => { + if (location === 'mainPanel') { this.addTab( name, - profile.displayName, + displayName, () => this.event.emit('switchApp', name), () => { this.event.emit('closeApp', name) - this.appManager.deactivateOne(name) + this.appManager.deactivatePlugin(name) }, - profile.icon + icon ) this.switchTab(name) } }) - appManager.event.on('deactivate', (name) => { - this.removeTab(name) + appManager.event.on('deactivate', (profile) => { + this.removeTab(profile.name) }) appManager.event.on('ensureActivated', (name) => { diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index f9ea36f932..6b94f7774b 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -45,7 +45,7 @@ class Terminal extends Plugin { self._api = api self._opts = opts self.data = { - lineLength: opts.lineLength || 80, + lineLength: opts.lineLength || 80, // ???? session: [], activeFilters: { commands: {}, input: '' }, filterFns: {} @@ -95,12 +95,7 @@ class Terminal extends Plugin { self._jsSandboxContext = {} self._jsSandboxRegistered = {} - // TODO move this to the application start. Put it in mainView. - // We should have a HostPlugin which add the terminal. - opts.appManager.register(this) - opts.appManager.activate('terminal') - - if (opts.shell) self._shell = opts.shell + if (opts.shell) self._shell = opts.shell // ??? register(self) } logHtml (html) { @@ -139,7 +134,7 @@ class Terminal extends Plugin { self._view.inputSearch = yo` @@ -438,10 +433,10 @@ class Terminal extends Plugin { self._shell('remix.help()', self.commands, () => {}) self.commands.html(intro) - self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this, self.blockchain) - self._components.txLogger.event.register('debuggingRequested', (hash) => { + self._components.txLogger = new TxLogger(this, self.blockchain) + self._components.txLogger.event.register('debuggingRequested', async (hash) => { // TODO should probably be in the run module - if (!self._opts.appManager.isActive('debugger')) self._opts.appManager.activateOne('debugger') + if (!await self._opts.appManager.isActive('debugger')) await self._opts.appManager.activatePlugin('debugger') this.call('debugger', 'debug', hash) this.call('menuicons', 'select', 'debugger') }) diff --git a/src/app/tabs/test-tab.js b/src/app/tabs/test-tab.js index 28bc2ba059..68e0fdaad1 100644 --- a/src/app/tabs/test-tab.js +++ b/src/app/tabs/test-tab.js @@ -227,7 +227,7 @@ module.exports = class TestTab extends ViewPlugin { updateRunAction (currentFile) { let el = yo`` - const isSolidityActive = this.appManager.isActive('solidity') + const isSolidityActive = this.appManager.actives.includes('solidity') if (!currentFile || !isSolidityActive) { el.setAttribute('disabled', 'disabled') if (!currentFile) el.setAttribute('title', 'No file selected') diff --git a/src/app/udapp/make-udapp.js b/src/app/udapp/make-udapp.js index e9a8262718..9b7a247f50 100644 --- a/src/app/udapp/make-udapp.js +++ b/src/app/udapp/make-udapp.js @@ -52,6 +52,5 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) { } }) txlistener.startListening() - - return {txlistener, eventsDecoder} + registry.put({api: eventsDecoder, name: 'eventsDecoder'}) } diff --git a/src/app/ui/auto-complete-popup.js b/src/app/ui/auto-complete-popup.js index 2163e83143..9a472c503d 100644 --- a/src/app/ui/auto-complete-popup.js +++ b/src/app/ui/auto-complete-popup.js @@ -189,13 +189,12 @@ class AutoCompletePopup { extendAutocompletion () { // TODO: this is not using the appManager interface. Terminal should be put as module - this.opts.appManager.event.on('activate', (id) => { - const profile = this.opts.appManager.getOne(id).profile + this.opts.appManager.event.on('activate', async (profile) => { if (!profile.methods) return profile.methods.forEach((method) => { - const key = `remix.call({name: '${id}', key:'${method}', payload: []}).then((result) => { console.log(result) }).catch((error) => { console.log(error) })` + const key = `remix.call({name: '${profile.name}', key:'${method}', payload: []}).then((result) => { console.log(result) }).catch((error) => { console.log(error) })` const keyValue = {} - keyValue[key] = `call ${id} - ${method}` + keyValue[key] = `call ${profile.name} - ${method}` if (this.extraCommands.includes(keyValue)) return this.extraCommands.push(keyValue) }) diff --git a/src/app/ui/txLogger.js b/src/app/ui/txLogger.js index 15c45f6982..2301ccbc06 100644 --- a/src/app/ui/txLogger.js +++ b/src/app/ui/txLogger.js @@ -116,7 +116,7 @@ var css = csjs` * */ class TxLogger { - constructor (eventsDecoder, txListener, terminal, blockchain) { + constructor (terminal, blockchain) { this.event = new EventManager() this.seen = {} function filterTx (value, query) { @@ -125,8 +125,8 @@ class TxLogger { } return false } - this.eventsDecoder = eventsDecoder - this.txListener = txListener + this.eventsDecoder = globlalRegistry.get('eventsDecoder').api + this.txListener = globlalRegistry.get('txlistener').api this.terminal = terminal // dependencies this._deps = { diff --git a/src/remixAppManager.js b/src/remixAppManager.js index 98e35da48e..809a5b136b 100644 --- a/src/remixAppManager.js +++ b/src/remixAppManager.js @@ -1,75 +1,77 @@ /* global localStorage, fetch */ -import { PluginEngine, IframePlugin } from '@remixproject/engine' +import { PluginManager, IframePlugin } from '@remixproject/engine' import { EventEmitter } from 'events' -import { PermissionHandler } from './app/ui/persmission-handler' import QueryParams from './lib/query-params' const requiredModules = [ // services + layout views + system views - 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', + 'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileExplorers', 'terminal', 'settings', 'pluginManager'] -const settings = { - permissionHandler: new PermissionHandler(), - autoActivate: false, - natives: ['vyper', 'workshops', 'ethdoc', 'etherscan'] // Force iframe plugin to be seen as native +export function isNative (name) { + const nativePlugins = ['vyper', 'workshops', 'ethdoc', 'etherscan'] + return nativePlugins.includes(name) || requiredModules.includes(name) } -export class RemixAppManager extends PluginEngine { +export class RemixAppManager extends PluginManager { constructor (plugins) { - super(plugins, settings) + super() this.event = new EventEmitter() - this.registered = {} this.pluginsDirectory = 'https://raw.githubusercontent.com/ethereum/remix-plugins-directory/master/build/metadata.json' this.pluginLoader = new PluginLoader() } - onActivated (plugin) { + async canActivate (from, to) { + return from.name === 'manager' + } + + async canDeactivate (from, to) { + return from.name === 'manager' + } + + async canCall (From, to, method) { + // todo This is the dafault behaviour, we could save user choises in session scope + return true + } + + onPluginActivated (plugin) { this.pluginLoader.set(plugin, this.actives) - this.event.emit('activate', plugin.name) + this.event.emit('activate', plugin) } getAll () { - return Object.keys(this.registered).map((p) => { - return this.registered[p] + return Object.keys(this.profiles).map((p) => { + return this.profiles[p] }) } - getOne (name) { - return this.registered[name] - } - getIds () { - return Object.keys(this.registered) + return Object.keys(this.profiles) } - onDeactivated (plugin) { + onPluginDeactivated (plugin) { this.pluginLoader.set(plugin, this.actives) - this.event.emit('deactivate', plugin.name) + this.event.emit('deactivate', plugin) } onRegistration (plugin) { - if (!this.registered) this.registered = {} - this.registered[plugin.name] = plugin this.event.emit('added', plugin.name) } - // TODO check whether this can be removed - ensureActivated (apiName) { - if (!this.isActive(apiName)) this.activateOne(apiName) + async ensureActivated (apiName) { + await this.activatePlugin(apiName) this.event.emit('ensureActivated', apiName) } - // TODO check whether this can be removed - ensureDeactivated (apiName) { - if (this.isActive(apiName)) this.deactivateOne(apiName) + async ensureDeactivated (apiName) { + await this.deactivatePlugin(apiName) this.event.emit('ensureDeactivated', apiName) } - deactivateOne (name) { + deactivatePlugin (name) { if (requiredModules.includes(name)) return - super.deactivateOne(name) + super.deactivatePlugin(name) } isRequired (name) { diff --git a/test-browser/tests/pluginManager.js b/test-browser/tests/pluginManager.js index dbcfac6fb8..10eace0641 100644 --- a/test-browser/tests/pluginManager.js +++ b/test-browser/tests/pluginManager.js @@ -22,20 +22,20 @@ module.exports = { 'Should Search for plugins': function (browser) { browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]') - .click('*[data-id="pluginManagerComponentSearchInput"]') - .keys('debugger') - .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtondebugger"]') - .clearValue('*[data-id="pluginManagerComponentSearchInput"]') - .click('*[data-id="pluginManagerComponentSearchInput"]') - .keys('Deploy & run transactions') - .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonudapp"]') - .clearValue('*[data-id="pluginManagerComponentSearchInput"]') - .click('*[data-id="pluginManagerComponentSearchInput"]') - .keys('ZoKrates') - .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonZoKrates"]') - .clearValue('*[data-id="pluginManagerComponentSearchInput"]') - .click('*[data-id="pluginManagerComponentSearchInput"]') - .keys(browser.Keys.ENTER) + .click('*[data-id="pluginManagerComponentSearchInput"]') + .keys('debugger') + .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtondebugger"]') + .clearValue('*[data-id="pluginManagerComponentSearchInput"]') + .click('*[data-id="pluginManagerComponentSearchInput"]') + .keys('Deploy & run transactions') + .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonudapp"]') + .clearValue('*[data-id="pluginManagerComponentSearchInput"]') + .click('*[data-id="pluginManagerComponentSearchInput"]') + .keys('ZoKrates') + .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonZoKrates"]') + .clearValue('*[data-id="pluginManagerComponentSearchInput"]') + .click('*[data-id="pluginManagerComponentSearchInput"]') + .keys(browser.Keys.ENTER) }, 'Should activate plugins': function (browser) { @@ -58,6 +58,7 @@ module.exports = { .waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonudapp"]') }, + /* 'Should grant plugin permission (ZOKRATES)': function (browser) { browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]') .click('*[data-id="pluginManagerSettingsButton"]') @@ -93,6 +94,7 @@ module.exports = { .assert.containsText('*[data-id="pluginManagerSettingsPermissionForm"]', 'No Permission requested yet') .modalFooterOKClick() }, + */ 'Should connect a local plugin': function (browser) { browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]') @@ -125,6 +127,5 @@ module.exports = { .assert.containsText('*[data-id="tooltipPopup"]', 'Cannot create Plugin : This name has already been used') .end() }, - tearDown: sauce }