Merge branch 'swap_it' into bootstrap_compiletab_tighten

pull/1/head
Rob Stupay 6 years ago
commit 912b6a0c55
  1. 2
      .circleci/config.yml
  2. 8
      src/app/components/vertical-icons-component.js
  3. 21
      src/app/files/file-explorer.js
  4. 8
      src/app/files/styles/file-explorer-styles.js
  5. 14
      src/app/panels/editor-panel.js
  6. 11
      src/app/panels/styles/terminal-styles.js
  7. 2
      src/app/panels/tab-proxy.js
  8. 12
      src/app/panels/terminal.js
  9. 12
      src/app/tabs/compile-tab.js
  10. 16
      src/app/ui/dropdown.js
  11. 212
      src/app/ui/landing-page/landing-page.js
  12. 17
      src/app/ui/landing-page/section.js
  13. 41
      src/app/ui/landing-page/workspace.js
  14. 18
      src/app/ui/styles/dropdown-styles.js
  15. 4
      src/app/ui/styles/modaldialog-styles.js
  16. 1
      src/remixAppManager.js
  17. 2
      test-browser/helpers/contracts.js
  18. 4
      test-browser/helpers/init.js

@ -19,7 +19,7 @@ jobs:
- ENCRYPTION_LABEL3: "1b1c118ea62d"
- COMMIT_AUTHOR_EMAIL: "chris@ethereum.org"
- 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
steps:

@ -56,8 +56,8 @@ class VerticalIconComponent {
* Add an icon to the map
* @param {ModuleProfile} profile The profile of the module
*/
addIcon ({kind, name, icon}) {
this.icons[name] = yo`<div class="${css.icon}" onclick="${(e) => { this._iconClick(name) }}" title="${name}" ><img src="${icon}" alt="${name}" /></div>`
addIcon ({kind, name, icon, displayName}) {
this.icons[name] = yo`<div class="${css.icon}" onclick="${(e) => { this._iconClick(name) }}" plugin="${name}" title="${displayName || name}" ><img src="${icon}" alt="${name}" /></div>`
this.iconKind[kind || 'other'].appendChild(this.icons[name])
}
@ -95,11 +95,11 @@ class VerticalIconComponent {
let currentTitle = currentActive.getAttribute('title')
currentActive.classList.toggle(`${css.active}`)
if (currentTitle !== name) {
let activate = this.view.querySelector(`[title="${name}"]`)
let activate = this.view.querySelector(`[plugin="${name}"]`)
if (activate) activate.classList.toggle(`${css.active}`)
}
} else {
let activate = this.view.querySelector(`[title="${name}"]`)
let activate = this.view.querySelector(`[plugin="${name}"]`)
if (activate) activate.classList.toggle(`${css.active}`)
}
this.events.emit('showContent', name)

@ -10,7 +10,6 @@ var Treeview = require('../ui/TreeView')
var modalDialog = require('../ui/modaldialog')
var EventManager = require('../../lib/events')
var contextMenu = require('../ui/contextMenu')
var addTooltip = require('../ui/tooltip')
var css = require('./styles/file-explorer-styles')
var globalRegistry = require('../../global/registry')
var queryParams = new QueryParams()
@ -63,6 +62,8 @@ function fileExplorer (localRegistry, files, menuItems) {
fileManager: self._components.registry.get('filemanager').api
}
self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` })
// warn if file changed outside of Remix
function remixdDialog () {
return yo`<div>This file has been changed outside of Remix IDE.</div>`
@ -175,12 +176,12 @@ function fileExplorer (localRegistry, files, menuItems) {
MENU_HANDLE && MENU_HANDLE.hide(null, true)
MENU_HANDLE = contextMenu(event, {
'Rename': () => {
if (self.files.readonly) { return addTooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') }
if (self.files.readonly) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') }
var name = label.querySelector('label[data-path="' + key + '"]')
if (name) editModeOn(name)
},
'Delete': () => {
if (self.files.readonly) { return addTooltip('cannot delete folder. ' + self.files.type + ' is a read only explorer') }
if (self.files.readonly) { return tooltip('cannot delete folder. ' + self.files.type + ' is a read only explorer') }
modalDialogCustom.confirm(null, 'Do you want to delete this folder?', () => { files.remove(key) }, () => {})
}
})
@ -191,12 +192,12 @@ function fileExplorer (localRegistry, files, menuItems) {
MENU_HANDLE && MENU_HANDLE.hide(null, true)
MENU_HANDLE = contextMenu(event, {
'Rename': () => {
if (self.files.readonly) { return addTooltip('cannot rename file. ' + self.files.type + ' is a read only explorer') }
if (self.files.readonly) { return tooltip('cannot rename file. ' + self.files.type + ' is a read only explorer') }
var name = label.querySelector('label[data-path="' + key + '"]')
if (name) editModeOn(name)
},
'Delete': () => {
if (self.files.readonly) { return addTooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') }
if (self.files.readonly) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') }
modalDialogCustom.confirm(null, 'Do you want to delete this file?', () => { files.remove(key) }, () => {})
}
})
@ -427,7 +428,7 @@ fileExplorer.prototype.packageFiles = function (filesProvider, callback) {
else {
async.eachSeries(Object.keys(files), (path, cb) => {
filesProvider.get(path, (error, content) => {
if (/^\s+$/.test(content)) {
if (/^\s+$/.test(content) || !content.length) {
content = '// this line is added to create a gist. Empty file is not allowed.'
}
if (error) cb(error)
@ -507,7 +508,7 @@ fileExplorer.prototype.renderMenuItems = function () {
items = this.menuItems.map(({action, title, icon}) => {
if (action === 'uploadFile') {
return yo`
<label class="${icon} ${css.newFile}">
<label class="${icon} ${css.newFile}" title="${title}">
<input type="file" onchange=${(event) => {
event.stopPropagation()
this.uploadFile(event)
@ -516,14 +517,12 @@ fileExplorer.prototype.renderMenuItems = function () {
`
} else {
return yo`
<span onclick=${(event) => { event.stopPropagation(); this[ action ]() }} class="newFile ${css.newFile}" title=${title}>
<i class=${icon}></i>
</span>
<span onclick=${(event) => { event.stopPropagation(); this[ action ]() }} class="newFile ${icon} ${css.newFile}" title=${title}></span>
`
}
})
}
return yo`<span class=${css.menu}>${items}</span>`
return yo`<span class=" ${css.menu}">${items}</span>`
}
fileExplorer.prototype.ensureRoot = function (cb) {

@ -2,7 +2,7 @@ var csjs = require('csjs-inject')
var css = csjs`
.label {
margin-bottom : 0px;
margin-top : 4px
}
.fileexplorer {
box-sizing : border-box;
@ -19,13 +19,13 @@ var css = csjs`
padding : 4px;
}
.newFile {
padding : 4px;
padding-right : 5px;
}
.newFile i {
cursor : pointer;
}
.newFile i:hover {
color : var(--secondary)
.newFile:hover {
transform : scale(1.3);
}
.menu {
margin-left : 20px;

@ -50,6 +50,13 @@ class EditorPanel {
pluginManager: self._components.registry.get('pluginmanager').api
}
self.tabProxy = new TabProxy(self._deps.fileManager, self._components.editor, self.appStore, self.appManager)
let showApp = function (name) {
self.mainPanelComponent.showContent(name)
self._view.editor.style.display = 'none'
self._components.contextView.hide()
self._view.mainPanel.style.display = 'block'
}
self.appManager.event.on('ensureActivated', (name) => { if (name === 'home') { showApp(name) } })
/*
We listen here on event from the tab component to display / hide the editor and mainpanel
depending on the content that should be displayed
@ -65,12 +72,7 @@ class EditorPanel {
})
self.tabProxy.event.on('closeFile', (file) => {
})
self.tabProxy.event.on('switchApp', (name) => {
self.mainPanelComponent.showContent(name)
self._view.editor.style.display = 'none'
self._components.contextView.hide()
self._view.mainPanel.style.display = 'block'
})
self.tabProxy.event.on('switchApp', showApp)
self.tabProxy.event.on('closeApp', (name) => {
self._view.editor.style.display = 'block'
self._components.contextView.hide()

@ -21,6 +21,8 @@ var css = csjs`
display : flex;
align-items : center;
width : 100%;
border-bottom-style : ridge;
max-height : 35px;
}
.clear {
margin-right : 20px;
@ -91,7 +93,9 @@ var css = csjs`
.search {
display : flex;
align-items : center;
margin-right: 10px;
width : 200px;
padding-left : 20px;
height : 100%;
}
.filter {
width : 200px;
@ -99,15 +103,17 @@ var css = csjs`
margin-right : 0px;
border-top-left-radius : 0px;
border-bottom-left-radius : 0px;
height : 100%;
}
.searchIcon {
height : 25px;
height : 100%;
width : 25px;
border-top-left-radius : 3px;
border-bottom-left-radius : 3px;
display : flex;
align-items : center;
justify-content : center;
margin-right : 5px;
}
.listen {
margin-right : 30px;
@ -122,7 +128,6 @@ var css = csjs`
.verticalLine {
border-left : 1px solid var(--secondary)
height : 65%;
margin-right : 30px;
}
.pendingTx {
border : 1px solid var(--secondary);

@ -107,7 +107,7 @@ export class TabProxy {
</div>
`
let tabsbar = yo`
<div class="d-flex">
<div class="d-flex border-bottom">
<div class="m-1">
<span class="p-1">
<i class="m-1 fa fa-plus" style="color: var(--text-dark)" onclick=${increase} aria-hidden="true" title="increase editor font size"></i>

@ -128,7 +128,7 @@ class Terminal {
self._view.bar = yo`
<div class="${css.bar}">
${self._view.dragbar}
<div class=${css.menu}>
<div class="${css.menu} bg-light">
${self._view.icon}
<div class=${css.clear} onclick=${clear}>
<i class="fa fa-ban" aria-hidden="true" title="Clear console"
@ -136,15 +136,15 @@ class Terminal {
</div>
${self._view.pendingTxCount}
<div class=${css.verticalLine}></div>
<div class=${css.listen}>
<div class="form-check">
<input id="listenNetworkCheck" onchange=${listenOnNetwork} type="checkbox" class="form-check-input "
title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you">
<label class="${css.listenLabel} form-check-label" title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you" for="listenNetworkCheck">listen on network</label>
<label class="form-check-label" title="If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you" for="listenNetworkCheck">listen on network</label>
</div>
${self._view.dropdown}
<div class=${css.search}>
<i class="fa fa-search ${css.searchIcon} bg-light btn" aria-hidden="true"></i>
<input spellcheck="false" type="text" class=${css.filter} onkeydown=${filter} placeholder="Search transactions">
<i class="fa fa-search ${css.searchIcon} bg-light btn-light" aria-hidden="true"></i>
<input spellcheck="false" type="text" class="${css.filter} form-control" onkeydown=${filter} placeholder="Search transactions">
</div>
</div>
</div>
@ -158,7 +158,7 @@ class Terminal {
</div>
`
self._view.el = yo`
<div class="${css.panel}">
<div class="${css.panel}" style="height: 180px;">
${self._view.bar}
${self._view.term}
</div>

@ -111,7 +111,8 @@ class CompileTab extends ApiFactory {
if (data['error']) {
this.renderer.error(data['error'].formattedMessage, this._view.errorContainer, {type: data['error'].severity || 'error'})
if (data['error'].mode === 'panic') {
return modalDialogCustom.alert(yo`<div><i class="fa fa-exclamation-circle ${css.panicError}" aria-hidden="true"></i>
return modalDialogCustom.alert(yo`
<div><i class="fa fa-exclamation-circle ${css.panicError}" aria-hidden="true"></i>
The compiler returned with the following internal error: <br> <b>${data['error'].formattedMessage}.<br>
The compiler might be in a non-sane state, please be careful and do not use further compilation data to deploy to mainnet.
It is heavily recommended to use another browser not affected by this issue (Firefox is known to not be affected).</b><br>
@ -155,7 +156,7 @@ class CompileTab extends ApiFactory {
*/
contractSelection (contractList = []) {
return contractList.length !== 0
? yo`<section class="${css.container}">
? yo`<section class="${css.container} clearfix">
<!-- Select Compiler Version -->
<header class="navbar navbar-light bg-light input-group mb-3 ${css.compilerArticle}">
<div class="input-group-prepend">
@ -193,7 +194,7 @@ class CompileTab extends ApiFactory {
</div>
</article>
</section>`
: yo`<section class="${css.container}"><article class="${css.compilerArticle}">
: yo`<section class="${css.container} clearfix"><article class="${css.compilerArticle}">
<span class="alert alert-warning" role="alert">No Contract Compiled Yet</span>
</article></section>`
}
@ -293,7 +294,10 @@ class CompileTab extends ApiFactory {
})
if (details[propertyName] !== '') {
try {
node = yo`<div>${treeView.render(typeof details[propertyName] === 'object' ? details[propertyName] : JSON.parse(details[propertyName]))}</div>` // catch in case the parsing fails.
node = yo`
<div>
${treeView.render(typeof details[propertyName] === 'object' ? details[propertyName] : JSON.parse(details[propertyName]))}
</div>` // catch in case the parsing fails.
} catch (e) {
node = yo`<div>Unable to display "${propertyName}": ${e.message}</div>`
}

@ -45,11 +45,19 @@ class Dropdown {
</div>
`
self._view.el = yo`
<div class=${css.dropdown} onclick=${show}>
<div name="dropdown" class="${css.dropdown} form-control form-control-sm" onclick=${show}>
${self._view.selected}
<div class=${css.options} style="display: none;">
<div class="${css.options} bg-light" style="display: none;}">
${self.data._options.map(label => {
var input = yo`<input data-idx=${self.data._elements.length} onchange=${emit} type="checkbox" />`
let index = self.data._elements.length
var input = yo`
<input
data-idx=${index}
onchange=${emit}
type="${index === 2 ? 'checkbox' : 'radio'}"
id="${label}"
/>
`
if (self.data.selected.indexOf(label) !== -1) {
input.checked = true
self.event.trigger('select', [label])
@ -58,7 +66,7 @@ class Dropdown {
return yo`
<div class=${css.option}>
${input}
<label>${label}</label>
<label class="text-dark" for="${label}">${label}</label>
</div>
`
})}

File diff suppressed because one or more lines are too long

@ -3,23 +3,21 @@ let csjs = require('csjs-inject')
var css = csjs`
.text {
background-color : var(--success);
cursor: pointer;
color: var(--primary);
font-weight: normal;
max-width: 300px;
user-select: none;
}
.text:hover {
font-weight: bold;
}
.link {
cursor: pointer;
background-color : var(--primary);
color: var(--success);
font-weight: normal;
text-decoration : none;
user-select: none;
}
.link:hover {
color: var(--success);
font-weight: bold;
text-decoration : none;
}
@ -29,13 +27,12 @@ class Section {
constructor (title, actions) {
this.title = title
this.actions = actions
this.cardStyle = (this.title === 'Workspaces') ? 'bg-success text-primary' : 'bg-primary text-success border-success'
}
render () {
let sectionLook = yo`
<div class="card ${this.cardStyle} p-3" style="min-width: 300px;">
<div class="card-header font-weight-bold">${this.title}</div>
<div class="card border-0 bg-light bd-light text-dark p-1" style="min-width: 300px; min-height: 210px;">
<div class="card-header font-weight-bold" style="user-select: none;">${this.title}</div>
<p></p>
</div>
`
@ -43,7 +40,7 @@ class Section {
if (this.actions[i].type === `callback`) {
sectionLook.appendChild(yo`
<div>
<span class ="${css.text}" onclick=${this.actions[i].payload} >
<span class="${css.text} text-dark" onclick=${this.actions[i].payload} >
${this.actions[i].label}
</span>
</div>
@ -51,7 +48,7 @@ class Section {
} else if (this.actions[i].type === `link`) {
sectionLook.appendChild(yo`
<div >
<a class="${css.link} text-decoration-none" href=${this.actions[i].payload} target="_blank" >
<a class="${css.link} text-dark text-decoration-none" href=${this.actions[i].payload} target="_blank" >
${this.actions[i].label}
</a>
</div>

@ -1,7 +1,8 @@
export class Workspace {
constructor (title, description, activate, deactivate) {
constructor (title, description, isMain, activate, deactivate) {
this.title = title
this.description = description
this.isMain = isMain
this.activate = activate
this.deactivate = deactivate
}
@ -9,37 +10,31 @@ export class Workspace {
export const defaultWorkspaces = (appManager) => {
return [
new Workspace('Solidity Basic', '', () => {
appManager.ensureActivated('solidity')
}, () => {}),
new Workspace('Solidity Unit testing', '', () => {
appManager.ensureActivated('solidity')
appManager.ensureActivated('solidityUnitTesting')
}, () => {}),
new Workspace('Solidity Full Environement', '', () => {
new Workspace(
'Solidity',
'Writing smart contracts. It is used for implementing smart contracts on various blockchain platforms',
true,
() => {
appManager.ensureActivated('solidity')
appManager.ensureActivated('run')
appManager.ensureActivated('solidityStaticAnalysis')
appManager.ensureActivated('solidityUnitTesting')
}, () => {}),
new Workspace('Vyper Basic', '', () => {
new Workspace(
'Vyper',
'Vyper is a contract-oriented, pythonic programming language that targets the Ethereum Virtual Machine (EVM)',
true,
() => {
appManager.ensureActivated('vyper')
}, () => {}),
new Workspace('Pipeline', '', () => {
appManager.ensureActivated('solidity')
appManager.ensureActivated('run')
appManager.ensureActivated('pipeline')
}, () => {}),
new Workspace('Deploy and Run Solidity', '', () => {
appManager.ensureActivated('solidity')
appManager.ensureActivated('run')
new Workspace('Debugger', 'Debug transactions with remix', false, () => {
appManager.ensureActivated('debugger')
}, () => {}),
new Workspace('Deploy and Run Vyper', '', () => {
appManager.ensureActivated('vyper')
new Workspace('Pipeline', '', false, () => {
appManager.ensureActivated('solidity')
appManager.ensureActivated('pipeline')
appManager.ensureActivated('run')
}, () => {}),
new Workspace('Debugger', '', () => {
appManager.ensureActivated('debugger')
}, () => {})
})
]
}

@ -6,23 +6,22 @@ var css = csjs`
position : relative;
display : flex;
flex-direction : column;
margin-right : 10px;
margin-left : 10px;
width : auto;
}
.selectbox {
display : flex;
align-items : center;
margin : 3px;
cursor : pointer;
}
.selected {
display : inline-block;
min-width : 30ch;
max-width : 30ch;
white-space : nowrap;
text-overflow : ellipsis;
overflow : hidden;
padding : 3px;
margin-right : 10px;
min-width : 200px;
}
.icon {
padding : 0px 5px;
@ -32,15 +31,18 @@ var css = csjs`
display : flex;
flex-direction : column;
align-items : end;
top : 24px;
top : 32px;
left : 0;
width : 250px;
border : 1px solid var(--primary);
width : 245px;
border : 1px solid var(--dark);
border-radius : 3px;
border-top : 0;
padding-left : 5px;
}
.option {
margin: 0;
margin-left : 5px;
margin-top : 5px;
width : -webkit-fill-available;
}
`

@ -56,16 +56,12 @@ var css = csjs`
animation-duration: 0.4s
}
.modalFooterOk {
background-color: var(--light);
color: var(--dark);
cursor: pointer;
}
.modalFooterOk:hover {
cursor: pointer;
}
.modalFooterCancel {
background-color: var(--light);
color: var(--dark);
margin-left: 1em;
cursor: pointer;
}

@ -18,6 +18,7 @@ export class RemixAppManager extends AppManagerApi {
ensureActivated (apiName) {
if (!this.store.isActive(apiName)) this.activateOne(apiName)
this.event.emit('ensureActivated', apiName)
}
proxy () {

@ -28,7 +28,7 @@ module.exports = {
}
function clickLaunchIcon (icon) {
this.click('#icon-panel div[title="' + icon + '"]')
this.click('#icon-panel div[plugin="' + icon + '"]')
return this
}

@ -17,7 +17,7 @@ module.exports = function (browser, callback) {
}
function initModules (browser, callback) {
browser.click('#icon-panel div[title="pluginManager"]')
browser.click('#icon-panel div[plugin="pluginManager"]')
.execute(function () {
document.querySelector('div[title="pluginManager"]').scrollTop = document.querySelector('div[title="pluginManager"]').scrollHeight
}, [], function () {
@ -25,7 +25,7 @@ function initModules (browser, callback) {
.click('#pluginManager article[title="run"] button')
.click('#pluginManager article[title="solidityStaticAnalysis"] button')
.click('#pluginManager article[title="debugger"] button')
.click('#icon-panel div[title="fileExplorers"]')
.click('#icon-panel div[plugin="fileExplorers"]')
.perform(() => { callback() })
})
}

Loading…
Cancel
Save