Merge pull request #2904 from ethereum/custom-tooltips-rdtxns

Custom Tooltips for Run and Deploy
pull/3032/head
Joseph Izang 2 years ago committed by GitHub
commit c9ea23105b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      apps/remix-ide-e2e/src/commands/addAtAddressInstance.ts
  2. 6
      apps/remix-ide-e2e/src/commands/clickFunction.ts
  3. 8
      apps/remix-ide-e2e/src/commands/testConstantFunction.ts
  4. 12
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  5. 17
      libs/remix-ui/run-tab/src/lib/components/account.tsx
  6. 42
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  7. 267
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  8. 13
      libs/remix-ui/run-tab/src/lib/components/deployButton.tsx
  9. 10
      libs/remix-ui/run-tab/src/lib/components/deployInput.tsx
  10. 8
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  11. 9
      libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx
  12. 33
      libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx
  13. 12
      libs/remix-ui/run-tab/src/lib/components/multiDeployInput.tsx
  14. 32
      libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx
  15. 151
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  16. 8
      libs/remix-ui/run-tab/src/lib/components/value.tsx

@ -21,15 +21,22 @@ function addInstance (browser: NightwatchBrowser, address: string, isValidFormat
.setValue('.ataddressinput', address, function () {
if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAdressButton"]:disabled')
else if (isAbi) {
browser.click('button[id^="runAndDeployAtAdressButton"]')
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]')
browser
.click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]',
locateStrategy: 'xpath'
})
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]', 5000)
.execute(function () {
const modal = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any
modal.click()
})
} else {
browser.click('button[id^="runAndDeployAtAdressButton"]')
browser.click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]',
locateStrategy: 'xpath'
})
}
callback()
})

@ -3,18 +3,18 @@ import EventEmitter from 'events'
class ClickFunction extends EventEmitter {
command (this: NightwatchBrowser, fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser {
this.api.waitForElementPresent('.instance button[title="' + fnFullName + '"]')
this.api.waitForElementPresent('.instance button[data-title="' + fnFullName + '"]')
.perform(function (client, done) {
client.execute(function () {
document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight
}, [], function () {
if (expectedInput) {
client.setValue('#runTabView input[title="' + expectedInput.types + '"]', expectedInput.values, _ => _)
client.setValue('#runTabView input[data-title="' + expectedInput.types + '"]', expectedInput.values, _ => _)
}
done()
})
})
.scrollAndClick('.instance button[title="' + fnFullName + '"]')
.scrollAndClick('.instance button[data-title="' + fnFullName + '"]')
.pause(2000)
.perform(() => {
this.emit('complete')

@ -15,18 +15,18 @@ class TestConstantFunction extends EventEmitter {
}
function testConstantFunction (browser: NightwatchBrowser, address: string, fnFullName: string, expectedInput: NightwatchTestConstantFunctionExpectedInput, expectedOutput: string, cb: VoidFunction) {
browser.waitForElementPresent('.instance button[title="' + fnFullName + '"]').perform(function (client, done) {
browser.waitForElementPresent('.instance button[data-title="' + fnFullName + '"]').perform(function (client, done) {
client.execute(function () {
document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight
}, [], function () {
if (expectedInput) {
client.waitForElementPresent('#runTabView input[title="' + expectedInput.types + '"]')
.setValue('#runTabView input[title="' + expectedInput.types + '"]', expectedInput.values)
client.waitForElementPresent('#runTabView input[data-title="' + expectedInput.types + '"]')
.setValue('#runTabView input[data-title="' + expectedInput.types + '"]', expectedInput.values)
}
done()
})
})
.click(`#instance${address} button[title="${fnFullName}"]`)
.click(`#instance${address} button[data-title="${fnFullName}"]`)
.pause(1000)
.waitForElementPresent('#instance' + address + ' .udapp_contractActionsContainer .udapp_value')
.scrollInto('#instance' + address + ' .udapp_contractActionsContainer .udapp_value')

@ -19,8 +19,8 @@ module.exports = {
.clickLaunchIcon('solidity').click('*[data-id="compilerContainerCompileBtn"]')
.pause(4000)
.clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 60000)
.click('*[title="Deploy - transact (not payable)"]')
.waitForElementPresent('*[data-title="Deploy - transact (not payable)"]', 60000)
.click('*[data-title="Deploy - transact (not payable)"]')
.debugTransaction(0)
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.clearConsole()
@ -30,8 +30,8 @@ module.exports = {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.clickLaunchIcon('udapp')
.clickInstance(0)
.scrollAndClick('*[title="string name, uint256 goal"]')
.setValue('*[title="string name, uint256 goal"]', '"toast", 999')
.scrollAndClick('*[data-title="string name, uint256 goal"]')
.setValue('*[data-title="string name, uint256 goal"]', '"toast", 999')
.click('*[data-id="createProject - transact (not payable)"]')
.debugTransaction(0)
.pause(2000)
@ -88,7 +88,7 @@ module.exports = {
.clickLaunchIcon('solidity')
.testContracts('externalImport.sol', sources[1]['externalImport.sol'], ['ERC20'])
.clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 35000)
.waitForElementPresent('*[data-title="Deploy - transact (not payable)"]', 35000)
.selectContract('ERC20')
.createContract('"tokenName", "symbol"')
.debugTransaction(0)
@ -159,7 +159,7 @@ module.exports = {
.clickLaunchIcon('solidity')
.testContracts('locals.sol', sources[3]['locals.sol'], ['testLocals'])
.clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 40000)
.waitForElementPresent('*[data-title="Deploy - transact (not payable)"]', 40000)
.createContract('')
.pause(2000)
.clearConsole()

@ -3,6 +3,7 @@ import React, { useEffect, useState, useRef } from 'react'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { AccountProps } from '../types'
import { PassphrasePrompt } from './passphrase'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
export function AccountUI (props: AccountProps) {
const { selectedAccount, loadedAccounts } = props.accounts
@ -150,9 +151,15 @@ export function AccountUI (props: AccountProps) {
<div className="udapp_crow">
<label className="udapp_settingsLabel">
Account
<span id="remixRunPlusWraper" title={plusOpt.title}>
<OverlayTrigger placement={'top-start'} overlay={
<Tooltip className="text-wrap" id="remixPlusWrapperTooltip">
<span>{plusOpt.title}</span>
</Tooltip>
}>
<span id="remixRunPlusWraper">
<i id="remixRunPlus" className={`fas fa-plus-circle udapp_icon ${plusOpt.classList}`} aria-hidden="true" onClick={newAccount}></i>
</span>
</OverlayTrigger>
</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) => { props.setAccount(e.target.value) }}>
@ -161,7 +168,13 @@ export function AccountUI (props: AccountProps) {
}
</select>
<div style={{ marginLeft: -5 }}><CopyToClipboard tip='Copy account to clipboard' 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"></i>
<OverlayTrigger placement={'top-start'} overlay={
<Tooltip className="text-nowrap" id="remixSignMsgTooltip">
<span>{"Sign a message using this account"}</span>
</Tooltip>
}>
<i id="remixRunSignMsg" data-id="settingsRemixRunSignMsg" className="mx-1 fas fa-edit udapp_icon" aria-hidden="true" onClick={signMessage}></i>
</OverlayTrigger>
</div>
</div>
)

@ -2,10 +2,10 @@
import React, { useEffect, useRef, useState } from 'react'
import { ContractDropdownProps, DeployMode } from '../types'
import { ContractData, FuncABI } from '@remix-project/core-plugin'
import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line
import * as ethJSUtil from 'ethereumjs-util'
import { ContractGUI } from './contractGUI'
import { deployWithProxyMsg, upgradeWithProxyMsg } from '@remix-ui/helper'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
const _paq = window._paq = window._paq || []
export function ContractDropdownUI(props: ContractDropdownProps) {
@ -115,7 +115,6 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
const initSelectedContract = () => {
const contracts = contractList[currentFile]
if (contracts && contracts.length > 0) {
const contract = contracts.find(contract => contract.alias === currentContract)
@ -276,13 +275,25 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
: null}
</div>
<div className="udapp_subcontainer">
<select ref={contractsRef} value={currentContract} onChange={handleContractChange} className="udapp_contractNames custom-select" disabled={contractOptions.disabled} title={contractOptions.title} style={{ display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block' }}>
<OverlayTrigger
placement={"right"}
overlay={
<Tooltip
className="text-nowrap"
id="remixUdappContractNamesTooltip"
>
<span>{contractOptions.title}</span>
</Tooltip>
}
>
<select ref={contractsRef} value={currentContract} onChange={handleContractChange} className="udapp_contractNames custom-select" disabled={contractOptions.disabled} style={{ display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block' }}>
{(contractList[currentFile] || []).map((contract, index) => {
return <option key={index} value={contract.alias}>
{contract.alias} - {contract.file}
</option>
})}
</select>
</OverlayTrigger>
<span className="py-1" style={{ display: abiLabel.display }}>{abiLabel.content}</span>
</div>
<div>
@ -311,28 +322,47 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
onChange={handleCheckedIPFS}
checked={props.ipfsCheckedState}
/>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-wrap" id="remixIpfsUdappTooltip">
<span>Publishing the source code and metadata to IPFS facilitates source code verification <br />using Sourcify and will greatly foster contract adoption (auditing, debugging, calling it, etc...)</span>
</Tooltip>
}>
<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>
</OverlayTrigger>
</div>
</div> : ''
}
</div>
<div className="udapp_orLabel mt-2" style={{ display: loadType === 'abi' && !isContractFile(currentFile) ? 'none' : 'block' }}>or</div>
<div className="udapp_button udapp_atAddressSect ">
<button className="udapp_atAddress btn btn-sm btn-info" id="runAndDeployAtAdressButton" disabled={atAddressOptions.disabled} title={atAddressOptions.title} onClick={loadFromAddress}>At Address</button>
<OverlayTrigger placement={'top-end'} overlay={
<Tooltip className="text-wrap" id="runAndDeployAddresstooltip">
<span>{atAddressOptions.title}</span>
</Tooltip>
}>
<div id="runAndDeployAtAdressButtonContainer" onClick={loadFromAddress} data-title={atAddressOptions.title}>
<button className="udapp_atAddress btn btn-sm btn-info" id="runAndDeployAtAdressButton" disabled={atAddressOptions.disabled} style={{ pointerEvents: 'none' }} onClick={loadFromAddress} data-title={atAddressOptions.title}
>At Address</button>
</div>
</OverlayTrigger>
<OverlayTrigger placement={'top-end'} overlay={
<Tooltip className="text-wrap" id="runAndDeployAddressInputtooltip">
<span>{"address of contract"}</span>
</Tooltip>
}>
<input
ref={atAddressValue}
className="udapp_input udapp_ataddressinput ataddressinput form-control"
placeholder="Load contract from Address"
title="address of contract"
onChange={atAddressChanged}
/>
</OverlayTrigger>
</div>
</div>
</div>

@ -3,6 +3,7 @@ import React, { useEffect, useRef, useState } from 'react'
import * as remixLib from '@remix-project/remix-lib'
import { ContractGUIProps } from '../types'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
const txFormat = remixLib.execution.txFormat
const txHelper = remixLib.execution.txHelper
@ -233,66 +234,187 @@ export function ContractGUI (props: ContractGUIProps) {
}
return (
<div className={`udapp_contractProperty ${(props.funcABI.inputs && props.funcABI.inputs.length > 0) || (props.funcABI.type === 'fallback') || (props.funcABI.type === 'receive') ? 'udapp_hasArgs' : ''}`}>
<div className="udapp_contractActionsContainerSingle pt-2" style={{ display: toggleContainer ? 'none' : 'flex' }}>
<button onClick={handleActionClick} title={buttonOptions.title} className={`udapp_instanceButton ${props.widthClass} btn btn-sm ${buttonOptions.classList}`} data-id={buttonOptions.dataId}>{title}</button>
<div
className={`udapp_contractProperty ${
(props.funcABI.inputs && props.funcABI.inputs.length > 0) ||
props.funcABI.type === "fallback" ||
props.funcABI.type === "receive"
? "udapp_hasArgs"
: ""
}`}
>
<div
className="udapp_contractActionsContainerSingle pt-2"
style={{ display: toggleContainer ? "none" : "flex" }}
>
<OverlayTrigger
placement={"right-start"}
overlay={
<Tooltip
className="text-wrap"
id="remixUdappInstanceButtonTooltip"
>
<span>{buttonOptions.title}</span>
</Tooltip>
}
>
<button
onClick={handleActionClick}
className={`udapp_instanceButton ${props.widthClass} btn btn-sm ${buttonOptions.classList}`}
data-id={buttonOptions.dataId}
data-title={buttonOptions.title}
>
{title}
</button>
</OverlayTrigger>
<OverlayTrigger
placement={"right"}
overlay={
<Tooltip className="text-nowrap" id="remixContractGuiTooltip">
<span>
{props.funcABI.type === "fallback" ||
props.funcABI.type === "receive"
? `'(${props.funcABI.type}')`
: props.inputs}
</span>
</Tooltip>
}
>
<input
className="form-control"
data-id={props.funcABI.type === 'fallback' || props.funcABI.type === 'receive' ? `'(${props.funcABI.type}')` : 'multiParamManagerBasicInputField'}
data-id={
props.funcABI.type === "fallback" ||
props.funcABI.type === "receive"
? `'(${props.funcABI.type}')`
: "multiParamManagerBasicInputField"
}
placeholder={props.inputs}
title={props.funcABI.type === 'fallback' || props.funcABI.type === 'receive' ? `'(${props.funcABI.type}')` : props.inputs}
onChange={handleBasicInput}
data-title={
props.funcABI.type === "fallback" ||
props.funcABI.type === "receive"
? `'(${props.funcABI.type}')`
: props.inputs
}
ref={basicInputRef}
style={{ visibility: !((props.funcABI.inputs && props.funcABI.inputs.length > 0) || (props.funcABI.type === 'fallback') || (props.funcABI.type === 'receive')) ? 'hidden' : 'visible' }} />
style={{
visibility: !(
(props.funcABI.inputs && props.funcABI.inputs.length > 0) ||
props.funcABI.type === "fallback" ||
props.funcABI.type === "receive"
)
? "hidden"
: "visible",
}}
/>
</OverlayTrigger>
<i
className="fas fa-angle-down udapp_methCaret"
onClick={switchMethodViewOn}
title={title}
style={{ visibility: !(props.funcABI.inputs && props.funcABI.inputs.length > 0) ? 'hidden' : 'visible' }}></i>
style={{
visibility: !(
props.funcABI.inputs && props.funcABI.inputs.length > 0
)
? "hidden"
: "visible",
}}
></i>
</div>
<div className="udapp_contractActionsContainerMulti" style={{ display: toggleContainer ? 'flex' : 'none' }}>
<div
className="udapp_contractActionsContainerMulti"
style={{ display: toggleContainer ? "flex" : "none" }}
>
<div className="udapp_contractActionsContainerMultiInner text-dark">
<div onClick={switchMethodViewOff} className="udapp_multiHeader">
<div className="udapp_multiTitle run-instance-multi-title">{title}</div>
<i className='fas fa-angle-up udapp_methCaret'></i>
<div className="udapp_multiTitle run-instance-multi-title">
{title}
</div>
<i className="fas fa-angle-up udapp_methCaret"></i>
</div>
<div>
{props.funcABI.inputs.map((inp, index) => {
return (
<div className="udapp_multiArg" key={index}>
<label htmlFor={inp.name}> {inp.name}: </label>
<input ref={el => { multiFields.current[index] = el }} className="form-control" placeholder={inp.type} title={inp.name} data-id={`multiParamManagerInput${inp.name}`} />
</div>)
<OverlayTrigger
placement="left-end"
overlay={
<Tooltip id="udappContractActionsTooltip" className="text-nowrap">
<span>{inp.name}</span>
</Tooltip>
}
>
<input
ref={(el) => {
multiFields.current[index] = el;
}}
className="form-control"
placeholder={inp.type}
data-id={`multiParamManagerInput${inp.name}`}
/>
</OverlayTrigger>
</div>
);
})}
</div>
<div className="d-flex udapp_group udapp_multiArg">
<CopyToClipboard tip='Copy calldata to clipboard' icon='fa-clipboard' direction={'bottom'} getContent={getEncodedCall} >
<CopyToClipboard
tip="Copy calldata to clipboard"
icon="fa-clipboard"
direction={"bottom"}
getContent={getEncodedCall}
>
<button className="btn remixui_copyButton">
<i id="copyCalldata" className="m-0 remixui_copyIcon far fa-copy" aria-hidden="true"></i>
<i
id="copyCalldata"
className="m-0 remixui_copyIcon far fa-copy"
aria-hidden="true"
></i>
<label htmlFor="copyCalldata">Calldata</label>
</button>
</CopyToClipboard>
<CopyToClipboard tip='Copy encoded input parameters to clipboard' icon='fa-clipboard' direction={'bottom'} getContent={getEncodedParams} >
<CopyToClipboard
tip="Copy encoded input parameters to clipboard"
icon="fa-clipboard"
direction={"bottom"}
getContent={getEncodedParams}
>
<button className="btn remixui_copyButton">
<i id="copyParameters" className="m-0 remixui_copyIcon far fa-copy" aria-hidden="true"></i>
<i
id="copyParameters"
className="m-0 remixui_copyIcon far fa-copy"
aria-hidden="true"
></i>
<label htmlFor="copyParameters">Parameters</label>
</button>
</CopyToClipboard>
<OverlayTrigger
placement={"right"}
overlay={
<Tooltip
className="text-nowrap"
id="remixUdappInstanceButtonTooltip"
>
<span>{buttonOptions.title}</span>
</Tooltip>
}
>
<button
type="button"
onClick={handleExpandMultiClick}
title={buttonOptions.title}
data-id={buttonOptions.dataId}
className={`udapp_instanceButton ${buttonOptions.classList}`}
>
{buttonOptions.content}
</button>
</OverlayTrigger>
</div>
</div>
</div>
{ props.deployOption && (props.deployOption || []).length > 0 ?
{props.deployOption && (props.deployOption || []).length > 0 ? (
<>
<div className='d-flex justify-content-between'>
<div className="d-flex justify-content-between">
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
id="deployWithProxy"
@ -312,30 +434,55 @@ export function ContractGUI (props: ContractGUIProps) {
</label>
</div>
<div>
{
props.initializerOptions && props.initializerOptions.initializeInputs ?
{props.initializerOptions &&
props.initializerOptions.initializeInputs ? (
<span onClick={handleToggleDeployProxy}>
<i className={!toggleDeployProxy ? 'fas fa-angle-right pt-2' : 'fas fa-angle-down'} aria-hidden="true"></i>
</span> : null
<i
className={
!toggleDeployProxy
? "fas fa-angle-right pt-2"
: "fas fa-angle-down"
}
aria-hidden="true"
></i>
</span>
) : null}
</div>
</div>
{
props.initializerOptions && props.initializerOptions.initializeInputs ?
<div className={`pl-4 flex-column ${toggleDeployProxy ? "d-flex" : "d-none"}`}>
<div className={`flex-column 'd-flex'}`}>{
props.initializerOptions.inputs.inputs.map((inp, index) => {
{props.initializerOptions &&
props.initializerOptions.initializeInputs ? (
<div
className={`pl-4 flex-column ${
toggleDeployProxy ? "d-flex" : "d-none"
}`}
>
<div className={`flex-column 'd-flex'}`}>
{props.initializerOptions.inputs.inputs.map((inp, index) => {
return (
<div className="mb-2" key={index}>
<label className='mt-2 text-left d-block' htmlFor={inp.name}> {inp.name}: </label>
<input ref={el => { initializeFields.current[index] = el }} style={{ height: 32 }} className="form-control udapp_input" placeholder={inp.type} title={inp.name} />
<label
className="mt-2 text-left d-block"
htmlFor={inp.name}
>
{" "}
{inp.name}:{" "}
</label>
<input
ref={(el) => {
initializeFields.current[index] = el;
}}
style={{ height: 32 }}
className="form-control udapp_input"
placeholder={inp.type}
title={inp.name}
/>
</div>
)})
}
);
})}
</div>
</div> : null
}
<div className='d-flex justify-content-between'>
</div>
) : null}
<div className="d-flex justify-content-between">
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
id="upgradeImplementation"
@ -355,10 +502,21 @@ export function ContractGUI (props: ContractGUIProps) {
</label>
</div>
<span onClick={handleToggleUpgradeImp}>
<i className={!toggleUpgradeImp ? 'fas fa-angle-right pt-2' : 'fas fa-angle-down'} aria-hidden="true"></i>
<i
className={
!toggleUpgradeImp
? "fas fa-angle-right pt-2"
: "fas fa-angle-down"
}
aria-hidden="true"
></i>
</span>
</div>
<div className={`pl-4 flex-column ${toggleUpgradeImp ? "d-flex" : "d-none"}`}>
<div
className={`pl-4 flex-column ${
toggleUpgradeImp ? "d-flex" : "d-none"
}`}
>
<div className={`flex-column 'd-flex'}`}>
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
@ -379,18 +537,33 @@ export function ContractGUI (props: ContractGUIProps) {
Use last deployed ERC1967 contract
</label>
</div>
{
!useLastProxy ?
{!useLastProxy ? (
<div className="mb-2">
<label className='mt-2 text-left d-block'>Proxy Address: </label>
<input style={{ height: 32 }} className="form-control udapp_input" data-id="ERC1967AddressInput" placeholder='proxy address' title='Enter previously deployed proxy address on the selected network' onChange={handleSetProxyAddress} />
</div> :
<span className='text-capitalize' data-id="lastDeployedERC1967Address" style={{ fontSize: '.8em' }}>{ proxyAddress || 'No proxy address available' }</span>
}
<label className="mt-2 text-left d-block">
Proxy Address:{" "}
</label>
<input
style={{ height: 32 }}
className="form-control udapp_input"
data-id="ERC1967AddressInput"
placeholder="proxy address"
title="Enter previously deployed proxy address on the selected network"
onChange={handleSetProxyAddress}
/>
</div>
) : (
<span
className="text-capitalize"
data-id="lastDeployedERC1967Address"
style={{ fontSize: ".8em" }}
>
{proxyAddress || "No proxy address available"}
</span>
)}
</div>
</> : null
}
</div>
)
</>
) : null}
</div>
);
}

@ -1,6 +1,6 @@
import React, { useState } from 'react'
import { DeployButtonProps } from '../types'
import { ButtonGroup, Dropdown } from 'react-bootstrap'
import { ButtonGroup, Dropdown, OverlayTrigger, Tooltip } from 'react-bootstrap'
export function DeployButton (props: DeployButtonProps) {
const [showOptions, setShowOptions] = useState<boolean>(false)
@ -24,9 +24,18 @@ export function DeployButton (props: DeployButtonProps) {
}
</Dropdown.Menu>
</Dropdown> :
<button onClick={props.handleActionClick} title={props.buttonOptions.title} className={`udapp_instanceButton ${props.buttonOptions.widthClass} btn btn-sm ${props.buttonOptions.classList}`} data-id={props.buttonOptions.dataId}>
<OverlayTrigger
placement="right-start"
overlay={
<Tooltip id="deployButtonTooltip" className="text-nowrap">
<span>{props.buttonOptions.title}</span>
</Tooltip>
}
>
<button onClick={props.handleActionClick} className={`udapp_instanceButton ${props.buttonOptions.widthClass} btn btn-sm ${props.buttonOptions.classList}`} data-id={props.buttonOptions.dataId}>
Deploy
</button>
</OverlayTrigger>
}
</>
)

@ -1,4 +1,5 @@
import React from 'react'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { DeployInputProps } from '../types'
import { DeployButton } from './deployButton'
@ -6,6 +7,14 @@ export function DeployInput (props: DeployInputProps) {
return (
<div className="udapp_contractActionsContainerSingle pt-2" style={{ display: 'flex' }}>
<DeployButton buttonOptions={props.buttonOptions} selectedIndex={props.selectedIndex} setSelectedIndex={props.setSelectedIndex} handleActionClick={props.handleActionClick} deployOptions={props.deployOptions} />
<OverlayTrigger
placement="right-start"
overlay={
<Tooltip id="deployInputTooltip" className="text-nowrap">
<span>{props.funcABI.type === 'fallback' || props.funcABI.type === 'receive' ? `'(${props.funcABI.type}')` : props.inputs}</span>
</Tooltip>
}
>
<input
className="form-control"
data-id={props.funcABI.type === 'fallback' || props.funcABI.type === 'receive' ? `'(${props.funcABI.type}')` : 'multiParamManagerBasicInputField'}
@ -15,6 +24,7 @@ export function DeployInput (props: DeployInputProps) {
ref={props.basicInputRef}
style={{ visibility: !props.inputs ? 'hidden' : 'visible' }}
/>
</OverlayTrigger>
</div>
)
}

@ -67,7 +67,13 @@ export function EnvironmentUI (props: EnvironmentProps) {
}
</Dropdown.Menu>
</Dropdown>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#environment" target="_blank" rel="noreferrer"><i className="udapp_infoDeployAction ml-2 fas fa-info" title="Click for docs about Environment"></i></a>
<OverlayTrigger placement={'bottom-start'} overlay={
<Tooltip className="text-wrap" id="runAndDeployAddresstooltip">
<span>{"Click for docs about Environment"}</span>
</Tooltip>
}>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#environment" target="_blank" rel="noreferrer"><i className="udapp_infoDeployAction ml-2 fas fa-info"></i></a>
</OverlayTrigger>
</div>
</div>
)

@ -1,5 +1,6 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { GasPriceProps } from '../types'
export function GasPriceUI (props: GasPriceProps) {
@ -10,7 +11,13 @@ 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" title="The default gas limit is 3M. Adjust as needed." id="gasLimit" value={props.gasLimit} onChange={handleGasLimit} />
<OverlayTrigger placement={'right-end'} overlay={
<Tooltip className="text-nowrap" id="remixGasPriceTooltip">
<span>{"The default gas limit is 3M. Adjust as needed."}</span>
</Tooltip>
}>
<input type="number" className="form-control udapp_gasNval udapp_col2" id="gasLimit" value={props.gasLimit} onChange={handleGasLimit} />
</OverlayTrigger>
</div>
)
}

@ -1,5 +1,6 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { InstanceContainerProps } from '../types'
import { UniversalDappUI } from './universalDappUI'
@ -12,15 +13,35 @@ export function InstanceContainerUI (props: InstanceContainerProps) {
return (
<div className="udapp_instanceContainer mt-3 border-0 list-group-item">
<label className="udapp_deployedContracts d-flex justify-content-between align-items-center pl-2 mb-2"
title="Autogenerated generic user interfaces for interaction with deployed contracts">
<div className="d-flex justify-content-between align-items-center pl-2 mb-2">
<OverlayTrigger
placement="top-start"
overlay={
<Tooltip className="text-nowrap" id="deployAndRunClearInstancesTooltip">
<span>{"Autogenerated generic user interfaces for interaction with deployed contracts"}</span>
</Tooltip>
}
>
<label className="udapp_deployedContracts">
Deployed Contracts
</label>
</OverlayTrigger>
{ instanceList.length > 0
? <i className="mr-2 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance}
title="Clear instances list and reset recorder" aria-hidden="true">
</i> : null
? (
<OverlayTrigger
placement="right"
overlay={
<Tooltip className="text-nowrap" id="deployAndRunClearInstancesTooltip">
<span>{"Clear instances list and reset recorder"}</span>
</Tooltip>
}
</label>
>
<i className="mr-2 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance} aria-hidden="true">
</i>
</OverlayTrigger>
) : null
}
</div>
{ instanceList.length > 0
? <div> { props.instances.instanceList.map((instance, index) => {
return <UniversalDappUI

@ -1,4 +1,5 @@
import React, { useRef, useState } from 'react'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { MultiDeployInputProps } from '../types'
import { DeployButton } from './deployButton'
@ -16,7 +17,16 @@ export function MultiDeployInput(props: MultiDeployInputProps) {
return (
<div className="udapp_multiArg" key={index}>
<label htmlFor={inp.name}> {inp.name}: </label>
<input ref={el => { multiFields.current[index] = el }} className="form-control" placeholder={inp.type} title={inp.name} data-id={`multiParamManagerInput${inp.name}`} />
<OverlayTrigger
placement="left-end"
overlay={
<Tooltip id="udappMultiArgTooltip" className="text-nowrap">
<span>{inp.name}</span>
</Tooltip>
}
>
<input ref={el => { multiFields.current[index] = el }} className="form-control" placeholder={inp.type} data-id={`multiParamManagerInput${inp.name}`} />
</OverlayTrigger>
</div>)
})}
</div>

@ -31,7 +31,13 @@ export function RecorderUI (props: RecorderProps) {
<div className="udapp_recorderSection d-flex justify-content-between" onClick={toggleClass}>
<div className="d-flex justify-content-center align-items-center">
<label className="mt-1 udapp_recorderSectionLabel">Transactions recorded</label>
<div className="ml-2 badge badge-pill badge-primary text-center" title="The number of recorded transactions">{props.count}</div>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="recordedTransactionsCounttooltip">
<span>{'The number of recorded transactions'}</span>
</Tooltip>
}>
<div className="ml-2 badge badge-pill badge-primary text-center" data-title="The number of recorded transactions">{props.count}</div>
</OverlayTrigger>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="info-recorder">
<span>Save transactions (deployed contracts and function executions) and replay them in another environment. <br/> e.g Transactions created in Remix VM can be replayed in the Injected Provider.
@ -59,19 +65,33 @@ export function RecorderUI (props: RecorderProps) {
</OverlayTrigger>
</div>
<div className="mb-1 mt-1 udapp_transactionActions">
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="tooltip-save-recorder">
<span>Save {props.count} transaction{props.count === 1 ? '' : 's'} as scenario file</span>
<OverlayTrigger placement={'bottom-start'} overlay={
<Tooltip className="text-nowrap" id="remixUdappTransactionSavetooltip">
<span>
{
props.count === 0 ? 'No transactions to save'
: props.count === 1 ? `Save ${props.count} transaction as scenario file`
: `Save ${props.count} transactions as scenario file`
}
</span>
</Tooltip>
}>
<button className="btn btn-sm btn-info savetransaction udapp_recorder" title={props.count === 0 ? 'No transactions to save' : ''} disabled={props.count === 0 ? true: false} onClick={triggerRecordButton}>Save</button>
<span>
<button className="btn btn-sm btn-info savetransaction udapp_recorder" disabled={props.count === 0 ? true: false} onClick={triggerRecordButton} style={{ pointerEvents: props.count === 0 ? 'none' : 'auto' }}>
Save
</button>
</span>
</OverlayTrigger>
<OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="tooltip-run-recorder">
<span>Run transaction(s) from the current scenario file</span>
</Tooltip>
}>
<button className="btn btn-sm btn-info runtransaction udapp_runTxs" data-id="runtransaction" title={enableRunButton ? 'No scenario file selected' : ''} disabled={enableRunButton} onClick={handleClickRunButton}>Run</button>
<span>
<button className="btn btn-sm btn-info runtransaction udapp_runTxs" data-id="runtransaction" disabled={enableRunButton} onClick={handleClickRunButton} style={{ pointerEvents: enableRunButton ? 'none' : 'auto' }}>
Run
</button>
</span>
</OverlayTrigger>
</div>
</div>

@ -7,6 +7,7 @@ import * as remixLib from '@remix-project/remix-lib'
import * as ethJSUtil from 'ethereumjs-util'
import { ContractGUI } from './contractGUI'
import { TreeView, TreeViewItem } from '@remix-ui/tree-view'
import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line
import { BN } from 'ethereumjs-util'
import { is0XPrefixed, isHexadecimal, isNumeric, shortenAddress } from '@remix-ui/helper'
@ -210,47 +211,90 @@ export function UniversalDappUI (props: UdappProps) {
}
return (
<div className={`instance udapp_instance udapp_run-instance border-dark ${toggleExpander ? 'udapp_hidesub' : 'bg-light'}`} id={`instance${address}`} data-shared="universalDappUiInstance">
<div
className={`instance udapp_instance udapp_run-instance border-dark ${
toggleExpander ? "udapp_hidesub" : "bg-light"
}`}
id={`instance${address}`}
data-shared="universalDappUiInstance"
>
<div className="udapp_title pb-0 alert alert-secondary">
<span data-id={`universalDappUiTitleExpander${props.index}`} className="btn udapp_titleExpander" onClick={toggleClass}>
<i className={`fas ${toggleExpander ? 'fa-angle-right' : 'fa-angle-down'}`} aria-hidden="true"></i>
<span
data-id={`universalDappUiTitleExpander${props.index}`}
className="btn udapp_titleExpander"
onClick={toggleClass}
>
<i
className={`fas ${
toggleExpander ? "fa-angle-right" : "fa-angle-down"
}`}
aria-hidden="true"
></i>
</span>
<div className="input-group udapp_nameNbuts">
<div className="udapp_titleText input-group-prepend">
<span className="input-group-text udapp_spanTitleText">
{props.instance.name} at {shortenAddress(address)} ({props.context})
{props.instance.name} at {shortenAddress(address)} (
{props.context})
</span>
</div>
<div className="btn-group">
<button className="btn p-1 btn-secondary"><CopyToClipboard content={address} direction={'top'} /></button>
<button className="btn p-1 btn-secondary">
<CopyToClipboard content={address} direction={"top"} />
</button>
</div>
</div>
<OverlayTrigger
placement="right"
overlay={
<Tooltip className="text-nowrap" id="udapp_udappCloseTooltip">
<span>{'Remove from the list'}</span>
</Tooltip>
}
>
<button
className="udapp_udappClose mr-1 p-1 btn btn-secondary align-items-center"
data-id="universalDappUiUdappClose"
onClick={remove}
title="Remove from the list"
>
<i className="udapp_closeIcon fas fa-times" aria-hidden="true"></i>
</button>
</OverlayTrigger>
</div>
<div className="udapp_cActionsWrapper" data-id="universalDappUiContractActionWrapper">
<div
className="udapp_cActionsWrapper"
data-id="universalDappUiContractActionWrapper"
>
<div className="udapp_contractActionsContainer">
<div className="d-flex" data-id="instanceContractBal">
<label>Balance: {instanceBalance} ETH</label>
</div>
{
contractABI && contractABI.map((funcABI, index) => {
if (funcABI.type !== 'function') return null
const isConstant = funcABI.constant !== undefined ? funcABI.constant : false
const lookupOnly = funcABI.stateMutability === 'view' || funcABI.stateMutability === 'pure' || isConstant
const inputs = props.getFuncABIInputs(funcABI)
{contractABI &&
contractABI.map((funcABI, index) => {
if (funcABI.type !== "function") return null;
const isConstant =
funcABI.constant !== undefined ? funcABI.constant : false;
const lookupOnly =
funcABI.stateMutability === "view" ||
funcABI.stateMutability === "pure" ||
isConstant;
const inputs = props.getFuncABIInputs(funcABI);
return <div key={index}>
return (
<div key={index}>
<ContractGUI
funcABI={funcABI}
clickCallBack={(valArray: { name: string, type: string }[], inputsValues: string) => {
runTransaction(lookupOnly, funcABI, valArray, inputsValues, index)
clickCallBack={(
valArray: { name: string; type: string }[],
inputsValues: string
) => {
runTransaction(
lookupOnly,
funcABI,
valArray,
inputsValues,
index
);
}}
inputs={inputs}
evmBC={evmBC}
@ -259,55 +303,98 @@ export function UniversalDappUI (props: UdappProps) {
/>
<div className="udapp_value" data-id="udapp_value">
<TreeView id="treeView">
{
Object.keys(props.instance.decodedResponse || {}).map((key) => {
const funcIndex = index.toString()
const response = props.instance.decodedResponse[key]
{Object.keys(props.instance.decodedResponse || {}).map(
(key) => {
const funcIndex = index.toString();
const response = props.instance.decodedResponse[key];
return key === funcIndex ? Object.keys(response || {}).map((innerkey, index) => {
return renderData(props.instance.decodedResponse[key][innerkey], response, innerkey, innerkey)
}) : null
})
return key === funcIndex
? Object.keys(response || {}).map(
(innerkey, index) => {
return renderData(
props.instance.decodedResponse[key][
innerkey
],
response,
innerkey,
innerkey
);
}
)
: null;
}
)}
</TreeView>
</div>
</div>
})
}
);
})}
</div>
<div className="d-flex flex-column">
<div className="d-flex flex-row justify-content-between mt-2">
<div className="py-2 border-top d-flex justify-content-start flex-grow-1">
Low level interactions
</div>
<OverlayTrigger
placement={"bottom-end"}
overlay={
<Tooltip className="text-wrap" id="receiveEthDocstoolTip">
<span>{"check out docs for using 'receive'/'fallback'"}</span>
</Tooltip>
}
>
<a
href="https://solidity.readthedocs.io/en/v0.6.2/contracts.html#receive-ether-function"
title="check out docs for using 'receive'/'fallback'"
target="_blank" rel="noreferrer"
target="_blank"
rel="noreferrer"
>
<i aria-hidden="true" className="fas fa-info my-2 mr-1"></i>
</a>
</OverlayTrigger>
</div>
<div className="d-flex flex-column align-items-start">
<label className="">CALLDATA</label>
<div className="d-flex justify-content-end w-100 align-items-center">
<input id="deployAndRunLLTxCalldata" onChange={handleCalldataChange} className="udapp_calldataInput form-control" title="The Calldata to send to fallback function of the contract." />
<OverlayTrigger
placement="bottom"
overlay={
<Tooltip className="text-nowrap" id="deployAndRunLLTxCalldataInputTooltip">
<span>{"The Calldata to send to fallback function of the contract."}</span>
</Tooltip>
}
>
<input
id="deployAndRunLLTxCalldata"
onChange={handleCalldataChange}
className="udapp_calldataInput form-control"
/>
</OverlayTrigger>
<OverlayTrigger
placement="right"
overlay={
<Tooltip className="text-nowrap" id="deployAndRunLLTxCalldataTooltip">
<span>Send data to contract.</span>
</Tooltip>
}
>
<button
id="deployAndRunLLTxSendTransaction"
data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction"
className="btn udapp_instanceButton p-0 w-50 border-warning text-warning"
title="Send data to contract."
onClick={sendData}
>
Transact
</button>
</OverlayTrigger>
</div>
</div>
<div>
<label id="deployAndRunLLTxError" className="text-danger my-2">{ llIError }</label>
<label id="deployAndRunLLTxError" className="text-danger my-2">
{llIError}
</label>
</div>
</div>
</div>
</div>
)
);
}

@ -3,6 +3,7 @@ import React, { useEffect, useRef, useState } from 'react'
import { BN } from 'ethereumjs-util'
import { isNumeric } from '@remix-ui/helper'
import { ValueProps } from '../types'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
export function ValueUI (props: ValueProps) {
const [sendValue, setSendValue] = useState<string>(props.sendValue)
@ -49,6 +50,11 @@ export function ValueUI (props: ValueProps) {
<div className="udapp_crow">
<label className="udapp_settingsLabel" data-id="remixDRValueLabel">Value</label>
<div className="udapp_gasValueContainer">
<OverlayTrigger placement={'top-start'} overlay={
<Tooltip className="text-nowrap" id="remixValueTooltip">
<span>{"Enter an amount and choose its unit"}</span>
</Tooltip>
}>
<input
ref={inputValue}
type="number"
@ -58,11 +64,11 @@ export function ValueUI (props: ValueProps) {
className="form-control udapp_gasNval udapp_col2"
id="value"
data-id="dandrValue"
title="Enter an amount and choose its unit"
onKeyPress={validateInputKey}
onChange={validateValue}
value={props.sendValue}
/>
</OverlayTrigger>
<select name="unit" value={props.sendUnit} className="form-control p-1 udapp_gasNvalUnit udapp_col2_2 custom-select" id="unit" onChange={(e) => { props.setUnit((e.target.value) as 'ether' | 'finney' | 'gwei' | 'wei') }}>
<option data-unit="wei" value='wei'>Wei</option>
<option data-unit="gwei" value="gwei">Gwei</option>

Loading…
Cancel
Save