Merge branch 'i2docs' into link2docs

pull/3094/head
Rob Stupay 6 years ago
commit 411230f9f1
  1. 4
      assets/css/font-awesome.min.css
  2. BIN
      assets/fonts/FontAwesome.otf
  3. BIN
      assets/fonts/fontawesome-webfont.eot
  4. 2671
      assets/fonts/fontawesome-webfont.svg
  5. BIN
      assets/fonts/fontawesome-webfont.ttf
  6. BIN
      assets/fonts/fontawesome-webfont.woff
  7. BIN
      assets/fonts/fontawesome-webfont.woff2
  8. BIN
      assets/img/gasStation_50.png
  9. 271121
      assets/js/0.7.7/app.js
  10. 4
      ci/browser_tests.sh
  11. 51
      index.html
  12. 6
      nightwatch.js
  13. 9
      package.json
  14. 1
      src/app/components/panel.js
  15. 36
      src/app/components/plugin-manager-settings.js
  16. 4
      src/app/components/swap-panel.js
  17. 12
      src/app/debugger/debuggerUI.js
  18. 63
      src/app/debugger/debuggerUI/TxBrowser.js
  19. 2
      src/app/debugger/debuggerUI/VmDebugger.js
  20. 2
      src/app/debugger/debuggerUI/vmDebugger/DropdownPanel.js
  21. 13
      src/app/editor/contextualListener.js
  22. 7
      src/app/files/fileManager.js
  23. 7
      src/app/panels/tab-proxy.js
  24. 45
      src/app/tabs/runTab/settings.js
  25. 20
      src/app/tabs/settings-tab.js
  26. 3
      src/app/tabs/styles/run-tab-styles.js
  27. 22
      src/app/ui/landing-page/landing-page.js
  28. 3
      src/app/ui/styles/tooltip-styles.js
  29. 2
      src/app/ui/tooltip.js
  30. 3
      src/config.js
  31. 7
      src/persmission-handler.js
  32. 8
      src/remixAppManager.js
  33. 2
      test-browser/helpers/init.js

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

File diff suppressed because one or more lines are too long

@ -21,8 +21,8 @@ else
fi fi
SC_VERSION="4.5.1" SC_VERSION="4.5.1"
SAUCECONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-$OS.$FILEFORMAT" SAUCECONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-$OS.$FILEFORMAT"
SAUCECONNECT_USERNAME="chriseth" SAUCECONNECT_USERNAME="yanneth"
SAUCECONNECT_ACCESSKEY="b781828a-9e9c-43d8-89d4-2fbb879595ca" SAUCECONNECT_ACCESSKEY="1f5a4560-b02b-41aa-b52b-f033aad30870"
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}} BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID" echo "$BUILD_ID"
SAUCECONNECT_JOBIDENTIFIER="browsersolidity_tests_${BUILD_ID}" SAUCECONNECT_JOBIDENTIFIER="browsersolidity_tests_${BUILD_ID}"

@ -27,14 +27,59 @@
THE SOFTWARE. THE SOFTWARE.
--> -->
<meta http-equiv="X-UA-Compatible" content="chrome=1"> <meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Remix - Solidity IDE</title> <title>Remix - Ethereum IDE</title>
<link rel="stylesheet" id="theme-link"/> <link rel="stylesheet" id="theme-link"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<link rel="stylesheet" href="assets/css/pygment_trac.css"> <link rel="stylesheet" href="assets/css/pygment_trac.css">
<link rel="icon" type="x-icon" href="icon.png"> <link rel="icon" type="x-icon" href="icon.png">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head> </head>
<body> <body>
<script src="build/app.js"></script> <script>
function urlParams () {
var qs = window.location.hash.substr(1)
if (window.location.search.length > 0) {
// use legacy query params instead of hash
window.location.hash = window.location.search.substr(1)
window.location.search = ''
}
var params = {}
var parts = qs.split('&')
for (var x in parts) {
var keyValue = parts[x].split('=')
if (keyValue[0] !== '') {
params[keyValue[0]] = keyValue[1]
}
}
return params
}
const defaultVersion = window.location.hostname === 'remix.ethereum.org' ? '0.7.7' : '0.8.0'
let versionToLoad = urlParams().appVersion ? urlParams().appVersion : defaultVersion
let assets = {
'0.8.0': ['https://use.fontawesome.com/releases/v5.8.1/css/all.css', 'assets/css/pygment_trac.css'],
'0.7.7': ['assets/css/font-awesome.min.css', 'assets/css/pygment_trac.css']
}
let versions = {
'0.7.7': 'assets/js/0.7.7/app.js', // commit 7b5c7ae3de935e0ccc32eadfd83bf7349478491e
'0.8.0': 'build/app.js'
}
for (let k in assets[versionToLoad]) {
let app = document.createElement('link')
app.setAttribute('rel', 'stylesheet')
app.setAttribute('href', assets[versionToLoad][k])
if (assets[versionToLoad][k] === 'https://use.fontawesome.com/releases/v5.8.1/css/all.css') {
app.setAttribute('integrity', 'sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf')
app.setAttribute('crossorigin', 'anonymous')
}
document.head.appendChild(app)
}
window.onload = () => {
let app = document.createElement('script')
app.setAttribute('src', versions[versionToLoad])
document.body.appendChild(app)
}
</script>
</body> </body>
</html> </html>

@ -16,8 +16,8 @@ module.exports = {
'selenium_host': 'ondemand.saucelabs.com', 'selenium_host': 'ondemand.saucelabs.com',
'selenium_port': 80, 'selenium_port': 80,
'silent': true, 'silent': true,
'username': 'chriseth', 'username': 'yanneth',
'access_key': 'b781828a-9e9c-43d8-89d4-2fbb879595ca', 'access_key': '1f5a4560-b02b-41aa-b52b-f033aad30870',
'use_ssl': false, 'use_ssl': false,
'globals': { 'globals': {
'waitForConditionTimeout': 10000, 'waitForConditionTimeout': 10000,
@ -78,7 +78,7 @@ module.exports = {
'selenium_port': 4444, 'selenium_port': 4444,
'selenium_host': 'localhost', 'selenium_host': 'localhost',
'desiredCapabilities': { 'desiredCapabilities': {
'browserName': 'firefox', 'browserName': 'chrome',
'javascriptEnabled': true, 'javascriptEnabled': true,
'acceptSslCerts': true 'acceptSslCerts': true
} }

@ -45,11 +45,11 @@
"npm-run-all": "^4.0.2", "npm-run-all": "^4.0.2",
"onchange": "^3.2.1", "onchange": "^3.2.1",
"remix-analyzer": "0.3.6", "remix-analyzer": "0.3.6",
"remix-debug": "0.3.6", "remix-debug": "0.3.7",
"remix-lib": "0.4.6", "remix-lib": "0.4.6",
"remix-solidity": "0.3.6", "remix-solidity": "0.3.6",
"remix-tabs": "^1.0.0", "remix-tabs": "^1.0.0",
"remix-tests": "0.1.7", "remix-tests": "0.1.8",
"remixd": "0.1.8-alpha.6", "remixd": "0.1.8-alpha.6",
"request": "^2.83.0", "request": "^2.83.0",
"rimraf": "^2.6.1", "rimraf": "^2.6.1",
@ -67,8 +67,8 @@
"yo-yoify": "^3.7.3" "yo-yoify": "^3.7.3"
}, },
"dependencies": { "dependencies": {
"remix-plugin": "0.0.2-alpha.6",
"http-server": "^0.11.1", "http-server": "^0.11.1",
"remix-plugin": "0.0.2-alpha.8",
"remixd": "0.1.8-alpha.6" "remixd": "0.1.8-alpha.6"
}, },
"repository": { "repository": {
@ -90,7 +90,8 @@
"ignore": [ "ignore": [
"build/", "build/",
"src/app/editor/mode-solidity.js", "src/app/editor/mode-solidity.js",
"soljson.js" "soljson.js",
"assets/js/0.7.7/app.js"
], ],
"parser": "babel-eslint" "parser": "babel-eslint"
}, },

@ -93,6 +93,7 @@ export class AbstractPanel {
const el = this.contents[name] const el = this.contents[name]
delete this.contents[name] delete this.contents[name]
if (el) el.parentElement.removeChild(el) if (el) el.parentElement.removeChild(el)
if (name === this.active) this.active = undefined
} }
/** /**

@ -25,6 +25,14 @@ const css = csjs`
.permissionForm hr { .permissionForm hr {
width: 80%; width: 80%;
} }
.permissionKey {
display: flex;
justify-content: space-between;
align-items: center;
}
.permissionKey i {
cursor: pointer;
}
.checkbox { .checkbox {
display: flex; display: flex;
align-items: center; align-items: center;
@ -39,7 +47,8 @@ export class PluginManagerSettings {
openDialog () { openDialog () {
const fromLocal = window.localStorage.getItem('plugins/permissions') const fromLocal = window.localStorage.getItem('plugins/permissions')
this.permissions = JSON.parse(fromLocal || '{}') this.permissions = JSON.parse(fromLocal || '{}')
modalDialog('Plugin Manager Settings', this.settings(), this.currentSetting = this.settings()
modalDialog('Plugin Manager Settings', this.currentSetting,
{ fn: () => this.onValidation() }, { fn: () => this.onValidation() },
) )
} }
@ -49,6 +58,23 @@ export class PluginManagerSettings {
window.localStorage.setItem('plugins/permissions', permissions) window.localStorage.setItem('plugins/permissions', permissions)
} }
/** Clear one permission from a plugin */
clearPersmission (from, to) {
if (!this.permissions[from]) return
delete this.permissions[from][to]
if (Object.keys(this.permissions[from]).length === 0) {
delete this.permissions[from]
}
yo.update(this.currentSetting, this.settings())
}
/** Clear all persmissions from a plugin */
clearAllPersmission (from) {
if (!this.permissions[from]) return
delete this.permissions[from]
yo.update(this.currentSetting, this.settings())
}
settings () { settings () {
const permissionByModule = (key, permission) => { const permissionByModule = (key, permission) => {
const permissionByPlugin = (name, plugin) => { const permissionByPlugin = (name, plugin) => {
@ -60,9 +86,12 @@ export class PluginManagerSettings {
: yo`<input onchange="${updatePermission}" type="checkbox" id="permission-${name}" aria-describedby="module ${key} ask permission for ${name}" />` : yo`<input onchange="${updatePermission}" type="checkbox" id="permission-${name}" aria-describedby="module ${key} ask permission for ${name}" />`
return yo` return yo`
<div class="form-group ${css.checkbox}"> <div class="form-group ${css.permissionKey}">
<div class="${css.checkbox}">
${checkbox} ${checkbox}
<label for="permission-${name}">Allow plugin ${name} to write on ${key}</label> <label for="permission-${name}">Allow plugin ${name} to write on ${key}</label>
</div>
<i onclick="${() => this.clearPersmission(key, name)}" class="fa fa-trash-alt"></i>
</div>` </div>`
} }
@ -72,7 +101,10 @@ export class PluginManagerSettings {
return yo` return yo`
<div> <div>
<div class="${css.permissionKey}">
<h6>${key} :</h6> <h6>${key} :</h6>
<i onclick="${() => this.clearAllPersmission(key)}" class="far fa-trash-alt"></i>
</div>
${byModule} ${byModule}
</div>` </div>`
} }

@ -66,8 +66,8 @@ export class SwapPanel extends AbstractPanel {
if (this.active) { if (this.active) {
const { profile } = this.store.getOne(this.active) const { profile } = this.store.getOne(this.active)
name = profile.displayName ? profile.displayName : profile.name name = profile.displayName ? profile.displayName : profile.name
const docsRoot = 'https://remix.readthedocs.io/en/docsnewlayout/' const docsRoot = 'https://remix.readthedocs.io/en/latest/'
docLink = profile.documentation ? yo`<a href="${docsRoot}${profile.documentation}" title="link to documentation" target="_blank"><sup><i aria-hidden="true" class="fas fa-asterisk"></i></sup></a>` : '' docLink = profile.documentation ? yo`<a href="${docsRoot}${profile.documentation}" title="link to documentation" target="_blank"><sup><i aria-hidden="true" class="fas fa-book"></i></sup></a>` : ''
} }
return yo` return yo`

@ -1,6 +1,7 @@
var TxBrowser = require('./debuggerUI/TxBrowser') var TxBrowser = require('./debuggerUI/TxBrowser')
var StepManagerUI = require('./debuggerUI/StepManager') var StepManagerUI = require('./debuggerUI/StepManager')
var VmDebugger = require('./debuggerUI/VmDebugger') var VmDebugger = require('./debuggerUI/VmDebugger')
var toaster = require('../ui/tooltip')
var Debugger = require('remix-debug').TransactionDebugger var Debugger = require('remix-debug').TransactionDebugger
@ -104,14 +105,12 @@ class DebuggerUI {
startDebugging (blockNumber, txNumber, tx) { startDebugging (blockNumber, txNumber, tx) {
const self = this const self = this
if (this.debugger) delete this.debugger if (this.debugger) this.unLoad()
let compilers = this.registry.get('compilersartefacts').api let compilers = this.registry.get('compilersartefacts').api
let lastCompilationResult let lastCompilationResult
if (compilers['__last']) lastCompilationResult = compilers['__last'] if (compilers['__last']) lastCompilationResult = compilers['__last']
// TODO debugging with source highlight is disabled. see line 98
executionContext.detectNetwork((error, network) => { executionContext.detectNetwork((error, network) => {
let web3 let web3
if (error || !network) { if (error || !network) {
@ -128,11 +127,14 @@ class DebuggerUI {
}) })
this.listenToEvents() this.listenToEvents()
this.debugger.debug(blockNumber, txNumber, tx, () => { this.debugger.debug(blockNumber, txNumber, tx, () => {
self.stepManager = new StepManagerUI(this.debugger.step_manager) self.stepManager = new StepManagerUI(this.debugger.step_manager)
self.vmDebugger = new VmDebugger(this.debugger.vmDebuggerLogic) self.vmDebugger = new VmDebugger(this.debugger.vmDebuggerLogic)
self.txBrowser.setState({ blockNumber, txNumber, debugging: true })
self.renderDebugger() self.renderDebugger()
}).catch((error) => {
toaster(error)
this.unLoad()
}) })
}) })
} }
@ -167,8 +169,10 @@ class DebuggerUI {
yo.update(this.stepManagerView, yo`<div></div>`) yo.update(this.stepManagerView, yo`<div></div>`)
if (this.vmDebugger) this.vmDebugger.remove() if (this.vmDebugger) this.vmDebugger.remove()
if (this.stepManager) this.stepManager.remove() if (this.stepManager) this.stepManager.remove()
if (this.txBrowser) this.txBrowser.setState({debugging: false})
this.vmDebugger = null this.vmDebugger = null
this.stepManager = null this.stepManager = null
if (this.debugger) delete this.debugger
this.event.trigger('traceUnloaded') this.event.trigger('traceUnloaded')
} }

@ -40,52 +40,39 @@ var css = csjs`
function TxBrowser () { function TxBrowser () {
this.event = new EventManager() this.event = new EventManager()
this.blockNumber this.state = {
this.txNumber txNumber: undefined,
this.view debugging: false
this.setDefaultValues()
}
TxBrowser.prototype.setDefaultValues = function () {
this.connectInfo = ''
if (this.view) {
yo.update(this.view, this.render())
} }
this.view
} }
TxBrowser.prototype.submit = function (tx) { TxBrowser.prototype.submit = function () {
this.event.trigger('requestDebug', [this.blockNumber, this.txNumber, tx]) if (this.state.debugging) {
} this.unload()
} else {
TxBrowser.prototype.update = function (error, tx) { this.event.trigger('requestDebug', [undefined, this.state.txNumber])
if (error) {
this.view.querySelector('#error').innerHTML = error
return
} }
yo.update(this.view, this.render())
if (!tx) {
this.view.querySelector('#error').innerHTML = 'Cannot find transaction with reference. Block number: ' + this.blockNumber + '. Transaction index/hash: ' + this.txNumber
return
}
this.view.querySelector('#error').innerHTML = ''
}
TxBrowser.prototype.updateBlockN = function (ev) {
this.blockNumber = ev.target.value
} }
TxBrowser.prototype.updateTxN = function (ev) { TxBrowser.prototype.updateTxN = function (ev) {
this.txNumber = ev.target.value this.state.txNumber = ev.target.value
} }
TxBrowser.prototype.load = function (txHash, tx) { TxBrowser.prototype.load = function (txHash, tx) {
this.txNumber = txHash this.state.txNumber = txHash
} }
TxBrowser.prototype.unload = function (txHash) { TxBrowser.prototype.unload = function () {
this.event.trigger('unloadRequested') this.event.trigger('unloadRequested')
this.setDefaultValues() }
TxBrowser.prototype.setState = function (state) {
this.state = {...this.state, ...state}
if (this.view) {
yo.update(this.view, this.render())
}
} }
TxBrowser.prototype.render = function () { TxBrowser.prototype.render = function () {
@ -93,17 +80,17 @@ TxBrowser.prototype.render = function () {
var view = yo`<div class="${css.container}"> var view = yo`<div class="${css.container}">
<div class="${css.txContainer}"> <div class="${css.txContainer}">
<div class="${css.txinputs} p-1 input-group"> <div class="${css.txinputs} p-1 input-group">
<input class="form-control" class="${css.txinput}" onkeyup=${function () { self.updateBlockN(arguments[0]) }} type='text' placeholder=${'Block number'} /> <input value="${this.state.txNumber || ''}" class="form-control ${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction hash'} />
<input class="form-control" class="${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction index or hash'} />
</div> </div>
<div class="${css.txbuttons} btn-group p-1"> <div class="${css.txbuttons} btn-group p-1">
<button class='btn btn-primary btn-sm' id='load' class='${css.txbutton}' title='start debugging' onclick=${function () { self.submit() }}>Start debugging</button> <button class='btn btn-primary btn-sm ${css.txbutton}' id='load' title='${this.state.debugging ? 'Stop' : 'Start'} debugging' onclick=${function () { self.submit() }}>${this.state.debugging ? 'Stop' : 'Start'} debugging</button>
<button class='btn btn-primary btn-sm' id='unload' class='${css.txbutton}' title='stop debugging' onclick=${function () { self.unload() }}>Stop</button>
</div> </div>
</div> </div>
<span id='error'></span> <span id='error'></span>
</div>` </div>`
if (this.state.debugging) {
view.querySelectorAll('input').forEach(element => { element.setAttribute('disabled', '') })
}
if (!this.view) { if (!this.view) {
this.view = view this.view = view
} }

@ -16,8 +16,10 @@ var DropdownPanel = require('./vmDebugger/DropdownPanel')
var css = csjs` var css = csjs`
.asmCode { .asmCode {
width: 100%;
} }
.stepDetail { .stepDetail {
width: 100%;
} }
.vmheadView { .vmheadView {
margin-top:10px; margin-top:10px;

@ -121,7 +121,7 @@ DropdownPanel.prototype.render = function (overridestyle, node) {
<div class='message' style='display:none'></div> <div class='message' style='display:none'></div>
</div>` </div>`
var view = yo` var view = yo`
<div class="border border-primary rounded p-1 m-1"> <div class="border rounded p-1 m-1 bg-light">
<style> <style>
@-moz-keyframes spin { @-moz-keyframes spin {
to { -moz-transform: rotate(359deg); } to { -moz-transform: rotate(359deg); }

@ -1,5 +1,6 @@
'use strict' 'use strict'
const remixLib = require('remix-lib') const remixLib = require('remix-lib')
const csjs = require('csjs-inject')
const SourceMappingDecoder = remixLib.SourceMappingDecoder const SourceMappingDecoder = remixLib.SourceMappingDecoder
const AstWalker = remixLib.AstWalker const AstWalker = remixLib.AstWalker
const EventManager = require('../../lib/events') const EventManager = require('../../lib/events')
@ -115,10 +116,16 @@ class ContextualListener {
let lastCompilationResult = this._deps.compilersArtefacts['__last'] let lastCompilationResult = this._deps.compilersArtefacts['__last']
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0) { if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0) {
let lineColumn = this._deps.offsetToLineColumnConverter.offsetToLineColumn(position, position.file, lastCompilationResult.getSourceCode().sources, lastCompilationResult.getAsts()) let lineColumn = this._deps.offsetToLineColumnConverter.offsetToLineColumn(position, position.file, lastCompilationResult.getSourceCode().sources, lastCompilationResult.getAsts())
let css = 'highlightreference' const css = csjs`
.highlightref_fullLine {
position:absolute;
z-index:2;
opacity: 0.4;
background-color: var(--info);
}
`
if (node.children && node.children.length) { if (node.children && node.children.length) {
// If node has children, highlight the entire line. if not, just highlight the current source position of the node. // If node has children, highlight the entire line. if not, just highlight the current source position of the node.
css = 'highlightreference'
lineColumn = { lineColumn = {
start: { start: {
line: lineColumn.start.line, line: lineColumn.start.line,
@ -132,7 +139,7 @@ class ContextualListener {
} }
const fileName = lastCompilationResult.getSourceName(position.file) const fileName = lastCompilationResult.getSourceName(position.file)
if (fileName) { if (fileName) {
return this.editor.addMarker(lineColumn, fileName, css) return this.editor.addMarker(lineColumn, fileName, css.highlightref_fullLine)
} }
} }
return null return null

@ -22,7 +22,7 @@ const profile = {
// File System profile // File System profile
// - events: ['currentFileChanged'] // - events: ['currentFileChanged']
// - methods: ['getFolder', 'getCurrentFile', 'getFile', 'setFile'] // - methods: ['getFolder', 'getCurrentFile', 'getFile', 'setFile', 'switchFile']
class FileManager extends FileSystemApi { class FileManager extends FileSystemApi {
constructor (localRegistry) { constructor (localRegistry) {
@ -113,10 +113,9 @@ class FileManager extends FileSystemApi {
return path ? path[1] : null return path ? path[1] : null
} }
async getCurrentFile () { getCurrentFile () {
const path = this.currentFile() const path = this.currentFile()
if (!path) throw new Error('no file selected') if (!path) throw new Error('No file selected')
console.log('Get current File', path)
return path return path
} }

@ -59,7 +59,8 @@ export class TabProxy {
() => { () => {
this.event.emit('closeApp', name) this.event.emit('closeApp', name)
this.appManager.deactivateOne(name) this.appManager.deactivateOne(name)
} },
profile.icon
) )
this.switchTab(name) this.switchTab(name)
} }
@ -105,7 +106,7 @@ export class TabProxy {
this._view.filetabs.activateTab(name) this._view.filetabs.activateTab(name)
} }
addTab (name, title, switchTo, close, kind) { addTab (name, title, switchTo, close, icon) {
if (this._handlers[name]) return if (this._handlers[name]) return
var slash = name.split('/') var slash = name.split('/')
@ -115,7 +116,7 @@ export class TabProxy {
this._view.filetabs.addTab({ this._view.filetabs.addTab({
id: name, id: name,
title, title,
icon: '', icon,
tooltip: name tooltip: name
}) })
this._handlers[name] = { switchTo, close } this._handlers[name] = { switchTo, close }

@ -24,9 +24,12 @@ class SettingsUI {
this._components.registry = globalRegistry this._components.registry = globalRegistry
this._deps = { this._deps = {
networkModule: this._components.registry.get('network').api networkModule: this._components.registry.get('network').api,
config: this._components.registry.get('config').api
} }
this._deps.config.events.on('settings/personal-mode_changed', this.onPersonalChange.bind(this))
setInterval(() => { setInterval(() => {
this.updateAccountBalances() this.updateAccountBalances()
}, 10 * 1000) }, 10 * 1000)
@ -87,7 +90,9 @@ class SettingsUI {
<div class="${css.crow}"> <div class="${css.crow}">
<div class="${css.col1_1}"> <div class="${css.col1_1}">
Account Account
<i class="fas fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${this.newAccount.bind(this)} title="Create a new account"></i> <span id="remixRunPlusWraper" title="Create a new account" onload=${this.updatePlusButton.bind(this)}>
<i id="remixRunPlus" class="fas fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${this.newAccount.bind(this)}"></i>
</span>
</div> </div>
<div class=${css.account}> <div class=${css.account}>
<select name="txorigin" class="form-control ${css.select}" id="txorigin"></select> <select name="txorigin" class="form-control ${css.select}" id="txorigin"></select>
@ -194,6 +199,42 @@ class SettingsUI {
this.event.trigger('clearInstance', []) this.event.trigger('clearInstance', [])
this.updateNetwork() this.updateNetwork()
this.fillAccountsList() this.fillAccountsList()
this.updatePlusButton()
}
updatePlusButton () {
// enable/disable + button
let plusBtn = document.getElementById('remixRunPlus')
let plusTitle = document.getElementById('remixRunPlusWraper')
switch (this.selectExEnv.value) {
case 'injected': {
plusBtn.classList.add(css.disableMouseEvents)
plusTitle.title = "Unfortunately it's not possible to create an account using injected web3. Please create the account directly from your provider (i.e metamask or other of the same type)."
}
break
case 'vm': {
plusBtn.classList.remove(css.disableMouseEvents)
plusTitle.title = 'Create a new account'
}
break
case 'web3': {
this.onPersonalChange()
}
break
default:
}
}
onPersonalChange () {
let plusBtn = document.getElementById('remixRunPlus')
let plusTitle = document.getElementById('remixRunPlusWraper')
if (!this._deps.config.get('settings/personal-mode')) {
plusBtn.classList.add(css.disableMouseEvents)
plusTitle.title = 'Creating an account is possible only in Personal mode. Please go to Settings to enable it.'
} else {
plusBtn.classList.remove(css.disableMouseEvents)
plusTitle.title = 'Create a new account'
}
} }
newAccount () { newAccount () {

@ -30,7 +30,10 @@ module.exports = class SettingsTab extends BaseApi {
} }
this._view = { /* eslint-disable */ this._view = { /* eslint-disable */
el: null, el: null,
optionVM: null, personal: null, warnPersonalMode: null, generateContractMetadata: null, optionVM: null,
personal: null,
warnPersonalMode: null,
generateContractMetadata: null,
config: { config: {
general: null, themes: null general: null, themes: null
} }
@ -73,12 +76,6 @@ module.exports = class SettingsTab extends BaseApi {
if (this.config.get('settings/always-use-vm')) this._view.optionVM.setAttribute('checked', '') if (this.config.get('settings/always-use-vm')) this._view.optionVM.setAttribute('checked', '')
this._view.personal = yo`<input onchange=${onchangePersonal} id="personal" type="checkbox" class="align-middle form-check-input">` this._view.personal = yo`<input onchange=${onchangePersonal} id="personal" type="checkbox" class="align-middle form-check-input">`
if (this.config.get('settings/personal-mode')) this._view.personal.setAttribute('checked', '') if (this.config.get('settings/personal-mode')) this._view.personal.setAttribute('checked', '')
var warnText = `Transaction sent over Web3 will use the web3.personal API - be sure the endpoint is opened before enabling it.
This mode allows to provide the passphrase in the Remix interface without having to unlock the account.
Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...).
It is not recommended (and also most likely not relevant) to use this mode with an injected provider (Mist, Metamask, ...) or with JavaScript VM.
Remix never persist any passphrase.`.split('\n').map(s => s.trim()).join(' ')
this._view.warnPersonalMode = yo`<i title=${warnText} class="${css.icon} fas fa-exclamation-triangle text-warning" aria-hidden="true"></i>`
this._view.generateContractMetadata = yo`<input onchange=${onchangeGenerateContractMetadata} id="generatecontractmetadata" type="checkbox" class="form-check-input">` this._view.generateContractMetadata = yo`<input onchange=${onchangeGenerateContractMetadata} id="generatecontractmetadata" type="checkbox" class="form-check-input">`
if (this.config.get('settings/generate-contract-metadata')) this._view.generateContractMetadata.setAttribute('checked', '') if (this.config.get('settings/generate-contract-metadata')) this._view.generateContractMetadata.setAttribute('checked', '')
@ -95,6 +92,13 @@ module.exports = class SettingsTab extends BaseApi {
<button class="btn btn-primary sm-1" onclick="${() => { window.open('https://gitter.im/ethereum/remix') }}">Gitter Channel</button> <button class="btn btn-primary sm-1" onclick="${() => { window.open('https://gitter.im/ethereum/remix') }}">Gitter Channel</button>
</div> </div>
</div>` </div>`
var warnText = `Transaction sent over Web3 will use the web3.personal API - be sure the endpoint is opened before enabling it.
This mode allows to provide the passphrase in the Remix interface without having to unlock the account.
Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...).
Remix never persist any passphrase.`.split('\n').map(s => s.trim()).join(' ')
this._view.warnPersonalMode = yo`<i class="${css.icon} fas fa-exclamation-triangle text-warning" aria-hidden="true"></i>`
this._view.config.general = yo` this._view.config.general = yo`
<div class="${css.info} card"> <div class="${css.info} card">
<div class="card-body"> <div class="card-body">
@ -113,7 +117,7 @@ module.exports = class SettingsTab extends BaseApi {
</div> </div>
<div class="form-check ${css.frow}"> <div class="form-check ${css.frow}">
<div>${this._view.personal}></div> <div>${this._view.personal}></div>
<label class="form-check-label align-middle" for="personal">Enable Personal Mode ${this._view.warnPersonalMode}></label> <label class="form-check-label align-middle" for="personal"> ${this._view.warnPersonalMode} Enable Personal Mode for web3 provider. ${warnText}></label>
</div> </div>
</div> </div>
</div> </div>

@ -178,6 +178,9 @@ var css = csjs`
border-radius: 3px; border-radius: 3px;
margin-left: 5px; margin-left: 5px;
} }
.disableMouseEvents {
pointer-events: none;
}
.icon { .icon {
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 12px;

File diff suppressed because one or more lines are too long

@ -7,13 +7,12 @@ var css = csjs`
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
position: fixed; position: fixed;
color: var(--primary)
min-height: 50px; min-height: 50px;
padding: 16px 24px 12px; padding: 16px 24px 12px;
border-radius: 3px; border-radius: 3px;
bottom: -300; bottom: -300;
left: 40%; left: 40%;
font-size: 12px; font-size: 14px;
text-align: center; text-align: center;
bottom: 0; bottom: 0;
} }

@ -29,7 +29,7 @@ class Toaster {
const shortTooltipText = tooltipText.length > 201 ? tooltipText.substring(0, 200) + '...' : tooltipText const shortTooltipText = tooltipText.length > 201 ? tooltipText.substring(0, 200) + '...' : tooltipText
this.tooltip = yo` this.tooltip = yo`
<div class="${css.tooltip} bg-secondary" onmouseenter=${() => { over() }} onmouseleave=${() => { out() }}> <div class="${css.tooltip} alert alert-info" onmouseenter=${() => { over() }} onmouseleave=${() => { out() }}>
<span>${shortTooltipText}<button class="btn btn-secondary btn-sm" onclick=${() => { modal.alert(tooltipText) }}>show full message</button></span> <span>${shortTooltipText}<button class="btn btn-secondary btn-sm" onclick=${() => { modal.alert(tooltipText) }}>show full message</button></span>
${action} ${action}
</div>` </div>`

@ -1,10 +1,12 @@
'use strict' 'use strict'
var CONFIG_FILE = '.remix.config' var CONFIG_FILE = '.remix.config'
const EventEmitter = require('events')
function Config (storage) { function Config (storage) {
this.items = {} this.items = {}
this.unpersistedItems = {} this.unpersistedItems = {}
this.events = new EventEmitter()
// load on instantiation // load on instantiation
try { try {
@ -28,6 +30,7 @@ function Config (storage) {
this.items[key] = content this.items[key] = content
try { try {
storage.set(CONFIG_FILE, JSON.stringify(this.items)) storage.set(CONFIG_FILE, JSON.stringify(this.items))
this.events.emit(key + '_changed', content)
} catch (exception) { } catch (exception) {
} }
} }

@ -39,8 +39,12 @@ function notAllowWarning (from, to) {
export class PermissionHandler { export class PermissionHandler {
constructor () { constructor () {
this.permissions = this._getFromLocal()
}
_getFromLocal () {
const permission = localStorage.getItem('plugins/permissions') const permission = localStorage.getItem('plugins/permissions')
this.permissions = permission ? JSON.parse(permission) : {} return permission ? JSON.parse(permission) : {}
} }
persistPermissions () { persistPermissions () {
@ -101,6 +105,7 @@ export class PermissionHandler {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
async askPermission (from, to) { async askPermission (from, to) {
this.permissions = this._getFromLocal()
if (!this.permissions[to.name]) this.permissions[to.name] = {} if (!this.permissions[to.name]) this.permissions[to.name] = {}
if (!this.permissions[to.name][from.name]) return this.openPermission(from, to) if (!this.permissions[to.name][from.name]) return this.openPermission(from, to)

@ -62,9 +62,11 @@ export class RemixAppManager extends AppManagerApi {
displayName: 'Vyper', displayName: 'Vyper',
events: ['compilationFinished'], events: ['compilationFinished'],
methods: [], methods: [],
notifications: {}, notifications: {
url: 'https://remix-vyper.surge.sh/', 'fileManager': ['currentFileChanged']
description: 'compile vyper contracts', },
url: 'https://remix-vyper-plugin.surge.sh',
description: 'Compile vyper contracts',
kind: 'compile', kind: 'compile',
icon: 'data:image/svg+xml;base64,PHN2ZyBpZD0iRmxhdF9Mb2dvIiBkYXRhLW5hbWU9IkZsYXQgTG9nbyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjA0OCAxNzczLjYyIj4gIDx0aXRsZT52eXBlci1sb2dvLWZsYXQ8L3RpdGxlPiAgPHBvbHlsaW5lIHBvaW50cz0iMTAyNCA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCAxNzczLjYyIDEyODAgMTMzMC4yMiAxMDI0IDg4Ni44MSIgc3R5bGU9ImZpbGw6IzMzMyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTI4MCA0NDMuNDEgMTAyNCA4ODYuODEgMTI4MCAxMzMwLjIyIDE1MzYgODg2LjgxIDEyODAgNDQzLjQxIiBzdHlsZT0iZmlsbDojNjY2Ii8+ICA8cG9seWxpbmUgcG9pbnRzPSI3NjggNDQzLjQxIDUxMiA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCA4ODYuODEgNzY4IDQ0My40MSIgc3R5bGU9ImZpbGw6IzY2NiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTUzNiAwIDEyODAgNDQzLjQxIDE1MzYgODg2LjgxIDE3OTIgNDQzLjQxIDE1MzYgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTE1MiAyMjEuNyA4OTYgMjIxLjcgNzY4IDQ0My40MSAxMDI0IDg4Ni44MSAxMjgwIDQ0My40MSAxMTUyIDIyMS43IiBzdHlsZT0iZmlsbDojOGM4YzhjIi8+ICA8cG9seWxpbmUgcG9pbnRzPSI1MTIgMCAyNTYgNDQzLjQxIDUxMiA4ODYuODEgNzY4IDQ0My40MSA1MTIgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMjA0OCAwIDE1MzYgMCAxNzkyIDQ0My40IDIwNDggMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iNTEyIDAgMCAwIDI1NiA0NDMuNCA1MTIgMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPjwvc3ZnPg==', icon: 'data:image/svg+xml;base64,PHN2ZyBpZD0iRmxhdF9Mb2dvIiBkYXRhLW5hbWU9IkZsYXQgTG9nbyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjA0OCAxNzczLjYyIj4gIDx0aXRsZT52eXBlci1sb2dvLWZsYXQ8L3RpdGxlPiAgPHBvbHlsaW5lIHBvaW50cz0iMTAyNCA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCAxNzczLjYyIDEyODAgMTMzMC4yMiAxMDI0IDg4Ni44MSIgc3R5bGU9ImZpbGw6IzMzMyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTI4MCA0NDMuNDEgMTAyNCA4ODYuODEgMTI4MCAxMzMwLjIyIDE1MzYgODg2LjgxIDEyODAgNDQzLjQxIiBzdHlsZT0iZmlsbDojNjY2Ii8+ICA8cG9seWxpbmUgcG9pbnRzPSI3NjggNDQzLjQxIDUxMiA4ODYuODEgNzY4IDEzMzAuMjIgMTAyNCA4ODYuODEgNzY4IDQ0My40MSIgc3R5bGU9ImZpbGw6IzY2NiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTUzNiAwIDEyODAgNDQzLjQxIDE1MzYgODg2LjgxIDE3OTIgNDQzLjQxIDE1MzYgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMTE1MiAyMjEuNyA4OTYgMjIxLjcgNzY4IDQ0My40MSAxMDI0IDg4Ni44MSAxMjgwIDQ0My40MSAxMTUyIDIyMS43IiBzdHlsZT0iZmlsbDojOGM4YzhjIi8+ICA8cG9seWxpbmUgcG9pbnRzPSI1MTIgMCAyNTYgNDQzLjQxIDUxMiA4ODYuODEgNzY4IDQ0My40MSA1MTIgMCIgc3R5bGU9ImZpbGw6IzhjOGM4YyIvPiAgPHBvbHlsaW5lIHBvaW50cz0iMjA0OCAwIDE1MzYgMCAxNzkyIDQ0My40IDIwNDggMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPiAgPHBvbHlsaW5lIHBvaW50cz0iNTEyIDAgMCAwIDI1NiA0NDMuNCA1MTIgMCIgc3R5bGU9ImZpbGw6I2IyYjJiMiIvPjwvc3ZnPg==',
location: 'swapPanel' location: 'swapPanel'

@ -17,7 +17,7 @@ module.exports = function (browser, callback) {
} }
function initModules (browser, callback) { function initModules (browser, callback) {
browser.click('#icon-panel div[plugin="pluginManager"]') browser.pause(3000).click('#icon-panel div[plugin="pluginManager"]')
.execute(function () { .execute(function () {
document.querySelector('div[id="pluginManager"]').scrollTop = document.querySelector('div[id="pluginManager"]').scrollHeight document.querySelector('div[id="pluginManager"]').scrollTop = document.querySelector('div[id="pluginManager"]').scrollHeight
}, [], function () { }, [], function () {

Loading…
Cancel
Save