Merge branch 'master' into intl

pull/2581/head
drafish 2 years ago
commit f22479469e
  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/home-tab/src/lib/components/customNavButtons.tsx
  6. 11
      libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx
  7. 57
      libs/remix-ui/home-tab/src/lib/components/homeTabFeaturedPlugins.tsx
  8. 64
      libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx
  9. 6
      libs/remix-ui/home-tab/src/lib/components/homeTabLearn.tsx
  10. 2
      libs/remix-ui/home-tab/src/lib/components/pluginButton.tsx
  11. 2
      libs/remix-ui/home-tab/src/lib/components/workspaceTemplate.tsx
  12. 2
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css
  13. 17
      libs/remix-ui/run-tab/src/lib/components/account.tsx
  14. 40
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  15. 267
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  16. 13
      libs/remix-ui/run-tab/src/lib/components/deployButton.tsx
  17. 10
      libs/remix-ui/run-tab/src/lib/components/deployInput.tsx
  18. 18
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  19. 9
      libs/remix-ui/run-tab/src/lib/components/gasPrice.tsx
  20. 33
      libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx
  21. 12
      libs/remix-ui/run-tab/src/lib/components/multiDeployInput.tsx
  22. 32
      libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx
  23. 151
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  24. 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 () { .setValue('.ataddressinput', address, function () {
if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAdressButton"]:disabled') if (!isValidFormat || !isValidChecksum) browser.assert.elementPresent('button[id^="runAndDeployAtAdressButton"]:disabled')
else if (isAbi) { else if (isAbi) {
browser.click('button[id^="runAndDeployAtAdressButton"]') browser
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]') .click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]',
locateStrategy: 'xpath'
})
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]', 5000)
.execute(function () { .execute(function () {
const modal = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any const modal = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any
modal.click() modal.click()
}) })
} else { } else {
browser.click('button[id^="runAndDeployAtAdressButton"]') browser.click({
selector: '//*[@id="runAndDeployAtAdressButtonContainer"]',
locateStrategy: 'xpath'
})
} }
callback() callback()
}) })

@ -3,18 +3,18 @@ import EventEmitter from 'events'
class ClickFunction extends EventEmitter { class ClickFunction extends EventEmitter {
command (this: NightwatchBrowser, fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser { 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) { .perform(function (client, done) {
client.execute(function () { client.execute(function () {
document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight
}, [], function () { }, [], function () {
if (expectedInput) { if (expectedInput) {
client.setValue('#runTabView input[title="' + expectedInput.types + '"]', expectedInput.values, _ => _) client.setValue('#runTabView input[data-title="' + expectedInput.types + '"]', expectedInput.values, _ => _)
} }
done() done()
}) })
}) })
.scrollAndClick('.instance button[title="' + fnFullName + '"]') .scrollAndClick('.instance button[data-title="' + fnFullName + '"]')
.pause(2000) .pause(2000)
.perform(() => { .perform(() => {
this.emit('complete') 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) { 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 () { client.execute(function () {
document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight document.querySelector('#runTabView').scrollTop = document.querySelector('#runTabView').scrollHeight
}, [], function () { }, [], function () {
if (expectedInput) { if (expectedInput) {
client.waitForElementPresent('#runTabView input[title="' + expectedInput.types + '"]') client.waitForElementPresent('#runTabView input[data-title="' + expectedInput.types + '"]')
.setValue('#runTabView input[title="' + expectedInput.types + '"]', expectedInput.values) .setValue('#runTabView input[data-title="' + expectedInput.types + '"]', expectedInput.values)
} }
done() done()
}) })
}) })
.click(`#instance${address} button[title="${fnFullName}"]`) .click(`#instance${address} button[data-title="${fnFullName}"]`)
.pause(1000) .pause(1000)
.waitForElementPresent('#instance' + address + ' .udapp_contractActionsContainer .udapp_value') .waitForElementPresent('#instance' + address + ' .udapp_contractActionsContainer .udapp_value')
.scrollInto('#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"]') .clickLaunchIcon('solidity').click('*[data-id="compilerContainerCompileBtn"]')
.pause(4000) .pause(4000)
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 60000) .waitForElementPresent('*[data-title="Deploy - transact (not payable)"]', 60000)
.click('*[title="Deploy - transact (not payable)"]') .click('*[data-title="Deploy - transact (not payable)"]')
.debugTransaction(0) .debugTransaction(0)
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000) .waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.clearConsole() .clearConsole()
@ -30,8 +30,8 @@ module.exports = {
browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]') browser.waitForElementVisible('*[data-id="verticalIconsKindudapp"]')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.clickInstance(0) .clickInstance(0)
.scrollAndClick('*[title="string name, uint256 goal"]') .scrollAndClick('*[data-title="string name, uint256 goal"]')
.setValue('*[title="string name, uint256 goal"]', '"toast", 999') .setValue('*[data-title="string name, uint256 goal"]', '"toast", 999')
.click('*[data-id="createProject - transact (not payable)"]') .click('*[data-id="createProject - transact (not payable)"]')
.debugTransaction(0) .debugTransaction(0)
.pause(2000) .pause(2000)
@ -88,7 +88,7 @@ module.exports = {
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.testContracts('externalImport.sol', sources[1]['externalImport.sol'], ['ERC20']) .testContracts('externalImport.sol', sources[1]['externalImport.sol'], ['ERC20'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 35000) .waitForElementPresent('*[data-title="Deploy - transact (not payable)"]', 35000)
.selectContract('ERC20') .selectContract('ERC20')
.createContract('"tokenName", "symbol"') .createContract('"tokenName", "symbol"')
.debugTransaction(0) .debugTransaction(0)
@ -159,7 +159,7 @@ module.exports = {
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.testContracts('locals.sol', sources[3]['locals.sol'], ['testLocals']) .testContracts('locals.sol', sources[3]['locals.sol'], ['testLocals'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 40000) .waitForElementPresent('*[data-title="Deploy - transact (not payable)"]', 40000)
.createContract('') .createContract('')
.pause(2000) .pause(2000)
.clearConsole() .clearConsole()

@ -2,15 +2,24 @@
import React from 'react' import React from 'react'
const CustomNavButtons = ({ next, previous, goToSlide, ...rest }) => { const CustomNavButtons = ({ next, previous, goToSlide, ...rest }) => {
const { carouselState: { currentSlide, totalItems } } = rest const { carouselState: { currentSlide, totalItems, itemWidth, containerWidth } } = rest
return ( return (
<div className="mt-1 d-flex justify-content-end carousel-button-group"> <div className="mt-1 d-flex justify-content-end carousel-button-group">
<button className={currentSlide === 0 ? 'disable py-1 border btn' : 'py-1 border btn'} onClick={() => previous()}> <button
className={currentSlide === 0 ? 'disable py-1 border btn' : 'py-1 border btn'}
disabled={currentSlide === 0}
onClick={() => previous()}
>
<i className="fas fa-angle-left"></i> <i className="fas fa-angle-left"></i>
</button> </button>
<button className={currentSlide + 1 === totalItems ? 'disable py-1 border btn' : 'py-1 border btn'} onClick={() => { <button
className={
((totalItems - currentSlide) * itemWidth + 5) < containerWidth ? 'disable py-1 border btn' : 'py-1 border btn'}
onClick={() => {
if (currentSlide + 1 < totalItems) goToSlide(currentSlide + 1) if (currentSlide + 1 < totalItems) goToSlide(currentSlide + 1)
}} > }}
disabled ={((totalItems - currentSlide) * itemWidth + 5) < containerWidth}
>
<i className="fas fa-angle-right"></i> <i className="fas fa-angle-right"></i>
</button> </button>
</div> </div>

@ -43,7 +43,8 @@ function HomeTabFeatured() {
<img src={"assets/img/bgRemi.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img> <img src={"assets/img/bgRemi.webp"} style={{ flex: "1", height: "170px", maxWidth: "170px" }} alt="" ></img>
<div className="h6 w-50 p-4" style={{ flex: "1" }}> <div className="h6 w-50 p-4" style={{ flex: "1" }}>
<h5>JUMP INTO WEB3</h5> <h5>JUMP INTO WEB3</h5>
<span>The Remix Project is a rich toolset which can be used for the entire journey of contract development by users of any knowledge level, and as a learning lab for teaching and experimenting with Ethereum.</span> <p>The Remix Project is a rich toolset which can be used for the entire journey of contract development by users of any knowledge level, and as a learning lab for teaching and experimenting with Ethereum.</p>
<a className="remixui_home_text" target="__blank" href="https://remix-project.org">More</a>
</div> </div>
</div> </div>
<div className="d-flex"> <div className="d-flex">
@ -51,7 +52,10 @@ function HomeTabFeatured() {
<div className="h6 p-4" style={{ flex: "1" }}> <div className="h6 p-4" style={{ flex: "1" }}>
<h5>REMIX REWARDS</h5> <h5>REMIX REWARDS</h5>
<p style={{ fontStyle: 'italic' }}>NFTs for our users!</p> <p style={{ fontStyle: 'italic' }}>NFTs for our users!</p>
<span>Remix Project rewards contributors, beta testers, and UX research participants with NFTs deployed on Optimism. Remix Reward holders are able to mint a second Remixer user NFT badge to give to any other user of their choice</span> <p>
Remix Project rewards contributors, beta testers, and UX research participants with NFTs deployed on Optimism. Remix Reward holders are able to mint a second Remixer user NFT badge to give to any other user of their choice.
</p>
<a className="remixui_home_text" target="__blank" href="https://rewards.remix.ethereum.eth.limo">More</a>
</div> </div>
</div> </div>
<div className="d-flex"> <div className="d-flex">
@ -59,7 +63,8 @@ function HomeTabFeatured() {
<div className="h6 p-4" style={{ flex: "1" }}> <div className="h6 p-4" style={{ flex: "1" }}>
<h5>BETA TESTING</h5> <h5>BETA TESTING</h5>
<p style={{ fontStyle: 'italic' }}>Our community supports us.</p> <p style={{ fontStyle: 'italic' }}>Our community supports us.</p>
<span>You can join Beta Testing before each release of Remix IDE. Help us test now and get a handle on new features!</span> <p>You can join Beta Testing before each release of Remix IDE. Help us test now and get a handle on new features!</p>
<a className="remixui_home_text" target="__blank" href="https://rewards.remix.ethereum.eth.limo">More</a>
</div> </div>
</div> </div>
</Carousel> </Carousel>

@ -1,18 +1,18 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect, useState, useRef, useContext } from 'react' import React, { useEffect, useRef, useContext } from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
import PluginButton from './pluginButton' import PluginButton from './pluginButton'
import { ThemeContext, themes } from '../themeContext' import { ThemeContext } from '../themeContext'
import Carousel from 'react-multi-carousel' import Carousel from 'react-multi-carousel'
import 'react-multi-carousel/lib/styles.css' import 'react-multi-carousel/lib/styles.css'
import CustomNavButtons from './customNavButtons' import CustomNavButtons from './customNavButtons'
const itemsToShow = 5
declare global { declare global {
interface Window { interface Window {
_paq: any _paq: any
} }
} }
const _paq = window._paq = window._paq || [] //eslint-disable-line const _paq = window._paq = window._paq || [] //eslint-disable-line
interface HomeTabFeaturedPluginsProps { interface HomeTabFeaturedPluginsProps {
plugin: any plugin: any
} }
@ -21,16 +21,40 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
const themeFilter = useContext(ThemeContext) const themeFilter = useContext(ThemeContext)
const carouselRef = useRef(null) const carouselRef = useRef(null)
const carouselRefDiv = useRef(null)
// Todo doesn't work
useEffect(() => { useEffect(() => {
window.addEventListener("scroll", handleScroll) document.addEventListener("wheel", handleScroll)
return () => { return () => {
window.removeEventListener("scroll", handleScroll) document.removeEventListener("wheel", handleScroll)
} }
}, []) }, [])
function isDescendant(parent, child) {
let node = child.parentNode;
while (node != null) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
return false;
}
const handleScroll = (e) => { const handleScroll = (e) => {
if (isDescendant(carouselRefDiv.current, e.target)) {
e.stopPropagation()
let nextSlide = 0
if (e.wheelDelta < 0) {
nextSlide = carouselRef.current.state.currentSlide + 1;
if ((carouselRef.current.state.totalItems - carouselRef.current.state.currentSlide) * carouselRef.current.state.itemWidth + 5 < carouselRef.current.state.containerWidth) return // 5 is approx margins
carouselRef.current.goToSlide(nextSlide)
} else {
nextSlide = carouselRef.current.state.currentSlide - 1;
if (nextSlide < 0) nextSlide = 0
carouselRef.current.goToSlide(nextSlide)
}
}
} }
const startSolidity = async () => { const startSolidity = async () => {
@ -62,17 +86,30 @@ function HomeTabFeaturedPlugins ({plugin}: HomeTabFeaturedPluginsProps) {
return ( return (
<div className="pl-2 w-100" id="hTFeaturedPlugins"> <div className="pl-2 w-100" id="hTFeaturedPlugins">
<label className="" style={{fontSize: "1.2rem"}}><FormattedMessage id='home.featuredPlugins' defaultMessage='Featured Plugins' /></label> <label className="" style={{fontSize: "1.2rem"}}><FormattedMessage id='home.featuredPlugins' defaultMessage='Featured Plugins' /></label>
<div className="w-100 d-flex flex-column"> <div ref={carouselRefDiv} className="w-100 d-flex flex-column">
<ThemeContext.Provider value={ themeFilter }> <ThemeContext.Provider value={ themeFilter }>
<Carousel <Carousel
ref={carouselRef} ref={carouselRef}
focusOnSelect focusOnSelect={true}
customButtonGroup={<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />} customButtonGroup={
<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />
}
arrows={false} arrows={false}
swipeable={false} swipeable={false}
draggable={true} draggable={true}
showDots={false} showDots={false}
responsive={{ desktop: { breakpoint: { max: 3000, min: 1024 }, items: 5} }} responsive={
{
superLargeDesktop: {
breakpoint: { max: 4000, min: 3000 },
items: itemsToShow
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: itemsToShow
}
}
}
renderButtonGroupOutside={true} renderButtonGroupOutside={true}
ssr={true} // means to render carousel on server-side. ssr={true} // means to render carousel on server-side.
keyBoardControl={true} keyBoardControl={true}

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect, useState, useRef, useContext } from 'react' import React, { useEffect, useRef, useContext } from 'react'
import { ThemeContext, themes } from '../themeContext' import { ThemeContext} from '../themeContext'
import Carousel from 'react-multi-carousel' import Carousel from 'react-multi-carousel'
import WorkspaceTemplate from './workspaceTemplate' import WorkspaceTemplate from './workspaceTemplate'
import 'react-multi-carousel/lib/styles.css' import 'react-multi-carousel/lib/styles.css'
@ -11,13 +11,48 @@ declare global {
} }
} }
const _paq = window._paq = window._paq || [] //eslint-disable-line const _paq = window._paq = window._paq || [] //eslint-disable-line
interface HomeTabGetStartedProps { interface HomeTabGetStartedProps {
plugin: any plugin: any
} }
function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) { function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
const themeFilter = useContext(ThemeContext) const themeFilter = useContext(ThemeContext)
const carouselRef = useRef(null)
const carouselRefDiv = useRef(null)
useEffect(() => {
document.addEventListener("wheel", handleScroll)
return () => {
document.removeEventListener("wheel", handleScroll)
}
}, [])
function isDescendant(parent, child) {
let node = child.parentNode;
while (node != null) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
return false;
}
const handleScroll = (e) => {
if (isDescendant(carouselRefDiv.current, e.target)) {
e.stopPropagation()
let nextSlide = 0
if (e.wheelDelta < 0) {
nextSlide = carouselRef.current.state.currentSlide + 1;
if ((carouselRef.current.state.totalItems - carouselRef.current.state.currentSlide) * carouselRef.current.state.itemWidth + 5 < carouselRef.current.state.containerWidth) return // 5 is approx margins
carouselRef.current.goToSlide(nextSlide)
} else {
nextSlide = carouselRef.current.state.currentSlide - 1;
if (nextSlide < 0) nextSlide = 0
carouselRef.current.goToSlide(nextSlide)
}
}
}
const createWorkspace = async (templateName) => { const createWorkspace = async (templateName) => {
await plugin.appManager.activatePlugin('filePanel') await plugin.appManager.activatePlugin('filePanel')
@ -36,16 +71,31 @@ function HomeTabGetStarted ({plugin}: HomeTabGetStartedProps) {
</span> </span>
- Project Templates - Project Templates
</label> </label>
<div className="w-100 d-flex flex-column"> <div ref={carouselRefDiv} className="w-100 d-flex flex-column">
<ThemeContext.Provider value={ themeFilter }> <ThemeContext.Provider value={ themeFilter }>
<Carousel <Carousel
focusOnSelect ref={carouselRef}
customButtonGroup={<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />} focusOnSelect={true}
customButtonGroup={
<CustomNavButtons next={undefined} previous={undefined} goToSlide={undefined} />
}
arrows={false} arrows={false}
swipeable={false} swipeable={false}
draggable={true} draggable={true}
showDots={false} showDots={false}
responsive={{ desktop: { breakpoint: { max: 3000, min: 1024 }, items: 5} }} responsive={
{
superLargeDesktop: {
breakpoint: { max: 4000, min: 3000 },
items: 5
},
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 5,
partialVisibilityGutter: 0
}
}
}
renderButtonGroupOutside={true} renderButtonGroupOutside={true}
ssr={true} // means to render carousel on server-side. ssr={true} // means to render carousel on server-side.
keyBoardControl={true} keyBoardControl={true}

@ -50,20 +50,20 @@ function HomeTabLearn ({plugin}: HomeTabLearnProps) {
</div> </div>
<div className="d-flex flex-column"> <div className="d-flex flex-column">
<button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Basics }})}> <button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Basics }})}>
<label className="float-left" style={{fontSize: "1rem"}}>Remix Basics</label> <label className="m-0 float-left" style={{fontSize: "1rem"}}>Remix Basics</label>
{(state.visibleTutorial === VisibleTutorial.Basics) && <div className="pt-2 d-flex flex-column text-left"> {(state.visibleTutorial === VisibleTutorial.Basics) && <div className="pt-2 d-flex flex-column text-left">
<span>Introduction to Remix's interface and concepts used in Ethereum, as well as the basics of Solidity.</span> <span>Introduction to Remix's interface and concepts used in Ethereum, as well as the basics of Solidity.</span>
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('basics')}>Get Started</button> <button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('basics')}>Get Started</button>
</div>} </div>}
</button> </button>
<button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Intermediate }})}> <button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Intermediate }})}>
<label className="float-left" style={{fontSize: "1rem"}}>Remix Intermediate</label> <label className="m-0 float-left" style={{fontSize: "1rem"}}>Remix Intermediate</label>
{(state.visibleTutorial === VisibleTutorial.Intermediate) && <div className="pt-2 d-flex flex-column text-left">Using the web3.js to interact with a contract. Using Recorder tool. {(state.visibleTutorial === VisibleTutorial.Intermediate) && <div className="pt-2 d-flex flex-column text-left">Using the web3.js to interact with a contract. Using Recorder tool.
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('useofweb3js')}>Get Started</button> <button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('useofweb3js')}>Get Started</button>
</div>} </div>}
</button> </button>
<button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Advanced }})}> <button className="d-flex flex-column btn border" onClick={() => setState((prevState) => {return { ...prevState, visibleTutorial: VisibleTutorial.Advanced }})}>
<label className="float-left" style={{fontSize: "1rem"}}>Remix Advanced</label> <label className="m-0 float-left" style={{fontSize: "1rem"}}>Remix Advanced</label>
{(state.visibleTutorial === VisibleTutorial.Advanced) && <div className="pt-2 d-flex flex-column text-left">Learn the Proxy Pattern and working with Libraries in Remix. Learn to use the Debugger. {(state.visibleTutorial === VisibleTutorial.Advanced) && <div className="pt-2 d-flex flex-column text-left">Learn the Proxy Pattern and working with Libraries in Remix. Learn to use the Debugger.
<button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('deploylibraries')}>Get Started</button> <button className="btn btn-sm btn-secondary mt-2" style={{width: 'fit-content'}} onClick={() => startLearnEthTutorial('deploylibraries')}>Get Started</button>
</div>} </div>}

@ -23,7 +23,7 @@ function PluginButton ({ imgPath, envID, envText, callback, l2, description, rem
onClick={() => callback()} onClick={() => callback()}
> >
<img className="px-2 mb-2 align-self-center remixui_home_envLogo" id={envID} src={imgPath} alt="" style={ { filter: themeFilter.filter } } /> <img className="px-2 mb-2 align-self-center remixui_home_envLogo" id={envID} src={imgPath} alt="" style={ { filter: themeFilter.filter } } />
<div className="h-100 d-flex flex-column"> <div className="mb-2 h-100 d-flex flex-column">
<label className="text-uppercase text-dark remixui_home_cursorStyle">{envText}</label> <label className="text-uppercase text-dark remixui_home_cursorStyle">{envText}</label>
<div className="remixui_home_envLogoDescription">{description}</div> <div className="remixui_home_envLogoDescription">{description}</div>
</div> </div>

@ -16,7 +16,7 @@ function WorkspaceTemplate ({ gsID, workspaceTitle, description, callback }: Wor
data-id={'landingPageStart' + gsID} data-id={'landingPageStart' + gsID}
onClick={() => callback()} onClick={() => callback()}
> >
<div className="w-100 p-2 h-100 align-items-start d-flex flex-column"> <div className="mb-2 w-100 p-2 h-100 align-items-start d-flex flex-column">
<label className="h6 pb-1 text-uppercase text-dark remixui_home_cursorStyle">{workspaceTitle}</label> <label className="h6 pb-1 text-uppercase text-dark remixui_home_cursorStyle">{workspaceTitle}</label>
<div className="remixui_home_gtDescription">{description}</div> <div className="remixui_home_gtDescription">{description}</div>
</div> </div>

@ -1,11 +1,9 @@
.remixui_home_text { .remixui_home_text {
cursor: pointer;
font-size: 0.8rem; font-size: 0.8rem;
font-weight: normal; font-weight: normal;
max-width: 300px; max-width: 300px;
} }
.remixui_home_text:hover { .remixui_home_text:hover {
cursor: pointer;
text-decoration: underline; text-decoration: underline;
} }
.remixui_home_homeContainer { .remixui_home_homeContainer {

@ -4,6 +4,7 @@ import { FormattedMessage, useIntl } from 'react-intl'
import { CopyToClipboard } from '@remix-ui/clipboard' import { CopyToClipboard } from '@remix-ui/clipboard'
import { AccountProps } from '../types' import { AccountProps } from '../types'
import { PassphrasePrompt } from './passphrase' import { PassphrasePrompt } from './passphrase'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
export function AccountUI (props: AccountProps) { export function AccountUI (props: AccountProps) {
const { selectedAccount, loadedAccounts } = props.accounts const { selectedAccount, loadedAccounts } = props.accounts
@ -153,9 +154,15 @@ export function AccountUI (props: AccountProps) {
<div className="udapp_crow"> <div className="udapp_crow">
<label className="udapp_settingsLabel"> <label className="udapp_settingsLabel">
<FormattedMessage id='udapp.account' defaultMessage='Account' /> <FormattedMessage id='udapp.account' defaultMessage='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> <i id="remixRunPlus" className={`fas fa-plus-circle udapp_icon ${plusOpt.classList}`} aria-hidden="true" onClick={newAccount}></i>
</span> </span>
</OverlayTrigger>
</label> </label>
<div className="udapp_account"> <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) }}> <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) }}>
@ -164,7 +171,13 @@ export function AccountUI (props: AccountProps) {
} }
</select> </select>
<div style={{ marginLeft: -5 }}><CopyToClipboard tip='Copy account to clipboard' content={selectedAccount} direction='top' /></div> <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>
</div> </div>
) )

@ -3,10 +3,10 @@ import React, { useEffect, useRef, useState } from 'react'
import { FormattedMessage, useIntl } from 'react-intl' import { FormattedMessage, useIntl } from 'react-intl'
import { ContractDropdownProps, DeployMode } from '../types' import { ContractDropdownProps, DeployMode } from '../types'
import { ContractData, FuncABI } from '@remix-project/core-plugin' import { ContractData, FuncABI } from '@remix-project/core-plugin'
import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line
import * as ethJSUtil from 'ethereumjs-util' import * as ethJSUtil from 'ethereumjs-util'
import { ContractGUI } from './contractGUI' import { ContractGUI } from './contractGUI'
import { deployWithProxyMsg, upgradeWithProxyMsg } from '@remix-ui/helper' import { deployWithProxyMsg, upgradeWithProxyMsg } from '@remix-ui/helper'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
export function ContractDropdownUI (props: ContractDropdownProps) { export function ContractDropdownUI (props: ContractDropdownProps) {
@ -279,13 +279,25 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
: null} : null}
</div> </div>
<div className="udapp_subcontainer"> <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) => { {(contractList[currentFile] || []).map((contract, index) => {
return <option key={index} value={contract.alias}> return <option key={index} value={contract.alias}>
{contract.alias} - {contract.file} {contract.alias} - {contract.file}
</option> </option>
})} })}
</select> </select>
</OverlayTrigger>
<span className="py-1" style={{ display: abiLabel.display }}>{abiLabel.content}</span> <span className="py-1" style={{ display: abiLabel.display }}>{abiLabel.content}</span>
</div> </div>
<div> <div>
@ -314,14 +326,19 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
onChange={handleCheckedIPFS} onChange={handleCheckedIPFS}
checked={props.ipfsCheckedState} 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 <label
htmlFor="deployAndRunPublishToIPFS" htmlFor="deployAndRunPublishToIPFS"
data-id="contractDropdownIpfsCheckboxLabel" data-id="contractDropdownIpfsCheckboxLabel"
className="m-0 form-check-label custom-control-label udapp_checkboxAlign" 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...)"
> >
<FormattedMessage id='udapp.publishTo' defaultMessage='Publish to' /> IPFS <FormattedMessage id='udapp.publishTo' defaultMessage='Publish to' /> IPFS
</label> </label>
</OverlayTrigger>
</div> </div>
</div> : '' </div> : ''
} }
@ -330,16 +347,29 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
<FormattedMessage id='udapp.or' defaultMessage='or' /> <FormattedMessage id='udapp.or' defaultMessage='or' />
</div> </div>
<div className="udapp_button udapp_atAddressSect "> <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}> <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}>
<FormattedMessage id='udapp.atAddress' defaultMessage='At Address' /> <FormattedMessage id='udapp.atAddress' defaultMessage='At Address' />
</button> </button>
</div>
</OverlayTrigger>
<OverlayTrigger placement={'top-end'} overlay={
<Tooltip className="text-wrap" id="runAndDeployAddressInputtooltip">
<span>{"address of contract"}</span>
</Tooltip>
}>
<input <input
ref={atAddressValue} ref={atAddressValue}
className="udapp_input udapp_ataddressinput ataddressinput form-control" className="udapp_input udapp_ataddressinput ataddressinput form-control"
placeholder={intl.formatMessage({id: 'udapp.loadContractFromAddress', defaultMessage: "Load contract from Address"})} placeholder={intl.formatMessage({id: 'udapp.loadContractFromAddress', defaultMessage: "Load contract from Address"})}
title="address of contract"
onChange={atAddressChanged} onChange={atAddressChanged}
/> />
</OverlayTrigger>
</div> </div>
</div> </div>
</div> </div>

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

@ -1,7 +1,7 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
import { DeployButtonProps } from '../types' import { DeployButtonProps } from '../types'
import { ButtonGroup, Dropdown } from 'react-bootstrap' import { ButtonGroup, Dropdown, OverlayTrigger, Tooltip } from 'react-bootstrap'
export function DeployButton (props: DeployButtonProps) { export function DeployButton (props: DeployButtonProps) {
const [showOptions, setShowOptions] = useState<boolean>(false) const [showOptions, setShowOptions] = useState<boolean>(false)
@ -25,9 +25,18 @@ export function DeployButton (props: DeployButtonProps) {
} }
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> : </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}>
<FormattedMessage id='udapp.deploy' defaultMessage='Deploy' /> <FormattedMessage id='udapp.deploy' defaultMessage='Deploy' />
</button> </button>
</OverlayTrigger>
} }
</> </>
) )

@ -1,4 +1,5 @@
import React from 'react' import React from 'react'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { DeployInputProps } from '../types' import { DeployInputProps } from '../types'
import { DeployButton } from './deployButton' import { DeployButton } from './deployButton'
@ -6,6 +7,14 @@ export function DeployInput (props: DeployInputProps) {
return ( return (
<div className="udapp_contractActionsContainerSingle pt-2" style={{ display: 'flex' }}> <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} /> <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 <input
className="form-control" 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'}
@ -15,6 +24,7 @@ export function DeployInput (props: DeployInputProps) {
ref={props.basicInputRef} ref={props.basicInputRef}
style={{ visibility: !props.inputs ? 'hidden' : 'visible' }} style={{ visibility: !props.inputs ? 'hidden' : 'visible' }}
/> />
</OverlayTrigger>
</div> </div>
) )
} }

@ -1,12 +1,13 @@
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
import React from 'react' import React from 'react'
import { FormattedMessage, useIntl } from 'react-intl' import { FormattedMessage } from 'react-intl'
import { EnvironmentProps } from '../types' import { EnvironmentProps } from '../types'
import { Dropdown } from 'react-bootstrap' import { Dropdown } from 'react-bootstrap'
import { CustomMenu, CustomToggle } from '@remix-ui/helper' import { CustomMenu, CustomToggle } from '@remix-ui/helper'
import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line
export function EnvironmentUI (props: EnvironmentProps) { export function EnvironmentUI (props: EnvironmentProps) {
const handleChangeExEnv = (env: string) => { const handleChangeExEnv = (env: string) => {
const provider = props.providers.providerList.find(exEnv => exEnv.value === env) const provider = props.providers.providerList.find(exEnv => exEnv.value === env)
const fork = provider.fork // can be undefined if connected to an external source (External Http Provider / injected) const fork = provider.fork // can be undefined if connected to an external source (External Http Provider / injected)
@ -17,8 +18,6 @@ export function EnvironmentUI (props: EnvironmentProps) {
props.setExecutionContext({ context, fork }) props.setExecutionContext({ context, fork })
} }
const intl = useIntl()
const currentProvider = props.providers.providerList.find(exEnv => exEnv.value === props.selectedEnv) const currentProvider = props.providers.providerList.find(exEnv => exEnv.value === props.selectedEnv)
const bridges = { const bridges = {
'Optimism Provider': 'https://www.optimism.io/apps/bridges', 'Optimism Provider': 'https://www.optimism.io/apps/bridges',
@ -68,12 +67,13 @@ export function EnvironmentUI (props: EnvironmentProps) {
} }
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#environment" target="_blank" rel="noreferrer"> <OverlayTrigger placement={'bottom-start'} overlay={
<i <Tooltip className="text-wrap" id="runAndDeployAddresstooltip">
className="udapp_infoDeployAction ml-2 fas fa-info" <span><FormattedMessage id='udapp.environmentDocs' defaultMessage='Click for docs about Environment' /></span>
title={intl.formatMessage({id: 'udapp.environmentDocs', defaultMessage: "Click for docs about Environment"})} </Tooltip>
></i> }>
</a> <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>
</div> </div>
) )

@ -1,6 +1,7 @@
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
import React from 'react' import React from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { GasPriceProps } from '../types' import { GasPriceProps } from '../types'
export function GasPriceUI (props: GasPriceProps) { export function GasPriceUI (props: GasPriceProps) {
@ -11,7 +12,13 @@ export function GasPriceUI (props: GasPriceProps) {
return ( return (
<div className="udapp_crow"> <div className="udapp_crow">
<label className="udapp_settingsLabel"><FormattedMessage id='udapp.gasLimit' defaultMessage='Gas limit' /></label> <label className="udapp_settingsLabel"><FormattedMessage id='udapp.gasLimit' defaultMessage='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> </div>
) )
} }

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

@ -1,4 +1,5 @@
import React, { useRef, useState } from 'react' import React, { useRef, useState } from 'react'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import { MultiDeployInputProps } from '../types' import { MultiDeployInputProps } from '../types'
import { DeployButton } from './deployButton' import { DeployButton } from './deployButton'
@ -16,7 +17,16 @@ export function MultiDeployInput(props: MultiDeployInputProps) {
return ( return (
<div className="udapp_multiArg" key={index}> <div className="udapp_multiArg" key={index}>
<label htmlFor={inp.name}> {inp.name}: </label> <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>)
})} })}
</div> </div>

@ -34,7 +34,13 @@ export function RecorderUI (props: RecorderProps) {
<label className="mt-1 udapp_recorderSectionLabel"> <label className="mt-1 udapp_recorderSectionLabel">
<FormattedMessage id='udapp.transactionsRecorded' defaultMessage='Transactions recorded' /> <FormattedMessage id='udapp.transactionsRecorded' defaultMessage='Transactions recorded' />
</label> </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={ <OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="info-recorder"> <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. <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.
@ -62,19 +68,33 @@ export function RecorderUI (props: RecorderProps) {
</OverlayTrigger> </OverlayTrigger>
</div> </div>
<div className="mb-1 mt-1 udapp_transactionActions"> <div className="mb-1 mt-1 udapp_transactionActions">
<OverlayTrigger placement={'right'} overlay={ <OverlayTrigger placement={'bottom-start'} overlay={
<Tooltip className="text-nowrap" id="tooltip-save-recorder"> <Tooltip className="text-nowrap" id="remixUdappTransactionSavetooltip">
<span>Save {props.count} transaction{props.count === 1 ? '' : 's'} as scenario file</span> <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> </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>
<OverlayTrigger placement={'right'} overlay={ <OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="tooltip-run-recorder"> <Tooltip className="text-nowrap" id="tooltip-run-recorder">
<span>Run transaction(s) from the current scenario file</span> <span>Run transaction(s) from the current scenario file</span>
</Tooltip> </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> </OverlayTrigger>
</div> </div>
</div> </div>

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

@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl'
import { BN } from 'ethereumjs-util' import { BN } from 'ethereumjs-util'
import { isNumeric } from '@remix-ui/helper' import { isNumeric } from '@remix-ui/helper'
import { ValueProps } from '../types' import { ValueProps } from '../types'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
export function ValueUI (props: ValueProps) { export function ValueUI (props: ValueProps) {
const [sendValue, setSendValue] = useState<string>(props.sendValue) const [sendValue, setSendValue] = useState<string>(props.sendValue)
@ -50,6 +51,11 @@ export function ValueUI (props: ValueProps) {
<div className="udapp_crow"> <div className="udapp_crow">
<label className="udapp_settingsLabel" data-id="remixDRValueLabel"><FormattedMessage id='udapp.value' defaultMessage='Value' /></label> <label className="udapp_settingsLabel" data-id="remixDRValueLabel"><FormattedMessage id='udapp.value' defaultMessage='Value' /></label>
<div className="udapp_gasValueContainer"> <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 <input
ref={inputValue} ref={inputValue}
type="number" type="number"
@ -59,11 +65,11 @@ export function ValueUI (props: ValueProps) {
className="form-control udapp_gasNval udapp_col2" className="form-control udapp_gasNval udapp_col2"
id="value" id="value"
data-id="dandrValue" data-id="dandrValue"
title="Enter an amount and choose its unit"
onKeyPress={validateInputKey} onKeyPress={validateInputKey}
onChange={validateValue} onChange={validateValue}
value={props.sendValue} 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') }}> <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="wei" value='wei'>Wei</option>
<option data-unit="gwei" value="gwei">Gwei</option> <option data-unit="gwei" value="gwei">Gwei</option>

Loading…
Cancel
Save