Merge pull request #2547 from ethereum/use_http_or_https

Add validationFn to the prompt modal to validate the input
pull/5370/head
yann300 2 years ago committed by GitHub
commit e1b57a5b6f
  1. 8
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  2. 6
      apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts
  3. 8
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  4. 3
      apps/remix-ide-e2e/src/tests/providers.test.ts
  5. 4
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  6. 12
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  7. 3
      apps/remix-ide/src/app.js
  8. 14
      apps/remix-ide/src/app/tabs/abstract-provider.tsx
  9. 41
      apps/remix-ide/src/app/tabs/external-http-provider.tsx
  10. 14
      apps/remix-ide/src/app/udapp/run-tab.js
  11. 3
      apps/remix-ide/src/blockchain/execution-context.js
  12. 2
      apps/remix-ide/src/remixAppManager.js
  13. 33
      libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx
  14. 4
      libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
  15. 6
      libs/remix-ui/app/src/lib/remix-app/interface/index.ts
  16. 1
      libs/remix-ui/app/src/lib/remix-app/reducer/modals.ts
  17. 1
      libs/remix-ui/app/src/lib/remix-app/state/modals.ts
  18. 5
      libs/remix-ui/helper/src/lib/helper-components.tsx
  19. 10
      libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx
  20. 7
      libs/remix-ui/modal-dialog/src/lib/types/index.ts
  21. 25
      libs/remix-ui/run-tab/src/lib/actions/account.ts
  22. 2
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  23. 6
      libs/remix-ui/run-tab/src/lib/reducers/runTab.ts

@ -83,10 +83,10 @@ module.exports = {
browser browser
.openFile('Untitled.sol') .openFile('Untitled.sol')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsSelectEnvOptions"] *[data-id="External Http Provider"]')
.waitForElementPresent('[data-id="envNotification-modal-footer-ok-react"]') .waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]')
.execute(function () { .execute(function () {
const modal = document.querySelector('[data-id="envNotification-modal-footer-ok-react"]') as any const modal = document.querySelector('[data-id="basic-http-provider-modal-footer-ok-react"]') as any
modal.click() modal.click()
}) })
@ -96,7 +96,7 @@ module.exports = {
return env.value return env.value
}, [], function (result) { }, [], function (result) {
browser.assert.ok(result.value === 'web3', 'Web3 Provider not selected') browser.assert.ok(result.value === 'External Http Provider', 'Web3 Provider not selected')
}) })
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')

@ -78,10 +78,10 @@ module.exports = {
browser browser
.openFile('Untitled.sol') .openFile('Untitled.sol')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsSelectEnvOptions"] *[data-id="External Http Provider"]')
.waitForElementPresent('[data-id="envNotification-modal-footer-ok-react"]') .waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]')
.execute(function () { .execute(function () {
const modal = document.querySelector('[data-id="envNotification-modal-footer-ok-react"]') as any const modal = document.querySelector('[data-id="basic-http-provider-modal-footer-ok-react"]') as any
modal.click() modal.click()
}) })

@ -214,10 +214,10 @@ module.exports = {
.setSolidityCompilerVersion('soljson-v0.8.7+commit.e28d00a7.js') .setSolidityCompilerVersion('soljson-v0.8.7+commit.e28d00a7.js')
.addFile('useDebugNodes.sol', sources[5]['useDebugNodes.sol']) // compile contract .addFile('useDebugNodes.sol', sources[5]['useDebugNodes.sol']) // compile contract
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') // select web3 provider with debug nodes URL .click('*[data-id="settingsSelectEnvOptions"] *[data-id="External Http Provider"]') // select web3 provider with debug nodes URL
.clearValue('*[data-id="modalDialogCustomPromptText"]') .clearValue('*[data-id="modalDialogCustomPromp"]')
.setValue('*[data-id="modalDialogCustomPromptText"]', 'https://remix-rinkeby.ethdevops.io') .setValue('*[data-id="modalDialogCustomPromp"]', 'https://remix-rinkeby.ethdevops.io')
.modalFooterOKClick() .modalFooterOKClick('basic-http-provider')
.waitForElementPresent('*[title="Deploy - transact (not payable)"]', 65000) // wait for the compilation to succeed .waitForElementPresent('*[title="Deploy - transact (not payable)"]', 65000) // wait for the compilation to succeed
.clickLaunchIcon('debugger') .clickLaunchIcon('debugger')
.clearValue('*[data-id="debuggerTransactionInput"]') .clearValue('*[data-id="debuggerTransactionInput"]')

@ -44,9 +44,6 @@ module.exports = {
.waitForElementContainsText('*[data-id="foundry-providerModalDialogModalBody-react"]', 'Error while connecting to the provider') .waitForElementContainsText('*[data-id="foundry-providerModalDialogModalBody-react"]', 'Error while connecting to the provider')
.modalFooterOKClick('foundry-provider') .modalFooterOKClick('foundry-provider')
.waitForElementNotVisible('*[data-id="foundry-providerModalDialogModalBody-react"]') .waitForElementNotVisible('*[data-id="foundry-providerModalDialogModalBody-react"]')
.waitForElementVisible('*[data-id="PermissionHandler-modal-footer-ok-react"]')
.click('*[data-id="PermissionHandler-modal-footer-ok-react"]')
.waitForElementNotVisible('*[data-id="PermissionHandler-modal-footer-ok-react"]')
.pause(1000) .pause(1000)
}, },

@ -50,8 +50,8 @@ module.exports = {
browser browser
.click('*[data-id="terminalClearConsole"]') // clear the terminal .click('*[data-id="terminalClearConsole"]') // clear the terminal
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="settingsWeb3Mode"]') .click('*[data-id="settingsSelectEnvOptions"] *[data-id="External Http Provider"]')
.modalFooterOKClick('envNotification') .modalFooterOKClick('basic-http-provider')
.executeScript('web3.eth.getAccounts()') .executeScript('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '["', 60000) // we check if an array is present, don't need to check for the content .waitForElementContainsText('*[data-id="terminalJournal"]', '["', 60000) // we check if an array is present, don't need to check for the content
.waitForElementContainsText('*[data-id="terminalJournal"]', '"]', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', '"]', 60000)

@ -38,7 +38,7 @@ module.exports = {
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
.click('*[data-id="workspaceCreate"]') .click('*[data-id="workspaceCreate"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > span') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_remix_default' }) .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_remix_default' })
.waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
@ -94,7 +94,7 @@ module.exports = {
browser browser
.click('*[data-id="workspaceCreate"]') .click('*[data-id="workspaceCreate"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > span') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_blank' }) .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_blank' })
.click('select[id="wstemplate"]') .click('select[id="wstemplate"]')
@ -115,7 +115,7 @@ module.exports = {
browser browser
.click('*[data-id="workspaceCreate"]') .click('*[data-id="workspaceCreate"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > span') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc20' }) .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc20' })
.click('select[id="wstemplate"]') .click('select[id="wstemplate"]')
@ -163,7 +163,7 @@ module.exports = {
browser browser
.click('*[data-id="workspaceCreate"]') .click('*[data-id="workspaceCreate"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > span') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation
.execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc721' }) .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc721' })
.click('select[id="wstemplate"]') .click('select[id="wstemplate"]')
@ -213,7 +213,7 @@ module.exports = {
browser browser
.click('*[data-id="workspaceCreate"]') // create workspace_name .click('*[data-id="workspaceCreate"]') // create workspace_name
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > span') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
.click('*[data-id="modalDialogCustomPromptTextCreate"]') .click('*[data-id="modalDialogCustomPromptTextCreate"]')
.clearValue('*[data-id="modalDialogCustomPromptTextCreate"]') .clearValue('*[data-id="modalDialogCustomPromptTextCreate"]')
.setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name') .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name')
@ -225,7 +225,7 @@ module.exports = {
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
.click('*[data-id="workspaceCreate"]') // create workspace_name_1 .click('*[data-id="workspaceCreate"]') // create workspace_name_1
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]') .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
.waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > span') .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
.click('*[data-id="modalDialogCustomPromptTextCreate"]') .click('*[data-id="modalDialogCustomPromptTextCreate"]')
.clearValue('*[data-id="modalDialogCustomPromptTextCreate"]') .clearValue('*[data-id="modalDialogCustomPromptTextCreate"]')
.setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name_1') .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name_1')

@ -28,6 +28,7 @@ import { Blockchain } from './blockchain/blockchain.js'
import { HardhatProvider } from './app/tabs/hardhat-provider' import { HardhatProvider } from './app/tabs/hardhat-provider'
import { GanacheProvider } from './app/tabs/ganache-provider' import { GanacheProvider } from './app/tabs/ganache-provider'
import { FoundryProvider } from './app/tabs/foundry-provider' import { FoundryProvider } from './app/tabs/foundry-provider'
import { ExternalHttpProvider } from './app/tabs/external-http-provider'
const isElectron = require('is-electron') const isElectron = require('is-electron')
@ -179,6 +180,7 @@ class AppComponent {
const hardhatProvider = new HardhatProvider(blockchain) const hardhatProvider = new HardhatProvider(blockchain)
const ganacheProvider = new GanacheProvider(blockchain) const ganacheProvider = new GanacheProvider(blockchain)
const foundryProvider = new FoundryProvider(blockchain) const foundryProvider = new FoundryProvider(blockchain)
const externalHttpProvider = new ExternalHttpProvider(blockchain)
// ----------------- convert offset to line/column service ----------- // ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter() const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
Registry.getInstance().put({ Registry.getInstance().put({
@ -236,6 +238,7 @@ class AppComponent {
hardhatProvider, hardhatProvider,
ganacheProvider, ganacheProvider,
foundryProvider, foundryProvider,
externalHttpProvider,
this.walkthroughService, this.walkthroughService,
search search
]) ])

@ -58,6 +58,20 @@ export abstract class AbstractProvider extends Plugin {
modalType: ModalTypes.prompt, modalType: ModalTypes.prompt,
okLabel: 'OK', okLabel: 'OK',
cancelLabel: 'Cancel', cancelLabel: 'Cancel',
validationFn: (value) => {
if (!value) return { valid: false, message: "value is empty" }
if (value.startsWith('https://') || value.startsWith('http://')) {
return {
valid: true,
message: ''
}
} else {
return {
valid: false,
message: 'the provided value should contain the protocol ( e.g starts with http:// or https:// )'
}
}
},
okFn: (value: string) => { okFn: (value: string) => {
setTimeout(() => resolve(value), 0) setTimeout(() => resolve(value), 0)
}, },

@ -0,0 +1,41 @@
import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line
import { AbstractProvider } from './abstract-provider'
const profile = {
name: 'basic-http-provider',
displayName: 'External Http Provider',
kind: 'provider',
description: '',
methods: ['sendAsync'],
version: packageJson.version
}
export class ExternalHttpProvider extends AbstractProvider {
constructor (blockchain) {
super(profile, blockchain, 'http://127.0.0.1:8545')
}
body (): JSX.Element {
const thePath = '<path/to/local/folder/for/test/chain>'
return (
<>
<div className="">
Note: To use Geth & https://remix.ethereum.org, configure it to allow requests from Remix:(see <a href="https://geth.ethereum.org/docs/rpc/server" target="_blank" rel="noreferrer">Geth Docs on rpc server</a>)
<div className="border p-1">geth --http --http.corsdomain https://remix.ethereum.org</div>
<br />
To run Remix & a local Geth test node, use this command: (see <a href="https://geth.ethereum.org/getting-started/dev-mode" target="_blank" rel="noreferrer">Geth Docs on Dev mode</a>)
<div className="border p-1">geth --http --http.corsdomain="{window.origin}" --http.api web3,eth,debug,personal,net --vmdebug --datadir {thePath} --dev console</div>
<br />
<br />
<b>WARNING:</b> It is not safe to use the --http.corsdomain flag with a wildcard: <b>--http.corsdomain *</b>
<br />
<br />For more info: <a href="https://remix-ide.readthedocs.io/en/latest/run.html#more-about-web3-provider" target="_blank" rel="noreferrer">Remix Docs on Web3 Provider</a>
<br />
<br />
External HTTP Provider Endpoint
</div>
</>
)
}
}

@ -155,6 +155,20 @@ export class RunTab extends ViewPlugin {
} }
} }
}) })
await this.call('blockchain', 'addProvider', {
name: 'External Http Provider',
provider: {
async sendAsync (payload, callback) {
try {
const result = await udapp.call('basic-http-provider', 'sendAsync', payload)
callback(null, result)
} catch (e) {
callback(e)
}
}
}
})
} }
writeFile (fileName, content) { writeFile (fileName, content) {

@ -164,9 +164,6 @@ export class ExecutionContext {
} }
} }
if (context === 'web3') {
confirmCb(cb)
}
if (this.customNetWorks[context]) { if (this.customNetWorks[context]) {
var network = this.customNetWorks[context] var network = this.customNetWorks[context]
this.setProviderFromEndpoint(network.provider, { context: network.name }, (error) => { this.setProviderFromEndpoint(network.provider, { context: network.name }, (error) => {

@ -19,7 +19,7 @@ const sensitiveCalls = {
} }
export function isNative(name) { export function isNative(name) {
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider'] const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider']
return nativePlugins.includes(name) || requiredModules.includes(name) return nativePlugins.includes(name) || requiredModules.includes(name)
} }

@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from 'react' import React, { useEffect, useRef, useState } from 'react'
import { ModalDialog, ModalDialogProps } from '@remix-ui/modal-dialog' import { ModalDialog, ModalDialogProps, ValidationResult } from '@remix-ui/modal-dialog'
import { ModalTypes } from '../../types' import { ModalTypes } from '../../types'
interface ModalWrapperProps extends ModalDialogProps { interface ModalWrapperProps extends ModalDialogProps {
@ -29,12 +29,23 @@ const ModalWrapper = (props: ModalWrapperProps) => {
(props.cancelFn) ? props.cancelFn() : props.resolve(false) (props.cancelFn) ? props.cancelFn() : props.resolve(false)
} }
const createModalMessage = (defaultValue: string) => { const onInputChanged = (event) => {
if (props.validationFn) {
const validation = props.validationFn(event.target.value)
setState(prevState => {
return { ...prevState, message: createModalMessage(props.defaultValue, validation), validation }
})
}
}
const createModalMessage = (defaultValue: string, validation: ValidationResult) => {
return ( return (
<> <>
{props.message} {props.message}
<input type={props.modalType === ModalTypes.password ? 'password' : 'text'} defaultValue={defaultValue} data-id="modalDialogCustomPromp" ref={ref} className="form-control" /></> <input onChange={onInputChanged} type={props.modalType === ModalTypes.password ? 'password' : 'text'} defaultValue={defaultValue} data-id="modalDialogCustomPromp" ref={ref} className="form-control" />
) {!validation.valid && <span className='text-warning'>{validation.message}</span>}
</>
)
} }
useEffect(() => { useEffect(() => {
@ -47,13 +58,13 @@ const ModalWrapper = (props: ModalWrapperProps) => {
...props, ...props,
okFn: onFinishPrompt, okFn: onFinishPrompt,
cancelFn: onCancelFn, cancelFn: onCancelFn,
message: createModalMessage(props.defaultValue) message: createModalMessage(props.defaultValue, { valid: true })
}) })
break break
default: default:
setState({ setState({
...props, ...props,
okFn: (onOkFn), okFn: onOkFn,
cancelFn: onCancelFn cancelFn: onCancelFn
}) })
break break
@ -67,8 +78,16 @@ const ModalWrapper = (props: ModalWrapperProps) => {
} }
}, [props]) }, [props])
// reset the message and input if any, so when the modal is shown again it doesn't show the previous value.
const handleHide = () => {
setState(prevState => {
return { ...prevState, message: '' }
})
props.handleHide()
}
return ( return (
<ModalDialog id={props.id} {...state} handleHide={props.handleHide} /> <ModalDialog id={props.id} {...state} handleHide={handleHide} />
) )
} }
export default ModalWrapper export default ModalWrapper

@ -16,11 +16,11 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt
} }
const modal = (modalData: AppModal) => { const modal = (modalData: AppModal) => {
const { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue, hideFn, data } = modalData const { id, title, message, validationFn, okLabel, okFn, cancelLabel, cancelFn, modalType, defaultValue, hideFn, data } = modalData
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
dispatch({ dispatch({
type: modalActionTypes.setModal, type: modalActionTypes.setModal,
payload: { id, title, message, okLabel, okFn, cancelLabel, cancelFn, modalType: modalType || ModalTypes.default, defaultValue: defaultValue, hideFn, resolve, next: onNextFn, data } payload: { id, title, message, okLabel, validationFn, okFn, cancelLabel, cancelFn, modalType: modalType || ModalTypes.default, defaultValue: defaultValue, hideFn, resolve, next: onNextFn, data }
}) })
}) })
} }

@ -1,10 +1,16 @@
import { ModalTypes } from '../types' import { ModalTypes } from '../types'
export type ValidationResult = {
valid: boolean,
message?: string
}
export interface AppModal { export interface AppModal {
id: string id: string
timestamp?: number timestamp?: number
hide?: boolean hide?: boolean
title: string title: string
validationFn?: (value: string) => ValidationResult
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
message: string | JSX.Element message: string | JSX.Element
okLabel: string okLabel: string

@ -11,6 +11,7 @@ export const modalReducer = (state: ModalState = ModalInitialState, action: Moda
id: action.payload.id || timestamp.toString(), id: action.payload.id || timestamp.toString(),
hide: false, hide: false,
title: action.payload.title, title: action.payload.title,
validationFn: action.payload.validationFn,
message: action.payload.message, message: action.payload.message,
okLabel: action.payload.okLabel, okLabel: action.payload.okLabel,
okFn: action.payload.okFn, okFn: action.payload.okFn,

@ -8,6 +8,7 @@ export const ModalInitialState: ModalState = {
hide: true, hide: true,
title: '', title: '',
message: '', message: '',
validationFn: () => { return {valid: true, message: ''} },
okLabel: '', okLabel: '',
okFn: () => { }, okFn: () => { },
cancelLabel: '', cancelLabel: '',

@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import { Web3ProviderDialog } from './components/web3Dialog'
export const fileChangedToastMsg = (from: string, path: string) => ( export const fileChangedToastMsg = (from: string, path: string) => (
<div><i className="fas fa-exclamation-triangle text-danger mr-1"></i> <div><i className="fas fa-exclamation-triangle text-danger mr-1"></i>
@ -54,10 +53,6 @@ export const sourceVerificationNotAvailableToastMsg = () => (
</div> </div>
) )
export const web3Dialog = (externalEndpoint: string, setWeb3Endpoint: (value: string) => void) => (
<Web3ProviderDialog externalEndpoint={externalEndpoint} setWeb3Endpoint={setWeb3Endpoint} />
)
export const envChangeNotification = (env: { context: string, fork: string }, from: string) => ( export const envChangeNotification = (env: { context: string, fork: string }, from: string) => (
<div> <div>
<i className="fas fa-exclamation-triangle text-danger mr-1"></i> <i className="fas fa-exclamation-triangle text-danger mr-1"></i>

@ -96,18 +96,20 @@ export const ModalDialog = (props: ModalDialogProps) => {
</div> </div>
<div className="modal-footer" data-id={`${props.id}ModalDialogModalFooter-react`}> <div className="modal-footer" data-id={`${props.id}ModalDialogModalFooter-react`}>
{/* todo add autofocus ^^ */} {/* todo add autofocus ^^ */}
{ props.okLabel && <span { props.okLabel && <button
data-id={`${props.id}-modal-footer-ok-react`} data-id={`${props.id}-modal-footer-ok-react`}
className={'modal-ok btn btn-sm ' + (state.toggleBtn ? 'btn-dark' : 'btn-light')} className={'modal-ok btn btn-sm ' + (state.toggleBtn ? 'btn-dark' : 'btn-light')}
disabled={props.validation && !props.validation.valid}
onClick={() => { onClick={() => {
if (props.validation && !props.validation.valid) return
if (props.okFn) props.okFn() if (props.okFn) props.okFn()
handleHide() handleHide()
}} }}
> >
{props.okLabel ? props.okLabel : 'OK'} {props.okLabel ? props.okLabel : 'OK'}
</span> </button>
} }
{ props.cancelLabel && <span { props.cancelLabel && <button
data-id={`${props.id}-modal-footer-cancel-react`} data-id={`${props.id}-modal-footer-cancel-react`}
className={'modal-cancel btn btn-sm ' + (state.toggleBtn ? 'btn-light' : 'btn-dark')} className={'modal-cancel btn btn-sm ' + (state.toggleBtn ? 'btn-light' : 'btn-dark')}
data-dismiss="modal" data-dismiss="modal"
@ -117,7 +119,7 @@ export const ModalDialog = (props: ModalDialogProps) => {
}} }}
> >
{props.cancelLabel ? props.cancelLabel : 'Cancel'} {props.cancelLabel ? props.cancelLabel : 'Cancel'}
</span> </button>
} }
</div> </div>
</div> </div>

@ -1,8 +1,15 @@
export type ValidationResult = {
valid: boolean,
message?: string
}
/* eslint-disable no-undef */ /* eslint-disable no-undef */
export interface ModalDialogProps { export interface ModalDialogProps {
id: string id: string
timestamp?: number, timestamp?: number,
title?: string, title?: string,
validation?: ValidationResult
validationFn?: (value: string) => ValidationResult
message?: string | JSX.Element, message?: string | JSX.Element,
okLabel?: string, okLabel?: string,
okFn?: (value?:any) => void, okFn?: (value?:any) => void,

@ -1,4 +1,4 @@
import { shortenAddress, web3Dialog } from "@remix-ui/helper" import { shortenAddress } from "@remix-ui/helper"
import { RunTab } from "../types/run-tab" import { RunTab } from "../types/run-tab"
import { clearInstances, setAccount, setExecEnv } from "./actions" import { clearInstances, setAccount, setExecEnv } from "./actions"
import { displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, setExternalEndpoint, setMatchPassphrase, setPassphrase } from "./payload" import { displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, setExternalEndpoint, setMatchPassphrase, setPassphrase } from "./payload"
@ -74,28 +74,7 @@ const _getProviderDropdownValue = (plugin: RunTab): string => {
} }
export const setExecutionContext = (plugin: RunTab, dispatch: React.Dispatch<any>, executionContext: { context: string, fork: string }) => { export const setExecutionContext = (plugin: RunTab, dispatch: React.Dispatch<any>, executionContext: { context: string, fork: string }) => {
const displayContent = web3Dialog(plugin.REACT_API.externalEndpoint, (endpoint: string) => { plugin.blockchain.changeExecutionContext(executionContext, null, (alertMsg) => {
dispatch(setExternalEndpoint(endpoint))
})
plugin.blockchain.changeExecutionContext(executionContext, () => {
plugin.call('notification', 'modal', {
id: 'envNotification',
title: 'External node request',
message: displayContent,
okLabel: 'OK',
cancelLabel: 'Cancel',
okFn: () => {
plugin.blockchain.setProviderFromEndpoint(plugin.REACT_API.externalEndpoint, executionContext, (alertMsg) => {
if (alertMsg) plugin.call('notification', 'toast', alertMsg)
setFinalContext(plugin, dispatch)
})
},
cancelFn: () => {
setFinalContext(plugin, dispatch)
}
})
}, (alertMsg) => {
plugin.call('notification', 'toast', alertMsg) plugin.call('notification', 'toast', alertMsg)
}, () => { setFinalContext(plugin, dispatch) }) }, () => { setFinalContext(plugin, dispatch) })
} }

@ -8,7 +8,7 @@ export function EnvironmentUI (props: EnvironmentProps) {
const fork = provider.fork // can be undefined if connected to an external source (web3 provider / injected) const fork = provider.fork // can be undefined if connected to an external source (web3 provider / injected)
let context = provider.value let context = provider.value
context = context.startsWith('vm') ? 'vm' : context // context has to be 'vm', 'web3' or 'injected' context = context.startsWith('vm') ? 'vm' : context
props.setExecutionContext({ context, fork }) props.setExecutionContext({ context, fork })
} }

@ -135,12 +135,6 @@ export const runTabInitialState: RunTabState = {
title: 'Execution environment has been provided by Metamask or similar provider.', title: 'Execution environment has been provided by Metamask or similar provider.',
value: 'injected', value: 'injected',
content: `Injected Provider${(window && window.ethereum && window.ethereum.isMetaMask) ? ' - Metamask' : ''}` content: `Injected Provider${(window && window.ethereum && window.ethereum.isMetaMask) ? ' - Metamask' : ''}`
}, {
id: 'web3-mode',
dataId: 'settingsWeb3Mode',
title: `Execution environment connects to an external node. For security, only connect to trusted networks. If Remix is served via https and your node is accessed via http, it might not work. In this case, try cloning the repository and serving it via http.`,
value: 'web3',
content: 'External HTTP Provider'
}], }],
isRequesting: false, isRequesting: false,
isSuccessful: false, isSuccessful: false,

Loading…
Cancel
Save