Merge pull request #2166 from ethereum/newPlugEngine

Use the new remix-plugin engine
pull/1/head
yann300 5 years ago committed by GitHub
commit fd9c8d068a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      package.json
  2. 386
      src/app.js
  3. 33
      src/app/compiler/compiler-artefacts.js
  4. 23
      src/app/compiler/compiler-imports.js
  5. 13
      src/app/components/hidden-panel.js
  6. 14
      src/app/components/main-panel.js
  7. 66
      src/app/components/panel.js
  8. 39
      src/app/components/plugin-manager-component.js
  9. 36
      src/app/components/plugin-manager-proxy.js
  10. 47
      src/app/components/side-panel.js
  11. 74
      src/app/components/vertical-icons.js
  12. 10
      src/app/editor/SourceHighlighters.js
  13. 29
      src/app/editor/contextualListener.js
  14. 10
      src/app/editor/editor.js
  15. 10
      src/app/files/browser-files-tree.js
  16. 78
      src/app/files/compiler-metadata.js
  17. 59
      src/app/files/fileManager.js
  18. 11
      src/app/files/remixd-handle.js
  19. 30
      src/app/panels/file-panel.js
  20. 75
      src/app/panels/main-view.js
  21. 8
      src/app/panels/tab-proxy.js
  22. 32
      src/app/panels/terminal.js
  23. 14
      src/app/tabs/analysis-tab.js
  24. 34
      src/app/tabs/compile-tab.js
  25. 0
      src/app/tabs/compileTab/contractParser.js
  26. 13
      src/app/tabs/debugger-tab.js
  27. 10
      src/app/tabs/debugger/debuggerUI.js
  28. 2
      src/app/tabs/debugger/debuggerUI/ButtonNavigator.js
  29. 2
      src/app/tabs/debugger/debuggerUI/Slider.js
  30. 2
      src/app/tabs/debugger/debuggerUI/StepManager.js
  31. 2
      src/app/tabs/debugger/debuggerUI/TxBrowser.js
  32. 0
      src/app/tabs/debugger/debuggerUI/VmDebugger.js
  33. 0
      src/app/tabs/debugger/debuggerUI/styles/basicStyles.js
  34. 0
      src/app/tabs/debugger/debuggerUI/styles/dropdownPanel.js
  35. 0
      src/app/tabs/debugger/debuggerUI/styles/sliderStyles.js
  36. 0
      src/app/tabs/debugger/debuggerUI/styles/treeView.js
  37. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/CalldataPanel.js
  38. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/CallstackPanel.js
  39. 2
      src/app/tabs/debugger/debuggerUI/vmDebugger/CodeListView.js
  40. 4
      src/app/tabs/debugger/debuggerUI/vmDebugger/DropdownPanel.js
  41. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/FullStoragesChanges.js
  42. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/MemoryPanel.js
  43. 2
      src/app/tabs/debugger/debuggerUI/vmDebugger/SolidityLocals.js
  44. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/SolidityState.js
  45. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/StackPanel.js
  46. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/StepDetail.js
  47. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/StoragePanel.js
  48. 0
      src/app/tabs/debugger/debuggerUI/vmDebugger/utils/SolidityTypeFormatter.js
  49. 8
      src/app/tabs/network-module.js
  50. 49
      src/app/tabs/run-tab.js
  51. 4
      src/app/tabs/runTab/contractDropdown.js
  52. 41
      src/app/tabs/runTab/model/dropdownlogic.js
  53. 2
      src/app/tabs/runTab/recorder.js
  54. 10
      src/app/tabs/runTab/settings.js
  55. 4
      src/app/tabs/settings-tab.js
  56. 18
      src/app/tabs/staticanalysis/staticAnalysisView.js
  57. 0
      src/app/tabs/staticanalysis/styles/staticAnalysisView-styles.js
  58. 27
      src/app/tabs/test-tab.js
  59. 7
      src/app/tabs/theme-module.js
  60. 6
      src/app/ui/auto-complete-popup.js
  61. 2
      src/app/ui/confirmDialog.js
  62. 35
      src/app/ui/landing-page/landing-page.js
  63. 4
      src/app/ui/landing-page/workspace.js
  64. 4
      src/app/ui/multiParamManager.js
  65. 4
      src/app/ui/persmission-handler.js
  66. 37
      src/app/ui/txLogger.js
  67. 36
      src/app/ui/universal-dapp-ui.js
  68. 34
      src/framingService.js
  69. 7
      src/lib/cmdInterpreterAPI.js
  70. 0
      src/lib/commands.js
  71. 21
      src/lib/gist-handler.js
  72. 52
      src/lib/offsetToLineColumnConverter.js
  73. 0
      src/lib/publishOnSwarm.js
  74. 289
      src/lib/store.js
  75. 2
      src/lib/transactionReceiptResolver.js
  76. 22
      src/loadFilesFromParent.js
  77. 48
      src/makeUdapp.js
  78. 11
      src/module-id.js
  79. 86
      src/remixAppManager.js
  80. 7
      src/universal-dapp.js

@ -74,7 +74,7 @@
},
"dependencies": {
"http-server": "^0.11.1",
"remix-plugin": "0.0.2-alpha.10",
"@remixproject/engine": "^0.1.2-7",
"remixd": "0.1.8-alpha.6"
},
"repository": {

@ -2,38 +2,32 @@
'use strict'
var isElectron = require('is-electron')
var $ = require('jquery')
var csjs = require('csjs-inject')
var yo = require('yo-yo')
var async = require('async')
var request = require('request')
var remixLib = require('remix-lib')
var registry = require('./global/registry')
var UniversalDApp = require('./universal-dapp.js')
var UniversalDAppUI = require('./universal-dapp-ui.js')
var Remixd = require('./lib/remixd')
var OffsetToLineColumnConverter = require('./lib/offsetToLineColumnConverter')
var loadFileFromParent = require('./loadFilesFromParent')
var { OffsetToLineColumnConverter } = require('./lib/offsetToLineColumnConverter')
var QueryParams = require('./lib/query-params')
var GistHandler = require('./lib/gist-handler')
var helper = require('./lib/helper')
var makeUdapp = require('./makeUdapp')
var Storage = remixLib.Storage
var Browserfiles = require('./app/files/browser-files')
var SharedFolder = require('./app/files/shared-folder')
var Config = require('./config')
var Renderer = require('./app/ui/renderer')
var executionContext = require('./execution-context')
var examples = require('./app/editor/example-contracts')
var modalDialogCustom = require('./app/ui/modal-dialog-custom')
var TxLogger = require('./app/execution/txLogger')
var Txlistener = remixLib.execution.txListener
var EventsDecoder = remixLib.execution.EventsDecoder
var FileManager = require('./app/files/fileManager')
var BasicReadOnlyExplorer = require('./app/files/basicReadOnlyExplorer')
var NotPersistedExplorer = require('./app/files/NotPersistedExplorer')
var toolTip = require('./app/ui/tooltip')
var TransactionReceiptResolver = require('./transactionReceiptResolver')
var CompilerMetadata = require('./app/files/compiler-metadata')
var CompilerImport = require('./app/compiler/compiler-imports')
const PluginManagerComponent = require('./app/components/plugin-manager-component')
const CompilersArtefacts = require('./app/compiler/compiler-artefacts')
const CompileTab = require('./app/tabs/compile-tab')
const SettingsTab = require('./app/tabs/settings-tab')
@ -42,19 +36,19 @@ const DebuggerTab = require('./app/tabs/debugger-tab')
const TestTab = require('./app/tabs/test-tab')
const RunTab = require('./app/tabs/run-tab')
const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
import PanelsResize from './lib/panels-resize'
import { EntityStore } from './lib/store'
import { RemixAppManager } from './remixAppManager'
import { LandingPage } from './app/ui/landing-page/landing-page'
import framingService from './framingService'
import { FramingService } from './framingService'
import { MainView } from './app/panels/main-view'
import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module'
import { SidePanel } from './app/components/side-panel'
import { MainPanel } from './app/components/main-panel'
import { HiddenPanel } from './app/components/hidden-panel'
import { VerticalIcons } from './app/components/vertical-icons'
import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel'
var css = csjs`
html { box-sizing: border-box; }
@ -119,19 +113,15 @@ class App {
constructor (api = {}, events = {}, opts = {}) {
var self = this
self._components = {}
registry.put({api: self, name: 'app'})
// setup storage
var fileStorage = new Storage('sol:')
registry.put({api: fileStorage, name: 'fileStorage'})
var configStorage = new Storage('config-v0.8:')
registry.put({api: configStorage, name: 'configStorage'})
self._components.config = new Config(configStorage)
registry.put({api: self._components.config, name: 'config'})
self._components.gistHandler = new GistHandler()
// load app config
const config = new Config(configStorage)
registry.put({api: config, name: 'config'})
// load file system
self._components.filesProviders = {}
self._components.filesProviders['browser'] = new Browserfiles(fileStorage)
registry.put({api: self._components.filesProviders['browser'], name: 'fileproviders/browser'})
@ -198,44 +188,6 @@ class App {
`
return self._view.el
}
loadFromGist (params) {
const self = this
return self._components.gistHandler.handleLoad(params, function (gistId) {
request.get({
url: `https://api.github.com/gists/${gistId}`,
json: true
}, (error, response, data = {}) => {
if (error || !data.files) {
modalDialogCustom.alert(`Gist load error: ${error || data.message}`)
return
}
self.loadFiles(data.files, 'gist', (errorLoadingFile) => {
if (!errorLoadingFile) self._components.filesProviders['gist'].id = gistId
})
})
})
}
loadFiles (filesSet, fileProvider, callback) {
const self = this
if (!fileProvider) fileProvider = 'browser'
async.each(Object.keys(filesSet), (file, callback) => {
helper.createNonClashingName(file, self._components.filesProviders[fileProvider],
(error, name) => {
if (error) {
modalDialogCustom.alert('Unexpected error loading the file ' + error)
} else if (helper.checkSpecialChars(name)) {
modalDialogCustom.alert('Special characters are not allowed')
} else {
self._components.filesProviders[fileProvider].set(name, filesSet[file].content)
}
callback()
})
}, (error) => {
if (!error) self._components.fileManager.switchFile()
if (callback) callback(error)
})
}
}
module.exports = App
@ -243,6 +195,7 @@ module.exports = App
function run () {
var self = this
// check the origin and warn message
if (window.location.hostname === 'yann300.github.io') {
modalDialogCustom.alert('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.')
} else if (window.location.hostname === 'remix-alpha.ethereum.org' ||
@ -256,10 +209,11 @@ function run () {
This instance of Remix you are visiting WILL NOT BE UPDATED.\n
Please make a backup of your contracts and start using http://remix.ethereum.org`)
}
if (window.location.protocol.indexOf('https') === 0) {
toolTip('You are using an `https` connection. Please switch to `http` if you are using Remix against an `http Web3 provider` or allow Mixed Content in your browser.')
}
// workaround for Electron support
if (!isElectron()) {
// Oops! Accidentally trigger refresh or bookmark.
window.onbeforeunload = function () {
@ -267,248 +221,142 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
}
}
let appStore = new EntityStore('module', 'name')
// Get workspace before creating the App Manager
// APP_MANAGER
const appManager = new RemixAppManager({})
const workspace = JSON.parse(localStorage.getItem('workspace'))
const appManager = new RemixAppManager(appStore)
registry.put({api: appManager, name: 'appmanager'})
registry.put({api: msg => self._components.mainview.logHtmlMessage(msg), name: 'logCallback'})
// helper for converting offset to line/column
var offsetToLineColumnConverter = new OffsetToLineColumnConverter(appManager)
registry.put({api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter'})
// json structure for hosting the last compilattion result
self._components.compilersArtefacts = {} // store all the possible compilation data (key represent a compiler name)
registry.put({api: self._components.compilersArtefacts, name: 'compilersartefacts'})
// ----------------- UniversalDApp -----------------
const udapp = new UniversalDApp(registry)
// TODO: to remove when possible
registry.put({api: udapp, name: 'udapp'})
udapp.event.register('transactionBroadcasted', (txhash, networkName) => {
var txLink = executionContext.txDetailsLink(networkName, txhash)
if (txLink) registry.get('logCallback').api(yo`<a href="${txLink}" target="_blank">${txLink}</a>`)
})
const udappUI = new UniversalDAppUI(udapp, registry)
// TODO: to remove when possible
registry.put({api: udappUI, name: 'udappUI'})
// ----------------- Tx listener -----------------
const transactionReceiptResolver = new TransactionReceiptResolver()
const txlistener = new Txlistener({
api: {
contracts: function () {
if (self._components.compilersArtefacts['__last']) return self._components.compilersArtefacts['__last'].getContracts()
return null
},
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
},
event: {
udapp: udapp.event
}})
registry.put({api: txlistener, name: 'txlistener'})
udapp.startListening(txlistener)
const eventsDecoder = new EventsDecoder({
api: {
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
}
})
registry.put({api: eventsDecoder, name: 'eventsdecoder'})
txlistener.startListening()
// TODO: There are still a lot of dep between mainview and filemanager
// ----------------- file manager ----------------------------
self._components.fileManager = new FileManager()
const fileManager = self._components.fileManager
registry.put({api: fileManager, name: 'filemanager'})
// ----------------- Network ----------------------------
const networkModule = new NetworkModule()
registry.put({api: networkModule, name: 'network'})
// ----------------- theme module ----------------------------
// SERVICES
// ----------------- import content servive ----------------------------
const contentImport = new CompilerImport()
// ----------------- theme servive ----------------------------
const themeModule = new ThemeModule(registry)
registry.put({api: themeModule, name: 'themeModule'})
// ----------------- editor servive ----------------------------
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'})
// ----------------- compilation metadata generation servive ----------------------------
const compilerMetadataGenerator = new CompilerMetadata(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'})
// ----------------- universal dapp: run transaction, listen on transactions, decode events
const {udapp, eventsDecoder, txlistener} = makeUdapp(compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl))
// ----------------- network service (resolve network id / name) ----------------------------
const networkModule = new NetworkModule()
// ----------------- convert offset to line/column service ----------------------------
var offsetToLineColumnConverter = new OffsetToLineColumnConverter()
registry.put({api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter'})
// ----------------- landing page ----------------------------
// Need to have Home initialized before VerticalIconComponent render to access profile of it for icon
const landingPage = new LandingPage(appManager, appStore)
// ----------------- Vertical Icon ----------------------------
const verticalIcons = new VerticalIcons('sidePanel', appStore, landingPage)
registry.put({api: verticalIcons, name: 'verticalicon'})
const sidePanel = new SidePanel(appStore)
const mainPanel = new MainPanel(appStore)
const hiddenPanel = new HiddenPanel(appStore)
// ----------------- main view ----------------------
self._components.mainview = new MainView(appStore, appManager, mainPanel)
registry.put({ api: self._components.mainview, name: 'mainview' })
// ----------------- Renderer -----------------
const renderer = new Renderer()
registry.put({api: renderer, name: 'renderer'})
// ----------------- app manager ----------------------------
/*
TODOs:
- for each activated plugin,
an internal module (associated only with the plugin) should be created for accessing specific part of the UI. detail to be discussed
- the current API is not optimal. For instance methods of `app` only refers to `executionContext`, wich does not make really sense.
*/
// TODOs those are instanciated before hand. should be instanciated on demand
appManager.register([
contentImport,
themeModule,
editor.sourceHighlighters,
fileManager,
compilerMetadataGenerator,
compilersArtefacts,
udapp,
networkModule,
offsetToLineColumnConverter
])
const pluginManagerComponent = new PluginManagerComponent()
registry.put({api: appManager.proxy(), name: 'pluginmanager'})
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel()
const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder)
registry.put({ api: mainview, name: 'mainview' })
pluginManagerComponent.setApp(appManager)
pluginManagerComponent.setStore(appStore)
appManager.register([
appPanel
])
self._components.mainview.init()
// 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 filePanel = new FilePanel(appManager)
let settings = new SettingsTab(
registry.get('config').api,
editor,
appManager
)
self._components.fileManager.init()
self._view.mainpanel.appendChild(self._components.mainview.render())
self._view.iconpanel.appendChild(verticalIcons.render())
// adding Views to the DOM
self._view.mainpanel.appendChild(mainview.render())
self._view.iconpanel.appendChild(menuicons.render())
self._view.sidepanel.appendChild(sidePanel.render())
document.body.appendChild(hiddenPanel.render()) // Hidden Panel is display none, it can be directly on body
let filePanel = new FilePanel()
registry.put({api: filePanel, name: 'filepanel'})
appManager.register([
menuicons,
landingPage,
sidePanel,
pluginManagerComponent,
filePanel,
settings
])
// CONTENT VIEWS & DEFAULT PLUGINS
let compileTab = new CompileTab(
registry.get('editor').api,
editor,
registry.get('config').api,
registry.get('renderer').api,
new Renderer(),
registry.get('fileproviders/swarm').api,
registry.get('filemanager').api,
registry.get('fileproviders').api,
registry.get('pluginmanager').api
)
let run = new RunTab(
registry.get('udapp').api,
registry.get('udappUI').api,
udapp,
registry.get('config').api,
registry.get('filemanager').api,
registry.get('editor').api,
registry.get('logCallback').api,
registry.get('filepanel').api,
registry.get('pluginmanager').api,
registry.get('compilersartefacts').api
)
let settings = new SettingsTab(
registry.get('config').api,
registry.get('editor').api,
appManager
filePanel,
registry.get('compilersartefacts').api,
networkModule,
mainview
)
let analysis = new AnalysisTab(registry)
let debug = new DebuggerTab()
let test = new TestTab(
registry.get('filemanager').api,
registry.get('filepanel').api,
filePanel,
compileTab,
appStore
appManager
)
let sourceHighlighters = registry.get('editor').api.sourceHighlighters
appManager.init([
landingPage.api(),
udapp.api(),
fileManager.api(),
sourceHighlighters.api(),
filePanel.api(),
settings.api(),
pluginManagerComponent.api(),
networkModule.api(),
themeModule.api()
])
appManager.registerMany([
compileTab.api(),
run.api(),
debug.api(),
analysis.api(),
test.api(),
filePanel.remixdHandle.api(),
...appManager.plugins()
appManager.register([
compileTab,
run,
debug,
analysis,
test,
filePanel.remixdHandle,
...appManager.registeredPlugins()
])
// Set workspace after initial activation
if (Array.isArray(workspace)) {
appManager.activateMany(workspace)
}
framingService.start(appStore, sidePanel, verticalIcons, mainPanel, this._components.resizeFeature)
// The event listener needs to be registered as early as possible, because the
// parent will send the message upon the "load" event.
let filesToLoad = null
let loadFilesCallback = function (files) { filesToLoad = files } // will be replaced later
window.addEventListener('message', function (ev) {
if (typeof ev.data === typeof [] && ev.data[0] === 'loadFiles') {
loadFilesCallback(ev.data[1])
}
}, false)
appManager.activate(['contentImport', 'theme', 'sourceHighlighters', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'udapp', 'network', 'offsetToLineColumnConverter'])
appManager.activate(['mainPanel'])
appManager.activate(['menuicons', 'home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings'])
// Replace early callback with instant response
loadFilesCallback = function (files) {
self.loadFiles(files)
}
// Set workspace after initial activation
if (Array.isArray(workspace)) appManager.activate(workspace)
// Run if we did receive an event from remote instance while starting up
if (filesToLoad !== null) {
self.loadFiles(filesToLoad)
}
// Load and start the service who manager layout and frame
const framingService = new FramingService(sidePanel, menuicons, mainview, this._components.resizeFeature)
framingService.start()
const txLogger = new TxLogger() // eslint-disable-line
txLogger.event.register('debuggingRequested', (hash) => {
if (!appStore.isActive('debugger')) appManager.activateOne('debugger')
debug.debugger().debug(hash)
verticalIcons.select('debugger')
})
let transactionContextAPI = {
getAddress: (cb) => {
cb(null, $('#txorigin').val())
},
getValue: (cb) => {
try {
var number = document.querySelector('#value').value
var select = document.getElementById('unit')
var index = select.selectedIndex
var selectedUnit = select.querySelectorAll('option')[index].dataset.unit
var unit = 'ether' // default
if (['ether', 'finney', 'gwei', 'wei'].indexOf(selectedUnit) >= 0) {
unit = selectedUnit
}
cb(null, executionContext.web3().toWei(number, unit))
} catch (e) {
cb(e)
}
},
getGasLimit: (cb) => {
cb(null, $('#gasLimit').val())
}
}
udapp.resetAPI(transactionContextAPI)
// get the file list from the parent iframe
loadFileFromParent(fileManager)
// get the file from gist
const gistHandler = new GistHandler()
const queryParams = new QueryParams()
const loadingFromGist = self.loadFromGist(queryParams.get())
if (!loadingFromGist) {
const loadedFromGist = gistHandler.loadFromGist(queryParams.get(), fileManager)
if (!loadedFromGist) {
// insert ballot contract if there are no files to show
self._components.filesProviders['browser'].resolveDirectory('browser', (error, filesList) => {
if (error) console.error(error)

@ -0,0 +1,33 @@
'use strict'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
import CompilerAbstract from './compiler-abstract'
const profile = {
name: 'compilerArtefacts',
methods: [],
events: [],
version: packageJson.version,
required: true
}
module.exports = class CompilerArtefacts extends Plugin {
constructor () {
super(profile)
this.compilersArtefacts = {}
}
clear () {
this.compilersArtefacts = {}
}
onActivation () {
this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts['__last'] = new CompilerAbstract(languageVersion, data, source)
})
this.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => {
this.compilersArtefacts['__last'] = new CompilerAbstract(languageVersion, data, source)
})
}
}

@ -3,9 +3,19 @@ var base64 = require('js-base64').Base64
var swarmgw = require('swarmgw')()
var resolver = require('@resolver-engine/imports').ImportsEngine()
var request = require('request')
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
module.exports = class CompilerImports {
const profile = {
name: 'contentImport',
displayName: 'content import',
version: packageJson.version,
methods: ['resolve']
}
module.exports = class CompilerImports extends Plugin {
constructor (githubAccessToken) {
super(profile)
this.githubAccessToken = githubAccessToken || (() => {})
this.previouslyHandled = {} // cache import so we don't make the request at each compilation.
}
@ -90,7 +100,18 @@ module.exports = class CompilerImports {
return /^([^/]+)/.exec(url)
}
resolve (url) {
return new Promise((resolve, reject) => {
this.import(url, null, (error, content, cleanUrl, type, url) => {
if (error) return reject(error)
resolve({ content, cleanUrl, type, url })
})
})
}
import (url, loadingCb, cb) {
if (!loadingCb) loadingCb = () => {}
var self = this
var imported = this.previouslyHandled[url]
if (imported) {

@ -1,4 +1,5 @@
import { AbstractPanel } from './panel'
import * as packageJson from '../../../package.json'
const csjs = require('csjs-inject')
const yo = require('yo-yo')
@ -8,10 +9,18 @@ const css = csjs`
}
`
const profile = {
name: 'hiddenPanel',
displayName: 'Hidden Panel',
description: '',
version: packageJson.version,
required: true
}
export class HiddenPanel extends AbstractPanel {
constructor (appStore) {
super('hiddenPanel', appStore)
constructor () {
super(profile)
}
render () {

@ -1,4 +1,5 @@
import { AbstractPanel } from './panel'
import * as packageJson from '../../../package.json'
const yo = require('yo-yo')
const csjs = require('csjs-inject')
@ -10,9 +11,18 @@ const css = csjs`
}
`
const profile = {
name: 'mainPanel',
displayName: 'Main Panel',
description: '',
version: packageJson.version,
methods: ['addView', 'removeView'],
required: true
}
export class MainPanel extends AbstractPanel {
constructor (appStore, options) {
super('mainPanel', appStore, options)
constructor (options) {
super(profile, options)
}
render () {

@ -1,7 +1,7 @@
import { EventEmitter } from 'events'
const registry = require('../../global/registry')
const csjs = require('csjs-inject')
const yo = require('yo-yo')
const { HostPlugin } = require('@remixproject/engine')
const css = csjs`
.plugins {
@ -25,50 +25,17 @@ const css = csjs`
}
`
// Events are : 'toggle' | 'showing'
/** Abstract class used for hosting the view of a plugin */
export class AbstractPanel {
export class AbstractPanel extends HostPlugin {
constructor (panelName, appStore, opts) {
constructor (profile, opts) {
super(profile)
this.events = new EventEmitter()
this.contents = {}
this.active = undefined
// View where the plugin HTMLElement leaves
this.view = yo`<div id="plugins" class="${css.plugins}"></div>`
appStore.event.on('activate', (name) => {
const api = appStore.getOne(name)
const profile = api.profile
if (profile.location !== panelName) return
if (!profile.location && !opts.default) return
if (profile.icon && api.render && typeof api.render === 'function') {
this.add(name, api.render())
}
})
appStore.event.on('deactivate', (name) => {
if (this.contents[name]) this.remove(name)
})
const verticalIcon = registry.get('verticalicon').api
// Toggle content
verticalIcon.events.on('toggleContent', (name) => {
if (!this.contents[name]) return
if (this.active === name) {
this.events.emit('toggle', name)
return
}
this.showContent(name)
this.events.emit('showing', name)
})
// Force opening
verticalIcon.events.on('showContent', (name) => {
if (!this.contents[name]) return
this.showContent(name)
this.events.emit('showing', name)
})
}
/**
@ -76,15 +43,25 @@ export class AbstractPanel {
* @param {String} name the name of the plugin
* @param {HTMLElement} content the HTMLContent of the plugin
*/
add (name, content) {
add (view, name) {
console.log('panel', name, view)
if (this.contents[name]) throw new Error(`Plugin ${name} already rendered`)
content.style.height = '100%'
content.style.width = '100%'
content.style.border = '0'
this.contents[name] = yo`<div class="${css.plugItIn}" >${content}</div>`
view.style.height = '100%'
view.style.width = '100%'
view.style.border = '0'
this.contents[name] = yo`<div class="${css.plugItIn}" >${view}</div>`
this.contents[name].style.display = 'none'
this.view.appendChild(this.contents[name])
}
addView (profile, view) {
this.add(view, profile.name)
}
removeView (profile) {
this.remove(profile.name)
}
/**
* Remove a plugin from the panel
* @param {String} name The name of the plugin to remove
@ -101,6 +78,7 @@ export class AbstractPanel {
* @param {String} name The name of the plugin to display the content
*/
showContent (name) {
console.log('showContent', name, this.active)
if (!this.contents[name]) throw new Error(`Plugin ${name} is not yet activated`)
// hiding the current view and display the `moduleName`
if (this.active) {
@ -109,5 +87,9 @@ export class AbstractPanel {
this.contents[name].style.display = 'block'
this.active = name
}
focus (name) {
this.showContent(name)
}
}

@ -2,7 +2,7 @@ const yo = require('yo-yo')
const csjs = require('csjs-inject')
const EventEmitter = require('events')
const LocalPlugin = require('./local-plugin')
import { Plugin, BaseApi } from 'remix-plugin'
import { ViewPlugin, IframePlugin } from '@remixproject/engine'
import { PluginManagerSettings } from './plugin-manager-settings'
import * as packageJson from '../../../package.json'
const addToolTip = require('../ui/tooltip')
@ -59,38 +59,31 @@ const profile = {
kind: 'settings',
location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/plugin_manager.html',
version: packageJson.version
version: packageJson.version,
required: true
}
class PluginManagerComponent extends BaseApi {
class PluginManagerComponent extends ViewPlugin {
constructor () {
constructor (appManager) {
super(profile)
this.event = new EventEmitter()
this.appManager = appManager
this.views = {
root: null,
items: {}
}
this.localPlugin = new LocalPlugin()
this.filter = ''
}
setApp (appManager) {
this.appManager = appManager
}
setStore (store) {
this.store = store
this.store.event.on('activate', (name) => { this.reRender() })
this.store.event.on('deactivate', (name) => { this.reRender() })
this.store.event.on('add', (api) => { this.reRender() })
this.store.event.on('remove', (api) => { this.reRender() })
this.appManager.event.on('activate', () => { this.reRender() })
this.appManager.event.on('deactivate', () => { this.reRender() })
this.appManager.event.on('added', () => { this.reRender() })
}
renderItem (name) {
const api = this.store.getOne(name)
const api = this.appManager.getOne(name)
if (!api) return
const isActive = this.store.actives.includes(name)
const isActive = this.appManager.isActive(name)
const displayName = (api.profile.displayName) ? api.profile.displayName : name
// Check version of the plugin
@ -136,12 +129,12 @@ class PluginManagerComponent extends BaseApi {
*/
async openLocalPlugin () {
try {
const profile = await this.localPlugin.open(this.store.getAll())
const profile = await this.localPlugin.open(this.appManager.getAll())
if (!profile) return
if (this.store.ids.includes(profile.name)) {
if (this.appManager.getIds().includes(profile.name)) {
throw new Error('This name has already been used')
}
this.appManager.registerOne(new Plugin(profile))
this.appManager.registerOne(new IframePlugin(profile))
this.appManager.activateOne(profile.name)
} catch (err) {
// TODO : Use an alert to handle this error instead of a console.log
@ -161,12 +154,12 @@ class PluginManagerComponent extends BaseApi {
}
// Filter all active and inactive modules that are not required
const { actives, inactives } = this.store.getAll()
const { actives, inactives } = this.appManager.getAll()
.filter(isFiltered)
.filter(isNotRequired)
.sort(sortByName)
.reduce(({actives, inactives}, api) => {
return this.store.actives.includes(api.name)
return this.appManager.isActive(api.name)
? { actives: [...actives, api.name], inactives }
: { inactives: [...inactives, api.name], actives }
}, { actives: [], inactives: [] })

@ -1,36 +0,0 @@
var registry = require('../../global/registry')
const CompilerAbstract = require('../compiler/compiler-abstract')
const EventManager = require('remix-lib').EventManager
class PluginManagerProxy {
constructor () {
this.event = new EventManager()
this._listeners = {}
this._listeners['vyper'] = (file, source, languageVersion, data) => {
registry.get('compilersartefacts').api['__last'] = new CompilerAbstract(languageVersion, data, source)
this.event.trigger('sendCompilationResult', [file, source, languageVersion, data])
}
this._listeners['solidity'] = (file, source, languageVersion, data) => {
registry.get('compilersartefacts').api['__last'] = new CompilerAbstract(languageVersion, data, source)
this.event.trigger('sendCompilationResult', [file, source, languageVersion, data])
}
}
register (name, instance) {
if (this._listeners[name]) {
instance.events.on('compilationFinished', this._listeners[name])
}
}
unregister (name, instance) {
if (this._listeners[name]) {
instance.events.removeListener('compilationFinished', this._listeners[name])
}
}
}
module.exports = PluginManagerProxy

@ -1,4 +1,5 @@
import { AbstractPanel } from './panel'
import * as packageJson from '../../../package.json'
const csjs = require('csjs-inject')
const yo = require('yo-yo')
@ -49,12 +50,50 @@ const options = {
default: true
}
const sidePanel = {
name: 'sidePanel',
displayName: 'Side Panel',
description: '',
version: packageJson.version,
methods: ['addView', 'removeView'],
required: true
}
// TODO merge with vertical-icons.js
export class SidePanel extends AbstractPanel {
constructor (appStore) {
super('sidePanel', appStore, options)
constructor (appManager, verticalIcons) {
super(sidePanel, options)
this.appManager = appManager
this.header = this.renderHeader()
this.store = appStore
this.verticalIcons = verticalIcons
// Toggle content
verticalIcons.events.on('toggleContent', (name) => {
if (!this.contents[name]) return
if (this.active === name) {
this.events.emit('toggle', name)
return
}
this.showContent(name)
this.events.emit('showing', name)
})
// Force opening
verticalIcons.events.on('showContent', (name) => {
if (!this.contents[name]) return
this.showContent(name)
this.events.emit('showing', name)
})
}
removeView (profile) {
super.removeView(profile)
this.verticalIcons.unlinkContent(profile)
}
addView (profile, view) {
super.addView(profile, view)
this.verticalIcons.linkContent(profile)
}
/**
@ -72,7 +111,7 @@ export class SidePanel extends AbstractPanel {
let docLink = ''
let versionWarning
if (this.active) {
const { profile } = this.store.getOne(this.active)
const { profile } = this.appManager.getOne(this.active)
name = profile.displayName ? profile.displayName : profile.name
docLink = profile.documentation ? yo`<a href="${profile.documentation}" class="${css.titleInfo}" title="link to documentation" target="_blank"><i aria-hidden="true" class="fas fa-book"></i></a>` : ''
if (profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) {

@ -2,38 +2,30 @@ var yo = require('yo-yo')
var csjs = require('csjs-inject')
var helper = require('../../lib/helper')
let globalRegistry = require('../../global/registry')
const { Plugin } = require('@remixproject/engine')
import * as packageJson from '../../../package.json'
const EventEmitter = require('events')
// Component
export class VerticalIcons {
const profile = {
name: 'menuicons',
displayName: 'Vertical Icons',
description: '',
version: packageJson.version,
methods: ['select'],
required: true
}
// TODO merge with side-panel.js. VerticalIcons should not be a plugin
export class VerticalIcons extends Plugin {
constructor (name, appStore, homeProfile) {
this.store = appStore
this.homeProfile = homeProfile.profile
constructor (appManager) {
super(profile)
this.events = new EventEmitter()
this.appManager = appManager
this.icons = {}
this.iconKind = {}
this.iconStatus = {}
this.name = name
this.store.event.on('activate', (name) => {
const api = this.store.getOne(name)
if (!api.profile.icon) return
if (api.profile.location === this.name) {
this.addIcon(api.profile)
this.listenOnStatus(api)
}
})
this.store.event.on('deactivate', (name) => {
const api = this.store.getOne(name)
if (api && this.icons[name]) {
this.removeIcon(api.profile)
this.stopListenOnStatus(api)
}
})
this.store.event.on('add', (api) => { })
this.store.event.on('remove', (api) => { })
let themeModule = globalRegistry.get('themeModule').api
themeModule.events.on('themeChanged', (theme) => {
@ -41,18 +33,17 @@ export class VerticalIcons {
})
}
stopListenOnStatus (api) {
if (!api.events) return
let fn = this.iconStatus[api.profile.name]
if (fn) {
api.events.removeListener('statusChanged', fn)
delete this.iconStatus[api.profile.name]
}
linkContent (profile) {
if (!profile.icon) return
this.addIcon(profile)
this.listenOnStatus(profile)
}
listenOnStatus (api) {
if (!api.events) return
unlinkContent (profile) {
this.removeIcon(profile)
}
listenOnStatus (profile) {
// the list of supported keys. 'none' will remove the status
const keys = ['edited', 'succeed', 'none', 'loading', 'failed']
const types = ['error', 'warning', 'success', 'info', '']
@ -63,10 +54,10 @@ export class VerticalIcons {
if (typeof status.key === 'string' && (!keys.includes(status.key))) {
throw new Error('key should contain either number or ' + keys.join())
}
this.setIconStatus(api.profile.name, status)
this.setIconStatus(profile.name, status)
}
this.iconStatus[api.profile.name] = fn
api.events.on('statusChanged', this.iconStatus[api.profile.name])
this.iconStatus[profile.name] = fn
this.on(profile.name, 'statusChanged', this.iconStatus[profile.name])
}
/**
@ -223,21 +214,14 @@ export class VerticalIcons {
}
}
/**
* Show the home page
*/
showHome () {
globalRegistry.get('appmanager').api.ensureActivated('home')
}
render () {
let home = yo`
<div
class="${css.homeIcon}"
onclick="${(e) => {
this.showHome()
this.appManager.ensureActivated('home')
}}"
plugin="${this.homeProfile.name}" title="${this.homeProfile.displayName}"
plugin="home" title="Home"
>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="42px" height="42px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">

@ -1,20 +1,22 @@
'use strict'
const SourceHighlighter = require('./sourceHighlighter')
import { EditorApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const profile = {
displayName: 'source highlighters',
name: 'editor',
name: 'sourceHighlighters',
description: 'service - highlight source code',
version: packageJson.version
version: packageJson.version,
methods: ['highlight', 'discardHighlight'],
required: true
}
// EditorApi:
// - methods: ['highlight', 'discardHighlight'],
class SourceHighlighters extends EditorApi {
class SourceHighlighters extends Plugin {
constructor () {
super(profile)

@ -5,15 +5,26 @@ const SourceMappingDecoder = remixLib.SourceMappingDecoder
const AstWalker = remixLib.AstWalker
const EventManager = require('../../lib/events')
const globalRegistry = require('../../global/registry')
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const profile = {
name: 'contextualListener',
methods: [],
events: [],
version: packageJson.version,
required: true
}
/*
trigger contextChanged(nodes)
*/
class ContextualListener {
constructor (opts, localRegistry) {
class ContextualListener extends Plugin {
constructor (opts) {
super(profile)
this.event = new EventManager()
this._components = {}
this._components.registry = localRegistry || globalRegistry
this._components.registry = globalRegistry
this.editor = opts.editor
this.pluginManager = opts.pluginManager
this._deps = {
@ -26,8 +37,14 @@ class ContextualListener {
FlatReferences: {}
}
this._activeHighlights = []
this.editor.event.register('contentChanged', () => { this._stopHighlighting() })
this.sourceMappingDecoder = new SourceMappingDecoder()
this.astWalker = new AstWalker()
}
this.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => {
onActivation () {
this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => {
if (languageVersion.indexOf('soljson') !== 0) return
this._stopHighlighting()
this._index = {
@ -37,10 +54,6 @@ class ContextualListener {
this._buildIndex(data, source)
})
this.editor.event.register('contentChanged', () => { this._stopHighlighting() })
this.sourceMappingDecoder = new SourceMappingDecoder()
this.astWalker = new AstWalker()
setInterval(() => {
if (this._deps.compilersArtefacts['__last'] && this._deps.compilersArtefacts['__last'].languageversion.indexOf('soljson') === 0) {
this._highlightItems(this.editor.getCursorPosition(), this._deps.compilersArtefacts['__last'], this._deps.config.get('currentFile'))

@ -38,13 +38,11 @@ document.head.appendChild(yo`
class Editor {
constructor (opts = {}, localRegistry) {
constructor (opts = {}, themeModule) {
// Dependancies
this._components = {}
this._components.registry = localRegistry || globalRegistry
this._components.registry = globalRegistry
this._deps = {
themeModule: this._components.registry.get('themeModule').api,
fileManager: this._components.registry.get('filemanager').api,
config: this._components.registry.get('config').api
}
@ -52,7 +50,7 @@ class Editor {
'light': 'chrome',
'dark': 'chaos'
}
this._deps.themeModule.events.on('themeChanged', (theme) => {
themeModule.events.on('themeChanged', (theme) => {
this.setTheme(theme.quality)
})
@ -202,7 +200,7 @@ class Editor {
window.clearTimeout(this.saveTimeout)
}
this.saveTimeout = window.setTimeout(() => {
this._deps.fileManager.saveCurrentFile()
this.event.trigger('requiringToSaveCurrentfile', [])
}, 5000)
}

@ -2,16 +2,8 @@
var EventManager = require('../../lib/events')
import { BaseApi } from 'remix-plugin'
class FilesTree extends BaseApi {
class FilesTree {
constructor (name, storage) {
super({
name: name,
methods: ['get', 'set', 'remove'],
description:
'service - read/write file to the `config` explorer without need of additionnal permission.'
})
this.event = new EventManager()
this.storage = storage
this.type = name

@ -1,21 +1,33 @@
'use strict'
var executionContext = require('../../execution-context')
var CompilerAbstract = require('../compiler/compiler-abstract')
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
class CompilerMetadata {
constructor (opts) {
const profile = {
name: 'compilerMetadata',
methods: ['deployMetadataOf'],
events: [],
version: packageJson.version,
required: true
}
class CompilerMetadata extends Plugin {
constructor (fileManager, config) {
super(profile)
var self = this
self._opts = opts
self.fileManager = fileManager
self.config = config
self.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom']
}
syncContractMetadata () {
onActivation () {
var self = this
self._opts.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => {
if (!self._opts.config.get('settings/generate-contract-metadata')) return
this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => {
if (!self.config.get('settings/generate-contract-metadata')) return
let compiler = new CompilerAbstract(languageVersion, data, source)
var provider = self._opts.fileManager.currentFileProvider()
var path = self._opts.fileManager.currentPath()
var provider = self.fileManager.currentFileProvider()
var path = self.fileManager.currentPath()
if (provider && path) {
compiler.visitContracts((contract) => {
if (contract.file !== source.target) return
@ -75,30 +87,32 @@ class CompilerMetadata {
}
// TODO: is only called by dropdownLogic and can be moved there
deployMetadataOf (contractName, callback) {
var self = this
var provider = self._opts.fileManager.currentFileProvider()
var path = self._opts.fileManager.currentPath()
if (provider && path) {
executionContext.detectNetwork((err, { id, name } = {}) => {
if (err) {
console.log(err)
} else {
var fileName = path + '/' + contractName + '.json'
provider.get(fileName, (error, content) => {
if (error) return callback(error)
if (!content) return callback()
try {
var metadata = JSON.parse(content)
metadata = metadata.deploy || {}
return callback(null, metadata[name + ':' + id] || metadata[name] || metadata[id] || metadata[name.toLowerCase() + ':' + id] || metadata[name.toLowerCase()])
} catch (e) {
callback(e.message)
}
})
}
})
}
deployMetadataOf (contractName) {
return new Promise((resolve, reject) => {
var self = this
var provider = self.fileManager.currentFileProvider()
var path = self.fileManager.currentPath()
if (provider && path) {
executionContext.detectNetwork((err, { id, name } = {}) => {
if (err) {
console.log(err)
} else {
var fileName = path + '/' + contractName + '.json'
provider.get(fileName, (error, content) => {
if (error) return reject(error)
if (!content) return resolve()
try {
var metadata = JSON.parse(content)
metadata = metadata.deploy || {}
return resolve(metadata[name + ':' + id] || metadata[name] || metadata[id] || metadata[name.toLowerCase() + ':' + id] || metadata[name.toLowerCase()])
} catch (e) {
reject(e.message)
}
})
}
})
}
})
}
}

@ -1,12 +1,14 @@
'use strict'
import yo from 'yo-yo'
import async from 'async'
const EventEmitter = require('events')
const globalRegistry = require('../../global/registry')
const CompilerImport = require('../compiler/compiler-imports')
const toaster = require('../ui/tooltip')
const modalDialogCustom = require('../ui/modal-dialog-custom')
const helper = require('../../lib/helper.js')
import { FileSystemApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
/*
@ -20,26 +22,28 @@ const profile = {
description: 'Service - read/write to any files or folders, require giving permissions',
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNjk2IDM4NHE0MCAwIDY4IDI4dDI4IDY4djEyMTZxMCA0MC0yOCA2OHQtNjggMjhoLTk2MHEtNDAgMC02OC0yOHQtMjgtNjh2LTI4OGgtNTQ0cS00MCAwLTY4LTI4dC0yOC02OHYtNjcycTAtNDAgMjAtODh0NDgtNzZsNDA4LTQwOHEyOC0yOCA3Ni00OHQ4OC0yMGg0MTZxNDAgMCA2OCAyOHQyOCA2OHYzMjhxNjgtNDAgMTI4LTQwaDQxNnptLTU0NCAyMTNsLTI5OSAyOTloMjk5di0yOTl6bS02NDAtMzg0bC0yOTkgMjk5aDI5OXYtMjk5em0xOTYgNjQ3bDMxNi0zMTZ2LTQxNmgtMzg0djQxNnEwIDQwLTI4IDY4dC02OCAyOGgtNDE2djY0MGg1MTJ2LTI1NnEwLTQwIDIwLTg4dDQ4LTc2em05NTYgODA0di0xMTUyaC0zODR2NDE2cTAgNDAtMjggNjh0LTY4IDI4aC00MTZ2NjQwaDg5NnoiLz48L3N2Zz4=',
permission: true,
version: packageJson.version
version: packageJson.version,
methods: ['getFolder', 'getCurrentFile', 'getFile', 'setFile', 'switchFile'],
required: true
}
// File System profile
// - events: ['currentFileChanged']
// - methods: ['getFolder', 'getCurrentFile', 'getFile', 'setFile', 'switchFile']
class FileManager extends FileSystemApi {
constructor (localRegistry) {
class FileManager extends Plugin {
constructor (editor) {
super(profile)
this.openedFiles = {} // list all opened files
this.events = new EventEmitter()
this.editor = editor
this._components = {}
this._components.compilerImport = new CompilerImport()
this._components.registry = localRegistry || globalRegistry
this._components.registry = globalRegistry
this.init()
}
init () {
this._deps = {
editor: this._components.registry.get('editor').api,
config: this._components.registry.get('config').api,
browserExplorer: this._components.registry.get('fileproviders/browser').api,
localhostExplorer: this._components.registry.get('fileproviders/localhost').api,
@ -60,7 +64,7 @@ class FileManager extends FileSystemApi {
fileRenamedEvent (oldName, newName, isFolder) {
if (!isFolder) {
this._deps.config.set('currentFile', '')
this._deps.editor.discard(oldName)
this.editor.discard(oldName)
if (this.openedFiles[oldName]) {
delete this.openedFiles[oldName]
this.openedFiles[newName] = newName
@ -102,7 +106,7 @@ class FileManager extends FileSystemApi {
if (Object.keys(this.openedFiles).length) {
this.switchFile(Object.keys(this.openedFiles)[0])
} else {
this._deps.editor.displayEmptyReadOnlySession()
this.editor.displayEmptyReadOnlySession()
this._deps.config.set('currentFile', '')
this.events.emit('noFileSelected')
}
@ -127,6 +131,7 @@ class FileManager extends FileSystemApi {
if (!provider) throw new Error(`${path} not available`)
// TODO: change provider to Promise
return new Promise((resolve, reject) => {
if (this.currentFile() === path) return resolve(this.editor.currentContent())
provider.get(path, (err, content) => {
if (err) reject(err)
resolve(content)
@ -231,7 +236,7 @@ class FileManager extends FileSystemApi {
if (path === this._deps.config.get('currentFile')) {
this._deps.config.set('currentFile', '')
}
this._deps.editor.discard(path)
this.editor.discard(path)
delete this.openedFiles[path]
this.events.emit('fileRemoved', path)
this.switchFile()
@ -253,9 +258,9 @@ class FileManager extends FileSystemApi {
console.log(error)
} else {
if (this.fileProviderOf(file).isReadOnly(file)) {
this._deps.editor.openReadOnly(file, content)
this.editor.openReadOnly(file, content)
} else {
this._deps.editor.open(file, content)
this.editor.open(file, content)
}
this.events.emit('currentFileChanged', file)
}
@ -270,7 +275,7 @@ class FileManager extends FileSystemApi {
if (fileList.length) {
_switchFile(browserProvider.type + '/' + fileList[0])
} else {
this._deps.editor.displayEmptyReadOnlySession()
this.editor.displayEmptyReadOnlySession()
this.events.emit('noFileSelected')
}
})
@ -306,8 +311,8 @@ class FileManager extends FileSystemApi {
saveCurrentFile () {
var currentFile = this._deps.config.get('currentFile')
if (currentFile && this._deps.editor.current()) {
var input = this._deps.editor.get(currentFile)
if (currentFile && this.editor.current()) {
var input = this.editor.get(currentFile)
if (input) {
var provider = this.fileProviderOf(currentFile)
if (provider) {
@ -327,12 +332,34 @@ class FileManager extends FileSystemApi {
if (provider) {
provider.get(currentFile, (error, content) => {
if (error) console.log(error)
this._deps.editor.setText(content)
this.editor.setText(content)
})
} else {
console.log('cannot save ' + currentFile + '. Does not belong to any explorer')
}
}
setBatchFiles (filesSet, fileProvider, callback) {
const self = this
if (!fileProvider) fileProvider = 'browser'
async.each(Object.keys(filesSet), (file, callback) => {
helper.createNonClashingName(file, self._deps.filesProviders[fileProvider],
(error, name) => {
if (error) {
modalDialogCustom.alert('Unexpected error loading the file ' + error)
} else if (helper.checkSpecialChars(name)) {
modalDialogCustom.alert('Special characters are not allowed')
} else {
self._deps.filesProviders[fileProvider].set(name, filesSet[file].content)
}
callback()
})
}, (error) => {
if (!error) self.switchFile()
if (callback) callback(error)
})
}
}
module.exports = FileManager

@ -1,5 +1,4 @@
let globalRegistry = require('../../global/registry')
import { BaseApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
var yo = require('yo-yo')
var modalDialog = require('../ui/modaldialog')
@ -27,11 +26,12 @@ const profile = {
version: packageJson.version
}
export class RemixdHandle extends BaseApi {
constructor (fileSystemExplorer, locahostProvider) {
export class RemixdHandle extends Plugin {
constructor (fileSystemExplorer, locahostProvider, appManager) {
super(profile)
this.fileSystemExplorer = fileSystemExplorer
this.locahostProvider = locahostProvider
this.appManager = appManager
}
deactivate () {
@ -45,8 +45,7 @@ export class RemixdHandle extends BaseApi {
}
canceled () {
let appManager = globalRegistry.get('appmanager').api
appManager.ensureDeactivated('remixd')
this.appManager.ensureDeactivated('remixd')
}
/**

@ -1,12 +1,11 @@
var yo = require('yo-yo')
var CompilerMetadata = require('../files/compiler-metadata')
var EventManager = require('../../lib/events')
var FileExplorer = require('../files/file-explorer')
var { RemixdHandle } = require('../files/remixd-handle.js')
var globalRegistry = require('../../global/registry')
var css = require('./styles/file-panel-styles')
import { ViewPlugin } from '@remixproject/engine'
import { BaseApi } from 'remix-plugin'
import * as packageJson from '../../../package.json'
var canUpload = window.File || window.FileReader || window.FileList || window.Blob
@ -38,21 +37,21 @@ const profile = {
kind: 'fileexplorer',
location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/file_explorer.html',
version: packageJson.version
version: packageJson.version,
required: true
}
module.exports = class Filepanel extends BaseApi {
module.exports = class Filepanel extends ViewPlugin {
constructor (localRegistry) {
constructor (appManager) {
super(profile)
var self = this
self._components = {}
self._components.registry = localRegistry || globalRegistry
self._components.registry = globalRegistry
self._deps = {
fileProviders: self._components.registry.get('fileproviders').api,
fileManager: self._components.registry.get('filemanager').api,
config: self._components.registry.get('config').api,
pluginManager: self._components.registry.get('pluginmanager').api
config: self._components.registry.get('config').api
}
var fileExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['browser'],
['createNewFile', 'publishToGist', 'copyFiles', canUpload ? 'uploadFile' : '']
@ -64,20 +63,7 @@ module.exports = class Filepanel extends BaseApi {
var httpExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['http'])
var httpsExplorer = new FileExplorer(self._components.registry, self._deps.fileProviders['https'])
self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders['localhost'],
self._deps.fileProviders['localhost'].isReadOnly ? ['createNewFile'] : [])
// ----------------- editor panel ----------------------
self._compilerMetadata = new CompilerMetadata(
{
fileManager: self._deps.fileManager,
pluginManager: self._deps.pluginManager,
config: self._deps.config
}
)
self._compilerMetadata.syncContractMetadata()
self.compilerMetadata = () => { return self._compilerMetadata }
self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders['localhost'], appManager)
function template () {
return yo`

@ -2,7 +2,6 @@ var yo = require('yo-yo')
var EventManager = require('../../lib/events')
var Terminal = require('./terminal')
var Editor = require('../editor/editor')
var globalRegistry = require('../../global/registry')
var { TabProxy } = require('./tab-proxy.js')
@ -28,46 +27,43 @@ var css = csjs`
`
export class MainView {
constructor (appStore, appManager, mainPanel) {
constructor (editor, mainPanel, fileManager, appManager, txListener, eventsDecoder) {
var self = this
self.event = new EventManager()
self._view = {}
self._components = {}
self._components.registry = globalRegistry
self._components.editor = new Editor({})
self._components.registry.put({api: self._components.editor, name: 'editor'})
self.appStore = appStore
self.appManager = appManager
self.editor = editor
self.fileManager = fileManager
self.mainPanel = mainPanel
self.txListener = txListener
self.eventsDecoder = eventsDecoder
this.appManager = appManager
this.init()
}
showApp (name) {
this.fileManager.unselectCurrentFile()
this.mainPanel.showContent(name)
this._view.editor.style.display = 'none'
this._components.contextView.hide()
this._view.mainPanel.style.display = 'block'
}
getAppPanel () {
return this.mainPanel
}
init () {
var self = this
self._deps = {
config: self._components.registry.get('config').api,
txListener: self._components.registry.get('txlistener').api,
fileManager: self._components.registry.get('filemanager').api,
udapp: self._components.registry.get('udapp').api,
pluginManager: self._components.registry.get('pluginmanager').api
}
self.tabProxy = new TabProxy(self._deps.fileManager, self._components.editor, self.appStore, self.appManager)
let showApp = function (name) {
self._deps.fileManager.unselectCurrentFile()
self.mainPanel.showContent(name)
self._view.editor.style.display = 'none'
self._components.contextView.hide()
self._view.mainPanel.style.display = 'block'
fileManager: self._components.registry.get('filemanager').api
}
self.appManager.event.on('ensureActivated', (name) => {
if (name === 'home') {
showApp(name)
self.tabProxy.showTab('home')
}
})
self.tabProxy = new TabProxy(self.fileManager, self.editor, self.appManager)
/*
We listen here on event from the tab component to display / hide the editor and mainpanel
depending on the content that should be displayed
*/
self._deps.fileManager.events.on('currentFileChanged', (file) => {
self.fileManager.events.on('currentFileChanged', (file) => {
// we check upstream for "fileChanged"
self._view.editor.style.display = 'block'
self._view.mainPanel.style.display = 'none'
@ -80,7 +76,7 @@ export class MainView {
})
self.tabProxy.event.on('closeFile', (file) => {
})
self.tabProxy.event.on('switchApp', showApp)
self.tabProxy.event.on('switchApp', self.showApp.bind(self))
self.tabProxy.event.on('closeApp', (name) => {
self._view.editor.style.display = 'block'
self._components.contextView.show()
@ -95,15 +91,19 @@ export class MainView {
}
}
var contextualListener = new ContextualListener({editor: self._components.editor, pluginManager: self._deps.pluginManager})
var contextView = new ContextView({contextualListener, editor: self._components.editor})
var contextualListener = new ContextualListener({editor: self.editor})
this.appManager.registerOne(contextualListener)
this.appManager.activate('contextualListener')
var contextView = new ContextView({contextualListener, editor: self.editor})
self._components.contextualListener = contextualListener
self._components.contextView = contextView
self._components.terminal = new Terminal({
udapp: self._deps.udapp,
appStore: self.appStore,
appManager: self.appManager
appManager: this.appManager,
eventsDecoder: this.eventsDecoder,
txListener: this.txListener
},
{
getPosition: (event) => {
@ -117,9 +117,9 @@ export class MainView {
})
self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta))
if (self._deps.txListener) {
if (self.txListener) {
self._components.terminal.event.register('listenOnNetWork', (listenOnNetWork) => {
self._deps.txListener.setListenOnNetwork(listenOnNetWork)
self.txListener.setListenOnNetwork(listenOnNetWork)
})
}
}
@ -148,13 +148,16 @@ export class MainView {
self._view.editor.style.height = `${mainPanelHeight}px`
self._view.mainPanel.style.height = `${mainPanelHeight}px`
self._view.terminal.style.height = `${delta}px` // - menu bar height
self._components.editor.resize((document.querySelector('#editorWrap') || {}).checked)
self.editor.resize((document.querySelector('#editorWrap') || {}).checked)
self._components.terminal.scroll2bottom()
}
}
getTerminal () {
return this._components.terminal
}
getEditor () {
var self = this
return self._components.editor
return self.editor
}
refresh () {
var self = this
@ -176,7 +179,7 @@ export class MainView {
render () {
var self = this
if (self._view.el) return self._view.el
self._view.editor = self._components.editor.render()
self._view.editor = self.editor.render()
self._view.editor.style.display = 'none'
self._view.mainPanel = self.mainPanel.render()
self._view.terminal = self._components.terminal.render()

@ -5,7 +5,7 @@ const EventEmitter = require('events')
require('remix-tabs')
export class TabProxy {
constructor (fileManager, editor, appStore, appManager) {
constructor (fileManager, editor, appManager) {
this.event = new EventEmitter()
this.fileManager = fileManager
this.appManager = appManager
@ -49,8 +49,8 @@ export class TabProxy {
})
})
appStore.event.on('activate', (name) => {
const { profile } = appStore.getOne(name)
appManager.event.on('activate', (name) => {
const { profile } = appManager.getOne(name)
if (profile.location === 'mainPanel') {
this.addTab(
name,
@ -66,7 +66,7 @@ export class TabProxy {
}
})
appStore.event.on('deactivate', (name) => {
appManager.event.on('deactivate', (name) => {
this.removeTab(name)
})
}

@ -12,11 +12,12 @@ var swarmgw = require('swarmgw')()
var CommandInterpreterAPI = require('../../lib/cmdInterpreterAPI')
var executionContext = require('../../execution-context')
var AutoCompletePopup = require('../ui/auto-complete-popup')
var TxLogger = require('../../app/ui/txLogger')
var csjs = require('csjs-inject')
var css = require('./styles/terminal-styles')
import { BaseApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
var packageV = require('../../../package.json')
@ -33,11 +34,11 @@ const profile = {
methods: [],
events: [],
description: ' - ',
required: false,
required: true,
version: packageJson.version
}
class Terminal extends BaseApi {
class Terminal extends Plugin {
constructor (opts, api) {
super(profile)
var self = this
@ -95,14 +96,18 @@ class Terminal extends BaseApi {
self._jsSandboxContext = {}
self._jsSandboxRegistered = {}
self.externalApi = this.api()
self.externalApi.notifs = {'theme': ['switchTheme']}
opts.appManager.init([self.externalApi])
opts.appManager.activateRequestAndNotification(self.externalApi)
// 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
register(self)
}
logHtml (html) {
var command = this.commands['html']
if (typeof command === 'function') command(html)
}
focus () {
if (this._view.input) this._view.input.focus()
}
@ -194,8 +199,8 @@ class Terminal extends BaseApi {
${self._view.term}
</div>
`
setInterval(() => {
self._view.pendingTxCount.innerHTML = self._opts.udapp.pendingTransactionsCount()
setInterval(async () => {
self._view.pendingTxCount.innerHTML = await self.call('udapp', 'pendingTransactionsCount')
}, 1000)
function listenOnNetwork (ev) {
@ -430,6 +435,15 @@ class Terminal extends BaseApi {
self._shell('remix.help()', self.commands, () => {})
self.commands.html(intro)
self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this)
self._components.txLogger.event.register('debuggingRequested', (hash) => {
// TODO should probably be in the run module
if (!self._opts.appManager.isActive('debugger')) self._opts.appManager.activateOne('debugger')
this.call('debugger', 'debug', hash)
this.call('menuicons', 'select', 'debugger')
})
return self._view.el
function change (event) {

@ -1,9 +1,9 @@
var yo = require('yo-yo')
var StaticAnalysis = require('../staticanalysis/staticAnalysisView')
var StaticAnalysis = require('./staticanalysis/staticAnalysisView')
var EventManager = require('../../lib/events')
var css = require('./styles/analysis-tab-styles')
import { BaseApi } from 'remix-plugin'
import { ViewPlugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import * as packageJson from '../../../package.json'
@ -20,7 +20,7 @@ const profile = {
version: packageJson.version
}
class AnalysisTab extends BaseApi {
class AnalysisTab extends ViewPlugin {
constructor (registry) {
super(profile)
@ -30,15 +30,15 @@ class AnalysisTab extends BaseApi {
}
render () {
if (!this.staticanalysis) this.staticanalysis = new StaticAnalysis()
if (!this.staticanalysis) this.staticanalysis = new StaticAnalysis(this.registry, this)
this.staticanalysis.event.register('staticAnaysisWarning', (count) => {
if (count > 0) {
this.events.emit('statusChanged', {key: count, title: `${count} warning${count === 1 ? '' : 's'}`, type: 'warning'})
this.emit('statusChanged', {key: count, title: `${count} warning${count === 1 ? '' : 's'}`, type: 'warning'})
} else if (count === 0) {
this.events.emit('statusChanged', {key: 'succeed', title: 'no warning', type: 'success'})
this.emit('statusChanged', {key: 'succeed', title: 'no warning', type: 'success'})
} else {
// count ==-1 no compilation result
this.events.emit('statusChanged', {key: 'none'})
this.emit('statusChanged', {key: 'none'})
}
})
this.registry.put({api: this.staticanalysis, name: 'staticanalysis'})

@ -8,8 +8,8 @@ const TreeView = require('../ui/TreeView')
const modalDialog = require('../ui/modaldialog')
const copyToClipboard = require('../ui/copy-to-clipboard')
const modalDialogCustom = require('../ui/modal-dialog-custom')
const parseContracts = require('../contract/contractParser')
const publishOnSwarm = require('../contract/publishOnSwarm')
const parseContracts = require('./compileTab/contractParser')
const publishOnSwarm = require('../../lib/publishOnSwarm')
const addTooltip = require('../ui/tooltip')
var css = require('./styles/compile-tab-styles')
@ -17,7 +17,7 @@ var css = require('./styles/compile-tab-styles')
const CompileTabLogic = require('./compileTab/compileTab.js')
const CompilerContainer = require('./compileTab/compilerContainer.js')
import { CompilerApi } from 'remix-plugin'
import { ViewPlugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const profile = {
@ -29,16 +29,18 @@ const profile = {
permission: true,
location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html',
version: packageJson.version
version: packageJson.version,
methods: ['getCompilationResult']
}
// EditorApi:
// - events: ['compilationFinished'],
// - methods: ['getCompilationResult']
class CompileTab extends CompilerApi {
class CompileTab extends ViewPlugin {
constructor (editor, config, renderer, swarmfileProvider, fileManager, fileProviders, pluginManager) {
constructor (editor, config, renderer, swarmfileProvider, fileManager, fileProviders) {
super(profile)
this.events = new EventEmitter()
this._view = {
@ -56,12 +58,13 @@ class CompileTab extends CompilerApi {
this.swarmfileProvider = swarmfileProvider
this.fileManager = fileManager
this.fileProviders = fileProviders
this.pluginManager = pluginManager
this.data = {
contractsDetails: {}
}
}
onActivationInternal () {
this.compileTabLogic = new CompileTabLogic(this.queryParams, this.fileManager, this.editor, this.config, this.fileProviders)
this.compiler = this.compileTabLogic.compiler
this.compileTabLogic.init()
@ -80,23 +83,23 @@ class CompileTab extends CompilerApi {
listenToEvents () {
let onContentChanged = () => {
this.events.emit('statusChanged', {key: 'edited', title: 'the content has changed, needs recompilation', type: 'info'})
this.emit('statusChanged', {key: 'edited', title: 'the content has changed, needs recompilation', type: 'info'})
}
this.editor.event.register('contentChanged', onContentChanged)
this.compiler.event.register('loadingCompiler', () => {
this.events.emit('statusChanged', {key: 'loading', title: 'loading compiler...', type: 'info'})
this.emit('statusChanged', {key: 'loading', title: 'loading compiler...', type: 'info'})
})
this.compiler.event.register('compilerLoaded', () => {
this.events.emit('statusChanged', {key: 'none'})
this.emit('statusChanged', {key: 'none'})
})
this.compileTabLogic.event.on('startingCompilation', () => {
if (this._view.errorContainer) {
this._view.errorContainer.innerHTML = ''
}
this.events.emit('statusChanged', {key: 'loading', title: 'compiling...', type: 'info'})
this.emit('statusChanged', {key: 'loading', title: 'compiling...', type: 'info'})
})
this.fileManager.events.on('currentFileChanged', (name) => {
@ -110,14 +113,14 @@ class CompileTab extends CompilerApi {
this.compiler.event.register('compilationFinished', (success, data, source) => {
if (success) {
// forwarding the event to the appManager infra
this.events.emit('compilationFinished', source.target, source, 'soljson', data)
this.emit('compilationFinished', source.target, source, 'soljson', data)
if (data.errors) {
this.events.emit('statusChanged', {
this.emit('statusChanged', {
key: data.errors.length,
title: `compilation finished successful with warning${data.errors.length > 1 ? 's' : ''}`,
type: 'warning'
})
} else this.events.emit('statusChanged', {key: 'succeed', title: 'compilation successful', type: 'success'})
} else this.emit('statusChanged', {key: 'succeed', title: 'compilation successful', type: 'success'})
// Store the contracts
this.data.contractsDetails = {}
this.compiler.visitContracts((contract) => {
@ -129,7 +132,7 @@ class CompileTab extends CompilerApi {
})
} else {
const count = (data.errors ? data.errors.filter(error => error.severity === 'error').length : 0 + data.error ? 1 : 0)
this.events.emit('statusChanged', {key: count, title: 'compilation failed', type: 'error'})
this.emit('statusChanged', {key: count, title: 'compilation failed', type: 'error'})
}
// Update contract Selection
let contractMap = {}
@ -395,6 +398,7 @@ class CompileTab extends CompilerApi {
render () {
if (this._view.el) return this._view.el
this.onActivationInternal()
this.listenToEvents()
this._view.errorContainer = yo`<div class="${css.errorBlobs} p-2"></div>`
this._view.contractSelection = this.contractSelection()

@ -1,15 +1,15 @@
var yo = require('yo-yo')
var css = require('./styles/debugger-tab-styles')
var DebuggerUI = require('../debugger/debuggerUI')
var DebuggerUI = require('./debugger/debuggerUI')
import { BaseApi } from 'remix-plugin'
import { ViewPlugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const profile = {
name: 'debugger',
displayName: 'Debugger',
methods: [],
methods: ['debug'],
events: [],
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNjk2IDk2MHEwIDI2LTE5IDQ1dC00NSAxOWgtMjI0cTAgMTcxLTY3IDI5MGwyMDggMjA5cTE5IDE5IDE5IDQ1dC0xOSA0NXEtMTggMTktNDUgMTl0LTQ1LTE5bC0xOTgtMTk3cS01IDUtMTUgMTN0LTQyIDI4LjUtNjUgMzYuNS04MiAyOS05NyAxM3YtODk2aC0xMjh2ODk2cS01MSAwLTEwMS41LTEzLjV0LTg3LTMzLTY2LTM5LTQzLjUtMzIuNWwtMTUtMTQtMTgzIDIwN3EtMjAgMjEtNDggMjEtMjQgMC00My0xNi0xOS0xOC0yMC41LTQ0LjV0MTUuNS00Ni41bDIwMi0yMjdxLTU4LTExNC01OC0yNzRoLTIyNHEtMjYgMC00NS0xOXQtMTktNDUgMTktNDUgNDUtMTloMjI0di0yOTRsLTE3My0xNzNxLTE5LTE5LTE5LTQ1dDE5LTQ1IDQ1LTE5IDQ1IDE5bDE3MyAxNzNoODQ0bDE3My0xNzNxMTktMTkgNDUtMTl0NDUgMTkgMTkgNDUtMTkgNDVsLTE3MyAxNzN2Mjk0aDIyNHEyNiAwIDQ1IDE5dDE5IDQ1em0tNDgwLTU3NmgtNjQwcTAtMTMzIDkzLjUtMjI2LjV0MjI2LjUtOTMuNSAyMjYuNSA5My41IDkzLjUgMjI2LjV6Ii8+PC9zdmc+',
description: 'Debug transactions',
@ -19,7 +19,7 @@ const profile = {
version: packageJson.version
}
class DebuggerTab extends BaseApi {
class DebuggerTab extends ViewPlugin {
constructor () {
super(profile)
@ -33,11 +33,14 @@ class DebuggerTab extends BaseApi {
<div class="${css.debuggerTabView}" id="debugView">
<div id="debugger" class="${css.debugger}"></div>
</div>`
this.debuggerUI = new DebuggerUI(this.el.querySelector('#debugger'))
return this.el
}
debug (hash) {
if (this.debugger) this.debuggerUI.debug(hash)
}
debugger () {
return this.debuggerUI
}

@ -1,16 +1,16 @@
var TxBrowser = require('./debuggerUI/TxBrowser')
var StepManagerUI = require('./debuggerUI/StepManager')
var VmDebugger = require('./debuggerUI/VmDebugger')
var toaster = require('../ui/tooltip')
var toaster = require('../../ui/tooltip')
var Debugger = require('remix-debug').TransactionDebugger
var SourceHighlighter = require('../editor/sourceHighlighter')
var SourceHighlighter = require('../../editor/sourceHighlighter')
var EventManager = require('../../lib/events')
var EventManager = require('../../../lib/events')
var executionContext = require('../../execution-context')
var globalRegistry = require('../../global/registry')
var executionContext = require('../../../execution-context')
var globalRegistry = require('../../../global/registry')
var remixLib = require('remix-lib')

@ -1,5 +1,5 @@
'use strict'
var EventManager = require('../../../lib/events')
var EventManager = require('../../../../lib/events')
var yo = require('yo-yo')
var csjs = require('csjs-inject')

@ -1,5 +1,5 @@
'use strict'
var EventManager = require('../../../lib/events')
var EventManager = require('../../../../lib/events')
var yo = require('yo-yo')
class Slider {

@ -1,4 +1,4 @@
var EventManager = require('../../../lib/events')
var EventManager = require('../../../../lib/events')
var yo = require('yo-yo')
var ButtonNavigator = require('./ButtonNavigator')

@ -1,4 +1,4 @@
var EventManager = require('../../../lib/events')
var EventManager = require('../../../../lib/events')
var yo = require('yo-yo')
var csjs = require('csjs-inject')

@ -2,7 +2,7 @@
var style = require('../styles/basicStyles')
var yo = require('yo-yo')
var DropdownPanel = require('./DropdownPanel')
var EventManager = require('../../../../lib/events')
var EventManager = require('../../../../../lib/events')
var csjs = require('csjs-inject')
var css = csjs`

@ -1,8 +1,8 @@
'use strict'
var yo = require('yo-yo')
const copy = require('copy-text-to-clipboard')
var EventManager = require('../../../../lib/events')
var TreeView = require('../../../ui/TreeView') // TODO setup a direct reference to the UI components
var EventManager = require('../../../../../lib/events')
var TreeView = require('../../../../ui/TreeView') // TODO setup a direct reference to the UI components
var csjs = require('csjs-inject')

@ -1,5 +1,5 @@
'use strict'
var EventManager = require('../../../../lib/events')
var EventManager = require('../../../../../lib/events')
var DropdownPanel = require('./DropdownPanel')
var solidityTypeFormatter = require('./utils/SolidityTypeFormatter')
var yo = require('yo-yo')

@ -1,18 +1,20 @@
const executionContext = require('../../execution-context')
import { NetworkApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
export const profile = {
name: 'network',
description: 'Manage the network (mainnet, ropsten, goerli...) and the provider (web3, vm, injected)',
version: packageJson.version
methods: [],
version: packageJson.version,
required: true
}
// Network API has :
// - events: ['providerChanged']
// - methods: ['getNetworkProvider', 'getEndpoint', 'detectNetwork', 'addNetwork', 'removeNetwork']
export class NetworkModule extends NetworkApi {
export class NetworkModule extends Plugin {
constructor () {
super(profile)
// TODO: See with remix-lib to make sementic coherent

@ -1,3 +1,4 @@
var $ = require('jquery')
var yo = require('yo-yo')
var EventManager = require('../../lib/events')
var Card = require('../ui/card')
@ -8,13 +9,14 @@ var SettingsUI = require('./runTab/settings.js')
var DropdownLogic = require('./runTab/model/dropdownlogic.js')
var ContractDropdownUI = require('./runTab/contractDropdown.js')
var UniversalDAppUI = require('../ui/universal-dapp-ui')
var Recorder = require('./runTab/model/recorder.js')
var RecorderUI = require('./runTab/recorder.js')
const executionContext = require('../../execution-context')
import { BaseApi } from 'remix-plugin'
import { ViewPlugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const profile = {
@ -30,20 +32,46 @@ const profile = {
version: packageJson.version
}
class RunTab extends BaseApi {
class RunTab extends ViewPlugin {
constructor (udapp, udappUI, config, fileManager, editor, logCallback, filePanel, pluginManager, compilersArtefacts) {
constructor (udapp, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView) {
super(profile)
this.event = new EventManager()
this.config = config
this.udapp = udapp
this.udappUI = udappUI
this.fileManager = fileManager
this.editor = editor
this.logCallback = logCallback
this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) }
this.filePanel = filePanel
this.pluginManager = pluginManager
this.compilersArtefacts = compilersArtefacts
this.networkModule = networkModule
}
onActivationInternal () {
this.udappUI = new UniversalDAppUI(this.udapp, this.logCallback)
this.udapp.resetAPI({
getAddress: (cb) => {
cb(null, $('#txorigin').val())
},
getValue: (cb) => {
try {
var number = document.querySelector('#value').value
var select = document.getElementById('unit')
var index = select.selectedIndex
var selectedUnit = select.querySelectorAll('option')[index].dataset.unit
var unit = 'ether' // default
if (['ether', 'finney', 'gwei', 'wei'].indexOf(selectedUnit) >= 0) {
unit = selectedUnit
}
cb(null, executionContext.web3().toWei(number, unit))
} catch (e) {
cb(e)
}
},
getGasLimit: (cb) => {
cb(null, $('#gasLimit').val())
}
})
}
renderContainer () {
@ -90,15 +118,15 @@ class RunTab extends BaseApi {
renderSettings (udapp) {
var settings = new Settings(udapp)
this.settingsUI = new SettingsUI(settings)
this.settingsUI = new SettingsUI(settings, this.networkModule)
this.settingsUI.event.register('clearInstance', () => {
this.event.trigger('clearInstance', [])
})
}
renderDropdown (udappUI, fileManager, pluginManager, compilersArtefacts, config, editor, udapp, filePanel, logCallback) {
var dropdownLogic = new DropdownLogic(fileManager, pluginManager, compilersArtefacts, config, editor, udapp, filePanel)
renderDropdown (udappUI, fileManager, compilersArtefacts, config, editor, udapp, filePanel, logCallback) {
var dropdownLogic = new DropdownLogic(fileManager, compilersArtefacts, config, editor, udapp, filePanel, this)
this.contractDropdownUI = new ContractDropdownUI(dropdownLogic, logCallback)
this.contractDropdownUI.event.register('clearInstance', () => {
@ -166,13 +194,14 @@ class RunTab extends BaseApi {
}
render () {
this.onActivationInternal()
executionContext.init(this.config)
executionContext.stopListenOnLastBlock()
executionContext.listenOnLastBlock()
this.udapp.resetEnvironment()
this.renderInstanceContainer()
this.renderSettings(this.udapp)
this.renderDropdown(this.udappUI, this.fileManager, this.pluginManager, this.compilersArtefacts, this.config, this.editor, this.udapp, this.filePanel, this.logCallback)
this.renderDropdown(this.udappUI, this.fileManager, this.compilersArtefacts, this.config, this.editor, this.udapp, this.filePanel, this.logCallback)
this.renderRecorder(this.udapp, this.udappUI, this.fileManager, this.config, this.logCallback)
this.renderRecorderCard()
return this.renderContainer()

@ -3,9 +3,9 @@ var css = require('../styles/run-tab-styles')
var modalDialogCustom = require('../../ui/modal-dialog-custom')
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
var confirmDialog = require('../../execution/confirmDialog')
var confirmDialog = require('../../ui/confirmDialog')
var modalDialog = require('../../ui/modaldialog')
var MultiParamManager = require('../../../multiParamManager')
var MultiParamManager = require('../../ui/multiParamManager')
class ContractDropdownUI {
constructor (dropdownLogic, logCallback) {

@ -9,12 +9,12 @@ var CompilerAbstract = require('../../../compiler/compiler-abstract')
var EventManager = remixLib.EventManager
class DropdownLogic {
constructor (fileManager, pluginManager, compilersArtefacts, config, editor, udapp, filePanel) {
this.pluginManager = pluginManager
constructor (fileManager, compilersArtefacts, config, editor, udapp, filePanel, runView) {
this.compilersArtefacts = compilersArtefacts
this.config = config
this.editor = editor
this.udapp = udapp
this.runView = runView
this.filePanel = filePanel
this.event = new EventManager()
@ -28,7 +28,7 @@ class DropdownLogic {
// TODO: can be moved up; the event in contractDropdown will have to refactored a method instead
listenToCompilationEvents () {
this.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => {
this.runView.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => {
// TODO check whether the tab is configured
let compiler = new CompilerAbstract(languageVersion, data, source)
this.compilersArtefacts[languageVersion] = compiler
@ -264,29 +264,32 @@ class DropdownLogic {
this.udapp.runTx(data, confirmationCb, continueCb, promptCb, finalCb)
}
forceSend (selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, cb) {
async forceSend (selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, cb) {
var constructor = selectedContract.getConstructorInterface()
// TODO: deployMetadataOf can be moved here
this.filePanel.compilerMetadata().deployMetadataOf(selectedContract.name, (error, contractMetadata) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
return txFormat.buildData(selectedContract.name, selectedContract.object, this.compilersArtefacts['__last'].getData().contracts, true, constructor, args, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, cb)
}, statusCb, (data, runTxCallback) => {
// called for libraries deployment
this.runTransaction(data, continueCb, promptCb, modalDialog, confirmDialog, runTxCallback)
})
}
if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.object, args, constructor, contractMetadata.linkReferences, selectedContract.bytecodeLinkReferences, (error, data) => {
let contractMetadata
try {
contractMetadata = await this.runView.call('compilerMetadata', 'deployMetadataOf', selectedContract.name)
} catch (error) {
return statusCb(`creation of ${selectedContract.name} errored: ` + error)
}
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
return txFormat.buildData(selectedContract.name, selectedContract.object, this.compilersArtefacts['__last'].getData().contracts, true, constructor, args, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, cb)
}, statusCb, (data, runTxCallback) => {
// called for libraries deployment
this.runTransaction(data, continueCb, promptCb, modalDialog, confirmDialog, runTxCallback)
})
}
if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.object, args, constructor, contractMetadata.linkReferences, selectedContract.bytecodeLinkReferences, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, cb)
})
}

@ -6,7 +6,7 @@ var css = require('../styles/run-tab-styles')
var modalDialogCustom = require('../../ui/modal-dialog-custom')
var modalDialog = require('../../ui/modaldialog')
var confirmDialog = require('../../execution/confirmDialog')
var confirmDialog = require('../../ui/confirmDialog')
class RecorderUI {

@ -11,7 +11,7 @@ const globalRegistry = require('../../../global/registry')
class SettingsUI {
constructor (settings) {
constructor (settings, networkModule) {
this.settings = settings
this.event = new EventManager()
this._components = {}
@ -21,10 +21,12 @@ class SettingsUI {
if (!lookupOnly) this.el.querySelector('#value').value = '0'
this.updateAccountBalances()
})
this._components = {
registry: globalRegistry,
networkModule: networkModule
}
this._components.registry = globalRegistry
this._deps = {
networkModule: this._components.registry.get('network').api,
config: this._components.registry.get('config').api
}
@ -307,7 +309,7 @@ class SettingsUI {
this.netUI.innerHTML = 'can\'t detect network '
return
}
let network = this._deps.networkModule.getNetworkProvider
let network = this._components.networkModule.getNetworkProvider
this.netUI.innerHTML = (network() !== 'vm') ? `${name} (${id || '-'}) network` : ''
})
this.fillAccountsList()

@ -4,7 +4,7 @@ var tooltip = require('../ui/tooltip')
var copyToClipboard = require('../ui/copy-to-clipboard')
var EventManager = require('../../lib/events')
var css = require('./styles/settings-tab-styles')
import { BaseApi } from 'remix-plugin'
import { ViewPlugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
const profile = {
@ -20,7 +20,7 @@ const profile = {
version: packageJson.version
}
module.exports = class SettingsTab extends BaseApi {
module.exports = class SettingsTab extends ViewPlugin {
constructor (config, editor, appManager) {
super(profile)
this.config = config

@ -5,11 +5,11 @@ var $ = require('jquery')
var remixLib = require('remix-lib')
var utils = remixLib.util
var css = require('./styles/staticAnalysisView-styles')
var globlalRegistry = require('../../global/registry')
var Renderer = require('../../ui/renderer')
var EventManager = require('../../lib/events')
var EventManager = require('../../../lib/events')
function staticAnalysisView (localRegistry) {
function staticAnalysisView (localRegistry, analysisModule) {
var self = this
this.event = new EventManager()
this.view = null
@ -17,16 +17,16 @@ function staticAnalysisView (localRegistry) {
this.modulesView = this.renderModules()
this.lastCompilationResult = null
this.lastCompilationSource = null
self._components = {}
self._components.registry = localRegistry || globlalRegistry
self._components = {
renderer: new Renderer()
}
self._components.registry = localRegistry
// dependencies
self._deps = {
pluginManager: self._components.registry.get('pluginmanager').api,
renderer: self._components.registry.get('renderer').api,
offsetToLineColumnConverter: self._components.registry.get('offsettolinecolumnconverter').api
}
self._deps.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => {
analysisModule.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => {
self.lastCompilationResult = null
self.lastCompilationSource = null
$('#staticanalysisresult').empty()
@ -119,7 +119,7 @@ staticAnalysisView.prototype.run = function () {
}
warningCount++
var msg = yo`<span>${location} ${item.warning} ${item.more ? yo`<span><br><a href="${item.more}" target="blank">more</a></span>` : yo`<span></span>`}</span>`
self._deps.renderer.error(msg, warningContainer, {type: 'staticAnalysisWarning alert alert-warning', useSpan: true})
self._components.renderer.error(msg, warningContainer, {type: 'staticAnalysisWarning alert alert-warning', useSpan: true})
})
})
self.event.trigger('staticAnaysisWarning', [warningCount])

@ -3,7 +3,7 @@ var async = require('async')
var tooltip = require('../ui/tooltip')
var css = require('./styles/test-tab-styles')
var remixTests = require('remix-tests')
import { BaseApi } from 'remix-plugin'
import { ViewPlugin } from '@remixproject/engine'
const TestTabLogic = require('./testTab/testTab')
@ -18,32 +18,29 @@ const profile = {
documentation: 'https://remix-ide.readthedocs.io/en/latest/unittesting.html'
}
module.exports = class TestTab extends BaseApi {
constructor (fileManager, filePanel, compileTab, appStore) {
module.exports = class TestTab extends ViewPlugin {
constructor (fileManager, filePanel, compileTab, appManager) {
super(profile)
this.compileTab = compileTab
this._view = { el: null }
this.compileTab = compileTab
this.fileManager = fileManager
this.filePanel = filePanel
this.appStore = appStore
this.testTabLogic = new TestTabLogic(fileManager)
this.data = {}
this.appStore.event.on('activate', (name) => {
this.appManager = appManager
appManager.event.on('activate', (name) => {
if (name === 'solidity') this.updateRunAction(fileManager.currentFile())
})
this.appStore.event.on('deactivate', (name) => {
appManager.event.on('deactivate', (name) => {
if (name === 'solidity') this.updateRunAction(fileManager.currentFile())
})
}
activate () {
onActivationInternal () {
this.testTabLogic = new TestTabLogic(this.fileManager)
this.listenToEvents()
}
deactivate () {
}
listenToEvents () {
this.filePanel.event.register('newTestFileCreated', file => {
var testList = this.view.querySelector("[class^='testList']")
@ -144,8 +141,7 @@ module.exports = class TestTab extends BaseApi {
runTest (testFilePath, callback) {
this.loading.hidden = false
this.fileManager.fileProviderOf(testFilePath).get(testFilePath, (error, content) => {
if (error) return
this.fileManager.getFile(testFilePath).then((content) => {
var runningTest = {}
runningTest[testFilePath] = { content }
remixTests.runTestSources(runningTest, (result) => { this.testCallback(result) }, (_err, result, cb) => { this.resultsCallback(_err, result, cb) }, (error, result) => {
@ -155,6 +151,8 @@ module.exports = class TestTab extends BaseApi {
}, (url, cb) => {
return this.compileTab.compileTabLogic.importFileCb(url, cb)
})
}).catch((error) => {
if (error) return
})
}
@ -183,7 +181,7 @@ module.exports = class TestTab extends BaseApi {
updateRunAction (currentFile) {
let el = yo`<button class="${css.runButton} btn btn-primary" onclick="${this.runTests.bind(this)}">Run Tests</button>`
const isSolidityActive = this.appStore.isActive('solidity')
const isSolidityActive = this.appManager.isActive('solidity')
if (!currentFile || !isSolidityActive) {
el.setAttribute('disabled', 'disabled')
if (!currentFile) el.setAttribute('title', 'No file selected')
@ -209,6 +207,7 @@ module.exports = class TestTab extends BaseApi {
return this.testFilesListElement
}
render () {
this.onActivationInternal()
this.testsOutput = yo`<div class="${css.container} m-3 border border-primary border-right-0 border-left-0 border-bottom-0" hidden='true' id="tests"></div>`
this.testsSummary = yo`<div class="${css.container} border border-primary border-right-0 border-left-0 border-bottom-0" hidden='true' id="tests"></div>`
this.loading = yo`<span class='text-info ml-1'>Running tests...</span>`

@ -1,4 +1,4 @@
import { BaseApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import * as packageJson from '../../../package.json'
@ -21,10 +21,11 @@ const profile = {
name: 'theme',
events: ['themeChanged'],
methods: ['switchTheme', 'getThemes', 'currentTheme'],
version: packageJson.version
version: packageJson.version,
required: true
}
export class ThemeModule extends BaseApi {
export class ThemeModule extends Plugin {
constructor (registry) {
super(profile)

@ -1,7 +1,7 @@
var yo = require('yo-yo')
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
var Commands = require('../constants/commands')
var Commands = require('../../lib/commands')
// -------------- styling ----------------------
var css = require('./styles/auto-complete-popup-styles')
@ -189,8 +189,8 @@ class AutoCompletePopup {
extendAutocompletion () {
// TODO: this is not using the appManager interface. Terminal should be put as module
this.opts.appStore.event.on('activate', (id) => {
const profile = this.opts.appStore.getOne(id).profile
this.opts.appManager.event.on('activate', (id) => {
const profile = this.opts.appManager.getOne(id).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) })`

@ -1,6 +1,6 @@
var yo = require('yo-yo')
var csjs = require('csjs-inject')
const copyToClipboard = require('../ui/copy-to-clipboard')
const copyToClipboard = require('./copy-to-clipboard')
var css = csjs`
.txInfoBox {

File diff suppressed because one or more lines are too long

@ -1,5 +1,3 @@
let globalRegistry = require('../../../global/registry')
export class Workspace {
constructor (title, description, isMain, activate, deactivate) {
this.title = title
@ -21,7 +19,6 @@ export const defaultWorkspaces = (appManager) => {
appManager.ensureActivated('run')
appManager.ensureActivated('solidityStaticAnalysis')
appManager.ensureActivated('solidityUnitTesting')
globalRegistry.get('verticalicon').api.select('solidity')
}, () => {}),
new Workspace(
'Vyper',
@ -30,7 +27,6 @@ export const defaultWorkspaces = (appManager) => {
() => {
appManager.ensureActivated('vyper')
appManager.ensureActivated('run')
globalRegistry.get('verticalicon').api.select('vyper')
}, () => {}),
new Workspace('Debugger', 'Debug transactions with remix', false, () => {
appManager.ensureActivated('debugger')

@ -1,8 +1,8 @@
'use strict'
var yo = require('yo-yo')
var css = require('./universal-dapp-styles')
var copyToClipboard = require('./app/ui/copy-to-clipboard')
var css = require('../../universal-dapp-styles')
var copyToClipboard = require('./copy-to-clipboard')
var remixLib = require('remix-lib')
var txFormat = remixLib.execution.txFormat

@ -1,8 +1,8 @@
/* global localStorage */
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const addTooltip = require('./app/ui/tooltip')
const modalDialog = require('./app/ui/modaldialog')
const addTooltip = require('./tooltip')
const modalDialog = require('./modaldialog')
const css = csjs`
.permission h4 {

@ -1,6 +1,6 @@
'use strict'
var yo = require('yo-yo')
var copyToClipboard = require('../ui/copy-to-clipboard')
var copyToClipboard = require('./copy-to-clipboard')
// -------------- styling ----------------------
var csjs = require('csjs-inject')
@ -9,7 +9,7 @@ var remixLib = require('remix-lib')
var EventManager = require('../../lib/events')
var helper = require('../../lib/helper')
var executionContext = require('../../execution-context')
var modalDialog = require('../ui/modal-dialog-custom')
var modalDialog = require('./modal-dialog-custom')
var typeConversion = remixLib.execution.typeConversion
var globlalRegistry = require('../../global/registry')
@ -117,7 +117,7 @@ var css = csjs`
*
*/
class TxLogger {
constructor (localRegistry) {
constructor (eventsDecoder, txListener, terminal) {
this.event = new EventManager()
this.seen = {}
function filterTx (value, query) {
@ -126,18 +126,15 @@ class TxLogger {
}
return false
}
this._components = {}
this._components.registry = localRegistry || globlalRegistry
this.eventsDecoder = eventsDecoder
this.txListener = txListener
this.terminal = terminal
// dependencies
this._deps = {
mainView: this._components.registry.get('mainview').api,
txListener: this._components.registry.get('txlistener').api,
eventsDecoder: this._components.registry.get('eventsdecoder').api,
compilersArtefacts: this._components.registry.get('compilersartefacts').api
compilersArtefacts: globlalRegistry.get('compilersartefacts').api
}
this.logKnownTX = this._deps.mainView.registerCommand('knownTransaction', (args, cmds, append) => {
this.logKnownTX = this.terminal.registerCommand('knownTransaction', (args, cmds, append) => {
var data = args[0]
var el
if (data.tx.isCall) {
@ -149,35 +146,35 @@ class TxLogger {
append(el)
}, { activate: true, filterFn: filterTx })
this.logUnknownTX = this._deps.mainView.registerCommand('unknownTransaction', (args, cmds, append) => {
this.logUnknownTX = this.terminal.registerCommand('unknownTransaction', (args, cmds, append) => {
// triggered for transaction AND call
var data = args[0]
var el = renderUnknownTransaction(this, data)
append(el)
}, { activate: false, filterFn: filterTx })
this.logEmptyBlock = this._deps.mainView.registerCommand('emptyBlock', (args, cmds, append) => {
this.logEmptyBlock = this.terminal.registerCommand('emptyBlock', (args, cmds, append) => {
var data = args[0]
var el = renderEmptyBlock(this, data)
append(el)
}, { activate: true })
this._deps.txListener.event.register('newBlock', (block) => {
this.txListener.event.register('newBlock', (block) => {
if (!block.transactions || block.transactions && !block.transactions.length) {
this.logEmptyBlock({ block: block })
}
})
this._deps.txListener.event.register('newTransaction', (tx, receipt) => {
this.txListener.event.register('newTransaction', (tx, receipt) => {
log(this, tx, receipt)
})
this._deps.txListener.event.register('newCall', (tx) => {
this.txListener.event.register('newCall', (tx) => {
log(this, tx, null)
})
this._deps.mainView.updateTerminalFilter({ type: 'select', value: 'unknownTransaction' })
this._deps.mainView.updateTerminalFilter({ type: 'select', value: 'knownTransaction' })
this.terminal.updateJournal({ type: 'select', value: 'unknownTransaction' })
this.terminal.updateJournal({ type: 'select', value: 'knownTransaction' })
}
}
@ -191,13 +188,13 @@ function debug (e, data, self) {
}
function log (self, tx, receipt) {
var resolvedTransaction = self._deps.txListener.resolvedTransaction(tx.hash)
var resolvedTransaction = self.txListener.resolvedTransaction(tx.hash)
if (resolvedTransaction) {
var compiledContracts = null
if (self._deps.compilersArtefacts['__last']) {
compiledContracts = self._deps.compilersArtefacts['__last'].getContracts()
}
self._deps.eventsDecoder.parseLogs(tx, resolvedTransaction.contractName, compiledContracts, (error, logs) => {
self.eventsDecoder.parseLogs(tx, resolvedTransaction.contractName, compiledContracts, (error, logs) => {
if (!error) {
self.logKnownTX({ tx: tx, receipt: receipt, resolvedData: resolvedTransaction, logs: logs })
}

@ -5,30 +5,26 @@ var $ = require('jquery')
var yo = require('yo-yo')
var ethJSUtil = require('ethereumjs-util')
var BN = ethJSUtil.BN
var helper = require('./lib/helper')
var copyToClipboard = require('./app/ui/copy-to-clipboard')
var css = require('./universal-dapp-styles')
var helper = require('../../lib/helper')
var copyToClipboard = require('./copy-to-clipboard')
var css = require('../../universal-dapp-styles')
var MultiParamManager = require('./multiParamManager')
var remixLib = require('remix-lib')
var typeConversion = remixLib.execution.typeConversion
var txExecution = remixLib.execution.txExecution
var txFormat = remixLib.execution.txFormat
var executionContext = require('./execution-context')
var executionContext = require('../../execution-context')
var confirmDialog = require('./app/execution/confirmDialog')
var modalCustom = require('./app/ui/modal-dialog-custom')
var modalDialog = require('./app/ui/modaldialog')
var TreeView = require('./app/ui/TreeView')
var confirmDialog = require('./confirmDialog')
var modalCustom = require('./modal-dialog-custom')
var modalDialog = require('./modaldialog')
var TreeView = require('./TreeView')
function UniversalDAppUI (udapp, registry) {
function UniversalDAppUI (udapp, logCallback) {
this.udapp = udapp
this.registry = registry
this.logCallback = logCallback
this.compilerData = {contractsDetails: {}}
this._deps = {
compilersartefacts: registry.get('compilersartefacts').api
}
}
function decodeResponseToTreeView (response, fnabi) {
@ -251,9 +247,9 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
txFormat.buildData(args.contractName, args.contractAbi, {}, false, args.funABI, args.funABI.type !== 'fallback' ? value : '', (error, data) => {
if (!error) {
if (!args.funABI.constant) {
self.registry.get('logCallback').api(`${logMsg} pending ... `)
self.logCallback(`${logMsg} pending ... `)
} else {
self.registry.get('logCallback').api(`${logMsg}`)
self.logCallback(`${logMsg}`)
}
if (args.funABI.type === 'fallback') data.dataHex = value
self.udapp.callFunction(args.address, data, args.funABI, confirmationCb, continueCb, promptCb, (error, txResult) => {
@ -262,7 +258,7 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
if (isVM) {
var vmError = txExecution.checkVMError(txResult)
if (vmError.error) {
self.registry.get('logCallback').api(`${logMsg} errored: ${vmError.message} `)
self.logCallback(`${logMsg} errored: ${vmError.message} `)
return
}
}
@ -271,14 +267,14 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
outputCb(decoded)
}
} else {
self.registry.get('logCallback').api(`${logMsg} errored: ${error} `)
self.logCallback(`${logMsg} errored: ${error} `)
}
})
} else {
self.registry.get('logCallback').api(`${logMsg} errored: ${error} `)
self.logCallback(`${logMsg} errored: ${error} `)
}
}, (msg) => {
self.registry.get('logCallback').api(msg)
self.logCallback(msg)
}, (data, runTxCallback) => {
// called for libraries deployment
self.udapp.runTx(data, confirmationCb, runTxCallback)

@ -1,26 +1,34 @@
export default {
start: (appStore, sidePanel, verticalIcon, mainPanel, resizeFeature) => {
sidePanel.events.on('toggle', () => {
resizeFeature.panel1.clientWidth !== 0 ? resizeFeature.minimize() : resizeFeature.maximise()
export class FramingService {
constructor (sidePanel, verticalIcon, mainView, resizeFeature) {
this.sidePanel = sidePanel
this.verticalIcon = verticalIcon
this.mainPanel = mainView.getAppPanel()
this.mainView = mainView
this.resizeFeature = resizeFeature
}
start () {
this.sidePanel.events.on('toggle', () => {
this.resizeFeature.panel1.clientWidth !== 0 ? this.resizeFeature.minimize() : this.resizeFeature.maximise()
})
sidePanel.events.on('showing', () => {
resizeFeature.panel1.clientWidth === 0 ? resizeFeature.maximise() : ''
this.sidePanel.events.on('showing', () => {
this.resizeFeature.panel1.clientWidth === 0 ? this.resizeFeature.maximise() : ''
})
mainPanel.events.on('toggle', () => {
resizeFeature.maximise()
this.mainPanel.events.on('toggle', () => {
this.resizeFeature.maximise()
})
verticalIcon.select('fileExplorers')
verticalIcon.showHome()
this.verticalIcon.select('fileExplorers')
document.addEventListener('keypress', (e) => {
if (e.shiftKey && e.ctrlKey) {
if (e.code === 'KeyF') { // Ctrl+Shift+F
verticalIcon.select('fileExplorers')
this.verticalIcon.select('fileExplorers')
} else if (e.code === 'KeyA') { // Ctrl+Shift+A
verticalIcon.select('pluginManager')
this.verticalIcon.select('pluginManager')
} else if (e.code === 'KeyS') { // Ctrl+Shift+S
verticalIcon.select('settings')
this.verticalIcon.select('settings')
}
e.preventDefault()
}

@ -11,7 +11,8 @@ var globalRegistry = require('../global/registry')
var SourceHighlighter = require('../app/editor/sourceHighlighter')
var RemixDebug = require('remix-debug').EthDebugger
var TreeView = require('../app/ui/TreeView') // TODO setup a direct reference to the UI components
var solidityTypeFormatter = require('../app/debugger/debuggerUI/vmDebugger/utils/SolidityTypeFormatter')
var solidityTypeFormatter = require('../app/tabs/debugger/debuggerUI/vmDebugger/utils/SolidityTypeFormatter')
var GistHandler = require('./gist-handler')
class CmdInterpreterAPI {
constructor (terminal, localRegistry) {
@ -22,8 +23,8 @@ class CmdInterpreterAPI {
self._components.terminal = terminal
self._components.sourceHighlighter = new SourceHighlighter()
self._components.fileImport = new CompilerImport()
self._components.gistHandler = new GistHandler()
self._deps = {
app: self._components.registry.get('app').api,
fileManager: self._components.registry.get('filemanager').api,
editor: self._components.registry.get('editor').api,
compilersArtefacts: self._components.registry.get('compilersartefacts').api,
@ -138,7 +139,7 @@ class CmdInterpreterAPI {
}
loadgist (id, cb) {
const self = this
self._deps.app.loadFromGist({gist: id})
self._components.gistHandler.loadFromGist({gist: id}, this._deps.fileManager)
if (cb) cb()
}
loadurl (url, cb) {

@ -1,5 +1,7 @@
'use strict'
var modalDialogCustom = require('../app/ui/modal-dialog-custom')
var request = require('request')
// Allowing window to be overriden for testing
function GistHandler (_window) {
if (_window !== undefined) {
@ -38,6 +40,25 @@ function GistHandler (_window) {
var match = idr.exec(str)
return match ? match[0] : null
}
this.loadFromGist = (params, fileManager) => {
const gistProvider = fileManager.fileProviderOf('gist')
const self = this
return self.handleLoad(params, function (gistId) {
request.get({
url: `https://api.github.com/gists/${gistId}`,
json: true
}, (error, response, data = {}) => {
if (error || !data.files) {
modalDialogCustom.alert(`Gist load error: ${error || data.message}`)
return
}
fileManager.setBatchFiles(data.files, 'gist', (errorLoadingFile) => {
if (!errorLoadingFile) gistProvider.id = gistId
})
})
})
}
}
module.exports = GistHandler

@ -1,29 +1,43 @@
'use strict'
var SourceMappingDecoder = require('remix-lib').SourceMappingDecoder
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../package.json'
function offsetToColumnConverter (appManager) {
this.lineBreakPositionsByContent = {}
this.sourceMappingDecoder = new SourceMappingDecoder()
appManager.data.proxy.event.register('sendCompilationResult', () => {
this.clear()
})
const profile = {
name: 'offsetToLineColumnConverter',
methods: [],
events: [],
version: packageJson.version,
required: true
}
offsetToColumnConverter.prototype.offsetToLineColumn = function (rawLocation, file, sources, asts) {
if (!this.lineBreakPositionsByContent[file]) {
for (var filename in asts) {
var source = asts[filename]
if (source.id === file) {
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content)
break
export class OffsetToLineColumnConverter extends Plugin {
constructor () {
super(profile)
this.lineBreakPositionsByContent = {}
this.sourceMappingDecoder = new SourceMappingDecoder()
}
offsetToLineColumn (rawLocation, file, sources, asts) {
if (!this.lineBreakPositionsByContent[file]) {
for (var filename in asts) {
var source = asts[filename]
if (source.id === file) {
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content)
break
}
}
}
return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
}
return this.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, this.lineBreakPositionsByContent[file])
}
offsetToColumnConverter.prototype.clear = function () {
this.lineBreakPositionsByContent = {}
}
clear () {
this.lineBreakPositionsByContent = {}
}
module.exports = offsetToColumnConverter
activate () {
this.on('solidity', 'compilationFinished', () => {
this.clear()
})
}
}

@ -1,289 +0,0 @@
/* global localStorage */
import { EventEmitter } from 'events'
export class Store {
/**
* Instanciate the store from `localStorage` first
* @template T
* @param {string} name The name of the store
* @param {T} initialState The initial state used if state is not available in `localStorage`
*/
static fromLocal (name, initialState) {
const fromLocal = localStorage.getItem(name)
const intial = fromLocal ? JSON.parse(fromLocal) : initialState
return new Store(name, intial)
}
/**
* Create a Store that hold the state of the component
* @template T
* @param {string} name The name of the store
* @param {T} initialState The initial state of the store
*/
constructor (name, initialState) {
this.event = new EventEmitter()
this.name = name
this.state = initialState || {}
}
/** Listen on event from the store */
get on () {
return this.event.on
}
/** Liste once on event from the store */
get once () {
return this.event.once
}
/**
* Update one field of the state
* @param {Partial<T>} state The part of the state updated
*/
update (state) {
this.state = { ...this.state, ...state }
this.dispatch()
}
/**
* Get one field of the state
* @template Key key of `this.state`
* @param {Key} key A key of the state
*/
get (key) {
return this.state[key]
}
/** Reset the state its initial value */
reset () {
this.state = this.initialState
}
/** Dispatch an event with the new state */
dispatch () {
this.event.emit('newState', this.state)
}
}
/**
* An entity inside a collection
* @typedef {Object} EntityState
* @property {string[]} ids The list of IDs of the entity in the state
* @property {string[]} actives The list of IDs of the activated entities
* @property {Object} entities A map of ids and entities
*/
export class EntityStore extends Store {
/**
* Instanciate the store from `localStorage` first
* @param {string} name The name of the store
* @param {(string|number)} keyId The name of the key used as a unique ID for the entity
* @param {EntityState} initialState The initial state used if state is not available in `localStorage`
*/
static fromLocal (name, keyId, initialState = {}) {
const fromLocal = localStorage.getItem(name)
const intial = fromLocal ? JSON.parse(fromLocal) : initialState
return new EntityStore(name, keyId, intial)
}
/**
* Create a entity Store that hold a map entity of the same model
* @param {string} name The name of the store
* @param {(string|number)} keyId The name of the key used as a unique ID for the entity
* @param {EntityState} initialState The initial state used if state is not available in `localStorage`
*/
constructor (name, keyId, initialState = { ids: [], actives: [], entities: {} }) {
super(name, initialState)
this.keyId = keyId || 'id'
}
/**
* The entities as a Map
* @returns {Object}
*/
get entities () {
return this.state.entities
}
/**
* List of all the ids
* @returns {(string|number)[]}
*/
get ids () {
return this.state.ids
}
/**
* List of all active ID
* @returns {Object[]}
*/
get actives () {
return this.state.actives
}
/**
* Return the length of the entity collection
* @returns {number}
*/
get length () {
return this.state.ids.length
}
/**
* Add a new entity to the state
* @param {Object} entity
*/
add (entity) {
const id = entity[this.keyId]
this.state.entities[id] = entity
this.state.ids.push(id)
this.event.emit('add', entity)
}
/**
* Add entities to the state
* @param {Array} entities
*/
addEntities (entities) {
entities.forEach((entity) => {
if (!entity[this.keyId]) throw new Error(`Key ${this.keyId} doesn't exist in ${entity}`)
this.add(entity[this.keyId], entity)
})
this.event.emit('add', entities)
}
/**
* Remove an entity from the state
* @param {(string|number)} id The id of the entity to remove
*/
remove (id) {
if (!this.state.entities[id]) throw new Error(`No entity with key ${id} found in store ${this.name}`)
delete this.state.entities[id]
this.state.ids.splice(this.state.ids.indexOf(id), 1)
this.state.actives.splice(this.state.ids.indexOf(id), 1)
this.event.emit('remove', id)
}
/** Remove all entity from the state and reset actives and ids to empty */
clear () {
this.state = {
ids: [],
actives: []
}
this.event.emit('clear')
}
/**
* Update one entity of the state
* @param {(string|number)} id The id of the entity to update
* @param {Object} update The fields to update in the entity
*/
updateOne (id, update) {
if (!this.state.entities[id]) throw new Error(`No entity with key ${id} found in store ${this.name}`)
this.state.entities[id] = {
...this.state.entities[id],
...update
}
this.event.emit('update', this.state.entities[id])
}
/**
* Activate one or several entity from the state
* @param {((string|number))} ids An id or a list of id to activate
*/
activate (id) {
if (this.actives.includes(id)) return
this.state.actives.push(id)
this.event.emit('activate', id)
}
/**
* Deactivate one or several entity from the state
* @param {(string|number))} ids An id or a list of id to deactivate
*/
deactivate (id) {
if (!this.actives.includes(id)) return
this.state.actives.splice(this.state.actives.indexOf(id), 1)
this.event.emit('deactivate', id)
}
// /////////
// QUERY //
// /////////
/**
* Get one entity
* @param {(string|number)} id The id of the entity to get
* @returns {Object}
*/
getOne (id) {
return this.state.entities[id]
}
/**
* Get many entities as an array
* @param {(string|number)[]} ids An array of id of entity to get
* @returns {Object[]}
*/
getMany (ids) {
return ids.map(id => this.state.entities[id])
}
/**
* Get all the entities as an array
* @returns {Object[]}
*/
getAll () {
return this.state.ids.map(id => this.state.entities[id])
}
/**
* Get all active entities
* @returns {Object[]}
*/
getActives () {
return this.state.actives.map(id => this.state.entities[id])
}
/**
* Is the entity active
* @param {(string|number)} id The id of the entity to check
* @returns {boolean}
*/
isActive (id) {
return this.state.actives.includes(id)
}
/**
* Is this id inside the store
* @param {(string|number)} id The id of the entity to check
* @returns {boolean}
*/
hasEntity (id) {
return this.state.ids.includes(id)
}
/**
* Is the state empty
* @param {(string|number)} id The id of the entity to check
* @returns {boolean}
*/
isEmpty () {
return this.state.ids.length === 0
}
}
/**
* Store the state of the stores into LocalStorage
* @param {Store[]} stores The list of stores to store into `localStorage`
*/
export function localState (stores) {
stores.forEach(store => {
const name = store.name
store.on('newState', (state) => {
localStorage.setItem(name, JSON.stringify(state))
})
})
}

@ -1,5 +1,5 @@
'use strict'
var executionContext = require('./execution-context')
var executionContext = require('../execution-context')
module.exports = class TransactionReceiptResolver {
constructor () {

@ -0,0 +1,22 @@
module.exports = (fileManager) => {
// The event listener needs to be registered as early as possible, because the
// parent will send the message upon the "load" event.
let filesToLoad = null
let loadFilesCallback = function (files) { filesToLoad = files } // will be replaced later
window.addEventListener('message', function (ev) {
if (typeof ev.data === typeof [] && ev.data[0] === 'loadFiles') {
loadFilesCallback(ev.data[1])
}
}, false)
// Replace early callback with instant response
loadFilesCallback = function (files) {
fileManager.setBatchFiles(files)
}
// Run if we did receive an event from remote instance while starting up
if (filesToLoad !== null) {
fileManager.setBatchFiles(filesToLoad)
}
}

@ -0,0 +1,48 @@
var UniversalDApp = require('./universal-dapp.js')
var registry = require('./global/registry')
var remixLib = require('remix-lib')
var yo = require('yo-yo')
var executionContext = remixLib.execution.executionContext
var Txlistener = remixLib.execution.txListener
var EventsDecoder = remixLib.execution.EventsDecoder
var TransactionReceiptResolver = require('./lib/transactionReceiptResolver')
module.exports = (compilersArtefacts, logHtmlCallback) => {
// ----------------- UniversalDApp -----------------
const udapp = new UniversalDApp(registry)
// TODO: to remove when possible
udapp.event.register('transactionBroadcasted', (txhash, networkName) => {
var txLink = executionContext.txDetailsLink(networkName, txhash)
if (txLink && logHtmlCallback) logHtmlCallback(yo`<a href="${txLink}" target="_blank">${txLink}</a>`)
})
// ----------------- Tx listener -----------------
const transactionReceiptResolver = new TransactionReceiptResolver()
const txlistener = new Txlistener({
api: {
contracts: function () {
if (compilersArtefacts['__last']) return compilersArtefacts['__last'].getContracts()
return null
},
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
},
event: {
udapp: udapp.event
}})
registry.put({api: txlistener, name: 'txlistener'})
udapp.startListening(txlistener)
const eventsDecoder = new EventsDecoder({
api: {
resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb)
}
}
})
txlistener.startListening()
return {udapp, txlistener, eventsDecoder}
}

@ -1,11 +0,0 @@
module.exports = stacktrace
/*
Not used yet
*/
function stacktrace () {
var _ = Error.prepareStackTrace
Error.prepareStackTrace = (_, stack) => stack
var callsites = new Error().stack
Error.prepareStackTrace = _
return callsites.slice(2).map(x => { return x.getFunctionName() }).reverse().join('.')
}

@ -1,64 +1,60 @@
/* global localStorage */
import { AppManagerApi, Plugin } from 'remix-plugin'
import { PluginEngine, IframePlugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import PluginManagerProxy from './app/components/plugin-manager-proxy'
import { PermissionHandler } from './persmission-handler'
import { PermissionHandler } from './app/ui/persmission-handler'
export class RemixAppManager extends AppManagerApi {
export class RemixAppManager extends PluginEngine {
constructor (store) {
super(null)
constructor (plugins) {
super(plugins)
this.permissionHandler = new PermissionHandler()
this.store = store
this.hiddenServices = {}
this.event = new EventEmitter()
this.data = {
proxy: new PluginManagerProxy()
}
this.registered = {}
}
ensureActivated (apiName) {
if (!this.store.isActive(apiName)) this.activateOne(apiName)
this.event.emit('ensureActivated', apiName)
onActivated (plugin) {
localStorage.setItem('workspace', JSON.stringify(this.actives))
this.event.emit('activate', plugin.name)
}
ensureDeactivated (apiName) {
if (this.store.isActive(apiName)) this.deactivateOne(apiName)
this.event.emit('ensureDeactivated', apiName)
getAll () {
return Object.keys(this.registered).map((p) => {
return this.registered[p]
})
}
proxy () {
// that's temporary. should be removed when we can have proper notification registration
return this.data.proxy
getOne (name) {
return this.registered[name]
}
setActive (name, isActive) {
const api = this.getEntity(name)
// temp
if (api && (name === 'solidity' || name === 'vyper')) {
isActive ? this.data.proxy.register(name, api) : this.data.proxy.unregister(name, api)
}
isActive ? this.store.activate(name) : this.store.deactivate(name)
if (!isActive) {
this.removeHiddenServices(api)
}
localStorage.setItem('workspace', JSON.stringify(this.store.actives))
getIds () {
return this.registered.map(el => el.name)
}
getEntity (apiName) {
return this.store.getOne(apiName)
onDeactivation (plugin) {
localStorage.setItem('workspace', JSON.stringify(this.actives))
this.event.emit('deactivate', plugin.name)
}
addEntity (api) {
this.store.add(api)
onRegistration (plugin) {
if (!this.registered) this.registered = {}
this.registered[plugin.name] = plugin
this.event.emit('added', plugin.name)
}
removeHiddenServices (profile) {
let hiddenServices = this.hiddenServices[profile.name]
if (hiddenServices) document.body.removeChild(hiddenServices)
// TODO check whether this can be removed
ensureActivated (apiName) {
if (!this.isActive(apiName)) this.activateOne(apiName)
this.event.emit('ensureActivated', apiName)
}
// TODO check whether this can be removed
ensureDeactivated (apiName) {
if (this.isActive(apiName)) this.deactivateOne(apiName)
this.event.emit('ensureDeactivated', apiName)
}
plugins () {
registeredPlugins () {
let vyper = {
name: 'vyper',
displayName: 'Vyper',
@ -143,12 +139,12 @@ export class RemixAppManager extends AppManagerApi {
location: 'sidePanel'
}
return [
new Plugin(pipeline),
new Plugin(vyper),
new Plugin(etherscan),
new Plugin(ethdoc),
new Plugin(mythx),
new Plugin(provable)
new IframePlugin(pipeline),
new IframePlugin(vyper),
new IframePlugin(etherscan),
new IframePlugin(ethdoc),
new IframePlugin(mythx),
new IframePlugin(provable)
]
}
}

@ -7,7 +7,7 @@ var TxRunner = remixLib.execution.txRunner
var txHelper = remixLib.execution.txHelper
var EventManager = remixLib.EventManager
var executionContext = remixLib.execution.executionContext
import { UdappApi } from 'remix-plugin'
import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import * as packageJson from '../package.json'
@ -16,10 +16,11 @@ const profile = {
displayName: 'universal dapp',
description: 'service - run transaction and access account',
permission: true,
version: packageJson.version
version: packageJson.version,
methods: ['createVMAccount', 'newTransaction', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount']
}
module.exports = class UniversalDApp extends UdappApi {
module.exports = class UniversalDApp extends Plugin {
constructor (registry) {
super(profile)

Loading…
Cancel
Save