Moved settingsUI and contract dropdown UI to react

yann300-patch-36
ioedeveloper 3 years ago committed by yann300
parent 3700e675e4
commit 54871aba44
  1. 30
      apps/remix-ide/src/app/udapp/run-tab.js
  2. 4
      libs/remix-ui/helper/src/lib/remix-ui-helper.ts
  3. 2
      libs/remix-ui/run-tab/src/index.ts
  4. 8
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  5. 149
      libs/remix-ui/run-tab/src/lib/components/account.tsx
  6. 418
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  7. 76
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  8. 12
      libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx
  9. 15
      libs/remix-ui/run-tab/src/lib/components/network.tsx
  10. 156
      libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx
  11. 69
      libs/remix-ui/run-tab/src/lib/components/value.tsx
  12. 219
      libs/remix-ui/run-tab/src/lib/css/run-tab.css
  13. 0
      libs/remix-ui/run-tab/src/lib/remix-ui-run-tab.module.css
  14. 14
      libs/remix-ui/run-tab/src/lib/remix-ui-run-tab.tsx
  15. 25
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  16. 32
      libs/remix-ui/run-tab/src/lib/types/index.ts
  17. 8
      libs/remix-ui/run-tab/tsconfig.json

@ -1,3 +1,6 @@
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import { RunTabUI } from '@remix-ui/run-tab'
import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
@ -47,6 +50,11 @@ export class RunTab extends ViewPlugin {
this.networkModule = networkModule
this.fileProvider = fileProvider
this.setupEvents()
this.el = document.createElement('div')
}
onActivation () {
this.renderComponent()
}
setupEvents () {
@ -104,21 +112,6 @@ export class RunTab extends ViewPlugin {
return this.blockchain.pendingTransactionsCount()
}
renderContainer () {
this.container = yo`<div class="${css.runTabView} run-tab" id="runTabView" data-id="runTabView"></div>`
var el = yo`
<div class="list-group list-group-flush">
${this.settingsUI.render()}
${this.contractDropdownUI.render()}
${this.recorderCard.render()}
${this.instanceContainer}
</div>
`
this.container.appendChild(el)
return this.container
}
renderInstanceContainer () {
this.instanceContainer = yo`<div class="${css.instanceContainer} border-0 list-group-item"></div>`
@ -225,6 +218,7 @@ export class RunTab extends ViewPlugin {
}
render () {
return this.el
this.udappUI = new UniversalDAppUI(this.blockchain, this.logCallback)
this.blockchain.resetAndInit(this.config, {
getAddress: (cb) => {
@ -283,4 +277,10 @@ export class RunTab extends ViewPlugin {
this.on('manager', 'pluginDeactivated', removePluginProvider.bind(this))
return this.renderContainer()
}
renderComponent () {
ReactDOM.render(
<RunTabUI plugin={this} />
, this.el)
}
}

@ -62,3 +62,7 @@ export const getPathIcon = (path: string) => {
? 'fab fa-ethereum' : path.endsWith('.cairo')
? 'fab fa-ethereum' : 'far fa-file' // TODO: add cairo icon
}
export const isNumeric = (value) => {
return /^\+?(0|[1-9]\d*)$/.test(value)
}

@ -1 +1 @@
export * from './lib/remix-ui-run-tab';
export * from './lib/run-tab'

@ -0,0 +1,8 @@
let plugin, dispatch: React.Dispatch<any>
const initSettingsTab = (udapp) => async (reducerDispatch: React.Dispatch<any>) => {
plugin = udapp
dispatch = reducerDispatch
}

@ -0,0 +1,149 @@
// eslint-disable-next-line no-use-before-define
import React, { useRef, useState } from 'react'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { AccountProps } from '../types'
export function AccountUI (props: AccountProps) {
const [selectedAccount, setSelectedAccount] = useState<string>('')
const plusBtn = useRef(null)
const plusTitle = useRef(null)
// // TODO: unclear what's the goal of accountListCallId, feels like it can be simplified
// async fillAccountsList () {
// this.accountListCallId++
// const callid = this.accountListCallId
// const txOrigin = this.el.querySelector('#txorigin')
// let accounts = []
// try {
// accounts = await this.blockchain.getAccounts()
// } catch (e) {
// addTooltip(`Cannot get account list: ${e}`)
// }
// if (!accounts) accounts = []
// if (this.accountListCallId > callid) return
// this.accountListCallId++
// for (const loadedaddress in this.loadedAccounts) {
// if (accounts.indexOf(loadedaddress) === -1) {
// txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]'))
// delete this.loadedAccounts[loadedaddress]
// }
// }
// for (const i in accounts) {
// const address = accounts[i]
// if (!this.loadedAccounts[address]) {
// txOrigin.appendChild(yo`<option value="${address}" >${address}</option>`)
// this.loadedAccounts[address] = 1
// }
// }
// txOrigin.setAttribute('value', accounts[0])
// }
const updatePlusButton = () => {
// enable/disable + button
switch (props.selectExEnv) {
case 'injected':
plusBtn.current.classList.add('udapp_disableMouseEvents')
plusTitle.current.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.current.classList.remove('udapp_disableMouseEvents')
plusTitle.current.title = 'Create a new account'
break
case 'web3':
this.onPersonalChange()
break
default: {
plusBtn.current.classList.add('udapp_disableMouseEvents')
plusTitle.current.title = `Unfortunately it's not possible to create an account using an external wallet (${props.selectExEnv}).`
}
}
}
const newAccount = () => {
// dispatch createNewBlockchainAccount
// this.blockchain.newAccount(
// '',
// (cb) => {
// modalDialogCustom.promptPassphraseCreation((error, passphrase) => {
// if (error) {
// return modalDialogCustom.alert(error)
// }
// cb(passphrase)
// }, () => {})
// },
// (error, address) => {
// if (error) {
// return addTooltip('Cannot create an account: ' + error)
// }
// addTooltip(`account ${address} created`)
// }
// )
}
const signMessage = () => {
// dispatch signMessageWithBlockchainAccounts
// this.blockchain.getAccounts((err, accounts) => {
// if (err) {
// return addTooltip(`Cannot get account list: ${err}`)
// }
// var signMessageDialog = { title: 'Sign a message', text: 'Enter a message to sign', inputvalue: 'Message to sign' }
// var $txOrigin = this.el.querySelector('#txorigin')
// if (!$txOrigin.selectedOptions[0] && (this.blockchain.isInjectedWeb3() || this.blockchain.isWeb3Provider())) {
// return addTooltip('Account list is empty, please make sure the current provider is properly connected to remix')
// }
// var account = $txOrigin.selectedOptions[0].value
// var promptCb = (passphrase) => {
// const modal = modalDialogCustom.promptMulti(signMessageDialog, (message) => {
// this.blockchain.signMessage(message, account, passphrase, (err, msgHash, signedData) => {
// if (err) {
// return addTooltip(err)
// }
// modal.hide()
// modalDialogCustom.alert(yo`
// <div>
// <b>hash:</b><br>
// <span id="remixRunSignMsgHash" data-id="settingsRemixRunSignMsgHash">${msgHash}</span>
// <br><b>signature:</b><br>
// <span id="remixRunSignMsgSignature" data-id="settingsRemixRunSignMsgSignature">${signedData}</span>
// </div>
// `)
// })
// }, false)
// }
// if (this.blockchain.isWeb3Provider()) {
// return modalDialogCustom.promptPassphrase(
// 'Passphrase to sign a message',
// 'Enter your passphrase for this account to sign the message',
// '',
// promptCb,
// false
// )
// }
// promptCb()
// })
}
return (
<div className="udapp_crow">
<label className="udapp_settingsLabel">
Account
<span ref={plusTitle} id="remixRunPlusWraper" title="Create a new account" onLoad={updatePlusButton}>
<i ref={plusBtn} id="remixRunPlus" className="fas fa-plus-circle udapp_icon" aria-hidden="true" onClick={newAccount}></i>
</span>
</label>
<div className="udapp_account">
<select id="txorigin" data-id="runTabSelectAccount" name="txorigin" className="form-control udapp_select custom-select pr-4" value={selectedAccount} onChange={(e) => { setSelectedAccount(e.target.value) }}></select>
<div style={{ marginLeft: -5 }}><CopyToClipboard content={selectedAccount} direction='top' /></div>
<i id="remixRunSignMsg" data-id="settingsRemixRunSignMsg" className="mx-1 fas fa-edit udapp_icon" aria-hidden="true" onClick={signMessage} title="Sign a message using this account key"></i>
</div>
</div>
)
}

@ -0,0 +1,418 @@
// eslint-disable-next-line no-use-before-define
import React, { SyntheticEvent, useEffect, useRef, useState } from 'react'
import { ContractDropdownProps } from '../types'
import * as ethJSUtil from 'ethereumjs-util'
export function ContractDropdownUI (props: ContractDropdownProps) {
const [networkName, setNetworkName] = useState<string>('')
const [abiLabel, setAbiLabel] = useState<{
display: string,
content: string
}>({
display: '',
content: ''
})
const [ipfsCheckedState, setIpfsCheckedState] = useState<boolean>(false)
const [loadType] = useState<string>('other')
const atAddressButtonInput = useRef(null)
const contracts = useRef(null)
useEffect(() => {
enableAtAddress(false)
const savedConfig = window.localStorage.getItem(`ipfs/${props.exEnvironment}/${networkName}`)
const isCheckedIPFS = savedConfig === 'true' ? true : false // eslint-disable-line
if (isCheckedIPFS) setIpfsCheckedState(true)
setAbiLabel({
display: 'none',
content: 'ABI file selected'
})
}, [])
useEffect(() => {
if (props.exEnvironment === 'vm') setNetworkName('VM')
}, [props.exEnvironment])
const enableAtAddress = (enable) => {
const atAddress = atAddressButtonInput.current
if (enable) {
if (!atAddress.value || !ethJSUtil.isValidAddress(atAddress.value)) {
enableAtAddress(false)
return
}
atAddress.removeAttribute('disabled')
atAddress.setAttribute('title', 'Interact with the given contract.')
} else {
atAddress.setAttribute('disabled', true)
if (atAddress.value === '') {
atAddress.setAttribute('title', '⚠ Compile *.sol file or select *.abi file & then enter the address of deployed contract.')
} else {
atAddress.setAttribute('title', '⚠ Compile *.sol file or select *.abi file.')
}
}
}
// constructor (blockchain, dropdownLogic, logCallback, runView) {
// this.blockchain = blockchain
// this.dropdownLogic = dropdownLogic
// this.logCallback = logCallback
// this.runView = runView
// this.event = new EventManager()
// this.listenToEvents()
// this.ipfsCheckedState = false
// this.exEnvironment = blockchain.getProvider()
// this.listenToContextChange()
// this.loadType = 'other'
// }
// listenToEvents () {
// this.dropdownLogic.event.register('newlyCompiled', (success, data, source, compiler, compilerFullName, file) => {
// if (!this.selectContractNames) return
// this.selectContractNames.innerHTML = ''
// if (success) {
// this.dropdownLogic.getCompiledContracts(compiler, compilerFullName).forEach((contract) => {
// this.selectContractNames.appendChild(yo`<option value="${contract.name}" compiler="${compilerFullName}">${contract.name} - ${contract.file}</option>`)
// })
// }
// this.enableAtAddress(success)
// this.enableContractNames(success)
// this.setInputParamsPlaceHolder()
// if (success) {
// this.compFails.style.display = 'none'
// } else {
// this.compFails.style.display = 'block'
// }
// })
// }
// listenToContextChange () {
// this.blockchain.event.register('networkStatus', ({ error, network }) => {
// if (error) {
// console.log('can\'t detect network')
// return
// }
// this.exEnvironment = this.blockchain.getProvider()
// this.networkName = network.name
// const savedConfig = window.localStorage.getItem(`ipfs/${this.exEnvironment}/${this.networkName}`)
// // check if an already selected option exist else use default workflow
// if (savedConfig !== null) {
// this.setCheckedState(savedConfig)
// } else {
// this.setCheckedState(this.networkName === 'Main')
// }
// })
// }
// setCheckedState (value) {
// value = value === 'true' ? true : value === 'false' ? false : value
// this.ipfsCheckedState = value
// if (this.ipfsCheckbox) this.ipfsCheckbox.checked = value
// }
// enableContractNames (enable) {
// if (enable) {
// if (this.selectContractNames.value === '') return
// this.selectContractNames.removeAttribute('disabled')
// this.selectContractNames.setAttribute('title', 'Select contract for Deploy or At Address.')
// } else {
// this.selectContractNames.setAttribute('disabled', true)
// if (this.loadType === 'sol') {
// this.selectContractNames.setAttribute('title', '⚠ Select and compile *.sol file to deploy or access a contract.')
// } else {
// this.selectContractNames.setAttribute('title', '⚠ Selected *.abi file allows accessing contracts, select and compile *.sol file to deploy and access one.')
// }
// }
// }
// changeCurrentFile (currentFile) {
// if (!this.selectContractNames) return
// if (/.(.abi)$/.exec(currentFile)) {
// this.createPanel.style.display = 'none'
// this.orLabel.style.display = 'none'
// this.compFails.style.display = 'none'
// this.loadType = 'abi'
// this.contractNamesContainer.style.display = 'block'
// this.abiLabel.style.display = 'block'
// this.abiLabel.innerHTML = currentFile
// this.selectContractNames.style.display = 'none'
// this.enableContractNames(true)
// this.enableAtAddress(true)
// } else if (/.(.sol)$/.exec(currentFile) ||
// /.(.vy)$/.exec(currentFile) || // vyper
// /.(.lex)$/.exec(currentFile) || // lexon
// /.(.contract)$/.exec(currentFile)) {
// this.createPanel.style.display = 'block'
// this.orLabel.style.display = 'block'
// this.contractNamesContainer.style.display = 'block'
// this.loadType = 'sol'
// this.selectContractNames.style.display = 'block'
// this.abiLabel.style.display = 'none'
// if (this.selectContractNames.value === '') this.enableAtAddress(false)
// } else {
// this.loadType = 'other'
// this.createPanel.style.display = 'block'
// this.orLabel.style.display = 'block'
// this.contractNamesContainer.style.display = 'block'
// this.selectContractNames.style.display = 'block'
// this.abiLabel.style.display = 'none'
// if (this.selectContractNames.value === '') this.enableAtAddress(false)
// }
// }
// setInputParamsPlaceHolder () {
// this.createPanel.innerHTML = ''
// if (this.selectContractNames.selectedIndex < 0 || this.selectContractNames.children.length <= 0) {
// this.createPanel.innerHTML = 'No compiled contracts'
// return
// }
// const selectedContract = this.getSelectedContract()
// const clickCallback = async (valArray, inputsValues) => {
// var selectedContract = this.getSelectedContract()
// this.createInstance(selectedContract, inputsValues)
// }
// const createConstructorInstance = new MultiParamManager(
// 0,
// selectedContract.getConstructorInterface(),
// clickCallback,
// selectedContract.getConstructorInputs(),
// 'Deploy',
// selectedContract.bytecodeObject,
// true
// )
// this.createPanel.appendChild(createConstructorInstance.render())
// this.createPanel.appendChild(this.deployCheckBox)
// }
// getSelectedContract () {
// var contract = this.selectContractNames.children[this.selectContractNames.selectedIndex]
// var contractName = contract.getAttribute('value')
// var compilerAtributeName = contract.getAttribute('compiler')
// return this.dropdownLogic.getSelectedContract(contractName, compilerAtributeName)
// }
// async createInstance (selectedContract, args) {
// if (selectedContract.bytecodeObject.length === 0) {
// return modalDialogCustom.alert('This contract may be abstract, not implement an abstract parent\'s methods completely or not invoke an inherited contract\'s constructor correctly.')
// }
// var continueCb = (error, continueTxExecution, cancelCb) => {
// if (error) {
// var msg = typeof error !== 'string' ? error.message : error
// modalDialog('Gas estimation failed', yo`<div>Gas estimation errored with the following message (see below).
// The transaction execution will likely fail. Do you want to force sending? <br>
// ${msg}
// </div>`,
// {
// label: 'Send Transaction',
// fn: () => {
// continueTxExecution()
// }
// }, {
// label: 'Cancel Transaction',
// fn: () => {
// cancelCb()
// }
// })
// } else {
// continueTxExecution()
// }
// }
// const self = this
// var promptCb = (okCb, cancelCb) => {
// modalDialogCustom.promptPassphrase('Passphrase requested', 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb)
// }
// var statusCb = (msg) => {
// return this.logCallback(msg)
// }
// var finalCb = (error, contractObject, address) => {
// self.event.trigger('clearInstance')
// if (error) {
// return this.logCallback(error)
// }
// self.event.trigger('newContractInstanceAdded', [contractObject, address, contractObject.name])
// const data = self.runView.compilersArtefacts.getCompilerAbstract(contractObject.contract.file)
// self.runView.compilersArtefacts.addResolvedContract(helper.addressToString(address), data)
// if (self.ipfsCheckedState) {
// _paq.push(['trackEvent', 'udapp', 'DeployAndPublish', this.networkName])
// publishToStorage('ipfs', self.runView.fileProvider, self.runView.fileManager, selectedContract)
// } else {
// _paq.push(['trackEvent', 'udapp', 'DeployOnly', this.networkName])
// }
// }
// let contractMetadata
// try {
// contractMetadata = await this.runView.call('compilerMetadata', 'deployMetadataOf', selectedContract.name, selectedContract.contract.file)
// } catch (error) {
// return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`)
// }
// const compilerContracts = this.dropdownLogic.getCompilerContracts()
// const confirmationCb = this.getConfirmationCb(modalDialog, confirmDialog)
// if (selectedContract.isOverSizeLimit()) {
// return modalDialog('Contract code size over limit', yo`<div>Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fails. <br>
// More info: <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md" target="_blank">eip-170</a>
// </div>`,
// {
// label: 'Force Send',
// fn: () => {
// this.deployContract(selectedContract, args, contractMetadata, compilerContracts, { continueCb, promptCb, statusCb, finalCb }, confirmationCb)
// }
// }, {
// label: 'Cancel',
// fn: () => {
// this.logCallback(`creation of ${selectedContract.name} canceled by user.`)
// }
// })
// }
// this.deployContract(selectedContract, args, contractMetadata, compilerContracts, { continueCb, promptCb, statusCb, finalCb }, confirmationCb)
// }
// deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) {
// _paq.push(['trackEvent', 'udapp', 'DeployContractTo', this.networkName])
// const { statusCb } = callbacks
// if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
// return this.blockchain.deployContractAndLibraries(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb)
// }
// if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
// this.blockchain.deployContractWithLibrary(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb)
// }
// getConfirmationCb (modalDialog, confirmDialog) {
// // this code is the same as in recorder.js. TODO need to be refactored out
// const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
// if (network.name !== 'Main') {
// return continueTxExecution(null)
// }
// const amount = this.blockchain.fromWei(tx.value, true, 'ether')
// const content = confirmDialog(tx, network, amount, gasEstimation, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice.bind(this.blockchain))
// modalDialog('Confirm transaction', content,
// {
// label: 'Confirm',
// fn: () => {
// this.blockchain.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked)
// // TODO: check if this is check is still valid given the refactor
// if (!content.gasPriceStatus) {
// cancelCb('Given transaction fee is not correct')
// } else {
// continueTxExecution(content.txFee)
// }
// }
// }, {
// label: 'Cancel',
// fn: () => {
// return cancelCb('Transaction canceled by user.')
// }
// }
// )
// }
// return confirmationCb
// }
const atAddressChanged = (event: SyntheticEvent) => {
const atAddress = atAddressButtonInput.current
const selectContractNames = contracts.current
if (!atAddress.value) {
enableAtAddress(false)
} else {
if ((selectContractNames && !selectContractNames.getAttribute('disabled') && loadType === 'sol') ||
loadType === 'abi') {
enableAtAddress(true)
} else {
enableAtAddress(false)
}
}
}
const loadFromAddress = () => {
// trigger dispatchLoadAddress
// this.event.trigger('clearInstance')
// let address = this.atAddressButtonInput.value
// if (!ethJSUtil.isValidChecksumAddress(address)) {
// addTooltip(yo`
// <span>
// It seems you are not using a checksumed address.
// <br>A checksummed address is an address that contains uppercase letters, as specified in <a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank">EIP-55</a>.
// <br>Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.
// </span>`)
// address = ethJSUtil.toChecksumAddress(address)
// }
// this.dropdownLogic.loadContractFromAddress(address,
// (cb) => {
// modalDialogCustom.confirm('At Address', `Do you really want to interact with ${address} using the current ABI definition?`, cb)
// },
// (error, loadType, abi) => {
// if (error) {
// return modalDialogCustom.alert(error)
// }
// if (loadType === 'abi') {
// return this.event.trigger('newContractABIAdded', [abi, address])
// }
// var selectedContract = this.getSelectedContract()
// this.event.trigger('newContractInstanceAdded', [selectedContract.object, address, this.selectContractNames.value])
// }
// )
}
const handleCheckedIPFS = () => {
setIpfsCheckedState(!ipfsCheckedState)
window.localStorage.setItem(`ipfs/${props.exEnvironment}/${networkName}`, ipfsCheckedState.toString())
}
return (
<div className="udapp_container" data-id="contractDropdownContainer">
<label className="udapp_settingsLabel">Contract</label>
<div className="udapp_subcontainer">
<select ref={contracts} className="udapp_contractNames custom-select" disabled title="Please compile *.sol file to deploy or access a contract"></select>
<i title="No contract compiled yet or compilation failed. Please check the compile tab for more information." className="m-2 ml-3 fas fa-times-circle udapp_errorIcon" ></i>
<span className="py-1" style={{ display: abiLabel.display }}>{ abiLabel.content }</span>
</div>
<div>
<div className="udapp_deployDropdown">
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
id="deployAndRunPublishToIPFS"
data-id="contractDropdownIpfsCheckbox"
className="form-check-input custom-control-input"
type="checkbox"
onChange={handleCheckedIPFS}
checked={ipfsCheckedState}
/>
<label
htmlFor="deployAndRunPublishToIPFS"
data-id="contractDropdownIpfsCheckboxLabel"
className="m-0 form-check-label custom-control-label udapp_checkboxAlign"
title="Publishing the source code and metadata to IPFS facilitates source code verification using Sourcify and will greatly foster contract adoption (auditing, debugging, calling it, etc...)"
>
Publish to IPFS
</label>
</div>
</div>
<div className="udapp_orLabel mt-2">or</div>
<div className="udapp_button udapp_atAddressSect">
<button className="udapp_atAddress btn btn-sm btn-info" id="runAndDeployAtAdressButton" onClick={loadFromAddress}>At Address</button>
<input ref={atAddressButtonInput} className="udapp_input udapp_ataddressinput ataddressinput form-control" placeholder="Load contract from Address" title="address of contract" onInput={atAddressChanged} />
</div>
</div>
</div>
// this.selectContractNames.addEventListener('change', this.setInputParamsPlaceHolder.bind(this))
// this.setInputParamsPlaceHolder()
)
}

@ -0,0 +1,76 @@
// eslint-disable-next-line no-use-before-define
import React, { useState } from 'react'
import { EnvironmentProps } from '../types'
export function EnvironmentUI (props: EnvironmentProps) {
const [exEnv, setExEnv] = useState<string>('')
// 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))
// selectExEnv.addEventListener('change', (event) => {
// const provider = selectExEnv.options[selectExEnv.selectedIndex]
// const fork = provider.getAttribute('fork') // can be undefined if connected to an external source (web3 provider / injected)
// let context = provider.value
// context = context.startsWith('vm') ? 'vm' : context // context has to be 'vm', 'web3' or 'injected'
// this.setExecutionContext({ context, fork })
// })
// selectExEnv.value = this._getProviderDropdownValue()
// }
const handleChangeExEnv = (env: string) => {
setExEnv(env)
props.updateExEnv(env)
}
return (
<div className="udapp_crow">
<label id="selectExEnv" className="udapp_settingsLabel">
Environment
</label>
<div className="udapp_environment">
<select id="selectExEnvOptions" data-id="settingsSelectEnvOptions" className="form-control udapp_select custom-select" value={exEnv} onChange={(e) => { handleChangeExEnv(e.target.value) }}>
<option id="vm-mode-london" data-id="settingsVMLondonMode"
title="Execution environment does not connect to any node, everything is local and in memory only."
value="vm-london"> JavaScript VM (London) {/* fork="london" */}
</option>
<option id="vm-mode-berlin" data-id="settingsVMBerlinMode"
title="Execution environment does not connect to any node, everything is local and in memory only."
value="vm-berlin"> JavaScript VM (Berlin) {/* fork="berlin" */}
</option>
<option id="injected-mode" data-id="settingsInjectedMode"
title="Execution environment has been provided by Metamask or similar provider."
value="injected"> 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"> Web3 Provider
</option>
</select>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#run-setup" target="_blank"><i className="udapp_infoDeployAction ml-2 fas fa-info" title="check out docs to setup Environment"></i></a>
</div>
</div>
)
}

@ -0,0 +1,12 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import { GasPriceProps } from '../types'
export function GasPriceUI (props: GasPriceProps) {
return (
<div className="udapp_crow">
<label className="udapp_settingsLabel">Gas limit</label>
<input type="number" className="form-control udapp_gasNval udapp_col2" id="gasLimit" defaultValue="3000000" />
</div>
)
}

@ -0,0 +1,15 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import { NetworkProps } from '../types'
export function NetworkUI (props: NetworkProps) {
return (
<div className="udapp_crow">
<div className="udapp_settingsLabel">
</div>
<div className="udapp_environment" data-id="settingsNetworkEnv">
<span className="udapp_network badge badge-secondary"></span>
</div>
</div>
)
}

@ -0,0 +1,156 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import { SettingsProps } from '../types'
import { EnvironmentUI } from './environment'
import { NetworkUI } from './network'
import { AccountUI } from './account'
import { GasPriceUI } from './gasPrice'
import { ValueUI } from './value'
export function SettingsUI (props: SettingsProps) {
// constructor () {
// this.blockchain = blockchain
// this.event = new EventManager()
// this._components = {}
// 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._components = {
// registry: globalRegistry,
// networkModule: networkModule
// }
// this._components.registry = globalRegistry
// this._deps = {
// 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
// }
// })
// })
// }
// setExecutionContext (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))
// }
// web3ProviderDialogBody () {
// const thePath = '<path/to/local/folder/for/test/chain>'
// return yo`
// <div class="">
// Note: To use Geth & https://remix.ethereum.org, configure it to allow requests from Remix:(see <a href="https://geth.ethereum.org/docs/rpc/server" target="_blank">Geth Docs on rpc server</a>)
// <div class="border p-1">geth --http --http.corsdomain https://remix.ethereum.org</div>
// <br>
// To run Remix & a local Geth test node, use this command: (see <a href="https://geth.ethereum.org/getting-started/dev-mode" target="_blank">Geth Docs on Dev mode</a>)
// <div class="border p-1">geth --http --http.corsdomain="${window.origin}" --http.api web3,eth,debug,personal,net --vmdebug --datadir ${thePath} --dev console</div>
// <br>
// <br>
// <b>WARNING:</b> It is not safe to use the --http.corsdomain flag with a wildcard: <b>--http.corsdomain *</b>
// <br>
// <br>For more info: <a href="https://remix-ide.readthedocs.io/en/latest/run.html#more-about-web3-provider" target="_blank">Remix Docs on Web3 Provider</a>
// <br>
// <br>
// Web3 Provider Endpoint
// </div>
// `
// }
// /**
// * generate a value used by the env dropdown list.
// * @return {String} - can return 'vm-berlin, 'vm-london', 'injected' or 'web3'
// */
// _getProviderDropdownValue () {
// const provider = this.blockchain.getProvider()
// const fork = this.blockchain.getCurrentFork()
// return provider === 'vm' ? provider + '-' + fork : provider
// }
// setFinalContext () {
// // set the final context. Cause it is possible that this is not the one we've originaly selected
// this.selectExEnv.value = this._getProviderDropdownValue()
// this.event.trigger('clearInstance', [])
// this.updatePlusButton()
// }
// 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'
// }
// }
// getSelectedAccount () {
// return this.el.querySelector('#txorigin').selectedOptions[0].value
// }
// getEnvironment () {
// return this.blockchain.getProvider()
// }
return (
// this.blockchain.event.register('contextChanged', (context, silent) => {
// this.setFinalContext()
// })
// this.blockchain.event.register('networkStatus', ({ error, network }) => {
// if (error) {
// this.netUI.innerHTML = 'can\'t detect network '
// return
// }
// const networkProvider = this._components.networkModule.getNetworkProvider.bind(this._components.networkModule)
// this.netUI.innerHTML = (networkProvider() !== 'vm') ? `${network.name} (${network.id || '-'}) network` : ''
// })
// setInterval(() => {
// this.fillAccountsList()
// }, 1000)
// this.el = el
// this.fillAccountsList()
// return el
<div className="udapp_settings">
<EnvironmentUI updateExEnv={props.updateExEnv} />
<NetworkUI />
<AccountUI selectExEnv={props.selectExEnv} />
<GasPriceUI />
<ValueUI />
</div>
)
}

@ -0,0 +1,69 @@
// eslint-disable-next-line no-use-before-define
import React, { useRef } from 'react'
import { BN } from 'ethereumjs-util'
import { isNumeric } from '@remix-ui/helper'
import { ValueProps } from '../types'
export function ValueUI (props: ValueProps) {
const inputValue = useRef(null)
const validateInputKey = (e) => {
// preventing not numeric keys
// preventing 000 case
if (!isNumeric(e.key) ||
(e.key === '0' && !parseInt(inputValue.current.value) && inputValue.current.value.length > 0)) {
e.preventDefault()
e.stopImmediatePropagation()
}
}
const validateValue = () => {
if (!inputValue.current.value) {
// assign 0 if given value is
// - empty
inputValue.current.value = 0
return
}
let v
try {
v = new BN(inputValue.current.value, 10)
inputValue.current.value = v.toString(10)
} catch (e) {
// assign 0 if given value is
// - not valid (for ex 4345-54)
// - contains only '0's (for ex 0000) copy past or edit
inputValue.current.value = 0
}
// if giveen value is negative(possible with copy-pasting) set to 0
if (v.lt(0)) inputValue.current.value = 0
}
return (
<div className="udapp_crow">
<label className="udapp_settingsLabel" data-id="remixDRValueLabel">Value</label>
<div className="udapp_gasValueContainer">
<input
type="number"
min="0"
pattern="^[0-9]"
step="1"
className="form-control udapp_gasNval udapp_col2"
id="value"
data-id="dandrValue"
value="0"
title="Enter the value and choose the unit"
onKeyPress={validateInputKey}
onChange={validateValue}
/>
<select name="unit" className="form-control p-1 udapp_gasNvalUnit udapp_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>
)
}

@ -0,0 +1,219 @@
.udapp_runTabView {
display: flex;
flex-direction: column;
}
.udapp_runTabView::-webkit-scrollbar {
display: none;
}
.udapp_settings {
padding: 0 24px 16px;
}
.udapp_crow {
display: block;
margin-top: 8px;
}
.udapp_col1 {
width: 30%;
float: left;
align-self: center;
}
.udapp_settingsLabel {
font-size: 11px;
margin-bottom: 4px;
text-transform: uppercase;
}
.udapp_environment {
display: flex;
align-items: center;
position: relative;
width: 100%;
}
.udapp_environment a {
margin-left: 7px;
}
.udapp_account {
display: flex;
align-items: center;
}
.udapp_account i {
margin-left: 12px;
}
.udapp_col2 {
border-radius: 3px;
}
.udapp_col2_1 {
width: 164px;
min-width: 164px;
}
.udapp_col2_2 {
}
.udapp_select {
font-weight: normal;
width: 100%;
overflow: hidden;
}
.udapp_instanceContainer {
display: flex;
flex-direction: column;
margin-bottom: 2%;
border: none;
text-align: center;
padding: 0 14px 16px;
}
.udapp_pendingTxsContainer {
display: flex;
flex-direction: column;
margin-top: 2%;
border: none;
text-align: center;
}
.udapp_container {
padding: 0 24px 16px;
}
.udapp_recorderDescription {
margin: 0 15px 15px 0;
}
.udapp_contractNames {
width: 100%;
border: 1px solid
}
.udapp_subcontainer {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 8px;
}
.udapp_subcontainer i {
width: 16px;
display: flex;
justify-content: center;
margin-left: 1px;
}
.udapp_button button{
flex: none;
}
.udapp_button {
display: flex;
align-items: center;
margin-top: 13px;
}
.udapp_transaction {
}
.udapp_atAddress {
margin: 0;
min-width: 100px;
width: 100px;
height: 100%;
word-break: inherit;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: 0;
}
.udapp_atAddressSect {
margin-top: 8px;
height: 32px;
}
.udapp_atAddressSect input {
height: 32px;
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.udapp_ataddressinput {
padding: .25rem;
}
.udapp_create {
}
.udapp_input {
font-size: 10px !important;
}
.udapp_noInstancesText {
font-style: italic;
text-align: left;
padding-left: 15px;
}
.udapp_pendingTxsText {
font-style: italic;
display: flex;
justify-content: space-evenly;
align-items: center;
flex-wrap: wrap;
}
.udapp_item {
margin-right: 1em;
display: flex;
align-items: center;
}
.udapp_pendingContainer {
display: flex;
align-items: baseline;
}
.udapp_pending {
height: 25px;
text-align: center;
padding-left: 10px;
border-radius: 3px;
margin-left: 5px;
}
.udapp_disableMouseEvents {
pointer-events: none;
}
.udapp_icon {
cursor: pointer;
font-size: 12px;
cursor: pointer;
margin-left: 5px;
}
.udapp_icon:hover {
font-size: 12px;
color: var(--warning);
}
.udapp_errorIcon {
color: var(--warning);
margin-left: 15px;
}
.udapp_failDesc {
color: var(--warning);
padding-left: 10px;
display: inline;
}
.udapp_network {
margin-left: 8px;
pointer-events: none;
}
.udapp_networkItem {
margin-right: 5px;
}
.udapp_transactionActions {
display: flex;
justify-content: space-evenly;
width: 145px;
}
.udapp_orLabel {
text-align: center;
text-transform: uppercase;
}
.udapp_infoDeployAction {
margin-left: 1px;
font-size: 13px;
color: var(--info);
}
.udapp_gasValueContainer {
flex-direction: row;
display: flex;
}
.udapp_gasNval {
width: 55%;
font-size: 0.8rem;
}
.udapp_gasNvalUnit {
width: 41%;
margin-left: 10px;
font-size: 0.8rem;
}
.udapp_deployDropdown {
text-align: center;
text-transform: uppercase;
}
.udapp_checkboxAlign {
padding-top: 2px;
}

@ -1,14 +0,0 @@
import './remix-ui-run-tab.module.css';
/* eslint-disable-next-line */
export interface RemixUiRunTabProps {}
export function RemixUiRunTab(props: RemixUiRunTabProps) {
return (
<div>
<h1>Welcome to remix-ui-run-tab!</h1>
</div>
);
}
export default RemixUiRunTab;

@ -0,0 +1,25 @@
// eslint-disable-next-line no-use-before-define
import React, { useState } from 'react'
import { ContractDropdownUI } from './components/contractDropdownUI'
import { SettingsUI } from './components/settingsUI'
import './css/run-tab.css'
import { RunTabProps } from './types'
export function RunTabUI (props: RunTabProps) {
const [selectExEnv, setSelectExEnv] = useState<string>('')
const updateExEnv = (env: string) => {
setSelectExEnv(env)
}
return (
<div className="udapp_runTabView run-tab" id="runTabView" data-id="runTabView">
<div className="list-group list-group-flush">
<SettingsUI selectExEnv={selectExEnv} updateExEnv={updateExEnv} />
<ContractDropdownUI exEnvironment={selectExEnv} />
{/* ${this.recorderCard.render()}
${this.instanceContainer} */}
</div>
</div>
)
}

@ -0,0 +1,32 @@
export interface RunTabProps {
plugin: any
}
export interface SettingsProps {
selectExEnv: string,
updateExEnv: (env: string) => void
}
export interface EnvironmentProps {
updateExEnv: (env: string) => void
}
export interface NetworkProps {
}
export interface AccountProps {
selectExEnv: string
}
export interface GasPriceProps {
}
export interface ValueProps {
}
export interface ContractDropdownProps {
exEnvironment: string
}

@ -1,14 +1,10 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],

Loading…
Cancel
Save