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
SC_VERSION="4.5.1"
SAUCECONNECT_URL="https://saucelabs.com/downloads/sc-$SC_VERSION-$OS.$FILEFORMAT"
SAUCECONNECT_USERNAME="chriseth"
SAUCECONNECT_ACCESSKEY="b781828a-9e9c-43d8-89d4-2fbb879595ca"
SAUCECONNECT_USERNAME="yanneth"
SAUCECONNECT_ACCESSKEY="1f5a4560-b02b-41aa-b52b-f033aad30870"
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
SAUCECONNECT_JOBIDENTIFIER="browsersolidity_tests_${BUILD_ID}"

@ -27,14 +27,59 @@
THE SOFTWARE.
-->
<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" 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="icon" type="x-icon" href="icon.png">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<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>
</html>

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

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

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

@ -25,6 +25,14 @@ const css = csjs`
.permissionForm hr {
width: 80%;
}
.permissionKey {
display: flex;
justify-content: space-between;
align-items: center;
}
.permissionKey i {
cursor: pointer;
}
.checkbox {
display: flex;
align-items: center;
@ -39,7 +47,8 @@ export class PluginManagerSettings {
openDialog () {
const fromLocal = window.localStorage.getItem('plugins/permissions')
this.permissions = JSON.parse(fromLocal || '{}')
modalDialog('Plugin Manager Settings', this.settings(),
this.currentSetting = this.settings()
modalDialog('Plugin Manager Settings', this.currentSetting,
{ fn: () => this.onValidation() },
)
}
@ -49,6 +58,23 @@ export class PluginManagerSettings {
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 () {
const permissionByModule = (key, permission) => {
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}" />`
return yo`
<div class="form-group ${css.checkbox}">
<div class="form-group ${css.permissionKey}">
<div class="${css.checkbox}">
${checkbox}
<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>`
}
@ -72,7 +101,10 @@ export class PluginManagerSettings {
return yo`
<div>
<div class="${css.permissionKey}">
<h6>${key} :</h6>
<i onclick="${() => this.clearAllPersmission(key)}" class="far fa-trash-alt"></i>
</div>
${byModule}
</div>`
}

@ -66,8 +66,8 @@ export class SwapPanel extends AbstractPanel {
if (this.active) {
const { profile } = this.store.getOne(this.active)
name = profile.displayName ? profile.displayName : profile.name
const docsRoot = 'https://remix.readthedocs.io/en/docsnewlayout/'
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>` : ''
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-book"></i></sup></a>` : ''
}
return yo`

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

@ -40,52 +40,39 @@ var css = csjs`
function TxBrowser () {
this.event = new EventManager()
this.blockNumber
this.txNumber
this.view
this.setDefaultValues()
}
TxBrowser.prototype.setDefaultValues = function () {
this.connectInfo = ''
if (this.view) {
yo.update(this.view, this.render())
this.state = {
txNumber: undefined,
debugging: false
}
this.view
}
TxBrowser.prototype.submit = function (tx) {
this.event.trigger('requestDebug', [this.blockNumber, this.txNumber, tx])
}
TxBrowser.prototype.update = function (error, tx) {
if (error) {
this.view.querySelector('#error').innerHTML = error
return
TxBrowser.prototype.submit = function () {
if (this.state.debugging) {
this.unload()
} else {
this.event.trigger('requestDebug', [undefined, this.state.txNumber])
}
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
yo.update(this.view, this.render())
}
TxBrowser.prototype.updateTxN = function (ev) {
this.txNumber = ev.target.value
this.state.txNumber = ev.target.value
}
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.setDefaultValues()
}
TxBrowser.prototype.setState = function (state) {
this.state = {...this.state, ...state}
if (this.view) {
yo.update(this.view, this.render())
}
}
TxBrowser.prototype.render = function () {
@ -93,17 +80,17 @@ TxBrowser.prototype.render = function () {
var view = yo`<div class="${css.container}">
<div class="${css.txContainer}">
<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 class="form-control" class="${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction index or hash'} />
<input value="${this.state.txNumber || ''}" class="form-control ${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction hash'} />
</div>
<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' id='unload' class='${css.txbutton}' title='stop debugging' onclick=${function () { self.unload() }}>Stop</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>
</div>
</div>
<span id='error'></span>
</div>`
if (this.state.debugging) {
view.querySelectorAll('input').forEach(element => { element.setAttribute('disabled', '') })
}
if (!this.view) {
this.view = view
}

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

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

@ -1,5 +1,6 @@
'use strict'
const remixLib = require('remix-lib')
const csjs = require('csjs-inject')
const SourceMappingDecoder = remixLib.SourceMappingDecoder
const AstWalker = remixLib.AstWalker
const EventManager = require('../../lib/events')
@ -115,10 +116,16 @@ class ContextualListener {
let lastCompilationResult = this._deps.compilersArtefacts['__last']
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0) {
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 has children, highlight the entire line. if not, just highlight the current source position of the node.
css = 'highlightreference'
lineColumn = {
start: {
line: lineColumn.start.line,
@ -132,7 +139,7 @@ class ContextualListener {
}
const fileName = lastCompilationResult.getSourceName(position.file)
if (fileName) {
return this.editor.addMarker(lineColumn, fileName, css)
return this.editor.addMarker(lineColumn, fileName, css.highlightref_fullLine)
}
}
return null

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

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

@ -24,9 +24,12 @@ class SettingsUI {
this._components.registry = globalRegistry
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(() => {
this.updateAccountBalances()
}, 10 * 1000)
@ -87,7 +90,9 @@ class SettingsUI {
<div class="${css.crow}">
<div class="${css.col1_1}">
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 class=${css.account}>
<select name="txorigin" class="form-control ${css.select}" id="txorigin"></select>
@ -194,6 +199,42 @@ class SettingsUI {
this.event.trigger('clearInstance', [])
this.updateNetwork()
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 () {

@ -30,7 +30,10 @@ module.exports = class SettingsTab extends BaseApi {
}
this._view = { /* eslint-disable */
el: null,
optionVM: null, personal: null, warnPersonalMode: null, generateContractMetadata: null,
optionVM: null,
personal: null,
warnPersonalMode: null,
generateContractMetadata: null,
config: {
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', '')
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', '')
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">`
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>
</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`
<div class="${css.info} card">
<div class="card-body">
@ -113,7 +117,7 @@ module.exports = class SettingsTab extends BaseApi {
</div>
<div class="form-check ${css.frow}">
<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>

@ -178,6 +178,9 @@ var css = csjs`
border-radius: 3px;
margin-left: 5px;
}
.disableMouseEvents {
pointer-events: none;
}
.icon {
cursor: pointer;
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;
align-items: center;
position: fixed;
color: var(--primary)
min-height: 50px;
padding: 16px 24px 12px;
border-radius: 3px;
bottom: -300;
left: 40%;
font-size: 12px;
font-size: 14px;
text-align: center;
bottom: 0;
}

@ -29,7 +29,7 @@ class Toaster {
const shortTooltipText = tooltipText.length > 201 ? tooltipText.substring(0, 200) + '...' : tooltipText
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>
${action}
</div>`

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

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

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

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

Loading…
Cancel
Save