Resolved merge conflicts in settings-tab.js

pull/5370/head
ioedeveloper 5 years ago
commit 5c5cae349c
  1. 49
      package-lock.json
  2. 2
      package.json
  3. 71
      src/app.js
  4. 3
      src/app/components/hidden-panel.js
  5. 5
      src/app/components/local-plugin.js
  6. 4
      src/app/components/main-panel.js
  7. 4
      src/app/components/panel.js
  8. 68
      src/app/components/plugin-manager-component.js
  9. 20
      src/app/components/side-panel.js
  10. 1
      src/app/components/vertical-icons.js
  11. 3
      src/app/files/fileManager.js
  12. 34
      src/app/panels/main-view.js
  13. 30
      src/app/panels/tab-proxy.js
  14. 17
      src/app/panels/terminal.js
  15. 8
      src/app/tabs/compile-tab.js
  16. 2
      src/app/tabs/runTab/contractDropdown.js
  17. 2
      src/app/tabs/settings-tab.js
  18. 2
      src/app/tabs/styles/settings-tab-styles.js
  19. 2
      src/app/tabs/test-tab.js
  20. 11
      src/app/tabs/theme-module.js
  21. 3
      src/app/udapp/make-udapp.js
  22. 7
      src/app/ui/auto-complete-popup.js
  23. 8
      src/app/ui/landing-page/landing-page.js
  24. 2
      src/app/ui/multiParamManager.js
  25. 53
      src/app/ui/persmission-handler.js
  26. 6
      src/app/ui/txLogger.js
  27. 64
      src/remixAppManager.js
  28. 1
      src/universal-dapp-styles.js
  29. 2
      test-browser/helpers/init.js
  30. 31
      test-browser/tests/pluginManager.js

49
package-lock.json generated

@ -1778,9 +1778,9 @@
"integrity": "sha512-ePDxG9UuU9Kobk90ZUjtmDW8IT9U7aRb1/Rl9683MRNM+ur0ocHL2v7TPH2ajTiVSBUFbbeW8vKIt9jrb0JIAA=="
},
"@remixproject/engine": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@remixproject/engine/-/engine-0.2.0.tgz",
"integrity": "sha512-J8UqkQSANp6hKMP5G4/rMYf6j0RJdBYSm4mfkwkpRAZi2/01nPjuBmgbaQ4tFNcwCOjdAMp24ySAKaCj0ciPDA=="
"version": "0.2.0-alpha.4",
"resolved": "https://registry.npmjs.org/@remixproject/engine/-/engine-0.2.0-alpha.4.tgz",
"integrity": "sha512-AY6HaF7Y4fR1oOdz60B2zt+gGftaT5fZWSl5ka7UuDHZUzeouNMx4O1+Uk4376Mv+M3vdmpGFo6KgfsZj6wSJw=="
},
"@resolver-engine/core": {
"version": "0.3.3",
@ -6737,8 +6737,7 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"optional": true
"bundled": true
},
"aproba": {
"version": "1.2.0",
@ -6756,13 +6755,11 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"optional": true
"bundled": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -6775,18 +6772,15 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"optional": true
"bundled": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"optional": true
"bundled": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"optional": true
"bundled": true
},
"core-util-is": {
"version": "1.0.2",
@ -6889,8 +6883,7 @@
},
"inherits": {
"version": "2.0.4",
"bundled": true,
"optional": true
"bundled": true
},
"ini": {
"version": "1.3.5",
@ -6900,7 +6893,6 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -6913,20 +6905,17 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true,
"optional": true
"bundled": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -6943,7 +6932,6 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -7024,8 +7012,7 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"optional": true
"bundled": true
},
"object-assign": {
"version": "4.1.1",
@ -7035,7 +7022,6 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -7111,8 +7097,7 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"optional": true
"bundled": true
},
"safer-buffer": {
"version": "2.1.2",
@ -7142,7 +7127,6 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -7160,7 +7144,6 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -7199,13 +7182,11 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"optional": true
"bundled": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"optional": true
"bundled": true
}
}
},
@ -17777,7 +17758,7 @@
"requires": {
"underscore": "1.8.3",
"web3-core-helpers": "1.0.0-beta.27",
"websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible"
"websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2"
},
"dependencies": {
"debug": {

@ -78,7 +78,7 @@
"yo-yoify": "^3.7.3"
},
"dependencies": {
"@remixproject/engine": "^0.2.0",
"@remixproject/engine": "^0.2.0-alpha.4",
"http-server": "^0.11.1",
"remixd": "0.1.8-alpha.10",
"standard": "^8.5.0"

@ -35,12 +35,14 @@ const DebuggerTab = require('./app/tabs/debugger-tab')
const TestTab = require('./app/tabs/test-tab')
const FilePanel = require('./app/panels/file-panel')
const Editor = require('./app/editor/editor')
const Terminal = require('./app/panels/terminal')
const ContextualListener = require('./app/editor/contextualListener')
import { basicLogo } from './app/ui/svgLogo'
import { RunTab, makeUdapp } from './app/udapp'
import PanelsResize from './lib/panels-resize'
import { Engine } from '@remixproject/engine'
import { RemixAppManager } from './remixAppManager'
import { FramingService } from './framingService'
import { MainView } from './app/panels/main-view'
@ -170,7 +172,7 @@ class App {
// center panel, resizable
self._view.sidepanel = yo`
<div id="side-panel" data-id="remixIdeSidePanel" style="min-width: 320px;" class=${css.sidepanel}>
<div id="side-panel" data-id="remixIdeSidePanel" style="min-width: 320px;" class="${css.sidepanel} border-right border-left">
${''}
</div>
`
@ -229,12 +231,14 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// APP_MANAGER
const appManager = new RemixAppManager({})
const engine = new Engine(appManager)
await engine.onload()
const workspace = appManager.pluginLoader.get()
// SERVICES
// ----------------- import content servive ----------------------------
// ----------------- import content servive ------------------------
const contentImport = new CompilerImport()
// ----------------- theme servive ----------------------------
// ----------------- theme servive ---------------------------------
const themeModule = new ThemeModule(registry)
registry.put({api: themeModule, name: 'themeModule'})
themeModule.initTheme(() => {
@ -247,6 +251,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const editor = new Editor({}, themeModule) // wrapper around ace editor
registry.put({api: editor, name: 'editor'})
editor.event.register('requiringToSaveCurrentfile', () => fileManager.saveCurrentFile())
// ----------------- fileManager servive ----------------------------
const fileManager = new FileManager(editor)
registry.put({api: fileManager, name: 'filemanager'})
@ -254,20 +259,38 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const blockchain = new Blockchain(registry.get('config').api)
const pluginUdapp = new PluginUDapp(blockchain)
// ----------------- compilation metadata generation servive ----------------------------
// ----------------- compilation metadata generation servive ---------
const compilerMetadataGenerator = new CompilerMetadata(blockchain, fileManager, registry.get('config').api)
// ----------------- compilation result service (can keep track of compilation results) ----------------------------
const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name)
registry.put({api: compilersArtefacts, name: 'compilersartefacts'})
const {eventsDecoder, txlistener} = makeUdapp(blockchain, compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl))
// ----------------- network service (resolve network id / name) ----------------------------
// ----------------- network service (resolve network id / name) -----
const networkModule = new NetworkModule(blockchain)
// ----------------- convert offset to line/column service ----------------------------
var offsetToLineColumnConverter = new OffsetToLineColumnConverter()
// ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
registry.put({api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter'})
appManager.register([
// -------------------Terminal----------------------------------------
const terminal = new Terminal(
{ appManager, blockchain },
{
getPosition: (event) => {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return height - newpos
}
}
)
makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl))
const contextualListener = new ContextualListener({editor})
engine.register([
contentImport,
themeModule,
editor,
@ -275,24 +298,24 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
compilerMetadataGenerator,
compilersArtefacts,
networkModule,
offsetToLineColumnConverter
offsetToLineColumnConverter,
contextualListener,
terminal
])
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel()
const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder, blockchain)
const mainview = new MainView(contextualListener, editor, appPanel, fileManager, appManager, terminal)
registry.put({ api: mainview, name: 'mainview' })
appManager.register([
appPanel
])
engine.register(appPanel)
// those views depend on app_manager
const menuicons = new VerticalIcons(appManager)
const landingPage = new LandingPage(appManager, menuicons)
const sidePanel = new SidePanel(appManager, menuicons)
const hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager)
const pluginManagerComponent = new PluginManagerComponent(appManager, engine)
const filePanel = new FilePanel(appManager)
let settings = new SettingsTab(
registry.get('config').api,
@ -306,7 +329,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
self._view.sidepanel.appendChild(sidePanel.render())
document.body.appendChild(hiddenPanel.render()) // Hidden Panel is display none, it can be directly on body
appManager.register([
engine.register([
menuicons,
landingPage,
sidePanel,
@ -344,7 +367,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
new Renderer()
)
appManager.register([
engine.register([
compileTab,
run,
debug,
@ -354,17 +377,17 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
])
try {
appManager.register(await appManager.registeredPlugins())
engine.register(await appManager.registeredPlugins())
} catch (e) {
console.log('couldn\'t register iframe plugins', e.message)
}
await appManager.activate(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter'])
await appManager.activate(['mainPanel'])
await appManager.activate(['menuicons', 'home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings'])
await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter'])
await appManager.activatePlugin(['mainPanel', 'menuicons'])
await appManager.activatePlugin(['home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings', 'contextualListener', 'terminal'])
// Set workspace after initial activation
if (Array.isArray(workspace)) await appManager.activate(workspace)
if (Array.isArray(workspace)) await appManager.activatePlugin(workspace)
// Load and start the service who manager layout and frame
const framingService = new FramingService(sidePanel, menuicons, mainview, this._components.resizeFeature)
@ -390,6 +413,6 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
}
if (isElectron()) {
appManager.activate(['remixd'])
appManager.activatePlugin('remixd')
}
}

@ -13,7 +13,8 @@ const profile = {
name: 'hiddenPanel',
displayName: 'Hidden Panel',
description: '',
version: packageJson.version
version: packageJson.version,
methods: []
}
export class HiddenPanel extends AbstractPanel {

@ -9,10 +9,9 @@ const defaultProfile = {
}
module.exports = class LocalPlugin {
/**
* Open a modal to create a local plugin
* @param {PluginApi[]} plugins The list of the plugins in the store
* @param {Profile[]} plugins The list of the plugins in the store
* @returns {Promise<{api: any, profile: any}>} A promise with the new plugin profile
*/
open (plugins) {
@ -26,7 +25,7 @@ module.exports = class LocalPlugin {
reject(err)
}
}
modalDialog('Local Plugin', this.form(plugins),
modalDialog('Local Plugin', this.form(),
{ fn: () => onValidation() },
{ fn: () => resolve() }
)

@ -20,8 +20,8 @@ const profile = {
}
export class MainPanel extends AbstractPanel {
constructor (options) {
super(profile, options)
constructor () {
super(profile)
}
render () {

@ -1,7 +1,7 @@
import { EventEmitter } from 'events'
const csjs = require('csjs-inject')
const yo = require('yo-yo')
const { HostPlugin } = require('@remixproject/engine')
import { HostPlugin } from '@remixproject/engine'
const css = csjs`
.plugins {
@ -28,7 +28,7 @@ const css = csjs`
/** Abstract class used for hosting the view of a plugin */
export class AbstractPanel extends HostPlugin {
constructor (profile, opts) {
constructor (profile) {
super(profile)
this.events = new EventEmitter()
this.contents = {}

@ -72,7 +72,7 @@ const profile = {
class PluginManagerComponent extends ViewPlugin {
constructor (appManager) {
constructor (appManager, engine) {
super(profile)
this.event = new EventEmitter()
this.appManager = appManager
@ -85,37 +85,46 @@ class PluginManagerComponent extends ViewPlugin {
this.appManager.event.on('activate', () => { this.reRender() })
this.appManager.event.on('deactivate', () => { this.reRender() })
this.appManager.event.on('added', () => { this.reRender() })
this.engine = engine
}
renderItem (name) {
const api = this.appManager.getOne(name)
if (!api) return
const isActive = this.appManager.isActive(name)
const displayName = (api.profile.displayName) ? api.profile.displayName : name
isActive (name) {
return this.appManager.actives.includes(name)
}
renderItem (profile) {
const displayName = (profile.displayName) ? profile.displayName : profile.name
// Check version of the plugin
let versionWarning
// Alpha
if (api.profile.version && api.profile.version.match(/\b(\w*alpha\w*)\b/g)) {
if (profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) {
versionWarning = yo`<small title="Version Alpha" class="${css.versionWarning} plugin-version">alpha</small>`
}
// Beta
if (api.profile.version && api.profile.version.match(/\b(\w*beta\w*)\b/g)) {
if (profile.version && profile.version.match(/\b(\w*beta\w*)\b/g)) {
versionWarning = yo`<small title="Version Beta" class="${css.versionWarning} plugin-version">beta</small>`
}
const activationButton = isActive
const activationButton = this.isActive(profile.name)
? yo`
<button onclick="${_ => this.appManager.deactivateOne(name)}" class="btn btn-secondary btn-sm" data-id="pluginManagerComponentDeactivateButton${name}">
<button
onclick="${_ => this.appManager.deactivatePlugin(profile.name)}"
class="btn btn-secondary btn-sm" data-id="pluginManagerComponentDeactivateButton${profile.name}"
>
Deactivate
</button>`
</button>
`
: yo`
<button onclick="${_ => this.appManager.activateOne(name)}" class="btn btn-success btn-sm" data-id="pluginManagerComponentActivateButton${name}">
<button
onclick="${_ => this.appManager.activatePlugin(profile.name)}"
class="btn btn-success btn-sm" data-id="pluginManagerComponentActivateButton${profile.name}"
>
Activate
</button>`
return yo`
<article id="remixPluginManagerListItem_${name}" class="list-group-item py-1 plugins-list-group-item" title="${displayName}" >
<article id="remixPluginManagerListItem_${profile.name}" class="list-group-item py-1 plugins-list-group-item" title="${displayName}" >
<div class="${css.row} justify-content-between align-items-center mb-2">
<h6 class="${css.displayName} plugin-name">
${displayName}
@ -123,7 +132,7 @@ class PluginManagerComponent extends ViewPlugin {
</h6>
${activationButton}
</div>
<p class="${css.description} text-body plugin-text">${api.profile.description}</p>
<p class="${css.description} text-body plugin-text">${profile.description}</p>
</article>
`
}
@ -141,10 +150,9 @@ class PluginManagerComponent extends ViewPlugin {
if (this.appManager.getIds().includes(profile.name)) {
throw new Error('This name has already been used')
}
const plugin = profile.type === 'iframe' ? new IframePlugin(profile) : new WebsocketPlugin(profile)
this.appManager.registerOne(plugin)
this.appManager.activateOne(profile.name)
this.engine.register(plugin)
this.appManager.activatePlugin(plugin.name)
} catch (err) {
// TODO : Use an alert to handle this error instead of a console.log
console.log(`Cannot create Plugin : ${err.message}`)
@ -154,25 +162,25 @@ class PluginManagerComponent extends ViewPlugin {
render () {
// Filtering helpers
const isFiltered = (api) => (api.profile.displayName ? api.profile.displayName : api.name).toLowerCase().includes(this.filter)
const isNotRequired = ({profile}) => !this.appManager.isRequired(profile.name)
const isNotHome = ({profile}) => profile.name !== 'home'
const sortByName = (a, b) => {
const nameA = ((a.profile.displayName) ? a.profile.displayName : a.profile.name).toUpperCase()
const nameB = ((b.profile.displayName) ? b.profile.displayName : b.profile.name).toUpperCase()
const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(this.filter)
const isNotRequired = (profile) => !this.appManager.isRequired(profile.name)
const isNotHome = (profile) => profile.name !== 'home'
const sortByName = (profileA, profileB) => {
const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase()
const nameB = ((profileB.displayName) ? profileB.displayName : profileB.name).toUpperCase()
return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0
}
// Filter all active and inactive modules that are not required
const { actives, inactives } = this.appManager.getAll()
const {actives, inactives} = this.appManager.getAll()
.filter(isFiltered)
.filter(isNotRequired)
.filter(isNotHome)
.sort(sortByName)
.reduce(({actives, inactives}, api) => {
return this.appManager.isActive(api.name)
? { actives: [...actives, api.name], inactives }
: { inactives: [...inactives, api.name], actives }
.reduce(({actives, inactives}, profile) => {
return this.isActive(profile.name)
? { actives: [...actives, profile], inactives }
: { inactives: [...inactives, profile], actives }
}, { actives: [], inactives: [] })
const activeTile = actives.length !== 0
@ -203,11 +211,11 @@ class PluginManagerComponent extends ViewPlugin {
<section data-id="pluginManagerComponentPluginManagerSection">
${activeTile}
<div class="list-group list-group-flush plugins-list-group" data-id="pluginManagerComponentActiveTile">
${actives.map(name => this.renderItem(name))}
${actives.map(profile => this.renderItem(profile))}
</div>
${inactiveTile}
<div class="list-group list-group-flush plugins-list-group" data-id="pluginManagerComponentInactiveTile">
${inactives.map(name => this.renderItem(name))}
${inactives.map(profile => this.renderItem(profile))}
</div>
</section>
${settings}

@ -48,10 +48,6 @@ const css = csjs`
}
`
const options = {
default: true
}
const sidePanel = {
name: 'sidePanel',
displayName: 'Side Panel',
@ -64,9 +60,10 @@ const sidePanel = {
export class SidePanel extends AbstractPanel {
constructor (appManager, verticalIcons) {
super(sidePanel, options)
super(sidePanel)
this.appManager = appManager
this.header = this.renderHeader()
this.header = yo`<header></header>`
this.renderHeader()
this.verticalIcons = verticalIcons
// Toggle content
@ -107,18 +104,18 @@ export class SidePanel extends AbstractPanel {
* Display content and update the header
* @param {String} name The name of the plugin to display
*/
showContent (name) {
async showContent (name) {
super.showContent(name)
yo.update(this.header, this.renderHeader())
this.renderHeader()
}
/** The header of the side panel */
renderHeader () {
async renderHeader () {
let name = ' - '
let docLink = ''
let versionWarning
if (this.active) {
const { profile } = this.appManager.getOne(this.active)
const profile = await this.appManager.getProfile(this.active)
name = profile.displayName ? profile.displayName : profile.name
docLink = profile.documentation ? yo`<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)) {
@ -130,13 +127,14 @@ export class SidePanel extends AbstractPanel {
}
}
return yo`
const header = yo`
<header class="${css.swapitHeader} px-3">
<h6 class="${css.swapitTitle}" data-id="sidePanelSwapitTitle">${name}</h6>
${docLink}
${versionWarning}
</header>
`
yo.update(this.header, header)
}
render () {

@ -66,6 +66,7 @@ export class VerticalIcons extends Plugin {
*/
addIcon ({kind, name, icon, displayName, tooltip}) {
let title = (tooltip || displayName || name)
title = title.replace(/^\w/, c => c.toUpperCase())
this.icons[name] = yo`
<div
class="${css.icon}"

@ -9,6 +9,7 @@ const toaster = require('../ui/tooltip')
const modalDialogCustom = require('../ui/modal-dialog-custom')
const helper = require('../../lib/helper.js')
import { Plugin } from '@remixproject/engine'
import { isNative } from '../../remixAppManager.js'
import * as packageJson from '../../../package.json'
/*
@ -172,7 +173,7 @@ class FileManager extends Plugin {
toaster.hide()
}
if (this.currentRequest) {
if (this.currentRequest.isFromNative) {
if (isNative(this.currentRequest.from)) {
this._setFileInternal(path, content)
return
}

@ -1,11 +1,9 @@
var yo = require('yo-yo')
var EventManager = require('../../lib/events')
var Terminal = require('./terminal')
var globalRegistry = require('../../global/registry')
var { TabProxy } = require('./tab-proxy.js')
var ContextualListener = require('../editor/contextualListener')
var ContextView = require('../editor/contextView')
var csjs = require('csjs-inject')
@ -20,7 +18,7 @@ var css = csjs`
`
export class MainView {
constructor (editor, mainPanel, fileManager, appManager, txListener, eventsDecoder, blockchain) {
constructor (contextualListener, editor, mainPanel, fileManager, appManager, terminal) {
var self = this
self.event = new EventManager()
self._view = {}
@ -29,9 +27,9 @@ export class MainView {
self.editor = editor
self.fileManager = fileManager
self.mainPanel = mainPanel
self.txListener = txListener
self.eventsDecoder = eventsDecoder
self.blockchain = blockchain
self.txListener = globalRegistry.get('txlistener').api
self._components.terminal = terminal
self._components.contextualListener = contextualListener
this.appManager = appManager
this.init()
}
@ -88,32 +86,10 @@ export class MainView {
}
}
var contextualListener = new ContextualListener({editor: self.editor})
this.appManager.registerOne(contextualListener)
this.appManager.activate('contextualListener')
var contextView = new ContextView({contextualListener, editor: self.editor})
const contextView = new ContextView({contextualListener: self._components.contextualListener, editor: self.editor})
self._components.contextualListener = contextualListener
self._components.contextView = contextView
self._components.terminal = new Terminal({
appManager: this.appManager,
eventsDecoder: this.eventsDecoder,
txListener: this.txListener,
blockchain: this.blockchain
},
{
getPosition: (event) => {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return height - newpos
}
})
self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta))
if (self.txListener) {
self._components.terminal.event.register('listenOnNetWork', (listenOnNetWork) => {

@ -1,6 +1,7 @@
var yo = require('yo-yo')
var $ = require('jquery')
const EventEmitter = require('events')
const globalRegistry = require('../../global/registry')
require('remix-tabs')
@ -14,6 +15,11 @@ export class TabProxy {
this._view = {}
this._handlers = {}
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
// update invert for all icons
this.updateImgStyles()
})
fileManager.events.on('fileRemoved', (name) => {
this.removeTab(name)
})
@ -49,25 +55,24 @@ export class TabProxy {
})
})
appManager.event.on('activate', (name) => {
const { profile } = appManager.getOne(name)
if (profile.location === 'mainPanel') {
appManager.event.on('activate', ({ name, location, displayName, icon }) => {
if (location === 'mainPanel') {
this.addTab(
name,
profile.displayName,
displayName,
() => this.event.emit('switchApp', name),
() => {
this.event.emit('closeApp', name)
this.appManager.deactivateOne(name)
this.appManager.deactivatePlugin(name)
},
profile.icon
icon
)
this.switchTab(name)
}
})
appManager.event.on('deactivate', (name) => {
this.removeTab(name)
appManager.event.on('deactivate', (profile) => {
this.removeTab(profile.name)
})
appManager.event.on('ensureActivated', (name) => {
@ -78,6 +83,14 @@ export class TabProxy {
}
})
}
updateImgStyles () {
const images = this._view.filetabs.getElementsByClassName('image')
if (images.length !== 0) {
for (let element of images) {
globalRegistry.get('themeModule').api.fixInvert(element)
};
}
}
switchTab (tabName) {
if (this._handlers[tabName]) {
@ -130,6 +143,7 @@ export class TabProxy {
icon,
tooltip: name
})
this.updateImgStyles()
this._handlers[name] = { switchTo, close }
}

@ -45,7 +45,7 @@ class Terminal extends Plugin {
self._api = api
self._opts = opts
self.data = {
lineLength: opts.lineLength || 80,
lineLength: opts.lineLength || 80, // ????
session: [],
activeFilters: { commands: {}, input: '' },
filterFns: {}
@ -95,12 +95,7 @@ class Terminal extends Plugin {
self._jsSandboxContext = {}
self._jsSandboxRegistered = {}
// TODO move this to the application start. Put it in mainView.
// We should have a HostPlugin which add the terminal.
opts.appManager.register(this)
opts.appManager.activate('terminal')
if (opts.shell) self._shell = opts.shell
if (opts.shell) self._shell = opts.shell // ???
register(self)
}
logHtml (html) {
@ -139,7 +134,7 @@ class Terminal extends Plugin {
self._view.inputSearch = yo`<input
spellcheck="false"
type="text"
class="${css.filter} form-control"
class="border ${css.filter} form-control"
id="searchInput"
onkeydown=${filter}
placeholder="Search with transaction hash or address">
@ -438,10 +433,10 @@ class Terminal extends Plugin {
self._shell('remix.help()', self.commands, () => {})
self.commands.html(intro)
self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this, self.blockchain)
self._components.txLogger.event.register('debuggingRequested', (hash) => {
self._components.txLogger = new TxLogger(this, self.blockchain)
self._components.txLogger.event.register('debuggingRequested', async (hash) => {
// TODO should probably be in the run module
if (!self._opts.appManager.isActive('debugger')) self._opts.appManager.activateOne('debugger')
if (!await self._opts.appManager.isActive('debugger')) await self._opts.appManager.activatePlugin('debugger')
this.call('debugger', 'debug', hash)
this.call('menuicons', 'select', 'debugger')
})

@ -168,12 +168,8 @@ class CompileTab extends ViewPlugin {
}
})
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
const invert = theme.quality === 'dark' ? 1 : 0
const img = document.getElementById('swarmLogo')
if (img) {
img.style.filter = `invert(${invert})`
}
globalRegistry.get('themeModule').api.events.on('themeChanged', () => {
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('swarmLogo'))
})
// Run the compiler instead of trying to save the website

@ -44,7 +44,7 @@ class ContractDropdownUI {
}
render () {
this.compFails = yo`<i title="No contract compiled yet or compilation failed. Please check the compile tab for more information." class="fas fa-times-circle ${css.errorIcon}" ></i>`
this.compFails = yo`<i title="No contract compiled yet or compilation failed. Please check the compile tab for more information." class="m-1 fas fa-times-circle ${css.errorIcon}" ></i>`
var info = yo`<i class="fas fa-info ${css.infoDeployAction}" aria-hidden="true" title="*.sol files allows deploying and accessing contracts. *.abi files only allows accessing contracts."></i>`
this.atAddress = yo`<button class="${css.atAddress} btn btn-sm btn-info" disabled id="runAndDeployAtAdressButton" onclick=${this.loadFromAddress.bind(this)}>At Address</button>`

@ -68,7 +68,7 @@ module.exports = class SettingsTab extends ViewPlugin {
if (self._view.el) return self._view.el
// Gist settings
var gistAccessToken = yo`<input id="gistaccesstoken" data-id="settingsTabGistAccessToken" type="password" class="form-control mb-2 ${css.inline}" placeholder="Token">`
var gistAccessToken = yo`<input id="gistaccesstoken" data-id="settingsTabGistAccessToken" type="password" class="border form-control mb-2 ${css.inline}" placeholder="Token">`
var token = this.config.get('settings/gist-access-token')
if (token) gistAccessToken.value = token
var gistAddToken = yo`<input class="${css.savegisttoken} btn btn-sm btn-primary" id="savegisttoken" data-id="settingsTabSaveGistToken" onclick=${() => { this.config.set('settings/gist-access-token', gistAccessToken.value); tooltip('Access token saved') }} value="Save" type="button">`

@ -85,7 +85,7 @@ const css = csjs`
}
.inline {
display: inline;
width: 50%;
width: 40%;
}
`

@ -227,7 +227,7 @@ module.exports = class TestTab extends ViewPlugin {
updateRunAction (currentFile) {
let el = yo`<button id="runTestsTabRunAction" class="${css.runButton} btn btn-primary" onclick="${this.runTests.bind(this)}">Run Tests</button>`
const isSolidityActive = this.appManager.isActive('solidity')
const isSolidityActive = this.appManager.actives.includes('solidity')
if (!currentFile || !isSolidityActive) {
el.setAttribute('disabled', 'disabled')
if (!currentFile) el.setAttribute('title', 'No file selected')

@ -84,4 +84,15 @@ export class ThemeModule extends Plugin {
this.emit('themeChanged', nextTheme)
this.events.emit('themeChanged', nextTheme)
}
/**
* fixes the invertion for images since this should be adjusted when we switch between dark/light qualified themes
* @param {element} [image] - the dom element which invert should be fixed to increase visibility
*/
fixInvert (image) {
const invert = this.currentTheme().quality === 'dark' ? 1 : 0
if (image) {
image.style.filter = `invert(${invert})`
}
}
}

@ -52,6 +52,5 @@ export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
}
})
txlistener.startListening()
return {txlistener, eventsDecoder}
registry.put({api: eventsDecoder, name: 'eventsDecoder'})
}

@ -189,13 +189,12 @@ class AutoCompletePopup {
extendAutocompletion () {
// TODO: this is not using the appManager interface. Terminal should be put as module
this.opts.appManager.event.on('activate', (id) => {
const profile = this.opts.appManager.getOne(id).profile
this.opts.appManager.event.on('activate', async (profile) => {
if (!profile.methods) return
profile.methods.forEach((method) => {
const key = `remix.call({name: '${id}', key:'${method}', payload: []}).then((result) => { console.log(result) }).catch((error) => { console.log(error) })`
const key = `remix.call({name: '${profile.name}', key:'${method}', payload: []}).then((result) => { console.log(result) }).catch((error) => { console.log(error) })`
const keyValue = {}
keyValue[key] = `call ${id} - ${method}`
keyValue[key] = `call ${profile.name} - ${method}`
if (this.extraCommands.includes(keyValue)) return
this.extraCommands.push(keyValue)
})

@ -163,12 +163,8 @@ export class LandingPage extends ViewPlugin {
this.verticalIcons.select('fileExplorers')
}
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
const invert = theme.quality === 'dark' ? 1 : 0
const img = document.getElementById('remixLogo')
if (img) {
img.style.filter = `invert(${invert})`
}
globalRegistry.get('themeModule').api.events.on('themeChanged', () => {
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('remixLogo'))
})
let switchToPreviousVersion = () => {

@ -125,7 +125,7 @@ class MultiParamManager {
}
let funcButton = yo`<button onclick=${() => onClick()} class="${css.instanceButton} btn btn-sm">${title}</button>`
this.contractActionsContainerSingle = yo`
<div class="${css.contractActionsContainerSingle}" >
<div class="${css.contractActionsContainerSingle} pt-2">
${funcButton}
${this.basicInputField}
<i class="fas fa-angle-down ${css.methCaret}" onclick=${() => this.switchMethodViewOn()} title=${title} ></i>

@ -3,6 +3,7 @@ const yo = require('yo-yo')
const csjs = require('csjs-inject')
const addTooltip = require('./tooltip')
const modalDialog = require('./modaldialog')
const globalRegistry = require('../../global/registry')
const css = csjs`
.permission h4 {
@ -140,37 +141,45 @@ export class PermissionHandler {
: delete this.permissions[to.name][from.name]
}
const rememberSwitch = remember
? yo`<input type="checkbox" onchange="${switchMode}" checkbox class="custom-control-input" id="remember" data-id="permissionHandlerRememberChecked">`
: yo`<input type="checkbox" onchange="${switchMode}" class="custom-control-input" id="remember" data-id="permissionHandlerRememberUnchecked">`
? yo`<input type="checkbox" onchange="${switchMode}" checkbox class="form-check-input" id="remember" data-id="permissionHandlerRememberChecked">`
: yo`<input type="checkbox" onchange="${switchMode}" class="form-check-input" id="remember" data-id="permissionHandlerRememberUnchecked">`
const message = remember
? `"${fromName}" has changed and would like to access "${toName}"`
: `"${fromName}" would like to access "${toName}"`
return yo`
<section class="${css.permission}">
const imgFrom = yo`<img id="permissionModalImagesFrom" src="${from.icon}" />`
const imgTo = yo`<img id="permissionModalImagesTo" src="${to.icon}" />`
const pluginsImages = yo`
<article class="${css.images}">
<img src="${from.icon}" />
${imgFrom}
<i class="fas fa-arrow-right"></i>
<img src="${to.icon}" />
</article>
<article>
<h4 data-id="permissionHandlerMessage">${message} :</h4>
<h6>${fromName}</h6>
<p>${from.description || yo`<i>No description Provided</i>`}</p>
<h6>${toName} :</p>
<p>${to.description || yo`<i>No description Provided</i>`}</p>
${imgTo}
</article>
<article class="${css.remember}">
<div class="custom-control custom-checkbox">
${rememberSwitch}
<label class="custom-control-label" for="remember" data-id="permissionHandlerRememberChoice">Remember this choice</label>
</div>
<button class="btn btn-sm" onclick="${_ => this.clear()}">Reset all Permissions</button>
</article>
`
globalRegistry.get('themeModule').api.fixInvert(imgFrom)
globalRegistry.get('themeModule').api.fixInvert(imgTo)
return yo`
<section class="${css.permission}">
${pluginsImages}
<article>
<h4 data-id="permissionHandlerMessage">${message} :</h4>
<h6>${fromName}</h6>
<p>${from.description || yo`<i>No description Provided</i>`}</p>
<h6>${toName} :</p>
<p>${to.description || yo`<i>No description Provided</i>`}</p>
</article>
</section>
<article class="${css.remember}">
<div class="form-check">
${rememberSwitch}
<label class="form-check-label" for="remember" data-id="permissionHandlerRememberChoice">Remember this choice</label>
</div>
<button class="btn btn-sm" onclick="${_ => this.clear()}">Reset all Permissions</button>
</article>
</section>
`
}
}

@ -116,7 +116,7 @@ var css = csjs`
*
*/
class TxLogger {
constructor (eventsDecoder, txListener, terminal, blockchain) {
constructor (terminal, blockchain) {
this.event = new EventManager()
this.seen = {}
function filterTx (value, query) {
@ -125,8 +125,8 @@ class TxLogger {
}
return false
}
this.eventsDecoder = eventsDecoder
this.txListener = txListener
this.eventsDecoder = globlalRegistry.get('eventsDecoder').api
this.txListener = globlalRegistry.get('txlistener').api
this.terminal = terminal
// dependencies
this._deps = {

@ -1,75 +1,77 @@
/* global localStorage, fetch */
import { PluginEngine, IframePlugin } from '@remixproject/engine'
import { PluginManager, IframePlugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import { PermissionHandler } from './app/ui/persmission-handler'
import QueryParams from './lib/query-params'
const requiredModules = [ // services + layout views + system views
'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport',
'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport',
'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileExplorers',
'terminal', 'settings', 'pluginManager']
const settings = {
permissionHandler: new PermissionHandler(),
autoActivate: false,
natives: ['vyper', 'workshops', 'ethdoc', 'etherscan'] // Force iframe plugin to be seen as native
export function isNative (name) {
const nativePlugins = ['vyper', 'workshops', 'ethdoc', 'etherscan']
return nativePlugins.includes(name) || requiredModules.includes(name)
}
export class RemixAppManager extends PluginEngine {
export class RemixAppManager extends PluginManager {
constructor (plugins) {
super(plugins, settings)
super()
this.event = new EventEmitter()
this.registered = {}
this.pluginsDirectory = 'https://raw.githubusercontent.com/ethereum/remix-plugins-directory/master/build/metadata.json'
this.pluginLoader = new PluginLoader()
}
onActivated (plugin) {
async canActivate (from, to) {
return from.name === 'manager'
}
async canDeactivate (from, to) {
return from.name === 'manager'
}
async canCall (From, to, method) {
// todo This is the dafault behaviour, we could save user choises in session scope
return true
}
onPluginActivated (plugin) {
this.pluginLoader.set(plugin, this.actives)
this.event.emit('activate', plugin.name)
this.event.emit('activate', plugin)
}
getAll () {
return Object.keys(this.registered).map((p) => {
return this.registered[p]
return Object.keys(this.profiles).map((p) => {
return this.profiles[p]
})
}
getOne (name) {
return this.registered[name]
}
getIds () {
return Object.keys(this.registered)
return Object.keys(this.profiles)
}
onDeactivated (plugin) {
onPluginDeactivated (plugin) {
this.pluginLoader.set(plugin, this.actives)
this.event.emit('deactivate', plugin.name)
this.event.emit('deactivate', plugin)
}
onRegistration (plugin) {
if (!this.registered) this.registered = {}
this.registered[plugin.name] = plugin
this.event.emit('added', plugin.name)
}
// TODO check whether this can be removed
ensureActivated (apiName) {
if (!this.isActive(apiName)) this.activateOne(apiName)
async ensureActivated (apiName) {
await this.activatePlugin(apiName)
this.event.emit('ensureActivated', apiName)
}
// TODO check whether this can be removed
ensureDeactivated (apiName) {
if (this.isActive(apiName)) this.deactivateOne(apiName)
async ensureDeactivated (apiName) {
await this.deactivatePlugin(apiName)
this.event.emit('ensureDeactivated', apiName)
}
deactivateOne (name) {
deactivatePlugin (name) {
if (requiredModules.includes(name)) return
super.deactivateOne(name)
super.deactivatePlugin(name)
}
isRequired (name) {

@ -163,7 +163,6 @@ var css = csjs`
.contractActionsContainerSingle {
display: flex;
width: 100%;
margin-bottom: 8px;
}
.contractActionsContainerSingle i {
line-height: 2;

@ -18,7 +18,7 @@ module.exports = function (browser, callback, url, preloadPlugins = true) {
}
function initModules (browser, callback) {
browser.pause(3000)
browser.pause(5000)
.click('#icon-panel div[plugin="pluginManager"]')
.scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_solidity"] button')
.pause(5000)

@ -22,20 +22,20 @@ module.exports = {
'Should Search for plugins': function (browser) {
browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys('debugger')
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtondebugger"]')
.clearValue('*[data-id="pluginManagerComponentSearchInput"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys('Deploy & run transactions')
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonudapp"]')
.clearValue('*[data-id="pluginManagerComponentSearchInput"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys('ZoKrates')
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonZoKrates"]')
.clearValue('*[data-id="pluginManagerComponentSearchInput"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys(browser.Keys.ENTER)
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys('debugger')
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtondebugger"]')
.clearValue('*[data-id="pluginManagerComponentSearchInput"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys('Deploy & run transactions')
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonudapp"]')
.clearValue('*[data-id="pluginManagerComponentSearchInput"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys('ZoKrates')
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonZoKrates"]')
.clearValue('*[data-id="pluginManagerComponentSearchInput"]')
.click('*[data-id="pluginManagerComponentSearchInput"]')
.keys(browser.Keys.ENTER)
},
'Should activate plugins': function (browser) {
@ -58,6 +58,7 @@ module.exports = {
.waitForElementVisible('*[data-id="pluginManagerComponentActivateButtonudapp"]')
},
/*
'Should grant plugin permission (ZOKRATES)': function (browser) {
browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]')
.click('*[data-id="pluginManagerSettingsButton"]')
@ -93,6 +94,7 @@ module.exports = {
.assert.containsText('*[data-id="pluginManagerSettingsPermissionForm"]', 'No Permission requested yet')
.modalFooterOKClick()
},
*/
'Should connect a local plugin': function (browser) {
browser.waitForElementVisible('*[data-id="pluginManagerComponentPluginManager"]')
@ -125,6 +127,5 @@ module.exports = {
.assert.containsText('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 'Cannot create Plugin : This name has already been used')
.end()
},
tearDown: sauce
}

Loading…
Cancel
Save