Unverified Commit 63f7e029 authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #1656 from ethereum/swap_it

Swap it
parents d5e1fa2b 66d80cf4
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
"transform-es2015-classes", "transform-es2015-classes",
"transform-es2015-computed-properties", "transform-es2015-computed-properties",
"transform-es2015-destructuring", "transform-es2015-destructuring",
"transform-object-rest-spread",
"transform-es2015-duplicate-keys", "transform-es2015-duplicate-keys",
"transform-es2015-for-of", "transform-es2015-for-of",
"transform-es2015-function-name", "transform-es2015-function-name",
......
...@@ -19,17 +19,17 @@ jobs: ...@@ -19,17 +19,17 @@ jobs:
- ENCRYPTION_LABEL3: "1b1c118ea62d" - ENCRYPTION_LABEL3: "1b1c118ea62d"
- COMMIT_AUTHOR_EMAIL: "chris@ethereum.org" - COMMIT_AUTHOR_EMAIL: "chris@ethereum.org"
- COMMIT_AUTHOR: "Circle CI" - COMMIT_AUTHOR: "Circle CI"
- FILES_TO_PACKAGE: "assets background.js build icon.png index.html manifest.json README.md soljson.js" - FILES_TO_PACKAGE: "assets background.js build icon.png index.html manifest.json README.md soljson.js package.json"
working_directory: ~/repo working_directory: ~/repo
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- dep-bundle-27-{{ checksum "package.json" }} - dep-bundle-29-{{ checksum "package.json" }}
- run: npm install - run: npm install
- save_cache: - save_cache:
key: dep-bundle-27-{{ checksum "package.json" }} key: dep-bundle-29-{{ checksum "package.json" }}
paths: paths:
- ~/repo/node_modules - ~/repo/node_modules
- run: npm run lint && npm run test && npm run make-mock-compiler && npm run build - run: npm run lint && npm run test && npm run make-mock-compiler && npm run build
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
#!/usr/bin/env node #!/usr/bin/env node
var path = require('path')
var httpServer = require('http-server') var httpServer = require('http-server')
var remixd = require('remixd') var remixd = require('remixd')
var server = httpServer.createServer({ var server = httpServer.createServer({
root: __dirname + '/../' root: path.join(__dirname, '/../')
}) })
var folder = process.argv.length > 2 ? process.argv[2] : process.cwd() var folder = process.argv.length > 2 ? process.argv[2] : process.cwd()
server.listen(8080, '127.0.0.1', function () {}) server.listen(8080, '127.0.0.1', function () {})
var router = new remixd.Router(65520, remixd.services.sharedFolder, { remixIdeUrl: 'http://localhost:8080' }, (webSocket) => { var router = new remixd.Router(65520, remixd.services.sharedFolder, { remixIdeUrl: 'http://localhost:8080' }, (webSocket) => {
remixd.services.sharedFolder.setWebSocket(webSocket) remixd.services.sharedFolder.setWebSocket(webSocket)
remixd.services.sharedFolder.setupNotifications(folder) remixd.services.sharedFolder.setupNotifications(folder)
remixd.services.sharedFolder.sharedFolder(folder, false) remixd.services.sharedFolder.sharedFolder(folder, false)
}) })
router.start() router.start()
......
...@@ -7,7 +7,7 @@ SHA=`git rev-parse --short --verify HEAD` ...@@ -7,7 +7,7 @@ SHA=`git rev-parse --short --verify HEAD`
git config user.name "$COMMIT_AUTHOR" git config user.name "$COMMIT_AUTHOR"
git config user.email "$COMMIT_AUTHOR_EMAIL" git config user.email "$COMMIT_AUTHOR_EMAIL"
git checkout --orphan gh-pages git checkout --orphan gh-pages
git rm --cached -r . git rm --cached -r -f .
echo "# Automatic build" > README.md echo "# Automatic build" > README.md
echo "Built website from \`$SHA\`. See https://github.com/ethereum/remix-ide/ for details." >> README.md echo "Built website from \`$SHA\`. See https://github.com/ethereum/remix-ide/ for details." >> README.md
echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md
......
...@@ -7,7 +7,7 @@ SHA=`git rev-parse --short --verify HEAD` ...@@ -7,7 +7,7 @@ SHA=`git rev-parse --short --verify HEAD`
git config user.name "$COMMIT_AUTHOR" git config user.name "$COMMIT_AUTHOR"
git config user.email "$COMMIT_AUTHOR_EMAIL" git config user.email "$COMMIT_AUTHOR_EMAIL"
git checkout --orphan gh-pages git checkout --orphan gh-pages
git rm --cached -r . git rm --cached -r -f .
echo "# Automatic build" > README.md echo "# Automatic build" > README.md
echo "Built website from \`$SHA\`. See https://github.com/ethereum/remix-ide/ for details." >> README.md echo "Built website from \`$SHA\`. See https://github.com/ethereum/remix-ide/ for details." >> README.md
echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md
......
...@@ -40,7 +40,7 @@ function load () { ...@@ -40,7 +40,7 @@ function load () {
} }
}) })
setInterval(function () { setInterval(function () {
remix.call('app', 'detectNetWork', [], function (error, result) { remix.call('network', 'detectNetWork', [], function (error, result) {
if (error) console.log(error) if (error) console.log(error)
if (network.innerHTML !== result[0].name + ' - ' + result[0].id) { if (network.innerHTML !== result[0].name + ' - ' + result[0].id) {
currentNetWork = result[0].name currentNetWork = result[0].name
......
...@@ -28,8 +28,9 @@ ...@@ -28,8 +28,9 @@
--> -->
<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 - Solidity 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="stylesheet" href="assets/css/pygment_trac.css">
<link rel="stylesheet" href="assets/css/font-awesome.min.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>
......
{ {
"name": "remix-ide", "name": "remix-ide",
"version": "v0.7.5", "version": "v0.8.0-alpha+002",
"description": "Minimalistic browser-based Solidity IDE", "description": "Minimalistic browser-based Solidity IDE",
"devDependencies": { "devDependencies": {
"@fortawesome/fontawesome-free": "^5.8.1",
"@resolver-engine/imports": "^0.3.0",
"ace-mode-solidity": "^0.1.0", "ace-mode-solidity": "^0.1.0",
"async": "^2.1.2", "async": "^2.1.2",
"babel-eslint": "^7.1.1", "babel-eslint": "^7.1.1",
"babel-plugin-transform-modern-regexp": "0.0.6",
"babel-plugin-transform-object-assign": "^6.22.0", "babel-plugin-transform-object-assign": "^6.22.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-yo-yoify": "^0.3.3", "babel-plugin-yo-yoify": "^0.3.3",
"babel-polyfill": "^6.22.0", "babel-polyfill": "^6.22.0",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
...@@ -21,7 +25,8 @@ ...@@ -21,7 +25,8 @@
"csjs-inject": "^1.0.1", "csjs-inject": "^1.0.1",
"csslint": "^1.0.2", "csslint": "^1.0.2",
"deep-equal": "^1.0.1", "deep-equal": "^1.0.1",
"ethereumjs-util": "^6.1.0", "ethereumjs-util": "^5.1.2",
"events": "^3.0.0",
"execr": "^1.0.1", "execr": "^1.0.1",
"exorcist": "^0.4.0", "exorcist": "^0.4.0",
"fast-async": "6.3.1", "fast-async": "6.3.1",
...@@ -38,11 +43,12 @@ ...@@ -38,11 +43,12 @@
"npm-link-local": "^1.1.0", "npm-link-local": "^1.1.0",
"npm-run-all": "^4.0.2", "npm-run-all": "^4.0.2",
"onchange": "^3.2.1", "onchange": "^3.2.1",
"remix-debug": "0.3.1", "remix-analyzer": "0.3.5",
"remix-analyzer": "0.3.1", "remix-debug": "0.3.5",
"remix-lib": "0.4.1", "remix-lib": "0.4.5",
"remix-solidity": "0.3.1", "remix-solidity": "0.3.5",
"remix-tests": "0.1.1", "remix-tabs": "^1.0.0",
"remix-tests": "0.1.6",
"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",
...@@ -60,7 +66,8 @@ ...@@ -60,7 +66,8 @@
"yo-yoify": "^3.7.3" "yo-yoify": "^3.7.3"
}, },
"dependencies": { "dependencies": {
"http-server": "0.9.0", "http-server-legacy": "latest",
"remix-plugin": "0.0.2-alpha.6",
"remixd": "0.1.8-alpha.6" "remixd": "0.1.8-alpha.6"
}, },
"repository": { "repository": {
...@@ -105,7 +112,8 @@ ...@@ -105,7 +112,8 @@
"transform-es2015-spread", "transform-es2015-spread",
"transform-es2015-parameters", "transform-es2015-parameters",
"transform-es2015-destructuring", "transform-es2015-destructuring",
"transform-es2015-block-scoping" "transform-es2015-block-scoping",
"transform-modern-regexp"
] ]
}, },
"browserify": { "browserify": {
...@@ -146,7 +154,7 @@ ...@@ -146,7 +154,7 @@
"remix-ide": "./bin/remix-ide" "remix-ide": "./bin/remix-ide"
}, },
"scripts": { "scripts": {
"setupremix": "npm run linkremixlib && npm run linkremixsolidity && npm run linkremixsimulator && npm run linkremixtests", "setupremix": "npm run linkremixdebug && npm run linkremixlib && npm run linkremixsolidity && npm run linkremixsimulator && npm run linkremixtests",
"pullremix": "git clone https://github.com/ethereum/remix", "pullremix": "git clone https://github.com/ethereum/remix",
"linkremixlib": "cd node_modules && rm -rf remix-lib && ln -s ../../remix/remix-lib remix-lib && cd ..", "linkremixlib": "cd node_modules && rm -rf remix-lib && ln -s ../../remix/remix-lib remix-lib && cd ..",
"linkremixsolidity": "cd node_modules && rm -rf remix-solidity && ln -s ../../remix/remix-solidity remix-solidity && cd ..", "linkremixsolidity": "cd node_modules && rm -rf remix-solidity && ln -s ../../remix/remix-solidity remix-solidity && cd ..",
...@@ -171,15 +179,16 @@ ...@@ -171,15 +179,16 @@
"nightwatch_remote_debugger_parallel": "nightwatch --config nightwatch_debugger.js --env safari,chrome,default", "nightwatch_remote_debugger_parallel": "nightwatch --config nightwatch_debugger.js --env safari,chrome,default",
"onchange": "onchange build/app.js -- npm-run-all lint", "onchange": "onchange build/app.js -- npm-run-all lint",
"prepublish": "mkdirp build; npm-run-all -ls downloadsolc_root build", "prepublish": "mkdirp build; npm-run-all -ls downloadsolc_root build",
"remixd": "./node_modules/remixd/bin/remixd -s ./contracts --remix-ide http://127.0.0.1:8080", "remixd": "remixd -s ./contracts --remix-ide http://127.0.0.1:8080",
"selenium": "execr --silent selenium-standalone start", "selenium": "execr --silent selenium-standalone start",
"selenium-install": "selenium-standalone install", "selenium-install": "selenium-standalone install",
"serve": "execr --silent http-server .", "serve": "npx http-server-legacy .",
"serve_debugger": "execr --silent http-server src/app/debugger/remix-debugger", "serve_debugger": "npx http-server-legacy src/app/debugger/remix-debugger",
"sourcemap": "exorcist --root ../ build/app.js.map > build/app.js", "sourcemap": "exorcist --root ../ build/app.js.map > build/app.js",
"start": "npm-run-all -lpr serve watch onchange remixd", "start": "npm-run-all -lpr serve watch onchange remixd",
"test": "npm run csslint; standard && node test/index.js", "test": "csslint && standard && node test/index.js",
"test-browser": "npm-run-all -lpr selenium downloadsolc_root make-mock-compiler serve browsertest", "test-browser": "npm-run-all -lpr selenium downloadsolc_root make-mock-compiler serve browsertest",
"watch": "watchify src/index.js -dv -p browserify-reload -o build/app.js --exclude solc" "watch": "watchify src/index.js -dv -p browserify-reload -o build/app.js --exclude solc",
"reinstall": "rm ./node-modules/ -rf; rm package-lock.json; rm ./build/ -rf; npm install; npm run build"
} }
} }
This diff is collapsed.
'use strict' 'use strict'
var base64 = require('js-base64').Base64 var base64 = require('js-base64').Base64
var swarmgw = require('swarmgw')() var swarmgw = require('swarmgw')()
var resolver = require('@resolver-engine/imports').ImportsEngine()
var request = require('request') var request = require('request')
module.exports = class CompilerImports { module.exports = class CompilerImports {
...@@ -10,10 +11,20 @@ module.exports = class CompilerImports { ...@@ -10,10 +11,20 @@ module.exports = class CompilerImports {
} }
handleGithubCall (root, path, cb) { handleGithubCall (root, path, cb) {
var accessToken = this.githubAccessToken() ? '?access_token=' + this.githubAccessToken() : '' let param = '?'
param += this.githubAccessToken() ? 'access_token=' + this.githubAccessToken() : ''
const regex = path.match(/blob\/([^/]+)\/(.*)/)
if (regex) {
// if we have /blob/master/+path we extract the branch name "master" and add it as a parameter to the github api
// the ref can be branch name, tag, commit id
const reference = regex[1]
param += 'ref=' + reference
path = path.replace(`blob/${reference}/`, '')
}
return request.get( return request.get(
{ {
url: 'https://api.github.com/repos/' + root + '/contents/' + path + accessToken, url: 'https://api.github.com/repos/' + root + '/contents/' + path + param,
json: true json: true
}, },
(err, r, data) => { (err, r, data) => {
...@@ -112,13 +123,22 @@ module.exports = class CompilerImports { ...@@ -112,13 +123,22 @@ module.exports = class CompilerImports {
}) })
} }
}) })
if (found) return
if (found) { resolver
return .resolve(url)
} else if (/^[^:]*:\/\//.exec(url)) { .then(result => {
cb('Unable to import "' + url + '": Unsupported URL schema') return resolver.require(url)
} else { })
.then(result => {
if (url.indexOf(result.provider + ':') === 0) {
url = url.substring(result.provider.length + 1) // remove the github prefix
}
cb(null, result.source, url, result.provider, result.url)
})
.catch(err => {
err
cb('Unable to import "' + url + '": File not found') cb('Unable to import "' + url + '": File not found')
} })
} }
} }
/* global localStorage */
const yo = require('yo-yo')
const modalDialog = require('../ui/modaldialog')
const unexposedEvents = ['statusChanged']
module.exports = class LocalPlugin {
/**
* Open a modal to create a local plugin
* @param {PluginApi[]} plugins The list of the plugins in the store
* @returns {Promise<{api: any, profile: any}>} A promise with the new plugin profile
*/
open (plugins) {
this.profile = JSON.parse(localStorage.getItem('plugins/local')) || { notifications: {} }
return new Promise((resolve, reject) => {
const onValidation = () => {
try {
const profile = this.create()
resolve(profile)
} catch (err) {
reject(err)
}
}
modalDialog('Local Plugin', this.form(plugins),
{ fn: () => onValidation() },
{ fn: () => resolve() }
)
})
}
/**
* Create the object to add to the plugin-list
*/
create () {
const profile = {
...this.profile,
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xMjYyIDEwNzVxLTM3IDEyMS0xMzggMTk1dC0yMjggNzQtMjI4LTc0LTEzOC0xOTVxLTgtMjUgNC00OC41dDM4LTMxLjVxMjUtOCA0OC41IDR0MzEuNSAzOHEyNSA4MCA5Mi41IDEyOS41dDE1MS41IDQ5LjUgMTUxLjUtNDkuNSA5Mi41LTEyOS41cTgtMjYgMzItMzh0NDktNCAzNyAzMS41IDQgNDguNXptLTQ5NC00MzVxMCA1My0zNy41IDkwLjV0LTkwLjUgMzcuNS05MC41LTM3LjUtMzcuNS05MC41IDM3LjUtOTAuNSA5MC41LTM3LjUgOTAuNSAzNy41IDM3LjUgOTAuNXptNTEyIDBxMCA1My0zNy41IDkwLjV0LTkwLjUgMzcuNS05MC41LTM3LjUtMzcuNS05MC41IDM3LjUtOTAuNSA5MC41LTM3LjUgOTAuNSAzNy41IDM3LjUgOTAuNXptMjU2IDI1NnEwLTEzMC01MS0yNDguNXQtMTM2LjUtMjA0LTIwNC0xMzYuNS0yNDguNS01MS0yNDguNSA1MS0yMDQgMTM2LjUtMTM2LjUgMjA0LTUxIDI0OC41IDUxIDI0OC41IDEzNi41IDIwNCAyMDQgMTM2LjUgMjQ4LjUgNTEgMjQ4LjUtNTEgMjA0LTEzNi41IDEzNi41LTIwNCA1MS0yNDguNXptMTI4IDBxMCAyMDktMTAzIDM4NS41dC0yNzkuNSAyNzkuNS0zODUuNSAxMDMtMzg1LjUtMTAzLTI3OS41LTI3OS41LTEwMy0zODUuNSAxMDMtMzg1LjUgMjc5LjUtMjc5LjUgMzg1LjUtMTAzIDM4NS41IDEwMyAyNzkuNSAyNzkuNSAxMDMgMzg1LjV6Ii8+PC9zdmc+',
methods: [],
hash: `local-${this.profile.name}`,
location: 'swapPanel'
}
profile.events = profile.events.filter((item) => { return item !== '' })
if (!profile.name) throw new Error('Plugin should have a name')
if (!profile.url) throw new Error('Plugin should have an URL')
localStorage.setItem('plugins/local', JSON.stringify(profile))
return profile
}
/**
* Add or remove a notification to/from the profile
* @param {Event} e The event when checkbox changes
* @param {string} pluginName The name of the plugin
* @param {string} eventName The name of the event to listen on
*/
toggleNotification (e, pluginName, eventName) {
const {checked} = e.target
if (checked) {
if (!this.profile.notifications[pluginName]) this.profile.notifications[pluginName] = []
this.profile.notifications[pluginName].push(eventName)
} else {
this.profile.notifications[pluginName].splice(this.profile.notifications[pluginName].indexOf(eventName), 1)
if (this.profile.notifications[pluginName].length === 0) delete this.profile.notifications[pluginName]
}
}
updateName ({target}) {
this.profile.name = target.value
}
updateUrl ({target}) {
this.profile.url = target.value
}
updateDisplayName ({target}) {
this.profile.displayName = target.value
}
updateEvents ({target}, index) {
if (this.profile.events[index] !== undefined) {
this.profile.events[index] = target.value
}
}
/**
* The checkbox for a couple module / event
* @param {string} plugin The name of the plugin
* @param {string} event The name of the event exposed by the plugin
*/
notificationCheckbox (plugin, event) {
const notifications = this.profile.notifications || {}
const checkbox = notifications[plugin] && notifications[plugin].includes(event)
? yo`<input type="checkbox" checked onchange="${e => this.toggleNotification(e, plugin, event)}">`
: yo`<input type="checkbox" onchange="${e => this.toggleNotification(e, plugin, event)}">`
return yo`<div>
${checkbox}
<label>${plugin} - ${event}</label>
</div>`
}
/**
* The form to create a local plugin
* @param {ProfileApi[]} plugins Liste of profile of the plugins
*/
form (plugins = []) {
const name = this.profile.name || ''
const url = this.profile.url || ''
const displayName = this.profile.displayName || ''
const profiles = plugins
.filter(({profile}) => profile.events && profile.events.length > 0)
.map(({profile}) => profile)
const eventsForm = (events) => {
return yo`<div>${events.map((event, i) => {
return yo`<input class="form-control" onchange="${e => this.updateEvents(e, i)}" value="${event}" />`
})}</div>`
}
const eventsEl = eventsForm(this.profile.events || [])
const pushEvent = () => {
if (!this.profile.events) this.profile.events = []
this.profile.events.push('')
yo.update(eventsEl, eventsForm(this.profile.events))
}
const addEvent = yo`<button type="button" class="btn btn-sm btn-light" onclick="${() => pushEvent()}">Add an event</button>`
return yo`
<form id="local-plugin-form">
<div class="form-group">
<label for="plugin-name">Plugin Name <small>(required)</small></label>
<input class="form-control" onchange="${e => this.updateName(e)}" value="${name}" id="plugin-name" placeholder="Should be camelCase">
</div>
<div class="form-group">
<label for="plugin-displayname">Display Name</label>
<input class="form-control" onchange="${e => this.updateDisplayName(e)}" value="${displayName}" id="plugin-displayname" placeholder="Name in the header">
</div>
<div class="form-group">
<label for="plugin-url">Url <small>(required)</small></label>
<input class="form-control" onchange="${e => this.updateUrl(e)}" value="${url}" id="plugin-url" placeholder="ex: https://localhost:8000">
</div>
<div class="form-group">
<label>Events</label>
${eventsEl}${addEvent}
</div>
<div class="form-group">
<label>Notifications</label>
${profiles.map(({name, events}) => {
return events
.filter(event => !unexposedEvents.includes(event))
.map(event => this.notificationCheckbox(name, event))
})}
</div>
</form>`
}
}
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const EventEmitter = require('events')
const LocalPlugin = require('./local-plugin')
import { Plugin, BaseApi } from 'remix-plugin'
const css = csjs`
.pluginSearch {
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--light);
padding: 10px;
position: sticky;
top: 0;
z-index: 2;
margin-bottom: 0px;
}
.localPluginBtn {
margin-top: 15px;
}
.displayName {
text-transform: capitalize;
}
.description {
text-transform: capitalize;
}
.row {
display: flex;
flex-direction: row;
}
.isStuck {
background-color: var(--primary);
color:
}
`
const profile = {
name: 'pluginManager',
displayName: 'Plugin manager',
methods: [],
events: [],
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNzU1IDQ1M3EzNyAzOCAzNyA5MC41dC0zNyA5MC41bC00MDEgNDAwIDE1MCAxNTAtMTYwIDE2MHEtMTYzIDE2My0zODkuNSAxODYuNXQtNDExLjUtMTAwLjVsLTM2MiAzNjJoLTE4MXYtMTgxbDM2Mi0zNjJxLTEyNC0xODUtMTAwLjUtNDExLjV0MTg2LjUtMzg5LjVsMTYwLTE2MCAxNTAgMTUwIDQwMC00MDFxMzgtMzcgOTEtMzd0OTAgMzcgMzcgOTAuNS0zNyA5MC41bC00MDAgNDAxIDIzNCAyMzQgNDAxLTQwMHEzOC0zNyA5MS0zN3Q5MCAzN3oiLz48L3N2Zz4=',
description: 'Start/stop services, modules and plugins',
kind: 'settings',
location: 'swapPanel'
}
class PluginManagerComponent extends BaseApi {
constructor () {
super(profile)
this.event = new EventEmitter()
this.views = {
root: null,
items: {}
}
this.localPlugin = new LocalPlugin()
this.filter = ''
}
setApp (appManager) {
this.appManager = appManager
}
setStore (store) {
this.store = store
this.store.event.on('activate', (name) => { this.reRender() })
this.store.event.on('deactivate', (name) => { this.reRender() })
this.store.event.on('add', (api) => { this.reRender() })
this.store.event.on('remove', (api) => { this.reRender() })
}
renderItem (name) {
const api = this.store.getOne(name)
if (!api) return
const isActive = this.store.actives.includes(name)
const displayName = (api.profile.displayName) ? api.profile.displayName : name
const activationButton = isActive
? yo`
<button onclick="${_ => this.appManager.deactivateOne(name)}" class="btn btn-secondary btn-sm">
Deactivate
</button>`
: yo`
<button onclick="${_ => this.appManager.activateOne(name)}" class="btn btn-success btn-sm">
Activate
</button>`
return yo`
<article class="list-group-item py-1" title="${name}" >
<div class="${css.row} justify-content-between align-items-center">
<h6 class="${css.displayName}">${displayName}</h6>
${activationButton}
</div>
<p class="${css.description}">${api.profile.description}</p>
</article>
`
}
/***************
* SUB-COMPONENT
*/
/**
* Add a local plugin to the list of plugins
*/
async openLocalPlugin () {
try {
const profile = await this.localPlugin.open(this.store.getAll())
if (!profile) return
this.appManager.registerOne(new Plugin(profile))
this.appManager.activateOne(profile.name)
} catch (err) {
// TODO : Use an alert to handle this error instead of a console.log
console.log(`Cannot create Plugin : ${err.message}`)
}
}
render () {
// Filtering helpers
const isFiltered = (api) => api.name.toLowerCase().includes(this.filter)
const isNotRequired = ({profile}) => !profile.required
const sortByName = (a, b) => {
const nameA = a.name.toUpperCase()
const nameB = b.name.toUpperCase()
return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0
}
// Filter all active and inactive modules that are not required
const { actives, inactives } = this.store.getAll()
.filter(isFiltered)
.filter(isNotRequired)
.sort(sortByName)
.reduce(({actives, inactives}, api) => {
return this.store.actives.includes(api.name)
? { actives: [...actives, api.name], inactives }
: { inactives: [...inactives, api.name], actives }
}, { actives: [], inactives: [] })
const activeTile = actives.length !== 0
? yo`
<nav class="navbar navbar-expand-lg navbar-light bg-light justify-content-between align-items-center">
<span class="navbar-brand">Active Modules</span>
<span class="badge badge-pill badge-primary">${actives.length}</span>
</nav>`
: ''
const inactiveTile = inactives.length !== 0
? yo`
<nav class="navbar navbar-expand-lg navbar-light bg-light justify-content-between align-items-center">
<span class="navbar-brand">Inactive Modules</span>
<span class="badge badge-pill badge-primary">${inactives.length}</span>
</nav>`
: ''
const rootView = yo`
<div id='pluginManager'>
<div class="form-group ${css.pluginSearch}">
<input onkeyup="${e => this.filterPlugins(e)}" class="form-control" placeholder="Search">
<button onclick="${_ => this.openLocalPlugin()}" class="btn btn-sm text-info ${css.localPluginBtn}">
Connect to a Local Plugin
</button>
</div>
<section>
${activeTile}
<div class="list-group list-group-flush">
${actives.map(name => this.renderItem(name))}
</div>
${inactiveTile}
<div class="list-group list-group-flush">
${inactives.map(name => this.renderItem(name))}
</div>
</section>
</div>
`
if (!this.views.root) this.views.root = rootView
return rootView
}
reRender () {
if (this.views.root) {
yo.update(this.views.root, this.render())
}
}
filterPlugins ({ target }) {
this.filter = target.value.toLowerCase()
this.reRender()
}
}
module.exports = PluginManagerComponent
var registry = require('../../global/registry')
const CompilerAbstract = require('../compiler/compiler-abstract')
const EventManager = require('remix-lib').EventManager
class PluginManagerProxy {
constructor () {
this.event = new EventManager()
this._listeners = {}
this._listeners['vyper'] = (file, source, languageVersion, data) => {
registry.get('compilersartefacts').api['__last'] = new CompilerAbstract(languageVersion, data, source)
this.event.trigger('sendCompilationResult', [file, source, languageVersion, data])
}
this._listeners['solidity'] = (file, source, languageVersion, data) => {
registry.get('compilersartefacts').api['__last'] = new CompilerAbstract(languageVersion, data, source)
this.event.trigger('sendCompilationResult', [file, source, languageVersion, data])
}
}
register (name, instance) {
if (this._listeners[name]) {
instance.events.on('compilationFinished', this._listeners[name])
}
}
unregister (name, instance) {
if (this._listeners[name]) {
instance.events.removeListener('compilationFinished', this._listeners[name])
}
}
}
module.exports = PluginManagerProxy
import EventEmmitter from 'events'
class SwapPanelApi {
constructor (swapPanelComponent, verticalIconsComponent) {
this.event = new EventEmmitter()
this.component = swapPanelComponent
this.currentContent
verticalIconsComponent.events.on('toggleContent', (moduleName) => {
if (!swapPanelComponent.contents[moduleName]) return
if (this.currentContent === moduleName) {
this.event.emit('toggle', moduleName)
return
}
this.showContent(moduleName)
this.event.emit('showing', moduleName)
})
verticalIconsComponent.events.on('showContent', (moduleName) => {
if (!swapPanelComponent.contents[moduleName]) return
this.showContent(moduleName)
this.event.emit('showing', moduleName)
})
}
showContent (moduleName) {
this.component.showContent(moduleName)
this.currentContent = moduleName
}
/*
content: DOM element
by appManager
*/
add (profile, content) {
return this.component.add(profile.name, content)
}
remove (profile) {
return this.component.remove(profile.name)
}
}
module.exports = SwapPanelApi
var yo = require('yo-yo')
var csjs = require('csjs-inject')
class SwapPanelComponent {
constructor (name, appStore, appManager, opt) {
this.name = name
this.opt = opt
this.store = appStore
// list of contents
this.contents = {}
// name of the current displayed content
this.currentNode
this.store.event.on('activate', (name) => {
const api = this.store.getOne(name)
const profile = api.profile
if (((profile.location === this.name) || (!profile.location && opt.default)) &&
profile.icon && api.render && typeof api.render === 'function') {
this.add(name, api.render())
}
})
this.store.event.on('deactivate', (name) => {
if (this.contents[name]) this.remove(name)
})
this.store.event.on('add', (api) => { })
this.store.event.on('remove', (api) => { })
}
showContent (moduleName) {
// hiding the current view and display the `moduleName`
if (this.contents[moduleName]) {
if (this.currentNode) {
this.contents[this.currentNode].style.display = 'none'
}
this.contents[moduleName].style.display = 'block'
this.currentNode = moduleName
var api = this.store.getOne(moduleName)
this.header.querySelector('h6').innerHTML = api.profile ? api.profile.displayName : ' - '
return
}
}
add (moduleName, content) {
content.style.height = '100%'
content.style.width = '100%'
content.style.border = '0'
this.contents[moduleName] = yo`<div class=${css.plugItIn} >${content}</div>`
this.view.appendChild(this.contents[moduleName])
}
remove (moduleName) {
let el = this.contents[moduleName]
if (el) el.parentElement.removeChild(el)
}
render () {
this.view = yo`
<div id='plugins' class=${css.plugins}>
</div>
`
this.header = yo`<header class="${css.swapitHeader}"><h6 class="${css.swapitTitle}"></h6></header>`
if (!this.opt.displayHeader) this.header.style.display = 'none'
return yo`<div class=${css.pluginsContainer}>
${this.header}
${this.view}
</div>`
}
}
module.exports = SwapPanelComponent
const css = csjs`
.plugins {
height : 95%;
}
.plugItIn {
display : none;
height : 100%;
}
.plugItIn > div {
overflow-y : auto;
height : 100%;
width : 100%;
}
.plugItIn.active {
display : block;
}
.pluginsContainer {
height: 100%;
overflow-y: hidden;
}
.swapitTitle {
text-transform: uppercase;
}
.swapitHeader {
height: 35px;
padding-top: 10px;
padding-left: 27px;
}
`
// API
class VerticalIconsApi {
constructor (verticalIconsComponent) {
this.component = verticalIconsComponent
}
addIcon (mod) {
this.component.addIcon(mod)
}
removeIcon (mod) {
this.component.removeIcon(mod)
}
select (moduleName) {
this.component.select(moduleName)
}
}
module.exports = VerticalIconsApi
This diff is collapsed.
...@@ -12,8 +12,6 @@ var executionContext = require('../../execution-context') ...@@ -12,8 +12,6 @@ var executionContext = require('../../execution-context')
var globalRegistry = require('../../global/registry') var globalRegistry = require('../../global/registry')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var Web3Providers = remixLib.vm.Web3Providers
var DummyProvider = remixLib.vm.DummyProvider
var init = remixLib.init var init = remixLib.init
...@@ -30,72 +28,12 @@ var css = csjs` ...@@ -30,72 +28,12 @@ var css = csjs`
} }
` `
class ContextManager {
constructor () {
this.executionContext = executionContext
this.web3 = this.executionContext.web3()
this.event = new EventManager()
}
initProviders () {
this.web3Providers = new Web3Providers()
this.addProvider('DUMMYWEB3', new DummyProvider())
this.switchProvider('DUMMYWEB3')
this.addProvider('vm', this.executionContext.vm())
this.addProvider('injected', this.executionContext.internalWeb3())
this.addProvider('web3', this.executionContext.internalWeb3())
this.switchProvider(this.executionContext.getProvider())
}
getWeb3 () {
return this.web3
}
addProvider (type, obj) {
this.web3Providers.addProvider(type, obj)
this.event.trigger('providerAdded', [type])
}
switchProvider (type) {
var self = this
this.web3Providers.get(type, function (error, obj) {
if (error) {
console.log('provider ' + type + ' not defined')
} else {
self.web3 = obj
self.executionContext.detectNetwork((error, network) => {
if (error || !network) {
self.web3 = obj
} else {
var webDebugNode = init.web3DebugNode(network.name)
self.web3 = (!webDebugNode ? obj : webDebugNode)
}
self.event.trigger('providerChanged', [type, self.web3])
})
self.event.trigger('providerChanged', [type, self.web3])
}
})
}
}
class DebuggerUI { class DebuggerUI {
constructor (container) { constructor (container) {
this.registry = globalRegistry this.registry = globalRegistry
this.event = new EventManager() this.event = new EventManager()
this.executionContext = executionContext
this.contextManager = new ContextManager()
this.contextManager.initProviders()
this.contextManager.event.register('providerChanged', () => {
if (this.debugger) this.debugger.updateWeb3(this.contextManager.getWeb3())
})
this.isActive = false this.isActive = false
this.sourceHighlighter = new SourceHighlighter() this.sourceHighlighter = new SourceHighlighter()
...@@ -173,19 +111,29 @@ class DebuggerUI { ...@@ -173,19 +111,29 @@ class DebuggerUI {
if (compilers['__last']) lastCompilationResult = compilers['__last'] if (compilers['__last']) lastCompilationResult = compilers['__last']
// TODO debugging with source highlight is disabled. see line 98 // TODO debugging with source highlight is disabled. see line 98
this.debugger = new Debugger({
web3: this.contextManager.getWeb3(),
offsetToLineColumnConverter: this.registry.get('offsettolinecolumnconverter').api,
compiler: { lastCompilationResult }
})
this.listenToEvents() executionContext.detectNetwork((error, network) => {
let web3
this.debugger.debugger.updateWeb3(this.executionContext.web3()) if (error || !network) {
this.debugger.debug(blockNumber, txNumber, tx, () => { web3 = init.web3DebugNode(executionContext.web3())
self.stepManager = new StepManagerUI(this.debugger.step_manager) } else {
self.vmDebugger = new VmDebugger(this.debugger.vmDebuggerLogic) var webDebugNode = init.web3DebugNode(network.name)
self.renderDebugger() web3 = (!webDebugNode ? executionContext.web3() : webDebugNode)
}
init.extendWeb3(web3)
this.debugger = new Debugger({
web3,
offsetToLineColumnConverter: this.registry.get('offsettolinecolumnconverter').api,
compiler: { lastCompilationResult }
})
this.listenToEvents()
this.debugger.debug(blockNumber, txNumber, tx, () => {
self.stepManager = new StepManagerUI(this.debugger.step_manager)
self.vmDebugger = new VmDebugger(this.debugger.vmDebuggerLogic)
self.renderDebugger()
})
}) })
} }
......
...@@ -3,8 +3,6 @@ var EventManager = require('../../../lib/events') ...@@ -3,8 +3,6 @@ var EventManager = require('../../../lib/events')
var yo = require('yo-yo') var yo = require('yo-yo')
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.buttons { .buttons {
...@@ -17,7 +15,6 @@ var css = csjs` ...@@ -17,7 +15,6 @@ var css = csjs`
justify-content: center; justify-content: center;
} }
.stepButton { .stepButton {
${styles.rightPanel.debuggerTab.button_Debugger}
} }
.jumpButtons { .jumpButtons {
width: 100%; width: 100%;
...@@ -25,13 +22,10 @@ var css = csjs` ...@@ -25,13 +22,10 @@ var css = csjs`
justify-content: center; justify-content: center;
} }
.jumpButton { .jumpButton {
${styles.rightPanel.debuggerTab.button_Debugger}
} }
.navigator { .navigator {
color: ${styles.rightPanel.debuggerTab.text_Primary};
} }
.navigator:hover { .navigator:hover {
color: ${styles.rightPanel.debuggerTab.button_Debugger_icon_HoverColor};
} }
` `
...@@ -51,20 +45,20 @@ function ButtonNavigator () { ...@@ -51,20 +45,20 @@ function ButtonNavigator () {
ButtonNavigator.prototype.render = function () { ButtonNavigator.prototype.render = function () {
var self = this var self = this
var view = yo`<div class="${css.buttons}"> var view = yo`<div class="${css.buttons}">
<div class="${css.stepButtons}"> <div class="${css.stepButtons} btn-group p-1">
<button id='overback' title='Step over back' class='${css.navigator} ${css.stepButton} fa fa-reply' onclick=${function () { self.event.trigger('stepOverBack') }} disabled=${this.overBackDisabled} ></button> <button id='overback' class='btn btn-primary btn-sm' title='Step over back' class='${css.navigator} ${css.stepButton} fas fa-reply' onclick=${function () { self.event.trigger('stepOverBack') }} disabled=${this.overBackDisabled} ></button>
<button id='intoback' title='Step back' class='${css.navigator} ${css.stepButton} fa fa-level-up' onclick=${function () { self.event.trigger('stepIntoBack') }} disabled=${this.intoBackDisabled} ></button> <button id='intoback' class='btn btn-primary btn-sm' title='Step back' class='${css.navigator} ${css.stepButton} fas fa-level-up-alt' onclick=${function () { self.event.trigger('stepIntoBack') }} disabled=${this.intoBackDisabled} ></button>
<button id='intoforward' title='Step into' class='${css.navigator} ${css.stepButton} fa fa-level-down' onclick=${function () { self.event.trigger('stepIntoForward') }} disabled=${this.intoForwardDisabled} ></button> <button id='intoforward' class='btn btn-primary btn-sm' title='Step into' class='${css.navigator} ${css.stepButton} fas fa-level-down-alt' onclick=${function () { self.event.trigger('stepIntoForward') }} disabled=${this.intoForwardDisabled} ></button>
<button id='overforward' title='Step over forward' class='${css.navigator} ${css.stepButton} fa fa-share' onclick=${function () { self.event.trigger('stepOverForward') }} disabled=${this.overForwardDisabled} ></button> <button id='overforward' class='btn btn-primary btn-sm' title='Step over forward' class='${css.navigator} ${css.stepButton} fas fa-share' onclick=${function () { self.event.trigger('stepOverForward') }} disabled=${this.overForwardDisabled} ></button>
</div> </div>
<div class="${css.jumpButtons}"> <div class="${css.jumpButtons} btn-group p-1">
<button id='jumppreviousbreakpoint' title='Jump to the previous breakpoint' class='${css.navigator} ${css.jumpButton} fa fa-step-backward' onclick=${function () { self.event.trigger('jumpPreviousBreakpoint') }} disabled=${this.jumpPreviousBreakpointDisabled} ></button> <button class='btn btn-primary btn-sm' id='jumppreviousbreakpoint' title='Jump to the previous breakpoint' class='${css.navigator} ${css.jumpButton} fas fa-step-backward' onclick=${function () { self.event.trigger('jumpPreviousBreakpoint') }} disabled=${this.jumpPreviousBreakpointDisabled} ></button>
<button id='jumpout' title='Jump out' class='${css.navigator} ${css.jumpButton} fa fa-eject' onclick=${function () { self.event.trigger('jumpOut') }} disabled=${this.jumpOutDisabled} ></button> <button class='btn btn-primary btn-sm' id='jumpout' title='Jump out' class='${css.navigator} ${css.jumpButton} fas fa-eject' onclick=${function () { self.event.trigger('jumpOut') }} disabled=${this.jumpOutDisabled} ></button>
<button id='jumpnextbreakpoint' title='Jump to the next breakpoint' class='${css.navigator} ${css.jumpButton} fa fa-step-forward' onclick=${function () { self.event.trigger('jumpNextBreakpoint') }} disabled=${this.jumpNextBreakpointDisabled} ></button> <button class='btn btn-primary btn-sm' id='jumpnextbreakpoint' title='Jump to the next breakpoint' class='${css.navigator} ${css.jumpButton} fas fa-step-forward' onclick=${function () { self.event.trigger('jumpNextBreakpoint') }} disabled=${this.jumpNextBreakpointDisabled} ></button>
</div> </div>
<div id='reverted' style="display:none"> <div id='reverted' style="display:none">
<button id='jumptoexception' title='Jump to exception' class='${css.navigator} ${css.button} fa fa-exclamation-triangle' onclick=${function () { self.event.trigger('jumpToException') }} disabled=${this.jumpOutDisabled} > <button class='btn btn-danger btn-sm' id='jumptoexception' title='Jump to exception' class='${css.navigator} ${css.button} fas fa-exclamation-triangle' onclick=${function () { self.event.trigger('jumpToException') }} disabled=${this.jumpOutDisabled} >
</button> </button>
<span>State changes made during this call will be reverted.</span> <span>State changes made during this call will be reverted.</span>
<span id='outofgas' style="display:none">This call will run out of gas.</span> <span id='outofgas' style="display:none">This call will run out of gas.</span>
......
var EventManager = require('../../../lib/events') var EventManager = require('../../../lib/events')
var yo = require('yo-yo') var yo = require('yo-yo')
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.container { .container {
...@@ -19,7 +17,6 @@ var css = csjs` ...@@ -19,7 +17,6 @@ var css = csjs`
justify-content: center; justify-content: center;
} }
.txinput { .txinput {
${styles.rightPanel.debuggerTab.input_Debugger}
margin: 3px; margin: 3px;
width: inherit; width: inherit;
} }
...@@ -29,14 +26,11 @@ var css = csjs` ...@@ -29,14 +26,11 @@ var css = csjs`
justify-content: center; justify-content: center;
} }
.txbutton { .txbutton {
${styles.rightPanel.debuggerTab.button_Debugger}
width: inherit; width: inherit;
} }
.txbuttonstart { .txbuttonstart {
${styles.rightPanel.debuggerTab.button_Debugger}
} }
.txbutton:hover { .txbutton:hover {
color: ${styles.rightPanel.debuggerTab.button_Debugger_icon_HoverColor};
} }
.vmargin { .vmargin {
margin-top: 10px; margin-top: 10px;
...@@ -99,13 +93,13 @@ TxBrowser.prototype.render = function () { ...@@ -99,13 +93,13 @@ TxBrowser.prototype.render = function () {
var self = this var self = this
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}"> <div class="${css.txinputs} p-1 input-group">
<input class="${css.txinput}" onkeyup=${function () { self.updateBlockN(arguments[0]) }} type='text' placeholder=${'Block number'} /> <input class="form-control" class="${css.txinput}" onkeyup=${function () { self.updateBlockN(arguments[0]) }} type='text' placeholder=${'Block number'} />
<input class="${css.txinput}" id='txinput' onkeyup=${function () { self.updateTxN(arguments[0]) }} type='text' placeholder=${'Transaction index or 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}"> <div class="${css.txbuttons} btn-group p-1">
<button id='load' class='${css.txbutton}' title='start debugging' onclick=${function () { self.submit() }}>Start debugging</button> <button class='btn btn-primary btn-sm' id='load' class='${css.txbutton}' title='start debugging' onclick=${function () { self.submit() }}>Start debugging</button>
<button id='unload' class='${css.txbutton}' title='stop debugging' onclick=${function () { self.unload() }}>Stop</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>
......
...@@ -16,8 +16,6 @@ var DropdownPanel = require('./vmDebugger/DropdownPanel') ...@@ -16,8 +16,6 @@ var DropdownPanel = require('./vmDebugger/DropdownPanel')
var css = csjs` var css = csjs`
.asmCode { .asmCode {
float: left;
width: 50%;
} }
.stepDetail { .stepDetail {
} }
...@@ -123,10 +121,10 @@ function VmDebugger (vmDebuggerLogic) { ...@@ -123,10 +121,10 @@ function VmDebugger (vmDebuggerLogic) {
} }
VmDebugger.prototype.renderHead = function () { VmDebugger.prototype.renderHead = function () {
var headView = yo`<div id='vmheadView' class=${css.vmheadView}> var headView = yo`<div id='vmheadView' class="${css.vmheadView} container">
<div> <div class="row" >
<div class=${css.asmCode}>${this.asmCode.render()}</div> <div class="${css.asmCode} column">${this.asmCode.render()}</div>
<div class=${css.stepDetail}>${this.stepDetail.render()}</div> <div class="${css.stepDetail} column">${this.stepDetail.render()}</div>
</div> </div>
</div>` </div>`
if (!this.headView) { if (!this.headView) {
......
...@@ -4,12 +4,9 @@ var yo = require('yo-yo') ...@@ -4,12 +4,9 @@ var yo = require('yo-yo')
var DropdownPanel = require('./DropdownPanel') var DropdownPanel = require('./DropdownPanel')
var EventManager = require('../../../../lib/events') var EventManager = require('../../../../lib/events')
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.instructions { .instructions {
${styles.rightPanel.debuggerTab.box_Debugger}
overflow-y: scroll; overflow-y: scroll;
max-height: 150px; max-height: 150px;
} }
...@@ -43,7 +40,8 @@ CodeListView.prototype.indexChanged = function (index) { ...@@ -43,7 +40,8 @@ CodeListView.prototype.indexChanged = function (index) {
} }
} }
this.itemSelected = this.codeView.children[index] this.itemSelected = this.codeView.children[index]
this.itemSelected.setAttribute('style', 'background-color: ' + styles.rightPanel.debuggerTab.text_BgHighlight) this.itemSelected.style.setProperty('background-color', 'var(--info)')
this.itemSelected.style.setProperty('color', 'var(--light)')
this.itemSelected.setAttribute('selected', 'selected') this.itemSelected.setAttribute('selected', 'selected')
if (this.itemSelected.firstChild) { if (this.itemSelected.firstChild) {
this.itemSelected.firstChild.setAttribute('style', 'margin-left: 2px') this.itemSelected.firstChild.setAttribute('style', 'margin-left: 2px')
......
...@@ -5,13 +5,9 @@ var EventManager = require('../../../../lib/events') ...@@ -5,13 +5,9 @@ var EventManager = require('../../../../lib/events')
var TreeView = require('../../../ui/TreeView') // TODO setup a direct reference to the UI components var TreeView = require('../../../ui/TreeView') // TODO setup a direct reference to the UI components
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.title { .title {
margin-top: 10px;
${styles.rightPanel.debuggerTab.dropdown_Debugger};
display: flex; display: flex;
align-items: center; align-items: center;
} }
...@@ -23,18 +19,16 @@ var css = csjs` ...@@ -23,18 +19,16 @@ var css = csjs`
margin-left: 3px; margin-left: 3px;
} }
.icon { .icon {
color: ${styles.rightPanel.debuggerTab.button_Debugger_icon_Color};
margin-right: 5%; margin-right: 5%;
} }
.eyeButton { .eyeButton {
margin: 3px; margin: 3px;
} }
.eyeButton:hover { .eyeButton:hover {
color: ${styles.rightPanel.debuggerTab.button_Debugger_icon_HoverColor};
} }
.dropdownpanel { .dropdownpanel {
${styles.rightPanel.debuggerTab.dropdown_Debugger};
width: 100%; width: 100%;
word-break: break-all;
} }
.dropdownrawcontent { .dropdownrawcontent {
padding: 2px; padding: 2px;
...@@ -71,7 +65,7 @@ DropdownPanel.prototype.setMessage = function (message) { ...@@ -71,7 +65,7 @@ DropdownPanel.prototype.setMessage = function (message) {
if (!this.view) return if (!this.view) return
this.view.querySelector('.dropdownpanel .dropdownrawcontent').style.display = 'none' this.view.querySelector('.dropdownpanel .dropdownrawcontent').style.display = 'none'
this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'none' this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'none'
this.view.querySelector('.dropdownpanel .fa-refresh').style.display = 'none' this.view.querySelector('.dropdownpanel > i').style.display = 'none'
this.message(message) this.message(message)
} }
...@@ -79,20 +73,18 @@ DropdownPanel.prototype.setLoading = function () { ...@@ -79,20 +73,18 @@ DropdownPanel.prototype.setLoading = function () {
if (!this.view) return if (!this.view) return
this.view.querySelector('.dropdownpanel .dropdownrawcontent').style.display = 'none' this.view.querySelector('.dropdownpanel .dropdownrawcontent').style.display = 'none'
this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'none' this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'none'
this.view.querySelector('.dropdownpanel .fa-refresh').style.display = 'inline-block' this.view.querySelector('.dropdownpanel > i').style.display = 'inline-block'
this.message('') this.message('')
} }
DropdownPanel.prototype.setUpdating = function () { DropdownPanel.prototype.setUpdating = function () {
if (!this.view) return if (!this.view) return
this.view.querySelector('.dropdownpanel .dropdowncontent').style.color = styles.appProperties.greyedText_color
} }
DropdownPanel.prototype.update = function (_data, _header) { DropdownPanel.prototype.update = function (_data, _header) {
if (!this.view) return if (!this.view) return
this.view.querySelector('.dropdownpanel .fa-refresh').style.display = 'none' this.view.querySelector('.dropdownpanel > i').style.display = 'none'
this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'block' this.view.querySelector('.dropdownpanel .dropdowncontent').style.display = 'block'
this.view.querySelector('.dropdownpanel .dropdowncontent').style.color = styles.appProperties.mainText_Color
this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = JSON.stringify(_data, null, '\t') this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = JSON.stringify(_data, null, '\t')
if (!this.displayContentOnly) { if (!this.displayContentOnly) {
this.view.querySelector('.title div.btn').style.display = 'block' this.view.querySelector('.title div.btn').style.display = 'block'
...@@ -106,11 +98,10 @@ DropdownPanel.prototype.update = function (_data, _header) { ...@@ -106,11 +98,10 @@ DropdownPanel.prototype.update = function (_data, _header) {
DropdownPanel.prototype.setContent = function (node) { DropdownPanel.prototype.setContent = function (node) {
if (!this.view) return if (!this.view) return
var parent = this.view.querySelector('.dropdownpanel div.dropdowncontent') yo.update(this.view, this.render(null, node))
parent.replaceChild(node, parent.firstElementChild)
} }
DropdownPanel.prototype.render = function (overridestyle) { DropdownPanel.prototype.render = function (overridestyle, node) {
var content = yo`<div>Empty</div>` var content = yo`<div>Empty</div>`
if (this.json) { if (this.json) {
content = this.treeView.render({}) content = this.treeView.render({})
...@@ -118,19 +109,19 @@ DropdownPanel.prototype.render = function (overridestyle) { ...@@ -118,19 +109,19 @@ DropdownPanel.prototype.render = function (overridestyle) {
overridestyle === undefined ? {} : overridestyle overridestyle === undefined ? {} : overridestyle
var self = this var self = this
var title = !self.displayContentOnly ? yo`<div class="${css.title} title"> var title = !self.displayContentOnly ? yo`<div class="${css.title} title">
<div class="${css.icon} fa fa-caret-right" onclick=${function () { self.toggle() }} ></div> <div class="${css.icon} fas fa-caret-right" onclick=${function () { self.toggle() }} ></div>
<div class="${css.name}" onclick=${function () { self.toggle() }} >${this.name}</div><span class="${css.nameDetail}" onclick=${function () { self.toggle() }} ></span> <div class="${css.name}" onclick=${function () { self.toggle() }} >${this.name}</div><span class="${css.nameDetail}" onclick=${function () { self.toggle() }} ></span>
<div onclick=${function () { self.copyClipboard() }} title='raw' class="${css.eyeButton} btn fa fa-clipboard"></div> <div onclick=${function () { self.copyClipboard() }} title='raw' class="${css.eyeButton} btn far fa-clipboard"></div>
</div>` : yo`<div></div>` </div>` : yo`<div></div>`
var contentNode = yo`<div class='dropdownpanel' style='display:none'> var contentNode = yo`<div class='dropdownpanel ${css.dropdownpanel}' style='display:none'>
<i class="${css.refresh} fa fa-refresh" aria-hidden="true"></i> <i class="${css.refresh} fas fa-sync" aria-hidden="true"></i>
<div class='dropdowncontent'>${content}</div> <div class='dropdowncontent'>${node || content}</div>
<div class='dropdownrawcontent' style='display:none'></div> <div class='dropdownrawcontent' style='display:none'></div>
<div class='message' style='display:none'></div> <div class='message' style='display:none'></div>
</div>` </div>`
var view = yo` var view = yo`
<div> <div class="border border-primary rounded p-1 m-1">
<style> <style>
@-moz-keyframes spin { @-moz-keyframes spin {
to { -moz-transform: rotate(359deg); } to { -moz-transform: rotate(359deg); }
...@@ -162,11 +153,11 @@ DropdownPanel.prototype.toggle = function () { ...@@ -162,11 +153,11 @@ DropdownPanel.prototype.toggle = function () {
var caret = this.view.querySelector('.title').firstElementChild var caret = this.view.querySelector('.title').firstElementChild
if (el.style.display === '') { if (el.style.display === '') {
el.style.display = 'none' el.style.display = 'none'
caret.className = `${css.icon} fa fa-caret-right` caret.className = `${css.icon} fas fa-caret-right`
this.event.trigger('hide', []) this.event.trigger('hide', [])
} else { } else {
el.style.display = '' el.style.display = ''
caret.className = `${css.icon} fa fa-caret-down` caret.className = `${css.icon} fas fa-caret-down`
this.event.trigger('show', []) this.event.trigger('show', [])
} }
} }
...@@ -176,7 +167,7 @@ DropdownPanel.prototype.hide = function () { ...@@ -176,7 +167,7 @@ DropdownPanel.prototype.hide = function () {
var caret = this.view.querySelector('.title').firstElementChild var caret = this.view.querySelector('.title').firstElementChild
var el = this.view.querySelector('.dropdownpanel') var el = this.view.querySelector('.dropdownpanel')
el.style.display = 'none' el.style.display = 'none'
caret.className = `${css.icon} fa fa-caret-right` caret.className = `${css.icon} fas fa-caret-right`
this.event.trigger('hide', []) this.event.trigger('hide', [])
} }
...@@ -185,7 +176,7 @@ DropdownPanel.prototype.show = function () { ...@@ -185,7 +176,7 @@ DropdownPanel.prototype.show = function () {
var caret = this.view.querySelector('.title').firstElementChild var caret = this.view.querySelector('.title').firstElementChild
var el = this.view.querySelector('.dropdownpanel') var el = this.view.querySelector('.dropdownpanel')
el.style.display = '' el.style.display = ''
caret.className = `${css.icon} fa fa-caret-down` caret.className = `${css.icon} fas fa-caret-down`
this.event.trigger('show', []) this.event.trigger('show', [])
} }
......
'use strict'
const SourceHighlighter = require('./sourceHighlighter')
import { EditorApi } from 'remix-plugin'
const profile = {
displayName: 'source highlighters',
name: 'editor',
description: 'service - highlight source code'
}
// EditorApi:
// - methods: ['highlight', 'discardHighlight'],
class SourceHighlighters extends EditorApi {
constructor () {
super(profile)
this.highlighters = {}
}
highlight (position, filePath, hexColor) {
const { from } = this.currentRequest
try {
if (!this.highlighters[from]) this.highlighters[from] = new SourceHighlighter()
this.highlighters[from].currentSourceLocation(null)
this.highlighters[from].currentSourceLocationFromfileName(position, filePath, hexColor)
} catch (e) {
throw e
}
}
discardHighlight () {
const { from } = this.currentRequest
if (this.highlighters[from]) this.highlighters[from].currentSourceLocation(null)
}
}
module.exports = SourceHighlighters
'use strict' 'use strict'
var yo = require('yo-yo') const yo = require('yo-yo')
var remixLib = require('remix-lib') const remixLib = require('remix-lib')
var SourceMappingDecoder = remixLib.SourceMappingDecoder const SourceMappingDecoder = remixLib.SourceMappingDecoder
var globalRegistry = require('../../global/registry') const globalRegistry = require('../../global/registry')
var css = require('./styles/contextView-styles') const css = require('./styles/contextView-styles')
/* /*
Display information about the current focused code: Display information about the current focused code:
...@@ -15,37 +15,38 @@ var css = require('./styles/contextView-styles') ...@@ -15,37 +15,38 @@ var css = require('./styles/contextView-styles')
*/ */
class ContextView { class ContextView {
constructor (opts, localRegistry) { constructor (opts, localRegistry) {
const self = this this._components = {}
self._components = {} this._components.registry = localRegistry || globalRegistry
self._components.registry = localRegistry || globalRegistry this.contextualListener = opts.contextualListener
self.contextualListener = opts.contextualListener this.editor = opts.editor
self.editor = opts.editor this._deps = {
self._deps = { compilersArtefacts: this._components.registry.get('compilersartefacts').api,
compilersArtefacts: self._components.registry.get('compilersartefacts').api, offsetToLineColumnConverter: this._components.registry.get('offsettolinecolumnconverter').api,
offsetToLineColumnConverter: self._components.registry.get('offsettolinecolumnconverter').api, config: this._components.registry.get('config').api,
config: self._components.registry.get('config').api, fileManager: this._components.registry.get('filemanager').api
fileManager: self._components.registry.get('filemanager').api
} }
this._view this._view
this._nodes this._nodes
this._current this._current
this.sourceMappingDecoder = new SourceMappingDecoder() this.sourceMappingDecoder = new SourceMappingDecoder()
this.previousElement = null this.previousElement = null
self.contextualListener.event.register('contextChanged', nodes => { this.contextualListener.event.register('contextChanged', nodes => {
this.show()
this._nodes = nodes this._nodes = nodes
this.update() this.update()
}) })
this.contextualListener.event.register('stopHighlighting', () => {
})
} }
render () { render () {
var view = yo`<div class=${css.contextview}> const view = yo`<div class="${css.contextview} ${css.contextviewcontainer} badge bg-light border-0">
<div class=${css.container}> <div class=${css.container}>
${this._renderTarget()} ${this._renderTarget()}
</div> </div>
</div>` </div>`
if (!this._view) { if (!this._view) {
this._view = view this._view = view
this.hide()
} }
return view return view
} }
...@@ -65,18 +66,18 @@ class ContextView { ...@@ -65,18 +66,18 @@ class ContextView {
update () { update () {
if (this._view) { if (this._view) {
yo.update(this._view, this.render()) yo.update(this._view, this.render())
this._view.style.display = this._current ? 'block' : 'none'
} }
} }
_renderTarget () { _renderTarget () {
var previous = this._current let last
const previous = this._current
if (this._nodes && this._nodes.length) { if (this._nodes && this._nodes.length) {
var last = this._nodes[this._nodes.length - 1] last = this._nodes[this._nodes.length - 1]
if (isDefinition(last)) { if (isDefinition(last)) {
this._current = last this._current = last
} else { } else {
var target = this.contextualListener.declarationOf(last) const target = this.contextualListener.declarationOf(last)
if (target) { if (target) {
this._current = target this._current = target
} else { } else {
...@@ -91,27 +92,26 @@ class ContextView { ...@@ -91,27 +92,26 @@ class ContextView {
} }
_jumpToInternal (position) { _jumpToInternal (position) {
var self = this const jumpToLine = (lineColumn) => {
function jumpToLine (lineColumn) {
if (lineColumn.start && lineColumn.start.line && lineColumn.start.column) { if (lineColumn.start && lineColumn.start.line && lineColumn.start.column) {
self.editor.gotoLine(lineColumn.start.line, lineColumn.end.column + 1) this.editor.gotoLine(lineColumn.start.line, lineColumn.end.column + 1)
} }
} }
let lastCompilationResult = self._deps.compilersArtefacts['__last'] let lastCompilationResult = this._deps.compilersArtefacts['__last']
if (lastCompilationResult && lastCompilationResult.data) { if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
var lineColumn = self._deps.offsetToLineColumnConverter.offsetToLineColumn( const lineColumn = this._deps.offsetToLineColumnConverter.offsetToLineColumn(
position, position,
position.file, position.file,
lastCompilationResult.getSourceCode().sources, lastCompilationResult.getSourceCode().sources,
lastCompilationResult.getAsts()) lastCompilationResult.getAsts())
var filename = lastCompilationResult.getSourceName(position.file) const filename = lastCompilationResult.getSourceName(position.file)
// TODO: refactor with rendererAPI.errorClick // TODO: refactor with rendererAPI.errorClick
if (filename !== self._deps.config.get('currentFile')) { if (filename !== this._deps.config.get('currentFile')) {
var provider = self._deps.fileManager.fileProviderOf(filename) const provider = this._deps.fileManager.fileProviderOf(filename)
if (provider) { if (provider) {
provider.exists(filename, (error, exist) => { provider.exists(filename, (error, exist) => {
if (error) return console.log(error) if (error) return console.log(error)
self._deps.fileManager.switchFile(filename) this._deps.fileManager.switchFile(filename)
jumpToLine(lineColumn) jumpToLine(lineColumn)
}) })
} }
...@@ -123,14 +123,13 @@ class ContextView { ...@@ -123,14 +123,13 @@ class ContextView {
_render (node, nodeAtCursorPosition) { _render (node, nodeAtCursorPosition) {
if (!node) return yo`<div></div>` if (!node) return yo`<div></div>`
var self = this let references = this.contextualListener.referencesOf(node)
var references = self.contextualListener.referencesOf(node) const type = (node.attributes && node.attributes.type) ? node.attributes.type : node.name
var type = (node.attributes && node.attributes.type) ? node.attributes.type : node.name
references = `${references ? references.length : '0'} reference(s)` references = `${references ? references.length : '0'} reference(s)`
var ref = 0 let ref = 0
var nodes = self.contextualListener.getActiveHighlights() const nodes = this.contextualListener.getActiveHighlights()
for (var k in nodes) { for (const k in nodes) {
if (nodeAtCursorPosition.id === nodes[k].nodeId) { if (nodeAtCursorPosition.id === nodes[k].nodeId) {
ref = k ref = k
break break
...@@ -138,44 +137,43 @@ class ContextView { ...@@ -138,44 +137,43 @@ class ContextView {
} }
// JUMP BETWEEN REFERENCES // JUMP BETWEEN REFERENCES
function jump (e) { const jump = (e) => {
e.target.dataset.action === 'next' ? ref++ : ref-- e.target.dataset.action === 'next' ? ref++ : ref--
if (ref < 0) ref = nodes.length - 1 if (ref < 0) ref = nodes.length - 1
if (ref >= nodes.length) ref = 0 if (ref >= nodes.length) ref = 0
self._jumpToInternal(nodes[ref].position) this._jumpToInternal(nodes[ref].position)
} }
function jumpTo () { const jumpTo = () => {
if (node && node.src) { if (node && node.src) {
var position = self.sourceMappingDecoder.decode(node.src) const position = this.sourceMappingDecoder.decode(node.src)
if (position) { if (position) {
self._jumpToInternal(position) this._jumpToInternal(position)
} }
} }
} }
return yo`<div class=${css.line}> const showGasEstimation = () => {
<div title=${type} class=${css.type}>${type}</div>
<div title=${node.attributes.name} class=${css.name}>${node.attributes.name}</div>
<i class="fa fa-share ${css.jump}" aria-hidden="true" onclick=${jumpTo}></i>
<span class=${css.referencesnb}>${references}</span>
<i data-action='previous' class="fa fa-chevron-up ${css.jump}" aria-hidden="true" onclick=${jump}></i>
<i data-action='next' class="fa fa-chevron-down ${css.jump}" aria-hidden="true" onclick=${jump}></i>
${showGasEstimation()}
</div>`
function showGasEstimation () {
if (node.name === 'FunctionDefinition') { if (node.name === 'FunctionDefinition') {
var result = self.contextualListener.gasEstimation(node) const result = this.contextualListener.gasEstimation(node)
var executionCost = 'Execution cost: ' + result.executionCost + ' gas' const executionCost = 'Execution cost: ' + result.executionCost + ' gas'
var codeDepositCost = 'Code deposit cost: ' + result.codeDepositCost + ' gas' const codeDepositCost = 'Code deposit cost: ' + result.codeDepositCost + ' gas'
var estimatedGas = result.codeDepositCost ? `${codeDepositCost}, ${executionCost}` : `${executionCost}` const estimatedGas = result.codeDepositCost ? `${codeDepositCost}, ${executionCost}` : `${executionCost}`
return yo`<div class=${css.gasEstimation}> return yo`<div class=${css.gasEstimation}>
<img class=${css.gasStationIcon} title='Gas estimation' src='assets/img/gasStation_50.png'> <img class=${css.gasStationIcon} title='Gas estimation' src='assets/img/gasStation_50.png'>
${estimatedGas} ${estimatedGas}
</div>` </div>`
} }
} }
return yo`<div class=${css.line}>${showGasEstimation()}
<div title=${type} class=${css.type}>${type}</div>
<div title=${node.attributes.name} class=${css.name}>${node.attributes.name}</div>
<i class="fas fa-share ${css.jump}" aria-hidden="true" onclick=${jumpTo}></i>
<span class=${css.referencesnb}>${references}</span>
<i data-action='previous' class="fas fa-chevron-up ${css.jump}" aria-hidden="true" onclick=${jump}></i>
<i data-action='next' class="fas fa-chevron-down ${css.jump}" aria-hidden="true" onclick=${jump}></i>
</div>`
} }
} }
......
This diff is collapsed.
This diff is collapsed.
'use strict' 'use strict'
var csjs = require('csjs-inject') const csjs = require('csjs-inject')
var globlalRegistry = require('../../global/registry') const globlalRegistry = require('../../global/registry')
var styleGuide = require('../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
class SourceHighlighter { class SourceHighlighter {
constructor (localRegistry) { constructor (localRegistry) {
const self = this this._components = {}
self._components = {} this._components.registry = localRegistry || globlalRegistry
self._components.registry = localRegistry || globlalRegistry
// dependencies // dependencies
self._deps = { this._deps = {
editor: self._components.registry.get('editor').api, editor: this._components.registry.get('editor').api,
config: self._components.registry.get('config').api, config: this._components.registry.get('config').api,
fileManager: self._components.registry.get('filemanager').api, fileManager: this._components.registry.get('filemanager').api,
compilerArtefacts: self._components.registry.get('compilersartefacts').api compilerArtefacts: this._components.registry.get('compilersartefacts').api
} }
this.statementMarker = null this.statementMarker = null
this.fullLineMarker = null this.fullLineMarker = null
...@@ -26,7 +23,7 @@ class SourceHighlighter { ...@@ -26,7 +23,7 @@ class SourceHighlighter {
if (this.fullLineMarker) this._deps.editor.removeMarker(this.fullLineMarker, this.source) if (this.fullLineMarker) this._deps.editor.removeMarker(this.fullLineMarker, this.source)
let lastCompilationResult = this._deps.compilerArtefacts['__last'] let lastCompilationResult = this._deps.compilerArtefacts['__last']
if (location && location.file !== undefined && lastCompilationResult) { if (location && location.file !== undefined && lastCompilationResult) {
var path = lastCompilationResult.getSourceName(location.file) const path = lastCompilationResult.getSourceName(location.file)
if (path) { if (path) {
this.currentSourceLocationFromfileName(lineColumnPos, path) this.currentSourceLocationFromfileName(lineColumnPos, path)
} }
...@@ -45,21 +42,24 @@ class SourceHighlighter { ...@@ -45,21 +42,24 @@ class SourceHighlighter {
this._deps.fileManager.switchFile(this.source) this._deps.fileManager.switchFile(this.source)
} }
var css = csjs` const css = csjs`
.highlightcode { .highlightcode {
position:absolute; position:absolute;
z-index:20; z-index:20;
background-color: ${style || styles.editor.backgroundColor_DebuggerMode}; background-color: ${style || 'var(--info)'};
} }
.highlightcode_fullLine { .highlightcode_fullLine {
position:absolute; position:absolute;
z-index:20; z-index:20;
background-color: ${style || styles.editor.backgroundColor_DebuggerMode};
opacity: 0.5; opacity: 0.5;
background-color: ${style || 'var(--info)'};
}
.customBackgroundColor {
background-color: ${style || 'var(--info)'};
} }
` `
this.statementMarker = this._deps.editor.addMarker(lineColumnPos, this.source, css.highlightcode) this.statementMarker = this._deps.editor.addMarker(lineColumnPos, this.source, css.highlightcode.className + ' ' + css.customBackgroundColor.className)
this._deps.editor.scrollToLine(lineColumnPos.start.line, true, true, function () {}) this._deps.editor.scrollToLine(lineColumnPos.start.line, true, true, function () {})
if (lineColumnPos.start.line === lineColumnPos.end.line) { if (lineColumnPos.start.line === lineColumnPos.end.line) {
...@@ -72,7 +72,7 @@ class SourceHighlighter { ...@@ -72,7 +72,7 @@ class SourceHighlighter {
line: lineColumnPos.start.line + 1, line: lineColumnPos.start.line + 1,
column: 0 column: 0
} }
}, this.source, css.highlightcode_fullLine) }, this.source, css.highlightcode_fullLine.className)
} }
} }
} }
......
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.contextview { .contextview {
opacity : 0.8; opacity : 1;
} position : relative;
height : 20px;
}
.container { .container {
padding : 1px 15px; padding : 1px 15px;
} }
...@@ -16,8 +16,7 @@ var css = csjs` ...@@ -16,8 +16,7 @@ var css = csjs`
text-overflow : ellipsis; text-overflow : ellipsis;
overflow : hidden; overflow : hidden;
white-space : nowrap; white-space : nowrap;
color : ${styles.editor.text_Primary}; font-size : 13px;
font-size : 11px;
} }
.type { .type {
font-style : italic; font-style : italic;
...@@ -29,17 +28,16 @@ var css = csjs` ...@@ -29,17 +28,16 @@ var css = csjs`
.jump { .jump {
cursor : pointer; cursor : pointer;
margin : 0 5px; margin : 0 5px;
color : ${styles.editor.icon_Color_Editor};
} }
.jump:hover { .jump:hover {
color : ${styles.editor.icon_HoverColor_Editor}; color : var(--secondary);
} }
.referencesnb { .referencesnb {
float : right; float : right;
margin-left : 15px; margin-left : 15px;
} }
.gasEstimation { .gasEstimation {
margin-left: 15px; margin-right: 15px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
...@@ -47,6 +45,11 @@ var css = csjs` ...@@ -47,6 +45,11 @@ var css = csjs`
height: 13px; height: 13px;
margin-right: 5px; margin-right: 5px;
} }
.contextviewcontainer{
z-index : 50;
border-radius : 1px;
border : 2px solid var(--secondary);
}
` `
module.exports = css module.exports = css
var yo = require('yo-yo') var yo = require('yo-yo')
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../ui/styles-guide/theme-chooser') const copyToClipboard = require('../ui/copy-to-clipboard')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.txInfoBox { .txInfoBox {
${styles.rightPanel.compileTab.box_CompileContainer}; // add askToConfirmTXContainer to Remix and then replace this styling
} }
.wrapword { .wrapword {
white-space: pre-wrap; /* Since CSS 2.1 */ white-space: pre-wrap; /* Since CSS 2.1 */
...@@ -38,11 +36,11 @@ function confirmDialog (tx, amount, gasEstimation, self, newGasPriceCb, initialP ...@@ -38,11 +36,11 @@ function confirmDialog (tx, amount, gasEstimation, self, newGasPriceCb, initialP
<div>Gas price: <input id='gasprice' oninput=${onGasPriceChange} /> Gwei <span> (visit <a target='_blank' href='https://ethgasstation.info'>ethgasstation.info</a> to get more info about gas price)</span></div> <div>Gas price: <input id='gasprice' oninput=${onGasPriceChange} /> Gwei <span> (visit <a target='_blank' href='https://ethgasstation.info'>ethgasstation.info</a> to get more info about gas price)</span></div>
<div>Max transaction fee:<span id='txfee'></span></div> <div>Max transaction fee:<span id='txfee'></span></div>
<div>Data:</div> <div>Data:</div>
<pre class=${css.wrapword}>${tx.data}</pre> <pre class=${css.wrapword}>${tx.data && tx.data.length > 50 ? tx.data.substring(0, 49) + '...' : tx.data} ${copyToClipboard(() => { return tx.data })}</pre>
</div> </div>
<div class=${css.checkbox}> <div class=${css.checkbox}>
<input id='confirmsetting' type="checkbox"> <input id='confirmsetting' type="checkbox">
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Do not ask for confirmation again. (the setting will not be persisted for the next page reload) <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> Do not ask for confirmation again. (the setting will not be persisted for the next page reload)
</div> </div>
</div> </div>
` `
......
...@@ -5,8 +5,6 @@ var copyToClipboard = require('../ui/copy-to-clipboard') ...@@ -5,8 +5,6 @@ var copyToClipboard = require('../ui/copy-to-clipboard')
// -------------- styling ---------------------- // -------------- styling ----------------------
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var styleGuide = require('../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var EventManager = require('../../lib/events') var EventManager = require('../../lib/events')
var helper = require('../../lib/helper') var helper = require('../../lib/helper')
...@@ -26,14 +24,14 @@ var css = csjs` ...@@ -26,14 +24,14 @@ var css = csjs`
opacity: 0.8; opacity: 0.8;
} }
.arrow { .arrow {
color: ${styles.terminal.icon_Color_Menu}; color: var(--text-info);
font-size: 20px; font-size: 20px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
margin-left: 10px; margin-left: 10px;
} }
.arrow:hover { .arrow:hover {
color: ${styles.terminal.icon_HoverColor_Menu}; color: var(--secondary);
} }
.txLog { .txLog {
} }
...@@ -44,28 +42,27 @@ var css = csjs` ...@@ -44,28 +42,27 @@ var css = csjs`
float: left; float: left;
} }
.succeeded { .succeeded {
color: ${styles.terminal.icon_Color_Log_Succeed}; color: var(--success);
} }
.failed { .failed {
color: ${styles.terminal.icon_Color_Log_Failed}; color: var(--danger);
} }
.notavailable { .notavailable {
} }
.call { .call {
font-size: 7px; font-size: 7px;
background-color: ${styles.terminal.icon_BackgroundColor_Log_Call};
border-radius: 50%; border-radius: 50%;
min-width: 20px; min-width: 20px;
min-height: 20px; min-height: 20px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: ${styles.terminal.icon_Color_Log_Call}; color: var(--text-info);
text-transform: uppercase; text-transform: uppercase;
font-weight: bold; font-weight: bold;
} }
.txItem { .txItem {
color: ${styles.terminal.text_Primary}; color: var(--text-info);
margin-right: 5px; margin-right: 5px;
float: left; float: left;
} }
...@@ -73,7 +70,7 @@ var css = csjs` ...@@ -73,7 +70,7 @@ var css = csjs`
font-weight: bold; font-weight: bold;
} }
.tx { .tx {
color: ${styles.terminal.text_Title_TransactionLog}; color: var(--text-info);
font-weight: bold; font-weight: bold;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
...@@ -83,8 +80,8 @@ var css = csjs` ...@@ -83,8 +80,8 @@ var css = csjs`
.td { .td {
border-collapse: collapse; border-collapse: collapse;
font-size: 10px; font-size: 10px;
color: ${styles.terminal.text_Primary}; color: var(--text-info);
border: 1px solid ${styles.terminal.text_Secondary}; border: 1px solid var(--text-info);
} }
#txTable { #txTable {
margin-top: 1%; margin-top: 1%;
...@@ -110,12 +107,7 @@ var css = csjs` ...@@ -110,12 +107,7 @@ var css = csjs`
margin-left: auto; margin-left: auto;
} }
.debug { .debug {
${styles.terminal.button_Log_Debug} white-space: nowrap;
width: 55px;
min-width: 55px;
min-height: 20px;
max-height: 20px;
font-size: 11px;
} }
.debug:hover { .debug:hover {
opacity: 0.8; opacity: 0.8;
...@@ -142,8 +134,7 @@ class TxLogger { ...@@ -142,8 +134,7 @@ class TxLogger {
editorPanel: this._components.registry.get('editorpanel').api, editorPanel: this._components.registry.get('editorpanel').api,
txListener: this._components.registry.get('txlistener').api, txListener: this._components.registry.get('txlistener').api,
eventsDecoder: this._components.registry.get('eventsdecoder').api, eventsDecoder: this._components.registry.get('eventsdecoder').api,
compilersArtefacts: this._components.registry.get('compilersartefacts').api, compilersArtefacts: this._components.registry.get('compilersartefacts').api
app: this._components.registry.get('app').api
} }
this.logKnownTX = this._deps.editorPanel.registerCommand('knownTransaction', (args, cmds, append) => { this.logKnownTX = this._deps.editorPanel.registerCommand('knownTransaction', (args, cmds, append) => {
...@@ -171,24 +162,8 @@ class TxLogger { ...@@ -171,24 +162,8 @@ class TxLogger {
append(el) append(el)
}, { activate: true }) }, { activate: true })
this._deps.editorPanel.event.register('terminalFilterChanged', (type, label) => {
if (type === 'deselect') {
if (label === 'only remix transactions') {
this._deps.editorPanel.updateTerminalFilter({ type: 'select', value: 'unknownTransaction' })
} else if (label === 'all transactions') {
this._deps.editorPanel.updateTerminalFilter({ type: 'deselect', value: 'unknownTransaction' })
}
} else if (type === 'select') {
if (label === 'only remix transactions') {
this._deps.editorPanel.updateTerminalFilter({ type: 'deselect', value: 'unknownTransaction' })
} else if (label === 'all transactions') {
this._deps.editorPanel.updateTerminalFilter({ type: 'select', value: 'unknownTransaction' })
}
}
})
this._deps.txListener.event.register('newBlock', (block) => { this._deps.txListener.event.register('newBlock', (block) => {
if (!block.transactions.length) { if (!block.transactions || block.transactions && !block.transactions.length) {
this.logEmptyBlock({ block: block }) this.logEmptyBlock({ block: block })
} }
}) })
...@@ -200,6 +175,9 @@ class TxLogger { ...@@ -200,6 +175,9 @@ class TxLogger {
this._deps.txListener.event.register('newCall', (tx) => { this._deps.txListener.event.register('newCall', (tx) => {
log(this, tx, null) log(this, tx, null)
}) })
this._deps.editorPanel.updateTerminalFilter({ type: 'select', value: 'unknownTransaction' })
this._deps.editorPanel.updateTerminalFilter({ type: 'select', value: 'knownTransaction' })
} }
} }
...@@ -208,7 +186,7 @@ function debug (e, data, self) { ...@@ -208,7 +186,7 @@ function debug (e, data, self) {
if (data.tx.isCall && data.tx.envMode !== 'vm') { if (data.tx.isCall && data.tx.envMode !== 'vm') {
modalDialog.alert('Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.') modalDialog.alert('Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.')
} else { } else {
self._deps.app.startdebugging(data.tx.hash) self.event.trigger('debuggingRequested', [data.tx.hash])
} }
} }
...@@ -241,9 +219,9 @@ function renderKnownTransaction (self, data) { ...@@ -241,9 +219,9 @@ function renderKnownTransaction (self, data) {
${checkTxStatus(data.receipt, txType)} ${checkTxStatus(data.receipt, txType)}
${context(self, {from, to, data})} ${context(self, {from, to, data})}
<div class=${css.buttons}> <div class=${css.buttons}>
<div class=${css.debug} onclick=${(e) => debug(e, data, self)}>Debug</div> <button class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div> </div>
<i class="${css.arrow} fa fa-angle-down"></i> <i class="${css.arrow} fas fa-angle-down"></i>
</div> </div>
</span> </span>
` `
...@@ -267,9 +245,9 @@ function renderCall (self, data) { ...@@ -267,9 +245,9 @@ function renderCall (self, data) {
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> <div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div>
</span> </span>
<div class=${css.buttons}> <div class=${css.buttons}>
<div class=${css.debug} onclick=${(e) => debug(e, data, self)}>Debug</div> <div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div> </div>
<i class="${css.arrow} fa fa-angle-down"></i> <i class="${css.arrow} fas fa-angle-down"></i>
</div> </div>
</span> </span>
` `
...@@ -287,9 +265,9 @@ function renderUnknownTransaction (self, data) { ...@@ -287,9 +265,9 @@ function renderUnknownTransaction (self, data) {
${checkTxStatus(data.receipt || data.tx, txType)} ${checkTxStatus(data.receipt || data.tx, txType)}
${context(self, {from, to, data})} ${context(self, {from, to, data})}
<div class=${css.buttons}> <div class=${css.buttons}>
<div class=${css.debug} onclick=${(e) => debug(e, data, self)}>Debug</div> <div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div> </div>
<i class="${css.arrow} fa fa-angle-down"></i> <i class="${css.arrow} fas fa-angle-down"></i>
</div> </div>
</span> </span>
` `
...@@ -305,14 +283,14 @@ function renderEmptyBlock (self, data) { ...@@ -305,14 +283,14 @@ function renderEmptyBlock (self, data) {
function checkTxStatus (tx, type) { function checkTxStatus (tx, type) {
if (tx.status === '0x1') { if (tx.status === '0x1') {
return yo`<i class="${css.txStatus} ${css.succeeded} fa fa-check-circle"></i>` return yo`<i class="${css.txStatus} ${css.succeeded} fas fa-check-circle"></i>`
} }
if (type === 'call' || type === 'unknownCall') { if (type === 'call' || type === 'unknownCall') {
return yo`<i class="${css.txStatus} ${css.call}">call</i>` return yo`<i class="${css.txStatus} ${css.call}">call</i>`
} else if (tx.status === '0x0') { } else if (tx.status === '0x0') {
return yo`<i class="${css.txStatus} ${css.failed} fa fa-times-circle"></i>` return yo`<i class="${css.txStatus} ${css.failed} fas fa-times-circle"></i>`
} else { } else {
return yo`<i class="${css.txStatus} ${css.notavailable} fa fa-circle-thin" title='Status not available' ></i>` return yo`<i class="${css.txStatus} ${css.notavailable} fas fa-circle-thin" title='Status not available' ></i>`
} }
} }
...@@ -379,8 +357,8 @@ function txDetails (e, tx, data, obj) { ...@@ -379,8 +357,8 @@ function txDetails (e, tx, data, obj) {
var to = obj.to var to = obj.to
var log = document.querySelector(`#${tx.id} [class^='log']`) var log = document.querySelector(`#${tx.id} [class^='log']`)
var arrow = document.querySelector(`#${tx.id} [class^='arrow']`) var arrow = document.querySelector(`#${tx.id} [class^='arrow']`)
var arrowUp = yo`<i class="${css.arrow} fa fa-angle-up"></i>` var arrowUp = yo`<i class="${css.arrow} fas fa-angle-up"></i>`
var arrowDown = yo`<i class="${css.arrow} fa fa-angle-down"></i>` var arrowDown = yo`<i class="${css.arrow} fas fa-angle-down"></i>`
if (table && table.parentNode) { if (table && table.parentNode) {
tx.removeChild(table) tx.removeChild(table)
log.removeChild(arrow) log.removeChild(arrow)
......
...@@ -2,21 +2,30 @@ ...@@ -2,21 +2,30 @@
var EventManager = require('../../lib/events') var EventManager = require('../../lib/events')
function FilesTree (name, storage) { import { BaseApi } from 'remix-plugin'
var self = this
var event = new EventManager() class FilesTree extends BaseApi {
this.event = event constructor (name, storage) {
this.type = name super({
this.structFile = '.' + name + '.tree' name: name,
this.tree = {} methods: ['get', 'set', 'remove'],
description:
this.exists = function (path, cb) { 'service - read/write file to the `config` explorer without need of additionnal permission.'
})
this.event = new EventManager()
this.storage = storage
this.type = name
this.structFile = '.' + name + '.tree'
this.tree = {}
}
exists (path, cb) {
cb(null, this._exists(path)) cb(null, this._exists(path))
} }
function updateRefs (path, type) { updateRefs (path, type) {
var split = path.split('/') // this should be unprefixed path var split = path.split('/') // this should be unprefixed path
var crawlpath = self.tree var crawlpath = this.tree
var intermediatePath = '' var intermediatePath = ''
split.forEach((pathPart, index) => { split.forEach((pathPart, index) => {
intermediatePath += pathPart intermediatePath += pathPart
...@@ -30,91 +39,94 @@ function FilesTree (name, storage) { ...@@ -30,91 +39,94 @@ function FilesTree (name, storage) {
delete crawlpath[intermediatePath] delete crawlpath[intermediatePath]
} }
}) })
storage.set(self.structFile, JSON.stringify(self.tree)) this.storage.set(this.structFile, JSON.stringify(this.tree))
} }
this._exists = function (path) { _exists (path) {
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
return storage.exists(unprefixedpath) return this.storage.exists(unprefixedpath)
} }
this.init = function (cb) { init (cb) {
var tree = storage.get(this.structFile) var tree = this.storage.get(this.structFile)
this.tree = tree ? JSON.parse(tree) : {} this.tree = tree ? JSON.parse(tree) : {}
if (cb) cb() if (cb) cb()
} }
this.get = function (path, cb) { get (path, cb) {
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
var content = storage.get(unprefixedpath) var content = this.storage.get(unprefixedpath)
if (cb) { if (cb) {
cb(null, content) cb(null, content)
} }
return content return content
} }
this.set = function (path, content, cb) { set (path, content, cb) {
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
updateRefs(unprefixedpath, 'add') this.updateRefs(unprefixedpath, 'add')
var exists = storage.exists(unprefixedpath) var exists = this.storage.exists(unprefixedpath)
if (!storage.set(unprefixedpath, content)) { if (!this.storage.set(unprefixedpath, content)) {
if (cb) cb('error updating ' + path) if (cb) cb('error updating ' + path)
return false return false
} }
if (!exists) { if (!exists) {
event.trigger('fileAdded', [this.type + '/' + unprefixedpath, false]) this.event.trigger('fileAdded', [this.type + '/' + unprefixedpath, false])
} else { } else {
event.trigger('fileChanged', [this.type + '/' + unprefixedpath]) this.event.trigger('fileChanged', [this.type + '/' + unprefixedpath])
} }
if (cb) cb() if (cb) cb()
return true return true
} }
this.addReadOnly = function (path, content) { addReadOnly (path, content) {
return this.set(path, content) return this.set(path, content)
} }
this.isReadOnly = function (path) { isReadOnly (path) {
return false return false
} }
this.remove = function (path) { remove (path) {
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
updateRefs(unprefixedpath, 'remove') this.updateRefs(unprefixedpath, 'remove')
if (!this._exists(unprefixedpath)) { if (!this._exists(unprefixedpath)) {
return false return false
} }
if (!storage.remove(unprefixedpath)) { if (!this.storage.remove(unprefixedpath)) {
return false return false
} }
event.trigger('fileRemoved', [this.type + '/' + unprefixedpath]) this.event.trigger('fileRemoved', [this.type + '/' + unprefixedpath])
return true return true
} }
this.rename = function (oldPath, newPath, isFolder) { rename (oldPath, newPath, isFolder) {
var unprefixedoldPath = this.removePrefix(oldPath) var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath) var unprefixednewPath = this.removePrefix(newPath)
updateRefs(unprefixedoldPath, 'remove') this.updateRefs(unprefixedoldPath, 'remove')
updateRefs(unprefixednewPath, 'add') this.updateRefs(unprefixednewPath, 'add')
if (storage.exists(unprefixedoldPath)) { if (this.storage.exists(unprefixedoldPath)) {
if (!storage.rename(unprefixedoldPath, unprefixednewPath)) { if (!this.storage.rename(unprefixedoldPath, unprefixednewPath)) {
return false return false
} }
event.trigger('fileRenamed', [this.type + '/' + unprefixedoldPath, this.type + '/' + unprefixednewPath, isFolder]) this.event.trigger('fileRenamed', [
this.type + '/' + unprefixedoldPath,
this.type + '/' + unprefixednewPath,
isFolder
])
return true return true
} }
return false return false
} }
this.resolveDirectory = function (path, callback) { resolveDirectory (path, callback) {
var self = this
if (path[0] === '/') path = path.substring(1) if (path[0] === '/') path = path.substring(1)
if (!path) return callback(null, { [self.type]: { } }) if (!path) return callback(null, { [this.type]: {} })
var tree = {} var tree = {}
path = self.removePrefix(path) path = this.removePrefix(path)
var split = path.split('/') // this should be unprefixed path var split = path.split('/') // this should be unprefixed path
var crawlpath = self.tree var crawlpath = this.tree
split.forEach((pathPart, index) => { split.forEach((pathPart, index) => {
if (crawlpath[pathPart]) crawlpath = crawlpath[pathPart] if (crawlpath[pathPart]) crawlpath = crawlpath[pathPart]
}) })
...@@ -125,7 +137,7 @@ function FilesTree (name, storage) { ...@@ -125,7 +137,7 @@ function FilesTree (name, storage) {
callback(null, tree) callback(null, tree)
} }
this.removePrefix = function (path) { removePrefix (path) {
path = path.indexOf(this.type) === 0 ? path.replace(this.type, '') : path path = path.indexOf(this.type) === 0 ? path.replace(this.type, '') : path
if (path[0] === '/') return path.substring(1) if (path[0] === '/') return path.substring(1)
return path return path
......
This diff is collapsed.
This diff is collapsed.
let globalRegistry = require('../../global/registry')
import { BaseApi } from 'remix-plugin'
var yo = require('yo-yo')
var modalDialog = require('../ui/modaldialog')
var modalDialogCustom = require('../ui/modal-dialog-custom')
var csjs = require('csjs-inject')
var css = csjs`
.dialog {
display: flex;
flex-direction: column;
}
.dialogParagraph {
margin-bottom: 2em;
word-break: break-word;
}
`
const profile = {
name: 'remixd',
methods: [],
events: [],
description: 'using Remixd daemon, allow to access file system',
kind: 'other'
}
export class RemixdHandle extends BaseApi {
constructor (fileSystemExplorer, locahostProvider) {
super(profile)
this.fileSystemExplorer = fileSystemExplorer
this.locahostProvider = locahostProvider
}
deactivate () {
this.locahostProvider.close((error) => {
if (error) console.log(error)
})
}
activate () {
this.connectToLocalhost()
}
canceled () {
let appManager = globalRegistry.get('appmanager').api
appManager.ensureDeactivated('remixd')
}
/**
* connect to localhost if no connection and render the explorer
* disconnect from localhost if connected and remove the explorer
*
* @param {String} txHash - hash of the transaction
*/
connectToLocalhost () {
if (this.locahostProvider.isConnected()) {
this.locahostProvider.close((error) => {
if (error) console.log(error)
})
} else {
modalDialog(
'Connect to localhost',
remixdDialog(),
{ label: 'Connect',
fn: () => {
this.locahostProvider.init((error) => {
if (error) {
console.log(error)
modalDialogCustom.alert(
'Cannot connect to the remixd daemon.' +
'Please make sure you have the remixd running in the background.'
)
this.canceled()
} else {
this.fileSystemExplorer.ensureRoot()
}
})
}
},
{ label: 'Cancel',
fn: () => {
this.canceled()
}
}
)
}
}
}
function remixdDialog () {
return yo`
<div class=${css.dialog}>
<div class=${css.dialogParagraph}>Interact with your file system from Remix. Click connect and find shared folder in the Remix file explorer (under localhost).
Before you get started, check out <a target="_blank" href="https://remix.readthedocs.io/en/latest/tutorial_remixd_filesystem.html">Tutorial_remixd_filesystem</a>
to find out how to run Remixd.
</div>
<div class=${css.dialogParagraph}>Connection will start a session between <em>${window.location.href}</em> and your local file system <i>ws://127.0.0.1:65520</i>
so please make sure your system is secured enough (port 65520 neither opened nor forwarded).
<i class="fas fa-link"></i> will show you current connection status.
</div>
<div class=${css.dialogParagraph}>This feature is still in Alpha, so we recommend you to keep a copy of the shared folder.</div>
</div>
`
}
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.label {
margin-top : 4px
}
.fileexplorer { .fileexplorer {
box-sizing : border-box; box-sizing : border-box;
} }
...@@ -15,13 +16,26 @@ var css = csjs` ...@@ -15,13 +16,26 @@ var css = csjs`
cursor : pointer; cursor : pointer;
} }
.file { .file {
color : ${styles.leftPanel.text_Teriary}; padding : 4px;
}
.newFile {
padding-right : 10px;
}
.newFile i {
cursor : pointer;
}
.newFile:hover {
transform : scale(1.3);
}
.menu {
margin-left : 20px;
}
.items {
display : inline
} }
.hasFocus { .hasFocus {
background-color : ${styles.leftPanel.backgroundColor_FileExplorer};
} }
.rename { .rename {
background-color : ${styles.leftPanel.backgroundColor_Panel};
} }
.remove { .remove {
margin-left : auto; margin-left : auto;
......
This diff is collapsed.
This diff is collapsed.
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const EventManager = require('../../lib/events')
var globalRegistry = require('../../global/registry')
const styleguide = require('../ui/styles-guide/theme-chooser')
const TabbedMenu = require('../tabs/tabbed-menu')
const PluginTab = require('../tabs/plugin-tab')
const DraggableContent = require('../ui/draggableContent')
const styles = styleguide.chooser()
const css = csjs`
.righthandpanel {
display : flex;
flex-direction : column;
top : 0;
right : 0;
bottom : 0;
box-sizing : border-box;
overflow : hidden;
height : 100%;
}
.header {
height : 100%;
}
.dragbar {
position : absolute;
width : ${styles.rightPanel.dragbarWidth};
top : 3em;
bottom : 0;
cursor : col-resize;
background-color : ${styles.rightPanel.dragbarBackgroundColor};
z-index : 999;
border-left : 2px solid ${styles.rightPanel.bar_Dragging};
}
.ghostbar {
width : 3px;
background-color : ${styles.rightPanel.bar_Ghost};
opacity : 0.5;
position : absolute;
cursor : col-resize;
z-index : 9999;
top : 0;
bottom : 0;
}
`
class RighthandPanel {
constructor ({pluginManager, tabs}, localRegistry) {
const self = this
self._components = {}
self._components.registry = localRegistry || globalRegistry
self._components.registry.put({api: this, name: 'righthandpanel'})
self.event = new EventManager()
self._view = {
element: null,
tabbedMenu: null,
tabbedMenuViewport: null,
dragbar: null
}
var tabbedMenu = new TabbedMenu(self._components.registry)
self._components = {
tabbedMenu: tabbedMenu,
tabs
}
self._components.tabs.settings.event.register('plugin-loadRequest', json => {
self.loadPlugin(json)
})
self.loadPlugin = function (json) {
var modal = new DraggableContent(() => {
pluginManager.unregister(json)
})
var tab = new PluginTab(json)
var content = tab.render()
document.querySelector('body').appendChild(modal.render(json.title, json.url, content))
pluginManager.register(json, modal, content)
}
self._view.dragbar = yo`<div id="dragbar" class=${css.dragbar}></div>`
self._view.element = yo`
<div id="righthand-panel" class=${css.righthandpanel}>
${self._view.dragbar}
<div id="header" class=${css.header}>
${self._components.tabbedMenu.render()}
${self._components.tabbedMenu.renderViewport()}
</div>
</div>`
const { compile, run, settings, analysis, debug, support, test } = tabs
self._components.tabbedMenu.addTab('Compile', 'compileView', compile.render())
self._components.tabbedMenu.addTab('Run', 'runView', run.render())
self._components.tabbedMenu.addTab('Analysis', 'staticanalysisView', analysis.render())
self._components.tabbedMenu.addTab('Testing', 'testView', test.render())
self._components.tabbedMenu.addTab('Debugger', 'debugView', debug.render())
self._components.tabbedMenu.addTab('Settings', 'settingsView', settings.render())
self._components.tabbedMenu.addTab('Support', 'supportView', support.render())
self._components.tabbedMenu.selectTabByTitle('Compile')
}
render () {
const self = this
if (self._view.element) return self._view.element
return self._view.element
}
debugger () {
return this._components.tabs.debug.debugger()
}
focusOn (x) {
if (this._components.tabbedMenu) this._components.tabbedMenu.selectTabByClassName(x)
}
init () {
// @TODO: init is for resizable drag bar only and should be refactored in the future
const self = this
const limit = 60
self._view.dragbar.addEventListener('mousedown', mousedown)
const ghostbar = yo`<div class=${css.ghostbar}></div>`
function mousedown (event) {
event.preventDefault()
if (event.which === 1) {
moveGhostbar(event)
document.body.appendChild(ghostbar)
document.addEventListener('mousemove', moveGhostbar)
document.addEventListener('mouseup', removeGhostbar)
document.addEventListener('keydown', cancelGhostbar)
}
}
function cancelGhostbar (event) {
if (event.keyCode === 27) {
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
}
}
function getPosition (event) {
const lhp = window['filepanel'].offsetWidth
const max = document.body.offsetWidth - limit
var newpos = (event.pageX > max) ? max : event.pageX
newpos = (newpos > (lhp + limit)) ? newpos : lhp + limit
return newpos
}
function moveGhostbar (event) { // @NOTE VERTICAL ghostbar
ghostbar.style.left = getPosition(event) + 'px'
}
function removeGhostbar (event) {
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
self.event.trigger('resize', [document.body.offsetWidth - getPosition(event)])
}
}
}
module.exports = RighthandPanel
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var cssTabs = yo`
<style>
#files .file {
padding: 0 0.6em;
box-sizing: border-box;
background-color: ${styles.editor.backgroundColor_Tabs_Highlights};
cursor: pointer;
margin-right: 10px;
margin-top: 5px;
position: relative;
display: table-cell;
text-align: center;
vertical-align: middle;
color: ${styles.editor.text_Teriary};
}
#files .file.active {
color: ${styles.editor.text_Primary};
font-weight: bold;
border-bottom: 0 none;
padding-right: 1.5em;
}
#files .file .remove {
font-size: 12px;
display: flex;
color: ${styles.editor.text_Primary};
position: absolute;
top: -7px;
right: 5px;
display: none;
}
#files .file input {
background-color: ${styles.colors.transparent};
border: 0 none;
border-bottom: 1px dotted ${styles.editor.text_Primary};
line-height: 1em;
margin: 0.5em 0;
}
#files .file.active .remove {
display: inline-block;
color: ${styles.editor.text_Primary};
}
</style>
`
var css = csjs`
.editorpanel {
display : flex;
flex-direction : column;
height : 100%;
}
.tabsbar {
background-color : ${styles.editor.backgroundColor_Panel};
display : flex;
overflow : hidden;
height : 30px;
}
.tabs {
position : relative;
display : flex;
margin : 0;
left : 10px;
margin-right : 10px;
width : 100%;
overflow : hidden;
}
.files {
display : flex;
position : relative;
list-style : none;
margin : 0;
font-size : 15px;
height : 2.5em;
box-sizing : border-box;
line-height : 2em;
top : 0;
border-bottom : 0 none;
}
.changeeditorfontsize {
margin : 0;
font-size : 9px;
margin-top : 0.5em;
}
.changeeditorfontsize i {
cursor : pointer;
display : block;
color : ${styles.editor.icon_Color_Editor};
}
.changeeditorfontsize i {
cursor : pointer;
}
.changeeditorfontsize i:hover {
color : ${styles.editor.icon_HoverColor_Editor};
}
.buttons {
display : flex;
flex-direction : row;
justify-content : space-around;
align-items : center;
min-width : 45px;
}
.toggleLHP {
display : flex;
padding : 10px;
width : 100%;
font-weight : bold;
color : ${styles.leftPanel.icon_Color_TogglePanel};
}
.toggleLHP i {
cursor : pointer;
font-size : 14px;
font-weight : bold;
}
.toggleLHP i:hover {
color : ${styles.leftPanel.icon_HoverColor_TogglePanel};
}
.scroller {
position : absolute;
z-index : 999;
text-align : center;
cursor : pointer;
vertical-align : middle;
background-color : ${styles.colors.general_BackgroundColor};
height : 100%;
font-size : 1.3em;
color : orange;
}
.scrollerright {
right : 0;
margin-right : 15px;
}
.scrollerleft {
left : 0;
}
.toggleRHP {
margin : 0.5em;
font-weight : bold;
color : ${styles.rightPanel.icon_Color_TogglePanel};
right : 0;
}
.toggleRHP i {
cursor : pointer;
font-size : 14px;
font-weight : bold;
}
.toggleRHP i:hover {
color : ${styles.rightPanel.icon_HoverColor_TogglePanel};
}
.show {
opacity : 1;
transition : .3s opacity ease-in;
}
.hide {
opacity : 0;
pointer-events : none;
transition : .3s opacity ease-in;
}
.content {
position : relative;
display : flex;
flex-direction : column;
height : 100%;
width : 100%;
}
.contextviewcontainer{
width : 100%;
height : 20px;
background-color : ${styles.editor.backgroundColor_Tabs_Highlights};
}
`
module.exports = {
cssTabs: cssTabs,
css: css
}
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.container { .container {
...@@ -15,22 +13,8 @@ var css = csjs` ...@@ -15,22 +13,8 @@ var css = csjs`
flex-direction : column; flex-direction : column;
position : relative; position : relative;
width : 100%; width : 100%;
} padding-left : 6px;
.menu { padding-top : 6px;
margin-top : -0.2em;
flex-shrink : 0;
display : flex;
flex-direction : row;
min-width : 160px;
}
.newFile {
padding : 10px;
}
.newFile i {
cursor : pointer;
}
.newFile i:hover {
color : ${styles.colors.orange};
} }
.gist { .gist {
padding : 10px; padding : 10px;
...@@ -57,49 +41,25 @@ var css = csjs` ...@@ -57,49 +41,25 @@ var css = csjs`
cursor : pointer; cursor : pointer;
} }
.connectToLocalhost i:hover { .connectToLocalhost i:hover {
color : ${styles.colors.orange}; color : var(--secondary)
} }
.uploadFile { .uploadFile {
padding : 10px; padding : 10px;
} }
.uploadFile label:hover { .uploadFile label:hover {
color : ${styles.colors.orange}; color : var(--secondary)
} }
.uploadFile label { .uploadFile label {
cursor : pointer; cursor : pointer;
} }
.treeview { .treeview {
background-color : ${styles.colors.general_BackgroundColor};
}
.treeviews {
overflow-y : auto; overflow-y : auto;
} }
.dragbar {
position : absolute;
top : 29px;
width : 0.5em;
right : 0;
bottom : 0;
cursor : col-resize;
z-index : 999;
border-right : ${styles.leftPanel.dragbarBorderRight};
}
.ghostbar {
width : 3px;
background-color : ${styles.colors.lightBlue};
opacity : 0.5;
position : absolute;
cursor : col-resize;
z-index : 9999;
top : 0;
bottom : 0;
}
.dialog { .dialog {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.dialogParagraph { .dialogParagraph {
${styles.infoTextBox}
margin-bottom: 2em; margin-bottom: 2em;
word-break: break-word; word-break: break-word;
} }
......
This diff is collapsed.
var yo = require('yo-yo')
var $ = require('jquery')
const EventEmitter = require('events')
require('remix-tabs')
export class TabProxy {
constructor (fileManager, editor, appStore, appManager) {
this.event = new EventEmitter()
this.fileManager = fileManager
this.appManager = appManager
this.editor = editor
this.data = {}
this._view = {}
this._handlers = {}
fileManager.events.on('fileRemoved', (name) => {
this.removeTab(name)
})
fileManager.events.on('fileClosed', (name) => {
this.removeTab(name)
})
fileManager.events.on('currentFileChanged', (file) => {
if (this._handlers[file]) {
this._view.filetabs.activateTab(file)
return
}
this.addTab(file, '', () => {
this.fileManager.switchFile(file)
this.event.emit('switchFile', file)
},
() => {
this.fileManager.closeFile(file)
this.event.emit('closeFile', file)
})
})
fileManager.events.on('fileRenamed', (oldName, newName) => {
this.removeTab(oldName)
this.addTab(newName, '', () => {
this.fileManager.switchFile(newName)
this.event.emit('switchFile', newName)
},
() => {
this.fileManager.closeFile(newName)
this.event.emit('closeFile', newName)
})
})
appStore.event.on('activate', (name) => {
const { profile } = appStore.getOne(name)
if (profile.location === 'mainPanel') {
this.addTab(
name,
profile.displayName,
() => this.event.emit('switchApp', name),
() => {
this.event.emit('closeApp', name)
this.appManager.deactivateOne(name)
}
)
this.switchTab(name)
}
})
appStore.event.on('deactivate', (name) => {
this.removeTab(name)
})
}
switchTab (tabName) {
if (this._handlers[tabName]) {
this._handlers[tabName].switchTo()
this._view.filetabs.activateTab(tabName)
}
}
switchNextTab () {
const active = this._view.filetabs.active
if (active && this._handlers[active]) {
const handlers = Object.keys(this._handlers)
let i = handlers.indexOf(active)
if (i >= 0) {
i = handlers[i + 1] ? i + 1 : 0
this.switchTab(handlers[i])
}
}
}
switchPreviousTab () {
const active = this._view.filetabs.active
if (active && this._handlers[active]) {
const handlers = Object.keys(this._handlers)
let i = handlers.indexOf(active)
if (i >= 0) {
i = handlers[i - 1] ? i - 1 : handlers.length - 1
this.switchTab(handlers[i])
}
}
}
showTab (name) {
this._view.filetabs.activateTab(name)
}
addTab (name, title, switchTo, close, kind) {
if (this._handlers[name]) return
var slash = name.split('/')
if (!title) {
title = name.indexOf('/') !== -1 ? slash[slash.length - 1] : name
}
this._view.filetabs.addTab({
id: name,
title,
icon: '',
tooltip: name
})
this._handlers[name] = { switchTo, close }
}
removeTab (name) {
this._view.filetabs.removeTab(name)
delete this._handlers[name]
}
addHandler (type, fn) {
this.handlers[type] = fn
}
renderTabsbar () {
this._view.filetabs = yo`<remix-tabs></remix-tabs>`
this._view.filetabs.addEventListener('tabClosed', (event) => {
if (this._handlers[event.detail]) this._handlers[event.detail].close()
})
this._view.filetabs.addEventListener('tabActivated', (event) => {
if (this._handlers[event.detail]) this._handlers[event.detail].switchTo()
})
this._view.filetabs.canAdd = false
this._view.tabs = yo`
<div style="width: 100%; height: 100%;">
${this._view.filetabs}
</div>
`
let tabsbar = yo`
<div class="d-flex align-items-center" style="max-height: 35px; height: 100%">
${this._view.tabs}
</div>
`
// tabs
var $filesEl = $(this._view.filetabs)
// Switch tab
var self = this
$filesEl.on('click', '.file:not(.active)', function (ev) {
ev.preventDefault()
var name = $(this).find('.name').text()
self._handlers[name].switchTo()
return false
})
// Remove current tab
$filesEl.on('click', '.file .remove', function (ev) {
ev.preventDefault()
var name = $(this).parent().find('.name').text()
self._handlers[name].close()
return false
})
return tabsbar
}
}
This diff is collapsed.
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);
}
}return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var RemixExtension = function () {
function RemixExtension() {
var _this = this;
_classCallCheck(this, RemixExtension);
this._notifications = {};
this._pendingRequests = {};
this._id = 0;
window.addEventListener('message', function (event) {
return _this._newMessage(event);
}, false);
}
_createClass(RemixExtension, [{
key: 'listen',
value: function listen(key, type, callback) {
if (!this._notifications[key]) this._notifications[key] = {};
this._notifications[key][type] = callback;
}
}, {
key: 'call',
value: function call(key, type, params, callback) {
this._id++;
this._pendingRequests[this._id] = callback;
window.parent.postMessage(JSON.stringify({
action: 'request',
key: key,
type: type,
value: params,
id: this._id
}), '*');
}
}, {
key: '_newMessage',
value: function _newMessage(event) {
if (!event.data) return;
if (typeof event.data !== 'string') return;
var msg;
try {
msg = JSON.parse(event.data);
} catch (e) {
return console.log('unable to parse data');
}
var _msg = msg,
action = _msg.action,
key = _msg.key,
type = _msg.type,
value = _msg.value;
if (action === 'notification') {
if (this._notifications[key] && this._notifications[key][type]) {
this._notifications[key][type](value);
}
} else if (action === 'response') {
var _msg2 = msg,
id = _msg2.id,
error = _msg2.error;
if (this._pendingRequests[id]) {
this._pendingRequests[id](error, value);
delete this._pendingRequests[id];
}
}
}
}]);
return RemixExtension;
}();
if (window) window.RemixExtension = RemixExtension;
if (module && module.exports) module.exports = RemixExtension;
},{}]},{},[1]);
'use strict'
class RemixExtension {
constructor () {
this._notifications = {}
this._pendingRequests = {}
this._id = 0
window.addEventListener('message', (event) => this._newMessage(event), false)
}
listen (key, type, callback) {
if (!this._notifications[key]) this._notifications[key] = {}
this._notifications[key][type] = callback
}
call (key, type, params, callback) {
this._id++
this._pendingRequests[this._id] = callback
window.parent.postMessage(JSON.stringify({
action: 'request',
key,
type,
value: params,
id: this._id
}), '*')
}
_newMessage (event) {
if (!event.data) return
if (typeof event.data !== 'string') return
var msg
try {
msg = JSON.parse(event.data)
} catch (e) {
return console.log('unable to parse data')
}
const {action, key, type, value} = msg
if (action === 'notification') {
if (this._notifications[key] && this._notifications[key][type]) {
this._notifications[key][type](value)
}
} else if (action === 'response') {
const {id, error} = msg
if (this._pendingRequests[id]) {
this._pendingRequests[id](error, value)
delete this._pendingRequests[id]
}
}
}
}
if (window) window.RemixExtension = RemixExtension
if (module && module.exports) module.exports = RemixExtension
{
"name": "remix-extension",
"version": "0.0.1",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
"name": "Yann Levreau",
"email": "yann@ethdev.com"
}
],
"main": "./index.js",
"dependencies": {
"babel-eslint": "^7.1.1",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-preset-es2015": "^6.24.0",
"babelify": "^7.3.0",
"standard": "^7.0.1",
"tape": "^4.6.0"
},
"scripts": {
"browserify": "browserify index.js -o bundle.js"
},
"standard": {
"ignore": [
"node_modules/*"
],
"parser": "babel-eslint"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ethereum/remix-ide.git"
},
"author": "cpp-ethereum team",
"license": "MIT",
"bugs": {
"url": "https://github.com/ethereum/remix-ide/issues"
},
"homepage": "https://github.com/ethereum/remix-ide#readme",
"browserify": {
"transform": [
[
"babelify",
{
"plugins": [
[
"fast-async",
{
"runtimePatten": null,
"compiler": {
"promises": true,
"es7": true,
"noRuntime": true,
"wrapAwait": true
}
}
],
"transform-object-assign"
]
}
],
[
"babelify",
{
"presets": [
"es2015"
]
}
]
]
}
}
plugin api
# current APIs:
## 1) notifications
### app (key: app)
- unfocus `[]`
- focus `[]`
### compiler (key: compiler)
- compilationFinished `[success (bool), data (obj), source (obj)]`
- compilationData `[compilationResult]`
### transaction listener (key: txlistener)
- newTransaction `tx (obj)`
## 2) interactions
### app
- getExecutionContextProvider `@return {String} provider (injected | web3 | vm)`
- getProviderEndpoint `@return {String} url`
- updateTitle `@param {String} title`
- detectNetWork `@return {Object} {name, id}`
- addProvider `@param {String} name, @param {String} url`
- removeProvider `@return {String} name`
### config
- setConfig `@param {String} path, @param {String} content`
- getConfig `@param {String} path`
- removeConfig `@param {String} path`
### compiler
- getCompilationResult `@return {Object} compilation result`
### udapp (only VM)
- runTx `@param {Object} tx`
- getAccounts `@return {Array} acccounts`
- createVMAccount `@param {String} privateKey, @param {String} balance (hex)`
### editor
- getFilesFromPath `@param {Array} [path]`
- getCurrentFile `@return {String} path`
- getFile `@param {String} path`
- setFile `@param {String} path, @param {String} content`
- highlight `@param {Object} lineColumnPos {start: {line, column}, end: {line, column}}, @param {String} path, @param {String} hexColor`
- discardHighlight
'use strict'
var executionContext = require('../../execution-context')
var SourceHighlighter = require('../editor/sourceHighlighter')
/*
Defines available API. `key` / `type`
*/
module.exports = (pluginManager, fileProviders, fileManager, compilesrArtefacts, udapp) => {
let highlighters = {}
return {
app: {
getExecutionContextProvider: (mod, cb) => {
cb(null, executionContext.getProvider())
},
getProviderEndpoint: (mod, cb) => {
if (executionContext.getProvider() === 'web3') {
cb(null, executionContext.web3().currentProvider.host)
} else {
cb('no endpoint: current provider is either injected or vm')
}
},
updateTitle: (mod, title, cb) => {
pluginManager.plugins[mod].modal.setTitle(title)
if (cb) cb()
},
detectNetWork: (mod, cb) => {
executionContext.detectNetwork((error, network) => {
cb(error, network)
})
},
addProvider: (mod, name, url, cb) => {
executionContext.addProvider({ name, url })
cb()
},
removeProvider: (mod, name, cb) => {
executionContext.removeProvider(name)
cb()
}
},
config: {
setConfig: (mod, path, content, cb) => {
fileProviders['config'].set(mod + '/' + path, content)
cb()
},
getConfig: (mod, path, cb) => {
cb(null, fileProviders['config'].get(mod + '/' + path))
},
removeConfig: (mod, path, cb) => {
cb(null, fileProviders['config'].remove(mod + '/' + path))
if (cb) cb()
}
},
compiler: {
getCompilationResult: (mod, cb) => {
cb(null, compilesrArtefacts['__last'])
},
sendCompilationResult: (mod, file, source, languageVersion, data, cb) => {
pluginManager.receivedDataFrom('sendCompilationResult', mod, [file, source, languageVersion, data])
}
},
udapp: {
runTx: (mod, tx, cb) => {
executionContext.detectNetwork((error, network) => {
if (error) return cb(error)
if (network.name === 'Main' && network.id === '1') {
return cb('It is not allowed to make this action against mainnet')
}
udapp.silentRunTx(tx, (error, result) => {
if (error) return cb(error)
cb(null, {
transactionHash: result.transactionHash,
status: result.result.status,
gasUsed: '0x' + result.result.gasUsed.toString('hex'),
error: result.result.vm.exceptionError,
return: result.result.vm.return ? '0x' + result.result.vm.return.toString('hex') : '0x',
createdAddress: result.result.createdAddress ? '0x' + result.result.createdAddress.toString('hex') : undefined
})
})
})
},
getAccounts: (mod, cb) => {
executionContext.detectNetwork((error, network) => {
if (error) return cb(error)
if (network.name === 'Main' && network.id === '1') {
return cb('It is not allowed to make this action against mainnet')
}
udapp.getAccounts(cb)
})
},
createVMAccount: (mod, privateKey, balance, cb) => {
if (executionContext.getProvider() !== 'vm') return cb('plugin API does not allow creating a new account through web3 connection. Only vm mode is allowed')
udapp.createVMAccount(privateKey, balance, (error, address) => {
cb(error, address)
})
}
},
editor: {
getFilesFromPath: (mod, path, cb) => {
fileManager.filesFromPath(path, cb)
},
getCurrentFile: (mod, cb) => {
var path = fileManager.currentFile()
if (!path) {
cb('no file selected')
} else {
cb(null, path)
}
},
getFile: (mod, path, cb) => {
var provider = fileManager.fileProviderOf(path)
if (provider) {
// TODO add approval to user for external plugin to get the content of the given `path`
provider.get(path, (error, content) => {
cb(error, content)
})
} else {
cb(path + ' not available')
}
},
setFile: (mod, path, content, cb) => {
var provider = fileManager.fileProviderOf(path)
if (provider) {
// TODO add approval to user for external plugin to set the content of the given `path`
provider.set(path, content, (error) => {
if (error) return cb(error)
fileManager.syncEditor(path)
cb()
})
} else {
cb(path + ' not available')
}
},
highlight: (mod, lineColumnPos, filePath, hexColor, cb) => {
var position
try {
position = JSON.parse(lineColumnPos)
} catch (e) {
return cb(e.message)
}
if (!highlighters[mod]) highlighters[mod] = new SourceHighlighter()
highlighters[mod].currentSourceLocation(null)
highlighters[mod].currentSourceLocationFromfileName(position, filePath, hexColor)
cb()
},
discardHighlight: (mod, cb) => {
if (highlighters[mod]) highlighters[mod].currentSourceLocation(null)
cb()
}
}
}
}
'use strict'
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
const PluginAPI = require('./pluginAPI')
/**
* Register and Manage plugin:
*
* Plugin registration is done in the settings tab,
* using the following format:
* {
* "title": "<plugin name>",
* "url": "<plugin url>"
* }
*
* structure of messages:
*
* - Notification sent by Remix:
*{
* action: 'notification',
* key: <string>,
* type: <string>,
* value: <array>
*}
*
* - Request sent by the plugin:
*{
* id: <number>,
* action: 'request',
* key: <string>,
* type: <string>,
* value: <array>
*}
*
* - Response sent by Remix and receive by the plugin:
*{
* id: <number>,
* action: 'response',
* key: <string>,
* type: <string>,
* value: <array>,
* error: (see below)
*}
* => The `error` property is `undefined` if no error happened.
* => In case of error (due to permission, system error, API error, etc...):
* error: { code, msg (optional), data (optional), stack (optional)
* => possible error code are still to be defined, but the generic one would be 500.
*
* Plugin receive 4 types of message:
* - focus (when he get focus)
* - unfocus (when he loose focus - is hidden)
* - compilationData (that is triggered just after a focus - and send the current compilation data or null)
* - compilationFinished (that is only sent to the plugin that has focus)
*
* Plugin can emit messages and receive response.
*
* CONFIG:
* - getConfig(filename). The data to send should be formatted like:
* {
* id: <requestid>,
* action: 'request',
* key: 'config',
* type: 'getConfig',
* value: ['filename.ext']
* }
* the plugin will reveice a response like:
* {
* id: <requestid>,
* action: 'response',
* key: 'config',
* type: 'getConfig',
* error,
* value: ['content of filename.ext']
* }
* same apply for the other call
* - setConfig(filename, content)
* - removeConfig
*
* See index.html and remix.js in test-browser folder for sample
*
*/
module.exports = class PluginManager {
constructor (app, compilersArtefacts, txlistener, fileProviders, fileManager, udapp) {
const self = this
self.event = new EventManager()
var pluginAPI = new PluginAPI(
this,
fileProviders,
fileManager,
compilersArtefacts,
udapp
)
self._components = { pluginAPI }
self.plugins = {}
self.origins = {}
self.inFocus
fileManager.event.register('currentFileChanged', (file, provider) => {
self.broadcast(JSON.stringify({
action: 'notification',
key: 'editor',
type: 'currentFileChanged',
value: [ file ]
}))
})
txlistener.event.register('newTransaction', (tx) => {
self.broadcast(JSON.stringify({
action: 'notification',
key: 'txlistener',
type: 'newTransaction',
value: [tx]
}))
})
window.addEventListener('message', (event) => {
if (event.type !== 'message') return
var extension = self.origins[event.origin]
if (!extension) return
function response (key, type, callid, error, result) {
self.postToOrigin(event.origin, JSON.stringify({
id: callid,
action: 'response',
key: key,
type: type,
error: error,
value: [ result ]
}))
}
var data = JSON.parse(event.data)
data.value.unshift(extension)
data.value.push((error, result) => {
response(data.key, data.type, data.id, error, result)
})
if (pluginAPI[data.key] && pluginAPI[data.key][data.type]) {
pluginAPI[data.key][data.type].apply({}, data.value)
} else {
response(data.key, data.type, data.id, `Endpoint ${data.key}/${data.type} not present`, null)
}
}, false)
}
unregister (desc) {
const self = this
self._components.pluginAPI.editor.discardHighlight(desc.title, () => {})
delete self.plugins[desc.title]
delete self.origins[desc.url]
}
register (desc, modal, content) {
const self = this
self.plugins[desc.title] = { content, modal, origin: desc.url }
self.origins[desc.url] = desc.title
}
broadcast (value) {
for (var plugin in this.plugins) {
this.post(plugin, value)
}
}
postToOrigin (origin, value) {
if (this.origins[origin]) {
this.post(this.origins[origin], value)
}
}
receivedDataFrom (methodName, mod, argumentsArray) {
// TODO check whether 'mod' as right to do that
console.log(argumentsArray)
this.event.trigger(methodName, argumentsArray) // forward to internal modules
this.broadcast(JSON.stringify({ // forward to plugins
action: 'notification',
key: mod,
type: methodName,
value: argumentsArray
}))
}
post (name, value) {
const self = this
if (self.plugins[name]) {
self.plugins[name].content.querySelector('iframe').contentWindow.postMessage(value, self.plugins[name].origin)
}
}
}
'use strict'
module.exports = {
'oraclize': {
url: 'https://remix-plugin.oraclize.it',
title: 'Oraclize'
},
'solium': {
url: 'https://two-water.surge.sh',
title: 'Solium'
},
'ethdoc': {
url: 'https://30400.swarm-gateways.net/bzz:/ethdoc.remixide.eth',
title: 'Ethdoc'
},
'openzeppelin snippet': {
url: 'https://left-edge.surge.sh',
title: 'Openzeppelin snippet'
},
'vyper': {
url: 'https://plugin.vyper.live',
title: 'Vyper'
},
'slither/mythril': {
url: 'http://jittery-space.surge.sh',
title: 'Slither/Mythril'
},
'pipeline': {
url: 'https://pipeline.pipeos.one',
title: 'Pipeline'
}
/*
'etherscan-general': {
url: 'http://127.0.0.1:8081',
title: 'Etherscan-general'
}
*/
}
...@@ -4,10 +4,6 @@ var yo = require('yo-yo') ...@@ -4,10 +4,6 @@ var yo = require('yo-yo')
var $ = require('jquery') var $ = require('jquery')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var utils = remixLib.util var utils = remixLib.util
var styleGuide = require('../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = require('./styles/staticAnalysisView-styles') var css = require('./styles/staticAnalysisView-styles')
var globlalRegistry = require('../../global/registry') var globlalRegistry = require('../../global/registry')
...@@ -34,6 +30,7 @@ function staticAnalysisView (localRegistry) { ...@@ -34,6 +30,7 @@ function staticAnalysisView (localRegistry) {
self.lastCompilationResult = null self.lastCompilationResult = null
self.lastCompilationSource = null self.lastCompilationSource = null
$('#staticanalysisresult').empty() $('#staticanalysisresult').empty()
if (languageVersion.indexOf('soljson') !== 0) return
self.lastCompilationResult = data self.lastCompilationResult = data
self.lastCompilationSource = source self.lastCompilationSource = source
if (self.view.querySelector('#autorunstaticanalysis').checked) { if (self.view.querySelector('#autorunstaticanalysis').checked) {
...@@ -46,30 +43,34 @@ staticAnalysisView.prototype.render = function () { ...@@ -46,30 +43,34 @@ staticAnalysisView.prototype.render = function () {
var self = this var self = this
var view = yo` var view = yo`
<div class="${css.analysis}"> <div class="${css.analysis}">
<div id="staticanalysismodules">
${this.modulesView}
</div>
<div class="${css.buttons}"> <div class="${css.buttons}">
<button class="${css.buttonRun}" onclick="${function () { self.run() }}" >Run</button> <div class="${css.buttonsInner}">
<label class="${css.label}" for="autorunstaticanalysis"> <button class="${css.buttonRun} btn btn-sm btn-primary" onclick="${function () { self.run() }}" >Run</button>
<input id="autorunstaticanalysis" <label class="${css.label}" for="autorunstaticanalysis">
type="checkbox" <input id="autorunstaticanalysis"
style="vertical-align:bottom" type="checkbox"
checked="true" style="vertical-align:bottom"
> checked="true"
Auto run >
</label> Auto run
<label class="${css.label}" for="checkAllEntries"> </label>
<input id="checkAllEntries" <label class="${css.label}" for="checkAllEntries">
type="checkbox" <input id="checkAllEntries"
onclick="${function (event) { self.checkAll(event) }}" type="checkbox"
style="vertical-align:bottom" onclick="${function (event) { self.checkAll(event) }}"
checked="true" style="vertical-align:bottom"
> checked="true"
Check/Uncheck all >
</label> Check/Uncheck all
</div> </label>
<div class="${css.result}" "id='staticanalysisresult'></div> </div>
</div>
<div id="staticanalysismodules" class="list-group list-group-flush ${css.container}">
${this.modulesView}
</div>
<hr>
<div><h6>Results:</h6></div>
<div class="${css.result}" id='staticanalysisresult'></div>
</div> </div>
` `
if (!this.view) { if (!this.view) {
...@@ -97,8 +98,8 @@ staticAnalysisView.prototype.run = function () { ...@@ -97,8 +98,8 @@ staticAnalysisView.prototype.run = function () {
var selected = this.selectedModules() var selected = this.selectedModules()
var warningContainer = $('#staticanalysisresult') var warningContainer = $('#staticanalysisresult')
warningContainer.empty() warningContainer.empty()
if (this.lastCompilationResult) { var self = this
var self = this if (this.lastCompilationResult && selected.length) {
var warningCount = 0 var warningCount = 0
this.runner.run(this.lastCompilationResult, selected, function (results) { this.runner.run(this.lastCompilationResult, selected, function (results) {
results.map(function (result, i) { results.map(function (result, i) {
...@@ -119,19 +120,16 @@ staticAnalysisView.prototype.run = function () { ...@@ -119,19 +120,16 @@ staticAnalysisView.prototype.run = function () {
} }
warningCount++ warningCount++
var msg = yo`<span>${location} ${item.warning} ${item.more ? yo`<span><br><a href="${item.more}" target="blank">more</a></span>` : yo`<span></span>`}</span>` var msg = yo`<span>${location} ${item.warning} ${item.more ? yo`<span><br><a href="${item.more}" target="blank">more</a></span>` : yo`<span></span>`}</span>`
self._deps.renderer.error(msg, warningContainer, {type: 'staticAnalysisWarning', useSpan: true}) self._deps.renderer.error(msg, warningContainer, {type: 'staticAnalysisWarning alert alert-warning', useSpan: true})
}) })
}) })
if (warningContainer.html() === '') {
$('#righthand-panel #menu .staticanalysisView').css('color', '')
warningContainer.html('No warning to report')
} else {
$('#righthand-panel #menu .staticanalysisView').css('color', styles.colors.red)
}
self.event.trigger('staticAnaysisWarning', [warningCount]) self.event.trigger('staticAnaysisWarning', [warningCount])
}) })
} else { } else {
warningContainer.html('No compiled AST available') if (selected.length) {
warningContainer.html('No compiled AST available')
}
self.event.trigger('staticAnaysisWarning', [-1])
} }
} }
...@@ -176,7 +174,7 @@ staticAnalysisView.prototype.renderModules = function () { ...@@ -176,7 +174,7 @@ staticAnalysisView.prototype.renderModules = function () {
</label> </label>
` `
}) })
return yo`<div class="${css.analysisModulesContainer}"> return yo`<div class="${css.analysisModulesContainer} list-group-item py-1">
<label class="${css.label}"><b>${category[0].categoryDisplayName}</b></label> <label class="${css.label}"><b>${category[0].categoryDisplayName}</b></label>
${entriesDom} ${entriesDom}
</div>` </div>`
......
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.analysis { .analysis {
display: flex; display: flex;
...@@ -10,27 +7,29 @@ var css = csjs` ...@@ -10,27 +7,29 @@ var css = csjs`
} }
.result { .result {
margin-top: 1%; margin-top: 1%;
max-height: 300px;
} }
.buttons { .buttons {
${styles.rightPanel.analysisTab.box_AnalysisContainer} margin: 1rem 0;
}
.buttonsInner {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-around;
} }
.buttonRun { .buttonRun {
${styles.rightPanel.analysisTab.button_Run_AnalysisTab}
margin-right: 1%; margin-right: 1%;
} }
.analysisModulesContainer { .analysisModulesContainer {
${styles.rightPanel.analysisTab.box_AnalysisContainer}
margin-bottom: 1%;
line-height: 2em;
display: flex;
flex-direction: column;
} }
.label { .label {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.container {
max-height: 300px;
overflow-y: auto;
}
` `
module.exports = css module.exports = css
...@@ -3,21 +3,46 @@ var StaticAnalysis = require('../staticanalysis/staticAnalysisView') ...@@ -3,21 +3,46 @@ var StaticAnalysis = require('../staticanalysis/staticAnalysisView')
var EventManager = require('../../lib/events') var EventManager = require('../../lib/events')
var css = require('./styles/analysis-tab-styles') var css = require('./styles/analysis-tab-styles')
class AnalysisTab { import { BaseApi } from 'remix-plugin'
import { EventEmitter } from 'events'
const profile = {
name: 'solidityStaticAnalysis',
displayName: 'Solidity static analysis',
methods: [],
events: [],
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMjA0OCIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMjA0OCAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0yMDQ4IDE1MzZ2MTI4aC0yMDQ4di0xNTM2aDEyOHYxNDA4aDE5MjB6bS0xMjgtMTI0OHY0MzVxMCAyMS0xOS41IDI5LjV0LTM1LjUtNy41bC0xMjEtMTIxLTYzMyA2MzNxLTEwIDEwLTIzIDEwdC0yMy0xMGwtMjMzLTIzMy00MTYgNDE2LTE5Mi0xOTIgNTg1LTU4NXExMC0xMCAyMy0xMHQyMyAxMGwyMzMgMjMzIDQ2NC00NjQtMTIxLTEyMXEtMTYtMTYtNy41LTM1LjV0MjkuNS0xOS41aDQzNXExNCAwIDIzIDl0OSAyM3oiLz48L3N2Zz4=',
description: 'Checks the contract code for security vulnerabilities and bad practices.',
kind: 'analysis',
location: 'swapPanel'
}
class AnalysisTab extends BaseApi {
constructor (registry) { constructor (registry) {
super(profile)
this.event = new EventManager() this.event = new EventManager()
this.events = new EventEmitter()
this.registry = registry this.registry = registry
} }
render () { render () {
var staticanalysis = new StaticAnalysis() if (!this.staticanalysis) this.staticanalysis = new StaticAnalysis()
this.registry.put({api: staticanalysis, name: 'staticanalysis'}) this.staticanalysis.event.register('staticAnaysisWarning', (count) => {
if (count > 0) {
this.events.emit('statusChanged', {key: count, title: `${count} warning${count === 1 ? '' : 's'}`, type: 'warning'})
} else if (count === 0) {
this.events.emit('statusChanged', {key: 'succeed', title: 'no warning', type: 'success'})
} else {
// count ==-1 no compilation result
this.events.emit('statusChanged', {key: 'none'})
}
})
this.registry.put({api: this.staticanalysis, name: 'staticanalysis'})
if (this.el) return this.el return yo`<div class="${css.analysisTabView}" id="staticanalysisView">${this.staticanalysis.render()}</div>`
this.el = yo`<div class="${css.analysisTabView} "id="staticanalysisView">${staticanalysis.render()}</div>`
return this.el
} }
} }
module.exports = AnalysisTab module.exports = AnalysisTab
This diff is collapsed.
const async = require('async')
const EventEmitter = require('events')
var remixTests = require('remix-tests')
var Compiler = require('remix-solidity').Compiler
var CompilerImport = require('../../compiler/compiler-imports')
// TODO: move this to the UI
const addTooltip = require('../../ui/tooltip')
class CompileTab {
constructor (queryParams, fileManager, editor, config, fileProviders) {
this.event = new EventEmitter()
this.queryParams = queryParams
this.compilerImport = new CompilerImport()
this.compiler = new Compiler((url, cb) => this.importFileCb(url, cb))
this.fileManager = fileManager
this.editor = editor
this.config = config
this.fileProviders = fileProviders
}
init () {
this.optimize = this.queryParams.get().optimize
this.optimize = this.optimize === 'true'
this.queryParams.update({ optimize: this.optimize })
this.compiler.setOptimize(this.optimize)
}
setOptimize (newOptimizeValue) {
this.optimize = newOptimizeValue
this.queryParams.update({ optimize: this.optimize })
this.compiler.setOptimize(this.optimize)
}
runCompiler () {
this.fileManager.saveCurrentFile()
this.editor.clearAnnotations()
var currentFile = this.config.get('currentFile')
if (!currentFile) return
if (!/\.sol/.exec(currentFile)) return
// only compile *.sol file.
var target = currentFile
var sources = {}
var provider = this.fileManager.fileProviderOf(currentFile)
if (!provider) return console.log('cannot compile ' + currentFile + '. Does not belong to any explorer')
provider.get(target, (error, content) => {
if (error) return console.log(error)
sources[target] = { content }
this.event.emit('startingCompilation')
setTimeout(() => {
// setTimeout fix the animation on chrome... (animation triggered by 'staringCompilation')
this.compiler.compile(sources, target)
}, 100)
})
}
importExternal (url, cb) {
this.compilerImport.import(url,
// TODO: move to an event that is generated, the UI shouldn't be here
(loadingMsg) => { addTooltip(loadingMsg) },
(error, content, cleanUrl, type, url) => {
if (error) return cb(error)
if (this.fileProviders[type]) {
this.fileProviders[type].addReadOnly(cleanUrl, content, url)
}
cb(null, content)
})
}
importFileCb (url, filecb) {
if (url.indexOf('/remix_tests.sol') !== -1) return filecb(null, remixTests.assertLibCode)
var provider = this.fileManager.fileProviderOf(url)
if (provider) {
if (provider.type === 'localhost' && !provider.isConnected()) {
return filecb(`file provider ${provider.type} not available while trying to resolve ${url}`)
}
return provider.exists(url, (error, exist) => {
if (error) return filecb(error)
if (exist) {
return provider.get(url, filecb)
}
this.importExternal(url, filecb)
})
}
if (this.compilerImport.isRelativeImport(url)) {
// try to resolve localhost modules (aka truffle imports)
var splitted = /([^/]+)\/(.*)$/g.exec(url)
return async.tryEach([
(cb) => { this.importFileCb('localhost/installed_contracts/' + url, cb) },
(cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.importFileCb('localhost/installed_contracts/' + splitted[1] + '/contracts/' + splitted[2], cb) } },
(cb) => { this.importFileCb('localhost/node_modules/' + url, cb) },
(cb) => { if (!splitted) { cb('URL not parseable: ' + url) } else { this.importFileCb('localhost/node_modules/' + splitted[1] + '/contracts/' + splitted[2], cb) } }],
(error, result) => { filecb(error, result) }
)
}
this.importExternal(url, filecb)
}
}
module.exports = CompileTab
This diff is collapsed.
...@@ -3,8 +3,23 @@ var css = require('./styles/debugger-tab-styles') ...@@ -3,8 +3,23 @@ var css = require('./styles/debugger-tab-styles')
var DebuggerUI = require('../debugger/debuggerUI') var DebuggerUI = require('../debugger/debuggerUI')
class DebuggerTab { import { BaseApi } from 'remix-plugin'
const profile = {
name: 'debugger',
displayName: 'Debugger',
methods: [],
events: [],
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTc5MiIgaGVpZ2h0PSIxNzkyIiB2aWV3Qm94PSIwIDAgMTc5MiAxNzkyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xNjk2IDk2MHEwIDI2LTE5IDQ1dC00NSAxOWgtMjI0cTAgMTcxLTY3IDI5MGwyMDggMjA5cTE5IDE5IDE5IDQ1dC0xOSA0NXEtMTggMTktNDUgMTl0LTQ1LTE5bC0xOTgtMTk3cS01IDUtMTUgMTN0LTQyIDI4LjUtNjUgMzYuNS04MiAyOS05NyAxM3YtODk2aC0xMjh2ODk2cS01MSAwLTEwMS41LTEzLjV0LTg3LTMzLTY2LTM5LTQzLjUtMzIuNWwtMTUtMTQtMTgzIDIwN3EtMjAgMjEtNDggMjEtMjQgMC00My0xNi0xOS0xOC0yMC41LTQ0LjV0MTUuNS00Ni41bDIwMi0yMjdxLTU4LTExNC01OC0yNzRoLTIyNHEtMjYgMC00NS0xOXQtMTktNDUgMTktNDUgNDUtMTloMjI0di0yOTRsLTE3My0xNzNxLTE5LTE5LTE5LTQ1dDE5LTQ1IDQ1LTE5IDQ1IDE5bDE3MyAxNzNoODQ0bDE3My0xNzNxMTktMTkgNDUtMTl0NDUgMTkgMTkgNDUtMTkgNDVsLTE3MyAxNzN2Mjk0aDIyNHEyNiAwIDQ1IDE5dDE5IDQ1em0tNDgwLTU3NmgtNjQwcTAtMTMzIDkzLjUtMjI2LjV0MjI2LjUtOTMuNSAyMjYuNSA5My41IDkzLjUgMjI2LjV6Ii8+PC9zdmc+',
description: 'Debug transactions',
kind: 'debugging',
location: 'swapPanel'
}
class DebuggerTab extends BaseApi {
constructor () { constructor () {
super(profile)
this.el = null this.el = null
} }
......
const executionContext = require('../../execution-context')
import { NetworkApi } from 'remix-plugin'
export const profile = {
name: 'network',
description: 'Manage the network (mainnet, ropsten, goerli...) and the provider (web3, vm, injected)'
}
// Network API has :
// - events: ['providerChanged']
// - methods: ['getNetworkProvider', 'getEndpoint', 'detectNetwork', 'addNetwork', 'removeNetwork']
export class NetworkModule extends NetworkApi {
constructor () {
super(profile)
// TODO: See with remix-lib to make sementic coherent
executionContext.event.register('contextChanged', (provider) => {
this.events.emit('providerChanged', provider)
})
/*
// Events that could be implemented later
executionContext.event.register('removeProvider', (provider) => {
this.events.emit('networkRemoved', provider)
})
executionContext.event.register('addProvider', (provider) => {
this.events.emit('networkAdded', provider)
})
executionContext.event.register('web3EndpointChanged', (provider) => {
this.events.emit('web3EndpointChanged', provider)
})
*/
}
/** Return the current network provider (web3, vm, injected) */
getNetworkProvider () {
return executionContext.getProvider()
}
/** Return the current network */
detectNetwork () {
return new Promise((resolve, reject) => {
executionContext.detectNetwork((error, network) => {
error ? reject(error) : resolve(network)
})
})
}
/** Return the url only if network provider is 'web3' */
getEndpoint () {
const provider = executionContext.getProvider()
if (provider !== 'web3') {
throw new Error('no endpoint: current provider is either injected or vm')
}
return provider.web3().currentProvider.host
}
/** Add a custom network to the list of available networks */
addNetwork (customNetwork) {
executionContext.addProvider(customNetwork)
}
/** Remove a network to the list of availble networks */
removeNetwork (name) {
executionContext.removeProvider(name)
}
}
...@@ -12,24 +12,42 @@ var ContractDropdownUI = require('./runTab/contractDropdown.js') ...@@ -12,24 +12,42 @@ var ContractDropdownUI = require('./runTab/contractDropdown.js')
var Recorder = require('./runTab/model/recorder.js') var Recorder = require('./runTab/model/recorder.js')
var RecorderUI = require('./runTab/recorder.js') var RecorderUI = require('./runTab/recorder.js')
class RunTab { const executionContext = require('../../execution-context')
import { BaseApi } from 'remix-plugin'
const profile = {
name: 'run',
displayName: 'Deploy and run transactions',
methods: [],
events: [],
icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxNi4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DQo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzFfY29weSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4Ig0KCSB5PSIwcHgiIHdpZHRoPSI3NDIuNTQ1cHgiIGhlaWdodD0iNjc2Ljg4NnB4IiB2aWV3Qm94PSIwIC0wLjIwNCA3NDIuNTQ1IDY3Ni44ODYiDQoJIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAtMC4yMDQgNzQyLjU0NSA2NzYuODg2IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxnPg0KCTxwb2x5Z29uIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludHM9IjI5NS45MTEsMC43MTEgNDg4LjkxMSwzMDQuMTg2IDQ4OC45MTEsMzk3LjE4MSAyOTMuOTExLDY3Ni41NTYgDQoJCTc0MS43ODYsMzQ5Ljk0MyAJIi8+DQoJPHBvbHlnb24gc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50cz0iNDE3LjA4Myw0MDYuNTg5IDIwOS43OTEsNTE5LjQ5NCAxLjg0Niw0MDYuMjM0IDIwOS43OTEsNjc1Ljg2MyAJIi8+DQoJPHBvbHlnb24gc3Ryb2tlPSIjRkZGRkZGIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50cz0iNDE3LjA4MywzMTguNzA3IDIwOS43OTEsMC43MTEgMS44NDYsMzE4LjQyOCAyMDkuNzkxLDQzMS42ODkgCSIvPg0KPC9nPg0KPC9zdmc+DQo=',
description: 'execute and save transactions',
kind: 'run',
location: 'swapPanel'
}
class RunTab extends BaseApi {
constructor (udapp, udappUI, config, fileManager, editor, logCallback, filePanel, pluginManager, compilersArtefacts) { constructor (udapp, udappUI, config, fileManager, editor, logCallback, filePanel, pluginManager, compilersArtefacts) {
super(profile)
this.event = new EventManager() this.event = new EventManager()
this.config = config
this.renderInstanceContainer() this.udapp = udapp
this.renderSettings(udapp) this.udappUI = udappUI
this.renderDropdown(udappUI, fileManager, pluginManager, compilersArtefacts, config, editor, udapp, filePanel, logCallback) this.fileManager = fileManager
this.renderRecorder(udapp, udappUI, fileManager, config, logCallback) this.editor = editor
this.renderRecorderCard() this.logCallback = logCallback
this.renderContainer() this.filePanel = filePanel
this.pluginManager = pluginManager
this.compilersArtefacts = compilersArtefacts
} }
renderContainer () { renderContainer () {
this.container = yo`<div class="${css.runTabView}" id="runTabView" ></div>` this.container = yo`<div class="${css.runTabView}" id="runTabView" ></div>`
var el = yo` var el = yo`
<div> <div class="list-group list-group-flush">
${this.settingsUI.render()} ${this.settingsUI.render()}
${this.contractDropdownUI.render()} ${this.contractDropdownUI.render()}
${this.recorderCard.render()} ${this.recorderCard.render()}
...@@ -37,6 +55,7 @@ class RunTab { ...@@ -37,6 +55,7 @@ class RunTab {
</div> </div>
` `
this.container.appendChild(el) this.container.appendChild(el)
return this.container
} }
renderInstanceContainer () { renderInstanceContainer () {
...@@ -46,7 +65,7 @@ class RunTab { ...@@ -46,7 +65,7 @@ class RunTab {
<div class=${css.instanceContainerTitle} <div class=${css.instanceContainerTitle}
title="Autogenerated generic user interfaces for interaction with deployed contracts"> title="Autogenerated generic user interfaces for interaction with deployed contracts">
Deployed Contracts Deployed Contracts
<i class="${css.clearinstance} ${css.icon} fa fa-trash" onclick=${() => this.event.trigger('clearInstance', [])} <i class="${css.clearinstance} ${css.icon} far fa-trash-alt" onclick=${() => this.event.trigger('clearInstance', [])}
title="Clear instances list and reset recorder" aria-hidden="true"> title="Clear instances list and reset recorder" aria-hidden="true">
</i> </i>
</div>` </div>`
...@@ -114,7 +133,7 @@ class RunTab { ...@@ -114,7 +133,7 @@ class RunTab {
renderRecorderCard () { renderRecorderCard () {
const collapsedView = yo` const collapsedView = yo`
<div class=${css.recorderCollapsedView}> <div class=${css.recorderCollapsedView}>
<div class=${css.recorderCount}>${this.recorderCount}</div> <div class="${css.recorderCount} badge badge-pill badge-primary">${this.recorderCount}</div>
</div>` </div>`
const expandedView = yo` const expandedView = yo`
...@@ -144,8 +163,18 @@ class RunTab { ...@@ -144,8 +163,18 @@ class RunTab {
} }
render () { render () {
return this.container executionContext.init(this.config)
executionContext.stopListenOnLastBlock()
executionContext.listenOnLastBlock()
this.udapp.resetEnvironment()
this.renderInstanceContainer()
this.renderSettings(this.udapp)
this.renderDropdown(this.udappUI, this.fileManager, this.pluginManager, this.compilersArtefacts, this.config, this.editor, this.udapp, this.filePanel, this.logCallback)
this.renderRecorder(this.udapp, this.udappUI, this.fileManager, this.config, this.logCallback)
this.renderRecorderCard()
return this.renderContainer()
} }
} }
module.exports = RunTab module.exports = RunTab
...@@ -18,6 +18,7 @@ class ContractDropdownUI { ...@@ -18,6 +18,7 @@ class ContractDropdownUI {
listenToEvents () { listenToEvents () {
this.dropdownLogic.event.register('newlyCompiled', (success, data, source, compiler, compilerFullName) => { this.dropdownLogic.event.register('newlyCompiled', (success, data, source, compiler, compilerFullName) => {
if (!document.querySelector(`.${css.contractNames.classNames[0]}`)) return
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
contractNames.innerHTML = '' contractNames.innerHTML = ''
if (success) { if (success) {
...@@ -43,11 +44,11 @@ class ContractDropdownUI { ...@@ -43,11 +44,11 @@ class ContractDropdownUI {
} }
render () { render () {
this.compFails = yo`<i title="Contract compilation failed. Please check the compile tab for more information." class="fa 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="fas fa-times-circle ${css.errorIcon}" ></i>`
var info = yo`<i class="fa fa-info ${css.infoDeployAction}" aria-hidden="true" title="*.sol files allows deploying and accessing contracts. *.abi files only allows accessing contracts."></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.atAddressButtonInput = yo`<input class="${css.input} ataddressinput" placeholder="Load contract from Address" title="atAddress" />` this.atAddressButtonInput = yo`<input class="${css.input} ${css.ataddressinput} ataddressinput form-control" placeholder="Load contract from Address" title="atAddress" />`
this.selectContractNames = yo`<select class="${css.contractNames}" disabled></select>` this.selectContractNames = yo`<select class="${css.contractNames} custom-select" disabled></select>`
this.createPanel = yo`<div class="${css.button}"></div>` this.createPanel = yo`<div class="${css.button}"></div>`
this.orLabel = yo`<div class="${css.orLabel}">or</div>` this.orLabel = yo`<div class="${css.orLabel}">or</div>`
...@@ -60,18 +61,19 @@ class ContractDropdownUI { ...@@ -60,18 +61,19 @@ class ContractDropdownUI {
${this.createPanel} ${this.createPanel}
${this.orLabel} ${this.orLabel}
<div class="${css.button} ${css.atAddressSect}"> <div class="${css.button} ${css.atAddressSect}">
<div class="${css.atAddress}" onclick=${this.loadFromAddress.bind(this)}>At Address</div> <div class="${css.atAddress} btn btn-sm btn-info" onclick=${this.loadFromAddress.bind(this)}>At Address</div>
${this.atAddressButtonInput} ${this.atAddressButtonInput}
</div> </div>
</div> </div>
</div> </div>
` `
this.selectContractNames.addEventListener('change', this.setInputParamsPlaceHolder.bind(this)) this.selectContractNames.addEventListener('change', this.setInputParamsPlaceHolder.bind(this))
this.setInputParamsPlaceHolder()
return el return el
} }
changeCurrentFile (currentFile) { changeCurrentFile (currentFile) {
if (!document.querySelector(`.${css.contractNames}`)) return
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError)
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
contractNames.innerHTML = '' contractNames.innerHTML = ''
...@@ -139,7 +141,7 @@ class ContractDropdownUI { ...@@ -139,7 +141,7 @@ class ContractDropdownUI {
} }
var promptCb = (okCb, cancelCb) => { var promptCb = (okCb, cancelCb) => {
modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) modalDialogCustom.promptPassphrase('Passphrase requested', 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb)
} }
var statusCb = (msg) => { var statusCb = (msg) => {
...@@ -153,7 +155,7 @@ class ContractDropdownUI { ...@@ -153,7 +155,7 @@ class ContractDropdownUI {
return this.logCallback(error) return this.logCallback(error)
} }
this.event.trigger('newContractInstanceAdded', [contractObject, address, this.selectContractNames.value]) this.event.trigger('newContractInstanceAdded', [contractObject, address, contractObject.name])
} }
if (selectedContract.isOverSizeLimit()) { if (selectedContract.isOverSizeLimit()) {
...@@ -163,7 +165,7 @@ class ContractDropdownUI { ...@@ -163,7 +165,7 @@ class ContractDropdownUI {
{ {
label: 'Force Send', label: 'Force Send',
fn: () => { fn: () => {
this.dropdownLogic.forceSend(selectedContract, args, continueCb, promptCb, modalDialogCustom, confirmDialog, statusCb, finalCb) this.dropdownLogic.forceSend(selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, finalCb)
}}, { }}, {
label: 'Cancel', label: 'Cancel',
fn: () => { fn: () => {
...@@ -171,7 +173,7 @@ class ContractDropdownUI { ...@@ -171,7 +173,7 @@ class ContractDropdownUI {
} }
}) })
} }
this.dropdownLogic.forceSend(selectedContract, args, continueCb, promptCb, modalDialogCustom, confirmDialog, statusCb, finalCb) this.dropdownLogic.forceSend(selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, finalCb)
} }
loadFromAddress () { loadFromAddress () {
...@@ -180,7 +182,7 @@ class ContractDropdownUI { ...@@ -180,7 +182,7 @@ class ContractDropdownUI {
var address = this.atAddressButtonInput.value var address = this.atAddressButtonInput.value
this.dropdownLogic.loadContractFromAddress(address, this.dropdownLogic.loadContractFromAddress(address,
(cb) => { (cb) => {
modalDialogCustom.confirm(null, 'Do you really want to interact with ' + address + ' using the current ABI definition ?', cb) modalDialogCustom.confirm(null, 'Do you really want to interact with ' + address + ' using the current ABI definition?', cb)
}, },
(error, loadType, abi) => { (error, loadType, abi) => {
if (error) { if (error) {
......
...@@ -21,7 +21,7 @@ class DropdownLogic { ...@@ -21,7 +21,7 @@ class DropdownLogic {
this.listenToCompilationEvents() this.listenToCompilationEvents()
fileManager.event.register('currentFileChanged', (currentFile) => { fileManager.events.on('currentFileChanged', (currentFile) => {
this.event.trigger('currentFileChanged', [currentFile]) this.event.trigger('currentFileChanged', [currentFile])
}) })
} }
...@@ -121,7 +121,7 @@ class DropdownLogic { ...@@ -121,7 +121,7 @@ class DropdownLogic {
} }
// TODO: check if selectedContract and data can be joined // TODO: check if selectedContract and data can be joined
createContract (selectedContract, data, continueCb, promptCb, confirmDialog, modalDialog, finalCb) { createContract (selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, finalCb) {
if (data) { if (data) {
data.contractName = selectedContract.name data.contractName = selectedContract.name
data.linkReferences = selectedContract.bytecodeLinkReferences data.linkReferences = selectedContract.bytecodeLinkReferences
......
...@@ -23,9 +23,9 @@ class RecorderUI { ...@@ -23,9 +23,9 @@ class RecorderUI {
.recorder {} .recorder {}
` `
this.runButton = yo`<i class="fa fa-play runtransaction ${css2.runTxs} ${css.icon}" title="Run Transactions" aria-hidden="true"></i>` this.runButton = yo`<i class="fas fa-play runtransaction ${css2.runTxs} ${css.icon}" title="Run Transactions" aria-hidden="true"></i>`
this.recordButton = yo` this.recordButton = yo`
<i class="fa fa-floppy-o savetransaction ${css2.recorder} ${css.icon}" <i class="fas fa-save savetransaction ${css2.recorder} ${css.icon}"
onclick=${this.triggerRecordButton.bind(this)} title="Save Transactions" aria-hidden="true"> onclick=${this.triggerRecordButton.bind(this)} title="Save Transactions" aria-hidden="true">
</i>` </i>`
...@@ -56,7 +56,7 @@ class RecorderUI { ...@@ -56,7 +56,7 @@ class RecorderUI {
} }
var promptCb = (okCb, cancelCb) => { var promptCb = (okCb, cancelCb) => {
modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) modalDialogCustom.promptPassphrase('Passphrase requested', 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb)
} }
var alertCb = (msg) => { var alertCb = (msg) => {
...@@ -76,7 +76,7 @@ class RecorderUI { ...@@ -76,7 +76,7 @@ class RecorderUI {
triggerRecordButton () { triggerRecordButton () {
this.recorder.saveScenario( this.recorder.saveScenario(
(path, cb) => { (path, cb) => {
modalDialogCustom.prompt(null, 'Transactions will be saved in a file under ' + path, 'scenario.json', cb) modalDialogCustom.prompt('Save transactions as scenario', 'Transactions will be saved in a file under ' + path, 'scenario.json', cb)
}, },
(error) => { (error) => {
if (error) return modalDialogCustom.alert(error) if (error) return modalDialogCustom.alert(error)
......
var $ = require('jquery') const $ = require('jquery')
var yo = require('yo-yo') const yo = require('yo-yo')
var remixLib = require('remix-lib') const remixLib = require('remix-lib')
var EventManager = remixLib.EventManager const EventManager = remixLib.EventManager
var css = require('../styles/run-tab-styles') const css = require('../styles/run-tab-styles')
var copyToClipboard = require('../../ui/copy-to-clipboard') const copyToClipboard = require('../../ui/copy-to-clipboard')
var modalDialogCustom = require('../../ui/modal-dialog-custom') const modalDialogCustom = require('../../ui/modal-dialog-custom')
var addTooltip = require('../../ui/tooltip') const addTooltip = require('../../ui/tooltip')
var helper = require('../../../lib/helper.js') const helper = require('../../../lib/helper.js')
const globalRegistry = require('../../../global/registry')
class SettingsUI { class SettingsUI {
constructor (settings) { constructor (settings) {
this.settings = settings this.settings = settings
this.event = new EventManager() this.event = new EventManager()
this._components = {}
this.settings.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => { this.settings.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
if (error) return if (error) return
...@@ -20,6 +22,11 @@ class SettingsUI { ...@@ -20,6 +22,11 @@ class SettingsUI {
this.updateAccountBalances() this.updateAccountBalances()
}) })
this._components.registry = globalRegistry
this._deps = {
networkModule: this._components.registry.get('network').api
}
setInterval(() => { setInterval(() => {
this.updateAccountBalances() this.updateAccountBalances()
}, 10 * 1000) }, 10 * 1000)
...@@ -40,7 +47,7 @@ class SettingsUI { ...@@ -40,7 +47,7 @@ class SettingsUI {
} }
render () { render () {
this.netUI = yo`<span class=${css.network}></span>` this.netUI = yo`<span class="${css.network} badge badge-secondary"></span>`
var environmentEl = yo` var environmentEl = yo`
<div class="${css.crow}"> <div class="${css.crow}">
...@@ -48,8 +55,7 @@ class SettingsUI { ...@@ -48,8 +55,7 @@ class SettingsUI {
Environment Environment
</div> </div>
<div class=${css.environment}> <div class=${css.environment}>
${this.netUI} <select id="selectExEnvOptions" onchange=${() => { this.updateNetwork() }} class="form-control ${css.select}">
<select id="selectExEnvOptions" onchange=${() => { this.updateNetwork() }} class="${css.select}">
<option id="vm-mode" <option id="vm-mode"
title="Execution environment does not connect to any node, everything is local and in memory only." title="Execution environment does not connect to any node, everything is local and in memory only."
value="vm" checked name="executionContext"> JavaScript VM value="vm" checked name="executionContext"> JavaScript VM
...@@ -64,48 +70,59 @@ class SettingsUI { ...@@ -64,48 +70,59 @@ class SettingsUI {
value="web3" name="executionContext"> Web3 Provider value="web3" name="executionContext"> Web3 Provider
</option> </option>
</select> </select>
<a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md" target="_blank"><i class="${css.icon} fa fa-info"></i></a> <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md" target="_blank"><i class="${css.infoDeployAction} fas fa-info"></i></a>
</div> </div>
</div> </div>
` `
const networkEl = yo`
var accountEl = yo` <div class="${css.crow}">
<div class="${css.col1_1}">
</div>
<div class="${css.environment}">
${this.netUI}
</div>
</div>
`
const accountEl = yo`
<div class="${css.crow}"> <div class="${css.crow}">
<div class="${css.col1_1}"> <div class="${css.col1_1}">
Account Account
<i class="fa fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${this.newAccount.bind(this)} title="Create a new account"></i> <i class="fas fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${this.newAccount.bind(this)} title="Create a new account"></i>
</div> </div>
<div class=${css.account}> <div class=${css.account}>
<select name="txorigin" class="${css.select}" id="txorigin"></select> <select name="txorigin" class="form-control ${css.select}" id="txorigin"></select>
${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)} ${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)}
<i class="fa fa-pencil-square-o ${css.icon}" aria-hiden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i> <i class="fas fa-edit ${css.icon}" aria-hiden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
</div> </div>
</div> </div>
` `
var gasPriceEl = yo` const gasPriceEl = yo`
<div class="${css.crow}"> <div class="${css.crow}">
<div class="${css.col1_1}">Gas limit</div> <div class="${css.col1_1}">Gas limit</div>
<input type="number" class="${css.col2}" id="gasLimit" value="3000000"> <input type="number" class="form-control ${css.gasNval} ${css.col2}" id="gasLimit" value="3000000">
</div> </div>
` `
var valueEl = yo` const valueEl = yo`
<div class="${css.crow}"> <div class="${css.crow}">
<div class="${css.col1_1}">Value</div> <div class="${css.col1_1}">Value</div>
<input type="text" class="${css.col2_1}" id="value" value="0" title="Enter the value and choose the unit"> <div class="${css.gasValueContainer}">
<select name="unit" class="${css.col2_2}" id="unit"> <input type="text" class="form-control ${css.gasNval} ${css.col2}" id="value" value="0" title="Enter the value and choose the unit">
<option data-unit="wei">wei</option> <select name="unit" class="form-control ${css.gasNvalUnit} ${css.col2_2}" id="unit">
<option data-unit="gwei">gwei</option> <option data-unit="wei">wei</option>
<option data-unit="finney">finney</option> <option data-unit="gwei">gwei</option>
<option data-unit="ether">ether</option> <option data-unit="finney">finney</option>
</select> <option data-unit="ether">ether</option>
</select>
</div>
</div> </div>
` `
var el = yo` const el = yo`
<div class="${css.settings}"> <div class="${css.settings}">
${environmentEl} ${environmentEl}
${networkEl}
${accountEl} ${accountEl}
${gasPriceEl} ${gasPriceEl}
${valueEl} ${valueEl}
...@@ -133,9 +150,12 @@ class SettingsUI { ...@@ -133,9 +150,12 @@ class SettingsUI {
this.settings.event.register('addProvider', (network) => { this.settings.event.register('addProvider', (network) => {
selectExEnv.appendChild(yo`<option selectExEnv.appendChild(yo`<option
title="Manually added environment: ${network.url}" title="Manually added environment: ${network.url}"
value="${network.name}" name="executionContext"> ${network.name} value="${network.name}"
</option>`) name="executionContext"
>
${network.name}
</option>`)
addTooltip(`${network.name} [${network.url}] added`) addTooltip(`${network.name} [${network.url}] added`)
}) })
...@@ -150,8 +170,8 @@ class SettingsUI { ...@@ -150,8 +170,8 @@ class SettingsUI {
selectExEnv.addEventListener('change', (event) => { selectExEnv.addEventListener('change', (event) => {
let context = selectExEnv.options[selectExEnv.selectedIndex].value let context = selectExEnv.options[selectExEnv.selectedIndex].value
this.settings.changeExecutionContext(context, () => { this.settings.changeExecutionContext(context, () => {
modalDialogCustom.confirm(null, 'Are you sure you want to connect to an ethereum node?', () => { modalDialogCustom.confirm('External node request', 'Are you sure you want to connect to an ethereum node?', () => {
modalDialogCustom.prompt(null, 'Web3 Provider Endpoint', 'http://localhost:8545', (target) => { modalDialogCustom.prompt('External node request', 'Web3 Provider Endpoint', 'http://localhost:8545', (target) => {
this.settings.setProviderFromEndpoint(target, context, (alertMsg) => { this.settings.setProviderFromEndpoint(target, context, (alertMsg) => {
if (alertMsg) { if (alertMsg) {
modalDialogCustom.alert(alertMsg) modalDialogCustom.alert(alertMsg)
...@@ -229,7 +249,8 @@ class SettingsUI { ...@@ -229,7 +249,8 @@ class SettingsUI {
this.netUI.innerHTML = 'can\'t detect network ' this.netUI.innerHTML = 'can\'t detect network '
return return
} }
this.netUI.innerHTML = `<i class="${css.networkItem} fa fa-plug" aria-hidden="true"></i> ${name} (${id || '-'})` let network = this._deps.networkModule.getNetworkProvider
this.netUI.innerHTML = (network() !== 'vm') ? `${name} (${id || '-'}) network` : ''
}) })
} }
......
This diff is collapsed.
...@@ -4,8 +4,6 @@ const css = csjs` ...@@ -4,8 +4,6 @@ const css = csjs`
.analysisTabView { .analysisTabView {
padding: 2%; padding: 2%;
padding-bottom: 3em; padding-bottom: 3em;
display: flex;
flex-direction: column;
} }
` `
......
const csjs = require('csjs-inject')
const css = csjs`
.compilerArticle {
padding: 10px;
}
.title {
font-size: 1.1em;
font-weight: bold;
margin-bottom: 1em;
}
.panicError {
color: red;
font-size: 20px;
}
.crow {
display: flex;
overflow: auto;
clear: both;
padding: .2em;
}
.checkboxText {
font-weight: normal;
}
.crow label {
cursor:pointer;
}
.crowNoFlex {
overflow: auto;
clear: both;
}
.info {
padding: 10px;
word-break: break-word;
}
.contract {
display: block;
margin: 3% 0;
}
.autocompileContainer {
display: flex;
align-items: center;
}
.hideWarningsContainer {
display: flex;
align-items: center;
}
.autocompile {}
.autocompileTitle {
font-weight: bold;
margin: 1% 0;
}
.autocompileText {
margin: 1% 0;
font-size: 12px;
overflow: hidden;
word-break: normal;
line-height: initial;
}
.warnCompilationSlow {
margin-left: 1%;
}
.compilerConfig {
display: flex;
align-items: center;
}
.compilerConfig label {
margin: 0;
}
.compilerSm {
padding-left: 1.25rem;
}
.name {
display: flex;
}
.size {
display: flex;
}
.checkboxes {
display: flex;
width: 100%;
justify-content: space-between;
flex-wrap: wrap;
}
.compileButton {
width: 100%;
margin: 15px 0 10px 0;
font-size: 12px;
}
.container {
margin: 0;
margin-bottom: 2%;
}
.optimizeContainer {
display: flex;
}
.noContractAlert {
display: flex;
justify-content: center;
align-items: center;
}
.contractHelperButtons {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: space-between;
float: right;
}
.copyToClipboard {
font-size: 1rem;
}
.copyIcon {
margin-right: 5px;
}
.log {
display: flex;
flex-direction: column;
margin-bottom: 5%;
overflow: visible;
}
.key {
margin-right: 5px;
text-transform: uppercase;
width: 100%;
}
.value {
display: flex;
width: 100%;
margin-top: 1.5%;
}
.questionMark {
margin-left: 2%;
cursor: pointer;
}
.questionMark:hover {
}
.detailsJSON {
padding: 8px 0;
border: none;
}
.icon {
margin-right: 0.3em;
}
.errorBlobs {
padding-left: 5px;
padding-right: 5px;
}
.spinningIcon {
display: inline-block;
position: relative;
animation: spin 2s infinite linear;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
-webkit-animation: spin 2s infinite linear;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-webkit-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-moz-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-o-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-ms-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.bouncingIcon {
display: inline-block;
position: relative;
-moz-animation: bounce 2s infinite linear;
-o-animation: bounce 2s infinite linear;
-webkit-animation: bounce 2s infinite linear;
animation: bounce 2s infinite linear;
}
@-webkit-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@-moz-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@-o-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@-ms-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
`
module.exports = css
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styles = require('../../ui/styles-guide/theme-chooser').chooser()
const css = csjs` const css = csjs`
.debuggerTabView { .debuggerTabView {
...@@ -7,7 +6,6 @@ const css = csjs` ...@@ -7,7 +6,6 @@ const css = csjs`
} }
.debugger { .debugger {
margin-bottom: 1%; margin-bottom: 1%;
${styles.rightPanel.debuggerTab.box_Debugger}
} }
` `
......
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
var styleGuide = require('../../ui/styles-guide/theme-chooser')
var styles = styleGuide.chooser()
var css = csjs` var css = csjs`
.runTabView { .runTabView {
...@@ -14,28 +12,25 @@ var css = csjs` ...@@ -14,28 +12,25 @@ var css = csjs`
font-size: 12px; font-size: 12px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding-left: 15px;
} }
.settings { .settings {
${styles.rightPanel.runTab.box_RunTab}
margin-bottom: 2%; margin-bottom: 2%;
padding: 10px 15px 15px 15px; padding: 10px 0px 15px 15px;
} }
.recorderCount { .recorderCount {
border: 1px solid ${styles.rightPanel.runTab.icon_HoverColor}; /* margin-right: 30px; */
border-radius: 50%; /* min-width: 13px; */
margin-right: 30px; /* display: flex; */
min-width: 13px; /* justify-content: center; */
height: 13px; /* align-items: center; */
display: flex; /* font-size: 10px; */
justify-content: center;
align-items: center;
font-size: 10px;
} }
.crow { .crow {
margin-top: .5em; margin-top: .5em;
display: flex; display: flex;
align-items: center; align-items: center;
width: 500px; /*width: 500px;*/
} }
.col1 { .col1 {
width: 30%; width: 30%;
...@@ -44,7 +39,6 @@ var css = csjs` ...@@ -44,7 +39,6 @@ var css = csjs`
} }
.col1_1 { .col1_1 {
font-size: 12px; font-size: 12px;
width: 15%;
min-width: 75px; min-width: 75px;
float: left; float: left;
align-self: center; align-self: center;
...@@ -53,43 +47,36 @@ var css = csjs` ...@@ -53,43 +47,36 @@ var css = csjs`
display: flex; display: flex;
align-items: center; align-items: center;
position: relative; position: relative;
width: 259px; width: 100%;
padding-right: 25px;
} }
.account { .account {
display: flex; display: flex;
align-items: center; align-items: center;
width: 266px; width: 90%;
} }
.col2 { .col2 {
${styles.rightPanel.runTab.input_RunTab}
border-radius: 3px; border-radius: 3px;
} }
.col2_1 { .col2_1 {
${styles.rightPanel.runTab.input_RunTab}
width: 164px; width: 164px;
min-width: 164px; min-width: 164px;
} }
.col2_2 { .col2_2 {
${styles.rightPanel.runTab.dropdown_RunTab}
width: 82px;
min-width: 82px;
} }
.select { .select {
${styles.rightPanel.runTab.dropdown_RunTab}
font-weight: normal; font-weight: normal;
width: 250px; width: 100%;
} }
.instanceContainer { .instanceContainer {
${styles.rightPanel.runTab.box_Instance}
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 2%; margin-bottom: 2%;
border: none; border: none;
text-align: center; text-align: center;
padding: 10px 0px 15px 15px; padding: 10px 0px 15px 0px;
} }
.pendingTxsContainer { .pendingTxsContainer {
${styles.rightPanel.runTab.box_Instance}
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-top: 2%; margin-top: 2%;
...@@ -97,8 +84,8 @@ var css = csjs` ...@@ -97,8 +84,8 @@ var css = csjs`
text-align: center; text-align: center;
} }
.container { .container {
${styles.rightPanel.runTab.box_RunTab} margin-bottom: 4%;
margin-bottom: 2%; padding-left: 15px;
} }
.recorderCollapsedView, .recorderCollapsedView,
.recorderExpandedView { .recorderExpandedView {
...@@ -109,12 +96,10 @@ var css = csjs` ...@@ -109,12 +96,10 @@ var css = csjs`
margin: 0 15px 15px 0; margin: 0 15px 15px 0;
} }
.contractNames { .contractNames {
${styles.rightPanel.runTab.dropdown_RunTab}
width: 100%; width: 100%;
border: 1px solid border: 1px solid
} }
.contractNamesError { .contractNamesError {
border: 1px solid ${styles.appProperties.errorText_Color}
} }
.subcontainer { .subcontainer {
display: flex; display: flex;
...@@ -127,18 +112,16 @@ var css = csjs` ...@@ -127,18 +112,16 @@ var css = csjs`
margin-top: 13px; margin-top: 13px;
} }
.transaction { .transaction {
${styles.rightPanel.runTab.button_transaction}
} }
.atAddress { .atAddress {
margin: 0; margin: 0;
min-width: 100px; min-width: 100px;
width: 100px; width: 100px;
font-size: 10px; /* font-size: 10px; */
word-break: inherit; word-break: inherit;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
border-right: 0; border-right: 0;
${styles.rightPanel.runTab.button_atAddress}
} }
.atAddressSect { .atAddressSect {
margin-top: 6px; margin-top: 6px;
...@@ -147,20 +130,20 @@ var css = csjs` ...@@ -147,20 +130,20 @@ var css = csjs`
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }
.ataddressinput {
padding: .25rem;
}
.create { .create {
${styles.rightPanel.runTab.button_Create}
} }
.input { .input {
${styles.rightPanel.runTab.input_RunTab};
font-size: 10px; font-size: 10px;
} }
.noInstancesText { .noInstancesText {
${styles.rightPanel.runTab.box_Instance}
font-style: italic; font-style: italic;
text-align: left; text-align: left;
padding-left: 15px;
} }
.pendingTxsText { .pendingTxsText {
${styles.rightPanel.runTab.borderBox_Instance}
font-style: italic; font-style: italic;
display: flex; display: flex;
justify-content: space-evenly; justify-content: space-evenly;
...@@ -173,15 +156,15 @@ var css = csjs` ...@@ -173,15 +156,15 @@ var css = csjs`
align-items: center; align-items: center;
} }
.transact { .transact {
color: ${styles.colors.lightRed}; color: var(--warning);
margin-right: .3em; margin-right: .3em;
} }
.payable { .payable {
color: ${styles.colors.red}; color: var(--warning);
margin-right: .3em; margin-right: .3em;
} }
.call { .call {
color: ${styles.colors.lightBlue}; color: var(--info);
margin-right: .3em; margin-right: .3em;
} }
.pendingContainer { .pendingContainer {
...@@ -199,31 +182,23 @@ var css = csjs` ...@@ -199,31 +182,23 @@ var css = csjs`
cursor: pointer; cursor: pointer;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
color: ${styles.rightPanel.runTab.icon_Color};
margin-left: 5px; margin-left: 5px;
} }
.icon:hover { .icon:hover {
font-size: 12px; font-size: 12px;
color: ${styles.rightPanel.runTab.icon_HoverColor}; color: var(--warning);
} }
.errorIcon { .errorIcon {
color: ${styles.appProperties.errorText_Color}; color: var(--warning);
margin-left: 15px; margin-left: 15px;
} }
.failDesc { .failDesc {
color: ${styles.appProperties.errorText_Color}; color: var(--warning);
padding-left: 10px; padding-left: 10px;
display: inline; display: inline;
} }
.network { .network {
display: flex; margin-left: 8px;
justify-content: flex-end;
align-items: center;
position: absolute;
color: grey;
width: 100%;
height: 100%;
padding-right: 28px;
pointer-events: none; pointer-events: none;
} }
.networkItem { .networkItem {
...@@ -235,7 +210,6 @@ var css = csjs` ...@@ -235,7 +210,6 @@ var css = csjs`
.transactionActions { .transactionActions {
display: flex; display: flex;
justify-content: space-evenly; justify-content: space-evenly;
${styles.rightPanel.runTab.box_Info_RunTab};
width: 145px; width: 145px;
} }
.orLabel { .orLabel {
...@@ -244,6 +218,24 @@ var css = csjs` ...@@ -244,6 +218,24 @@ var css = csjs`
.infoDeployAction { .infoDeployAction {
margin-left: 5px; margin-left: 5px;
font-size: 13px; font-size: 13px;
color: var(--info);
}
.gasValueContainer {
flex-direction: row;
display: flex;
}
.gasNval {
/* transform: scale(0.7); */
/* transform-origin: left; */
margin-right: 10px;
width: 100px;
font-size: 0.8rem;
}
.gasNvalUnit {
/* transform: scale(0.7); */
/* transform-origin: left; */
margin-right: 10px;
font-size: 0.8rem;
} }
` `
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment