move settings of deploy tab to react

move settings of deploy tab to react

fix lint

re-add some missing data-ids or update them in the tests

move settings of deploy tab to react

fix lint

Fix e2e tests

Update remaining tests

parse gas value so it doesn't allow values like 0000

replicate value selector validation behaviour
deploy_settings_cherry_picked
Iuri Matias 4 years ago
parent 0a95c8bf83
commit f9497b0d89
  1. 3
      apps/remix-ide-e2e/src/commands/addFile.ts
  2. 3
      apps/remix-ide-e2e/src/commands/renamePath.ts
  3. 2
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  4. 2
      apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts
  5. 3
      apps/remix-ide-e2e/src/tests/defaultLayout.test.ts
  6. 3
      apps/remix-ide-e2e/src/tests/fileExplorer.test.ts
  7. 2
      apps/remix-ide-e2e/src/tests/runAndDeploy.ts
  8. 12
      apps/remix-ide-e2e/src/tests/solidityImport.test.ts
  9. 2
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  10. 2
      apps/remix-ide/src/app/panels/file-panel.js
  11. 324
      apps/remix-ide/src/app/tabs/runTab/settings.js
  12. 2
      libs/remix-ui/debugger-ui/tsconfig.lib.json
  13. 4
      libs/remix-ui/run-tab/.babelrc
  14. 18
      libs/remix-ui/run-tab/.eslintrc
  15. 7
      libs/remix-ui/run-tab/README.md
  16. 1
      libs/remix-ui/run-tab/src/index.ts
  17. 34
      libs/remix-ui/run-tab/src/lib/settings/account-selector.css
  18. 75
      libs/remix-ui/run-tab/src/lib/settings/account-selector.tsx
  19. 29
      libs/remix-ui/run-tab/src/lib/settings/environment-selector.css
  20. 38
      libs/remix-ui/run-tab/src/lib/settings/environment-selector.tsx
  21. 16
      libs/remix-ui/run-tab/src/lib/settings/gas-price.css
  22. 15
      libs/remix-ui/run-tab/src/lib/settings/gas-price.tsx
  23. 3
      libs/remix-ui/run-tab/src/lib/settings/settings.css
  24. 22
      libs/remix-ui/run-tab/src/lib/settings/settings.tsx
  25. 31
      libs/remix-ui/run-tab/src/lib/settings/value-selector.css
  26. 36
      libs/remix-ui/run-tab/src/lib/settings/value-selector.tsx
  27. 16
      libs/remix-ui/run-tab/tsconfig.json
  28. 13
      libs/remix-ui/run-tab/tsconfig.lib.json
  29. 3
      nx.json
  30. 3
      tsconfig.json
  31. 16
      workspace.json

@ -16,7 +16,8 @@ class AddFile extends EventEmitter {
function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) {
browser.clickLaunchIcon('udapp')
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.click('.newFile')
.waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]')
// .scrollAndClick('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items')

@ -42,7 +42,8 @@ function renamePath (browser: NightwatchBrowser, path: string, newFileName: stri
})
})
.pause(1000)
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.pause(2000)
.waitForElementNotPresent('[data-path="' + path + '"]')
.waitForElementPresent('[data-path="' + renamedPath + '"]')

@ -71,7 +71,7 @@ module.exports = {
'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="settingsWeb3Mode"]')
.click('*[id="web3-mode"]')
.modalFooterOKClick()
.clickLaunchIcon('solidity')
.testContracts('Untitled.sol', sources[0]['browser/Untitled.sol'], ['Ballot'])

@ -79,7 +79,7 @@ module.exports = {
'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="settingsWeb3Mode"]')
.click('*[id="web3-mode"]')
.modalFooterOKClick()
.clickLaunchIcon('solidity')
.testContracts('Untitled.sol', sources[0]['browser/Untitled.sol'], ['Ballot'])

@ -23,7 +23,8 @@ module.exports = {
.waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/contracts"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/scripts"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/tests"]')
.waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/README.txt"]')
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
},
'Loads Main View': function (browser: NightwatchBrowser) {

@ -48,7 +48,8 @@ module.exports = {
'Should create a new folder': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/README.txt"]')
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.click('[data-id="fileExplorerNewFilecreateNewFolder"]')
.pause(1000)
.waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]')

@ -27,7 +27,7 @@ module.exports = {
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
.assert.containsText('*[data-id="sidePanelSwapitTitle"]', 'DEPLOY & RUN TRANSACTIONS')
.validateValueInput('#value', '0000', '0')
.validateValueInput('#value', '', '0')
// .validateValueInput('#value', '', '0')
.validateValueInput('#value', 'dragon', '0')
},

@ -49,7 +49,8 @@ module.exports = {
browser
.setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js') // open-zeppelin moved to pragma ^0.8.0 (master branch)
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"')
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.addFile('Untitled6.sol', sources[5]['browser/Untitled6.sol'])
.clickLaunchIcon('fileExplorers')
.verifyContracts(['test10', 'ERC20'], { wait: 10000 })
@ -58,7 +59,8 @@ module.exports = {
'Test Github Import - raw URL': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"')
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.addFile('Untitled7.sol', sources[6]['browser/Untitled7.sol'])
.clickLaunchIcon('fileExplorers')
.verifyContracts(['test11', 'ERC20'], { wait: 10000 })
@ -68,7 +70,8 @@ module.exports = {
browser
.setSolidityCompilerVersion('soljson-v0.7.4+commit.3f05b770.js')
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"')
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.addFile('Untitled8.sol', sources[7]['browser/Untitled8.sol'])
.clickLaunchIcon('fileExplorers')
.clickLaunchIcon('solidity')
@ -85,7 +88,8 @@ module.exports = {
browser
// .setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js')
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"')
.waitForElementPresent('[data-id="filePanelFileExplorer"]')
.click('[data-id="filePanelFileExplorer"]') // focus on root directory
.addFile('Untitled9.sol', sources[8]['browser/Untitled9.sol'])
.clickLaunchIcon('fileExplorers')
.verifyContracts(['test13', 'ERC20', 'SafeMath'], { wait: 30000 })

@ -73,7 +73,7 @@ module.exports = {
browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]')
.click('*[id="web3-mode"]')
.modalFooterOKClick()
.executeScript('web3.eth.getAccounts()')
.pause(2000)

@ -142,7 +142,7 @@ module.exports = class Filepanel extends ViewPlugin {
renderComponent () {
ReactDOM.render(
<div className='remixui_container'>
<div className='remixui_fileexplorer' onClick={() => this.resetFocus(true)}>
<div className='remixui_fileexplorer' data-id='filePanelFileExplorer' onClick={() => this.resetFocus(true)}>
<div className='remixui_fileExplorerTree'>
<div>
<div className='pl-2 remixui_treeview' data-id='filePanelFileExplorerTree'>

@ -1,24 +1,35 @@
const $ = require('jquery')
import { Settings } from '@remix-ui/run-tab' // eslint-disable-line
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
const asyncJS = require('async')
const yo = require('yo-yo')
const remixLib = require('@remix-project/remix-lib')
const EventManager = remixLib.EventManager
const css = require('../styles/run-tab-styles')
const copyToClipboard = require('../../ui/copy-to-clipboard')
const modalDialogCustom = require('../../ui/modal-dialog-custom')
const addTooltip = require('../../ui/tooltip')
const helper = require('../../../lib/helper.js')
const globalRegistry = require('../../../global/registry')
const defaultOptions = [
{ value: 'vm', name: 'JavaScript VM', title: 'Execution environment does not connect to any node, everything is local and in memory only.' },
{ value: 'injected', name: 'Injected Web3', title: 'Execution environment has been provided by Metamask or similar provider.' },
{ value: 'web3', name: 'Web3 Provider', title: 'Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse! If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http.' }
]
class SettingsUI {
constructor (blockchain, networkModule) {
this.blockchain = blockchain
this.event = new EventManager()
this._components = {}
this.options = defaultOptions
this.accounts = []
this.blockchain.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
if (!lookupOnly) this.el.querySelector('#value').value = 0
if (error) return
this.updateAccountBalances()
this.updateAccountsAndBalances()
})
this._components = {
registry: globalRegistry,
@ -29,205 +40,40 @@ class SettingsUI {
config: this._components.registry.get('config').api
}
this._deps.config.events.on('settings/personal-mode_changed', this.onPersonalChange.bind(this))
setInterval(() => {
this.updateAccountBalances()
}, 1000)
this.accountListCallId = 0
this.loadedAccounts = {}
}
updateAccountBalances () {
if (!this.el) return
var accounts = $(this.el.querySelector('#txorigin')).children('option')
accounts.each((index, account) => {
this.blockchain.getBalanceInEther(account.value, (err, balance) => {
if (err) return
const updated = helper.shortenAddress(account.value, balance)
if (updated !== account.innerText) { // check if the balance has been updated and update UI accordingly.
account.innerText = updated
}
})
})
this._deps.config.events.on('settings/personal-mode_changed', this.renderSettings.bind(this))
setInterval(this.updateAccountsAndBalances.bind(this), 2000)
}
validateInputKey (e) {
// preventing not numeric keys
// preventing 000 case
if (!helper.isNumeric(e.key) ||
(e.key === '0' && !parseInt(this.el.querySelector('#value').value) && this.el.querySelector('#value').value.length > 0)) {
e.preventDefault()
e.stopImmediatePropagation()
}
}
renderSettings () {
const personalModeChecked = this._deps.config.get('settings/personal-mode')
const selectedProvider = this.blockchain.getProvider()
validateValue () {
const valueEl = this.el.querySelector('#value')
valueEl.value = parseInt(valueEl.value)
// assign 0 if given value is
// - empty
// - not valid (for ex 4345-54)
// - contains only '0's (for ex 0000) copy past or edit
if (!valueEl.value) valueEl.value = 0
// if giveen value is negative(possible with copy-pasting) set to 0
if (valueEl.value < 0) valueEl.value = 0
ReactDOM.render(<Settings accounts={this.accounts} options={this.options} selectedProvider={selectedProvider} personalModeChecked={personalModeChecked} updateNetwork={this.updateNetwork.bind(this)} newAccount={this.newAccount.bind(this)} signMessage={this.signMessage.bind(this)} copyToClipboard={copyToClipboard} />, this.el)
}
render () {
this.netUI = yo`<span class="${css.network} badge badge-secondary"></span>`
this.el = yo`<span></span>`
var environmentEl = yo`
<div class="${css.crow}">
<label id="selectExEnv" class="${css.settingsLabel}">
Environment
</label>
<div class="${css.environment}">
<select id="selectExEnvOptions" data-id="settingsSelectEnvOptions" onchange=${() => { this.updateNetwork() }} class="form-control ${css.select} custom-select">
<option id="vm-mode"
title="Execution environment does not connect to any node, everything is local and in memory only."
value="vm" name="executionContext"> JavaScript VM
</option>
<option id="injected-mode"
title="Execution environment has been provided by Metamask or similar provider."
value="injected" name="executionContext"> Injected Web3
</option>
<option id="web3-mode" data-id="settingsWeb3Mode"
title="Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse!
If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http."
value="web3" name="executionContext"> Web3 Provider
</option>
</select>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#run-setup" target="_blank"><i class="${css.infoDeployAction} ml-2 fas fa-info" title="check out docs to setup Environment"></i></a>
</div>
</div>
`
const networkEl = yo`
<div class="${css.crow}">
<div class="${css.settingsLabel}">
</div>
<div class="${css.environment}" data-id="settingsNetworkEnv">
${this.netUI}
</div>
</div>
`
const accountEl = yo`
<div class="${css.crow}">
<label class="${css.settingsLabel}">
Account
<span id="remixRunPlusWraper" title="Create a new account" onload=${this.updatePlusButton.bind(this)}>
<i id="remixRunPlus" class="fas fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${this.newAccount.bind(this)}"></i>
</span>
</label>
<div class="${css.account}">
<select data-id="runTabSelectAccount" name="txorigin" class="form-control ${css.select} custom-select pr-4" id="txorigin"></select>
<div style="margin-left: -5px;">${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)}</div>
<i id="remixRunSignMsg" data-id="settingsRemixRunSignMsg" class="mx-1 fas fa-edit ${css.icon}" aria-hidden="true" onclick=${this.signMessage.bind(this)} title="Sign a message using this account key"></i>
</div>
</div>
`
this.renderSettings()
const gasPriceEl = yo`
<div class="${css.crow}">
<label class="${css.settingsLabel}">Gas limit</label>
<input type="number" class="form-control ${css.gasNval} ${css.col2}" id="gasLimit" value="3000000">
</div>
`
this.blockchain.event.register('addProvider', (network) => {
this.options.push({ title: `provider name: ${network.name}`, value: `${network.name}`, name: 'executionContext' })
this.renderSettings()
const valueEl = yo`
<div class="${css.crow}">
<label class="${css.settingsLabel}" data-id="remixDRValueLabel">Value</label>
<div class="${css.gasValueContainer}">
<input
type="number"
min="0"
pattern="^[0-9]"
step="1"
class="form-control ${css.gasNval} ${css.col2}"
id="value"
data-id="dandrValue"
value="0"
title="Enter the value and choose the unit"
onkeypress=${(e) => this.validateInputKey(e)}
onchange=${() => this.validateValue()}
>
<select name="unit" class="form-control p-1 ${css.gasNvalUnit} ${css.col2_2} custom-select" id="unit">
<option data-unit="wei">wei</option>
<option data-unit="gwei">gwei</option>
<option data-unit="finney">finney</option>
<option data-unit="ether">ether</option>
</select>
</div>
</div>
`
const el = yo`
<div class="${css.settings}">
${environmentEl}
${networkEl}
${accountEl}
${gasPriceEl}
${valueEl}
</div>
`
var selectExEnv = environmentEl.querySelector('#selectExEnvOptions')
this.setDropdown(selectExEnv)
this.blockchain.event.register('contextChanged', (context, silent) => {
this.setFinalContext()
})
setInterval(() => {
this.updateNetwork()
}, 1000)
this.el = el
this.fillAccountsList()
return el
}
setDropdown (selectExEnv) {
this.selectExEnv = selectExEnv
const addProvider = (network) => {
selectExEnv.appendChild(yo`<option
title="provider name: ${network.name}"
value="${network.name}"
name="executionContext"
>
${network.name}
</option>`)
addTooltip(yo`<span><b>${network.name}</b> provider added</span>`)
}
})
const removeProvider = (name) => {
var env = selectExEnv.querySelector(`option[value="${name}"]`)
if (env) {
selectExEnv.removeChild(env)
addTooltip(yo`<span><b>${name}</b> provider removed</span>`)
}
}
this.blockchain.event.register('addProvider', provider => addProvider(provider))
this.blockchain.event.register('removeProvider', name => removeProvider(name))
this.blockchain.event.register('removeProvider', (name) => {
this.options = this.options.filter((option) => option.name !== name)
this.renderSettings()
selectExEnv.addEventListener('change', (event) => {
const context = selectExEnv.options[selectExEnv.selectedIndex].value
this.blockchain.changeExecutionContext(context, () => {
modalDialogCustom.prompt('External node request', this.web3ProviderDialogBody(), 'http://127.0.0.1:8545', (target) => {
this.blockchain.setProviderFromEndpoint(target, context, (alertMsg) => {
if (alertMsg) addTooltip(alertMsg)
this.setFinalContext()
})
}, this.setFinalContext.bind(this))
}, (alertMsg) => {
addTooltip(alertMsg)
}, this.setFinalContext.bind(this))
addTooltip(yo`<span><b>${name}</b> provider removed</span>`)
})
selectExEnv.value = this.blockchain.getProvider()
this.blockchain.event.register('contextChanged', this.setFinalContext.bind(this))
setInterval(this.updateNetwork.bind(this), 1000)
return this.el
}
web3ProviderDialogBody () {
@ -252,51 +98,10 @@ class SettingsUI {
`
}
// set the final context. Cause it is possible that this is not the one we've originaly selected
setFinalContext () {
// set the final context. Cause it is possible that this is not the one we've originaly selected
this.selectExEnv.value = this.blockchain.getProvider()
this.event.trigger('clearInstance', [])
this.updateNetwork()
this.updatePlusButton()
}
updatePlusButton () {
// enable/disable + button
const plusBtn = document.getElementById('remixRunPlus')
const plusTitle = document.getElementById('remixRunPlusWraper')
switch (this.selectExEnv.value) {
case 'injected':
plusBtn.classList.add(css.disableMouseEvents)
plusTitle.title = "Unfortunately it's not possible to create an account using injected web3. Please create the account directly from your provider (i.e metamask or other of the same type)."
break
case 'vm':
plusBtn.classList.remove(css.disableMouseEvents)
plusTitle.title = 'Create a new account'
break
case 'web3':
this.onPersonalChange()
break
default: {
plusBtn.classList.add(css.disableMouseEvents)
plusTitle.title = `Unfortunately it's not possible to create an account using an external wallet (${this.selectExEnv.value}).`
}
}
}
onPersonalChange () {
const plusBtn = document.getElementById('remixRunPlus')
const plusTitle = document.getElementById('remixRunPlusWraper')
if (!this._deps.config.get('settings/personal-mode')) {
plusBtn.classList.add(css.disableMouseEvents)
plusTitle.title = 'Creating an account is possible only in Personal mode. Please go to Settings to enable it.'
} else {
plusBtn.classList.remove(css.disableMouseEvents)
plusTitle.title = 'Create a new account'
}
}
newAccount () {
@ -365,41 +170,44 @@ class SettingsUI {
})
}
updateNetwork () {
updateNetwork (context, cb) {
if (context) {
this.blockchain.changeExecutionContext(context, () => {
modalDialogCustom.prompt('External node request', this.web3ProviderDialogBody(), 'http://127.0.0.1:8545', (target) => {
this.blockchain.setProviderFromEndpoint(target, context, (alertMsg) => {
if (alertMsg) addTooltip(alertMsg)
this.setFinalContext()
})
}, this.setFinalContext.bind(this))
}, (alertMsg) => {
addTooltip(alertMsg)
}, this.setFinalContext.bind(this))
}
this.blockchain.updateNetwork((err, { id, name } = {}) => {
if (!cb) return
if (err) {
this.netUI.innerHTML = 'can\'t detect network '
return
return cb('can\'t detect network ')
}
const network = this._components.networkModule.getNetworkProvider.bind(this._components.networkModule)
this.netUI.innerHTML = (network() !== 'vm') ? `${name} (${id || '-'}) network` : ''
this.renderSettings()
cb((network() !== 'vm') ? `${name} (${id || '-'}) network` : '')
})
this.fillAccountsList()
this.updateAccountsAndBalances()
}
// TODO: unclear what's the goal of accountListCallId, feels like it can be simplified
fillAccountsList () {
this.accountListCallId++
var callid = this.accountListCallId
var txOrigin = this.el.querySelector('#txorigin')
this.blockchain.getAccounts((err, accounts) => {
if (this.accountListCallId > callid) return
this.accountListCallId++
if (err) { addTooltip(`Cannot get account list: ${err}`) }
for (var loadedaddress in this.loadedAccounts) {
if (accounts.indexOf(loadedaddress) === -1) {
txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]'))
delete this.loadedAccounts[loadedaddress]
}
}
for (var i in accounts) {
var address = accounts[i]
if (!this.loadedAccounts[address]) {
txOrigin.appendChild(yo`<option value="${address}" >${address}</option>`)
this.loadedAccounts[address] = 1
}
}
txOrigin.setAttribute('value', accounts[0])
async updateAccountsAndBalances () {
const accounts = await this.blockchain.getAccounts()
asyncJS.map(accounts, async (address, next) => {
this.blockchain.getBalanceInEther(address, (err, balance) => {
if (err) { return next(err) }
const updated = helper.shortenAddress(address, balance)
const newAccount = { address, name: updated }
next(null, newAccount)
})
}, (_err, results) => {
this.accounts = results
this.renderSettings()
})
}
}

@ -9,5 +9,5 @@
"../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "src/lib/run-tab/*.tsx"]
}

@ -0,0 +1,4 @@
{
"presets": [ "@nrwl/react/babel" ],
"plugins": []
}

@ -0,0 +1,18 @@
{
"env": {
"browser": true,
"es6": true
},
"extends": "../../../.eslintrc",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 11,
"sourceType": "module"
},
"rules": {
"standard/no-callback-literal": "off"
}
}

@ -0,0 +1,7 @@
# remix-ui-run-tab
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test remix-ui-run-tab` to execute the unit tests via [Jest](https://jestjs.io).

@ -0,0 +1 @@
export * from './lib/settings/settings';

@ -0,0 +1,34 @@
.remixui_crow {
display: block;
margin-top: 8px;
}
.remixui_settingsLabel {
font-size: 11px;
margin-bottom: 4px;
text-transform: uppercase;
}
.remixui_select {
font-weight: normal;
width: 100%;
overflow: hidden;
}
.remixui_icon {
cursor: pointer;
font-size: 12px;
cursor: pointer;
margin-left: 5px;
}
.remixui_icon:hover {
font-size: 12px;
color: var(--warning);
}
.remixui_account {
display: flex;
align-items: center;
}
.remixui_account i {
margin-left: 12px;
}
.remixui_disableMouseEvents {
pointer-events: none;
}

@ -0,0 +1,75 @@
import React, { useState, useEffect } from 'react'
import { CopyToClipboard } from '@remix-ui/clipboard'
/* eslint-disable-next-line */
import './account-selector.css'
const clipboardstyles = {
'margin-left': '-5px'
} as React.CSSProperties;
const plusButtonStyle = (providerName, personalModeChecked) => {
let css = { classList: "", title: "" }
switch (providerName) {
case 'injected':
css.classList = "remixui_disableMouseEvents"
css.title = "Unfortunately it's not possible to create an account using injected web3. Please create the account directly from your provider (i.e metamask or other of the same type)."
break
case 'vm':
css.classList = ""
css.title = 'Create a new account'
break
case 'web3':
if (!personalModeChecked) {
css.classList = "remixui_disableMouseEvents"
css.title = "Creating an account is possible only in Personal mode. Please go to Settings to enable it."
} else {
css.classList = ""
css.title = 'Create a new account'
}
break
default: {
css.classList = "remixui_disableMouseEvents"
css.title = `Unfortunately it's not possible to create an account using an external wallet (${providerName}).`
}
}
return css
}
export const AccountSelector = (props: any) => {
const { newAccount, signMessage, copyToClipboard, selectedProvider, personalModeChecked, accounts } = props
const plusButtonCss = plusButtonStyle(selectedProvider, personalModeChecked)
const [selectedAccount, setSelectedAccount] = useState(null)
useEffect(() => { setSelectedAccount(selectedAccount || accounts[0].address) }, [accounts])
const createAccount = () => {
if (selectedProvider === "injected") return
newAccount()
}
return (
<div className="remixui_crow">
<label className="remixui_settingsLabel">
Account
<span id="remixRunPlusWraper" title={plusButtonCss.title}>
<i id="remixRunPlus" className={`fas fa-plus-circle remixui_icon {plusButtonCss.classList}`} aria-hidden="true" onClick={() => { createAccount() }}></i>
</span>
</label>
<div className="remixui_account">
<select data-id="runTabSelectAccount" name="txorigin" className="form-control remixui_select custom-select pr-4" id="txorigin" onChange={(e) => setSelectedAccount(e.target.value)}>
{accounts.map((account, index) => (
<option key={account.address} value={account.address}>{account.name}</option>
))}
</select>
<CopyToClipboard content={selectedAccount} data-id="dropdownPanelCopyToClipboard" />
<i id="remixRunSignMsg" data-id="settingsRemixRunSignMsg" className="mx-1 fas fa-edit remixui_icon" aria-hidden="true" onClick={() => { signMessage() }} title="Sign a message using this account key"></i>
</div>
</div>
)
}
export default AccountSelector

@ -0,0 +1,29 @@
.remixui_crow {
display: block;
margin-top: 8px;
}
.remixui_settingsLabel {
font-size: 11px;
margin-bottom: 4px;
text-transform: uppercase;
}
.remixui_environment {
display: flex;
align-items: center;
position: relative;
width: 100%;
}
.remixui_select {
font-weight: normal;
width: 100%;
overflow: hidden;
}
.remixui_infoDeployAction {
margin-left: 1px;
font-size: 13px;
color: var(--info);
}
.remixui_network {
margin-left: 8px;
pointer-events: none;
}

@ -0,0 +1,38 @@
import React, { useState, useEffect } from 'react'
/* eslint-disable-next-line */
import './environment-selector.css'
export const EnvironmentSelector = (props: any) => {
const [networkMessage, setNetworkMessage] = useState("");
const { updateNetwork, selectedProvider } = props
const onSettingsChange = (e) => {
const provider = e.target.value
updateNetwork(provider, (msg) => { setNetworkMessage(msg) })
}
return (
<div className="remixui_crow">
<label id="selectExEnv" className="remixui_settingsLabel">
Environment
</label>
<div className="remixui_environment">
<select id="selectExEnvOptions" value={selectedProvider} data-id="settingsSelectEnvOptions" onChange={(e) => { onSettingsChange(e) }} className="form-control remixui_select custom-select">
{props.options.map((option, index) => (
<option id={`${option.value}-mode`} key={index} title={option.title} value={option.value}>{option.name}</option>
))}
</select>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#run-setup" target="_blank"><i className="remixui_infoDeployAction ml-2 fas fa-info" title="check out docs to setup Environment"></i></a>
</div>
<div className="remixui_crow">
<div className="remixui_settingsLabel">
</div>
<div className="remixui_environment" data-id="settingsNetworkEnv">
<span className="remixui_network badge badge-secondary">{networkMessage}</span>
</div>
</div>
</div>
)
}
export default EnvironmentSelector

@ -0,0 +1,16 @@
.remixui_crow {
display: block;
margin-top: 8px;
}
.remixui_settingsLabel {
font-size: 11px;
margin-bottom: 4px;
text-transform: uppercase;
}
.remixui_gasNval {
width: 55%;
font-size: 0.8rem;
}
.remixui_col2 {
border-radius: 3px;
}

@ -0,0 +1,15 @@
import React, { useState, useEffect } from 'react'
/* eslint-disable-next-line */
import './gas-price.css'
export const GasPrice = () => {
const [gasPrice, setGasPrice] = useState("3000000");
return (
<div className="remixui_crow">
<label className="remixui_settingsLabel">Gas limit</label>
<input type="number" className="form-control remixui_gasNval remixui_col2" id="gasLimit" value={gasPrice} onInput={(e) => setGasPrice((e.target as HTMLTextAreaElement).value)} />
</div>
)
}
export default GasPrice

@ -0,0 +1,3 @@
.remixui_settings {
padding: 0 24px 16px;
}

@ -0,0 +1,22 @@
import React, { useState, useEffect } from 'react'
/* eslint-disable-next-line */
import EnvironmentSelector from './environment-selector'
import AccountSelector from './account-selector'
import GasPrice from './gas-price'
import ValueSelector from './value-selector'
import './settings.css'
export const Settings = (props: any) => {
const { updateNetwork, newAccount, signMessage, copyToClipboard, options, personalModeChecked, selectedProvider, accounts } = props
return (
<div className="remixui_settings">
<EnvironmentSelector options={options} updateNetwork={updateNetwork} selectedProvider={selectedProvider} />
{/* ${networkEl} */}
<AccountSelector accounts={accounts} newAccount={newAccount} signMessage={signMessage} copyToClipboard={copyToClipboard} selectedProvider={selectedProvider} personalModeChecked={personalModeChecked} />
<GasPrice />
<ValueSelector />
</div>
)
}
export default Settings

@ -0,0 +1,31 @@
.remixui_crow {
display: block;
margin-top: 8px;
}
.remixui_settingsLabel {
font-size: 11px;
margin-bottom: 4px;
text-transform: uppercase;
}
.remixui_gasNval {
width: 55%;
font-size: 0.8rem;
}
.remixui_col2 {
border-radius: 3px;
}
.remixui_col2_1 {
width: 164px;
min-width: 164px;
}
.remixui_col2_2 {
}
.remixui_gasNvalUnit {
width: 41%;
margin-left: 10px;
font-size: 0.8rem;
}
.remixui_gasValueContainer {
flex-direction: row;
display: flex;
}

@ -0,0 +1,36 @@
import React, { useState } from 'react' // eslint-disable-line
/* eslint-disable-next-line */
import './value-selector.css'
export const ValueSelector = () => {
const [gasValue, setGasValue] = useState('0')
const changeGasValue = (newValue) => {
if (newValue === '') {
return setGasValue('')
}
let value = parseInt(newValue, 10)
setGasValue(String(isNaN(value) ? 0 : value))
}
const forceGasValue = () => {
if (gasValue === '') { setGasValue('0') }
}
return (
<div className="remixui_crow">
<label className="remixui_settingsLabel">Value</label>
<div className="remixui_gasValueContainer">
<input type="text" className="form-control remixui_gasNval remixui_col2" id="value" onBlur={forceGasValue} value={gasValue} onChange={(e) => changeGasValue((e.target as HTMLInputElement).value)} title="Enter the value and choose the unit" />
<select name="unit" className="form-control p-1 remixui_gasNvalUnit remixui_col2_2 custom-select" id="unit">
<option data-unit="wei">wei</option>
<option data-unit="gwei">gwei</option>
<option data-unit="finney">finney</option>
<option data-unit="ether">ether</option>
</select>
</div>
</div>
)
}
export default ValueSelector

@ -0,0 +1,16 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

@ -0,0 +1,13 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}

@ -92,6 +92,9 @@
},
"debugger": {
"tags": []
},
"remix-ui-run-tab": {
"tags": []
}
}
}

@ -35,7 +35,8 @@
"@remix-project/remix-solidity-ts": ["libs/remix-solidity/src/index.ts"],
"@remix-ui/modal-dialog": ["libs/remix-ui/modal-dialog/src/index.ts"],
"@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"],
"@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"]
"@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"],
"@remix-ui/run-tab": ["libs/remix-ui/run-tab/src/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]

@ -618,6 +618,22 @@
}
}
},
"remix-ui-run-tab": {
"root": "libs/remix-ui/run-tab",
"sourceRoot": "libs/remix-ui/run-tab/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/run-tab/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/run-tab/**/*"]
}
}
}
},
"remix-ui-file-explorer": {
"root": "libs/remix-ui/file-explorer",
"sourceRoot": "libs/remix-ui/file-explorer/src",

Loading…
Cancel
Save