universal udapp UI

yann300-patch-36
David Disu 3 years ago committed by yann300
parent 7ac5ebaa7a
commit b5d1060185
  1. 28
      apps/remix-ide/src/app/udapp/run-tab.js
  2. 58
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  3. 22
      libs/remix-ui/run-tab/src/lib/actions/payload.ts
  4. 157
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  5. 23
      libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx
  6. 190
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  7. 52
      libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
  8. 4
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  9. 18
      libs/remix-ui/run-tab/src/lib/types/index.ts

@ -108,33 +108,6 @@ export class RunTab extends ViewPlugin {
return this.blockchain.pendingTransactionsCount()
}
renderInstanceContainer () {
this.instanceContainer = yo`<div class="${css.instanceContainer} border-0 list-group-item"></div>`
const instanceContainerTitle = yo`
<div class="d-flex justify-content-between align-items-center pl-2 ml-1 mb-2"
title="Autogenerated generic user interfaces for interaction with deployed contracts">
Deployed Contracts
<i class="mr-2 ${css.icon} far fa-trash-alt" data-id="deployAndRunClearInstances" onclick=${() => this.event.trigger('clearInstance', [])}
title="Clear instances list and reset recorder" aria-hidden="true">
</i>
</div>`
this.noInstancesText = yo`
<span class="mx-2 mt-3 alert alert-warning" data-id="deployAndRunNoInstanceText" role="alert">
Currently you have no contract instances to interact with.
</span>`
this.event.register('clearInstance', () => { // setFinalContext calls this
this.instanceContainer.innerHTML = '' // clear the instances list
this.instanceContainer.appendChild(instanceContainerTitle)
this.instanceContainer.appendChild(this.noInstancesText)
})
this.instanceContainer.appendChild(instanceContainerTitle)
this.instanceContainer.appendChild(this.noInstancesText)
}
renderSettings () {
this.settingsUI = new SettingsUI(this.blockchain, this.networkModule)
@ -216,7 +189,6 @@ export class RunTab extends ViewPlugin {
render () {
return this.el
this.udappUI = new UniversalDAppUI(this.blockchain, this.logCallback)
this.renderInstanceContainer()
this.renderSettings()
this.renderDropdown(this.udappUI, this.fileManager, this.compilersArtefacts, this.config, this.editor, this.logCallback)
this.renderRecorder(this.udappUI, this.fileManager, this.config, this.logCallback)

@ -3,7 +3,7 @@ import React from 'react'
import * as ethJSUtil from 'ethereumjs-util'
import Web3 from 'web3'
import { addressToString, shortenAddress } from '@remix-ui/helper'
import { addProvider, displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, fetchContractListSuccess, hidePopUp, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentFile, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setIpfsCheckedState, setLoadType, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setSelectedAccount, setSendUnit, setSendValue, setTxFeeContent } from './payload'
import { addNewInstance, addProvider, clearAllInstances, displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, fetchContractListSuccess, hidePopUp, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentFile, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setIpfsCheckedState, setLoadType, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setSelectedAccount, setSendUnit, setSendValue, setTxFeeContent } from './payload'
import { RunTab } from '../types/run-tab'
import { CompilerAbstract } from '@remix-project/remix-solidity'
import * as remixLib from '@remix-project/remix-lib'
@ -201,7 +201,7 @@ const setFinalContext = () => {
const value = _getProviderDropdownValue()
setExecEnv(value)
// this.event.trigger('clearInstance', []) //check cleaIinstance event in run-tab.js
clearInstances()
}
const _getProviderDropdownValue = (): string => {
@ -303,15 +303,6 @@ const broadcastCompilationResult = (file, source, languageVersion, data) => {
dispatch(fetchContractListSuccess(contracts))
dispatch(setCurrentFile(file))
// this.enableAtAddress(success)
// this.enableContractNames(success)
// this.setInputParamsPlaceHolder()
// if (success) {
// this.compFails.style.display = 'none'
// } else {
// this.compFails.style.display = 'block'
// }
}
const loadContractFromAddress = (address, confirmCb, cb) => {
@ -455,13 +446,12 @@ export const createInstance = async (
}
const finalCb = (error, contractObject, address) => {
plugin.event.trigger('clearInstance')
if (error) {
const log = logBuilder(error)
return terminalLogger(log)
}
plugin.event.trigger('newContractInstanceAdded', [contractObject, address, contractObject.name])
addInstance({ contractData: contractObject, address, name: contractObject.name })
const data = plugin.compilersArtefacts.getCompilerAbstract(contractObject.contract.file)
@ -538,3 +528,45 @@ export const updateGasPrice = (price: string) => {
export const updateTxFeeContent = (content: string) => {
dispatch(setTxFeeContent(content))
}
const addInstance = (instance: { contractData: ContractData, address: string, name: string }) => {
dispatch(addNewInstance(instance))
}
export const removeInstance = (index: number) => {
dispatch(removeExistingInstance(index))
}
export const clearInstances = () => {
dispatch(clearAllInstances())
}
const loadAddress = () => {
clearInstances()
// let address = this.atAddressButtonInput.value
// if (!ethJSUtil.isValidChecksumAddress(address)) {
// addTooltip(yo`
// <span>
// It seems you are not using a checksumed address.
// <br>A checksummed address is an address that contains uppercase letters, as specified in <a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank">EIP-55</a>.
// <br>Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.
// </span>`)
// address = ethJSUtil.toChecksumAddress(address)
// }
// this.dropdownLogic.loadContractFromAddress(address,
// (cb) => {
// modalDialogCustom.confirm('At Address', `Do you really want to interact with ${address} using the current ABI definition?`, cb)
// },
// (error, loadType, abi) => {
// if (error) {
// return modalDialogCustom.alert(error)
// }
// if (loadType === 'abi') {
// return this.event.trigger('newContractABIAdded', [abi, address])
// }
// var selectedContract = this.getSelectedContract()
// addInstance({ contractData: selectedContract.object, address, name: contractObject.name })
// }
// )
}

@ -1,3 +1,5 @@
import { ContractData } from '../types'
export const fetchAccountsListRequest = () => {
return {
type: 'FETCH_ACCOUNTS_LIST_REQUEST',
@ -217,3 +219,23 @@ export const setTxFeeContent = (content: string) => {
payload: content
}
}
export const addNewInstance = (instance: { contractData: ContractData, address: string, name: string }) => {
return {
type: 'ADD_INSTANCE',
payload: instance
}
}
export const removeExistingInstance = (index: number) => {
return {
type: 'REMOVE_INSTANCE',
payload: index
}
}
export const clearAllInstances = () => {
return {
type: 'CLEAR_INSTANCES'
}
}

@ -145,134 +145,6 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
// })
// }
// async createInstance (selectedContract, args) {
// if (selectedContract.bytecodeObject.length === 0) {
// return modalDialogCustom.alert('This contract may be abstract, not implement an abstract parent\'s methods completely or not invoke an inherited contract\'s constructor correctly.')
// }
// var continueCb = (error, continueTxExecution, cancelCb) => {
// if (error) {
// var msg = typeof error !== 'string' ? error.message : error
// modalDialog('Gas estimation failed', yo`<div>Gas estimation errored with the following message (see below).
// The transaction execution will likely fail. Do you want to force sending? <br>
// ${msg}
// </div>`,
// {
// label: 'Send Transaction',
// fn: () => {
// continueTxExecution()
// }
// }, {
// label: 'Cancel Transaction',
// fn: () => {
// cancelCb()
// }
// })
// } else {
// continueTxExecution()
// }
// }
// const self = this
// var promptCb = (okCb, cancelCb) => {
// modalDialogCustom.promptPassphrase('Passphrase requested', 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb)
// }
// var statusCb = (msg) => {
// return this.logCallback(msg)
// }
// var finalCb = (error, contractObject, address) => {
// self.event.trigger('clearInstance')
// if (error) {
// return this.logCallback(error)
// }
// self.event.trigger('newContractInstanceAdded', [contractObject, address, contractObject.name])
// const data = self.runView.compilersArtefacts.getCompilerAbstract(contractObject.contract.file)
// self.runView.compilersArtefacts.addResolvedContract(helper.addressToString(address), data)
// if (self.ipfsCheckedState) {
// _paq.push(['trackEvent', 'udapp', 'DeployAndPublish', this.networkName])
// publishToStorage('ipfs', self.runView.fileProvider, self.runView.fileManager, selectedContract)
// } else {
// _paq.push(['trackEvent', 'udapp', 'DeployOnly', this.networkName])
// }
// }
// let contractMetadata
// try {
// contractMetadata = await this.runView.call('compilerMetadata', 'deployMetadataOf', selectedContract.name, selectedContract.contract.file)
// } catch (error) {
// return statusCb(`creation of ${selectedContract.name} errored: ${error.message ? error.message : error}`)
// }
// const compilerContracts = this.dropdownLogic.getCompilerContracts()
// const confirmationCb = this.getConfirmationCb(modalDialog, confirmDialog)
// if (selectedContract.isOverSizeLimit()) {
// return modalDialog('Contract code size over limit', yo`<div>Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fails. <br>
// More info: <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md" target="_blank">eip-170</a>
// </div>`,
// {
// label: 'Force Send',
// fn: () => {
// this.deployContract(selectedContract, args, contractMetadata, compilerContracts, { continueCb, promptCb, statusCb, finalCb }, confirmationCb)
// }
// }, {
// label: 'Cancel',
// fn: () => {
// this.logCallback(`creation of ${selectedContract.name} canceled by user.`)
// }
// })
// }
// this.deployContract(selectedContract, args, contractMetadata, compilerContracts, { continueCb, promptCb, statusCb, finalCb }, confirmationCb)
// }
// deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) {
// _paq.push(['trackEvent', 'udapp', 'DeployContractTo', this.networkName])
// const { statusCb } = callbacks
// if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
// return this.blockchain.deployContractAndLibraries(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb)
// }
// if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
// this.blockchain.deployContractWithLibrary(selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb)
// }
// getConfirmationCb (modalDialog, confirmDialog) {
// // this code is the same as in recorder.js. TODO need to be refactored out
// const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
// if (network.name !== 'Main') {
// return continueTxExecution(null)
// }
// const amount = this.blockchain.fromWei(tx.value, true, 'ether')
// const content = confirmDialog(tx, network, amount, gasEstimation, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice.bind(this.blockchain))
// modalDialog('Confirm transaction', content,
// {
// label: 'Confirm',
// fn: () => {
// this.blockchain.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked)
// // TODO: check if this is check is still valid given the refactor
// if (!content.gasPriceStatus) {
// cancelCb('Given transaction fee is not correct')
// } else {
// continueTxExecution(content.txFee)
// }
// }
// }, {
// label: 'Cancel',
// fn: () => {
// return cancelCb('Transaction canceled by user.')
// }
// }
// )
// }
// return confirmationCb
// }
const atAddressChanged = (event) => {
const value = event.target.value
@ -291,33 +163,6 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const loadFromAddress = () => {
// trigger dispatchLoadAddress
// this.event.trigger('clearInstance')
// let address = this.atAddressButtonInput.value
// if (!ethJSUtil.isValidChecksumAddress(address)) {
// addTooltip(yo`
// <span>
// It seems you are not using a checksumed address.
// <br>A checksummed address is an address that contains uppercase letters, as specified in <a href="https://eips.ethereum.org/EIPS/eip-55" target="_blank">EIP-55</a>.
// <br>Checksummed addresses are meant to help prevent users from sending transactions to the wrong address.
// </span>`)
// address = ethJSUtil.toChecksumAddress(address)
// }
// this.dropdownLogic.loadContractFromAddress(address,
// (cb) => {
// modalDialogCustom.confirm('At Address', `Do you really want to interact with ${address} using the current ABI definition?`, cb)
// },
// (error, loadType, abi) => {
// if (error) {
// return modalDialogCustom.alert(error)
// }
// if (loadType === 'abi') {
// return this.event.trigger('newContractABIAdded', [abi, address])
// }
// var selectedContract = this.getSelectedContract()
// this.event.trigger('newContractInstanceAdded', [selectedContract.object, address, this.selectContractNames.value])
// }
// )
}
const handleCheckedIPFS = () => {
@ -427,7 +272,5 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
</div>
</div>
</div>
// this.selectContractNames.addEventListener('change', this.setInputParamsPlaceHolder.bind(this))
// this.setInputParamsPlaceHolder()
)
}

@ -3,10 +3,10 @@ import React from 'react'
import { InstanceContainerProps } from '../types'
export function InstanceContainerUI (props: InstanceContainerProps) {
const { instanceList } = props.instances
const clearInstance = () => {
// this.instanceContainer.innerHTML = '' // clear the instances list
// this.instanceContainer.appendChild(instanceContainerTitle)
// this.instanceContainer.appendChild(this.noInstancesText)
props.clearInstances()
}
return (
@ -14,13 +14,18 @@ export function InstanceContainerUI (props: InstanceContainerProps) {
<div className="d-flex justify-content-between align-items-center pl-2 ml-1 mb-2"
title="Autogenerated generic user interfaces for interaction with deployed contracts">
Deployed Contracts
<i className="mr-2 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance}
title="Clear instances list and reset recorder" aria-hidden="true">
</i>
{ instanceList.length > 0
? <i className="mr-2 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance}
title="Clear instances list and reset recorder" aria-hidden="true">
</i> : null
}
</div>
<span className="mx-2 mt-3 alert alert-warning" data-id="deployAndRunNoInstanceText" role="alert">
Currently you have no contract instances to interact with.
</span>
{ instanceList.length > 0
? <div></div>
: <span className="mx-2 mt-3 alert alert-warning" data-id="deployAndRunNoInstanceText" role="alert">
Currently you have no contract instances to interact with.
</span>
}
</div>
)
}

@ -0,0 +1,190 @@
// eslint-disable-next-line no-use-before-define
import React, { useState } from 'react'
import { shortenAddress } from 'apps/remix-ide/src/lib/helper'
import { UdappProps } from '../types'
export function UniversalDappUI (props: UdappProps) {
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
// const self = this
// address = (address.slice(0, 2) === '0x' ? '' : '0x') + address.toString('hex')
// address = ethJSUtil.toChecksumAddress(address)
// var instance = yo`<div class="instance run-instance border-dark ${css.instance} ${css.hidesub}" id="instance${address}" data-shared="universalDappUiInstance"></div>`
// const context = this.blockchain.context()
// var shortAddress = helper.shortenAddress(address)
// var title = yo`
// <div class="${css.title} alert alert-secondary">
// <button data-id="universalDappUiTitleExpander" class="btn ${css.titleExpander}" onclick="${(e) => { toggleClass(e) }}">
// <i class="fas fa-angle-right" aria-hidden="true"></i>
// </button>
// <div class="input-group ${css.nameNbuts}">
// <div class="${css.titleText} input-group-prepend">
// <span class="input-group-text ${css.spanTitleText}">
// ${contractName} at ${shortAddress} (${context})
// </span>
// </div>
// <div class="btn-group">
// <button class="btn p-1 btn-secondary">${copyToClipboard(() => address)}</button>
// </div>
// </div>
// </div>
// `
// var close = yo`
// <button
// class="${css.udappClose} mr-1 p-1 btn btn-secondary align-items-center"
// data-id="universalDappUiUdappClose"
// onclick=${remove}
// title="Remove from the list"
// >
// <i class="${css.closeIcon} fas fa-times" aria-hidden="true"></i>
// </button>`
// title.querySelector('.btn-group').appendChild(close)
// var contractActionsWrapper = yo`
// <div class="${css.cActionsWrapper}" data-id="universalDappUiContractActionWrapper">
// </div>
// `
// function remove () {
// instance.remove()
// // @TODO perhaps add a callack here to warn the caller that the instance has been removed
// }
// function toggleClass (e) {
// $(instance).toggleClass(`${css.hidesub} bg-light`)
// // e.currentTarget.querySelector('i')
// e.currentTarget.querySelector('i').classList.toggle('fa-angle-right')
// e.currentTarget.querySelector('i').classList.toggle('fa-angle-down')
// }
// instance.appendChild(title)
// instance.appendChild(contractActionsWrapper)
// $.each(contractABI, (i, funABI) => {
// if (funABI.type !== 'function') {
// return
// }
// // @todo getData cannot be used with overloaded functions
// contractActionsWrapper.appendChild(this.getCallButton({
// funABI: funABI,
// address: address,
// contractABI: contractABI,
// contractName: contractName,
// contract
// }))
// })
// const calldataInput = yo`
// <input id="deployAndRunLLTxCalldata" class="${css.calldataInput} form-control" title="The Calldata to send to fallback function of the contract.">
// `
// const llIError = yo`
// <label id="deployAndRunLLTxError" class="text-danger my-2"></label>
// `
// // constract LLInteractions elements
// const lowLevelInteracions = yo`
// <div class="d-flex flex-column">
// <div class="d-flex flex-row justify-content-between mt-2">
// <div class="py-2 border-top d-flex justify-content-start flex-grow-1">
// Low level interactions
// </div>
// <a
// href="https://solidity.readthedocs.io/en/v0.6.2/contracts.html#receive-ether-function"
// title="check out docs for using 'receive'/'fallback'"
// target="_blank"
// >
// <i aria-hidden="true" class="fas fa-info my-2 mr-1"></i>
// </a>
// </div>
// <div class="d-flex flex-column align-items-start">
// <label class="">CALLDATA</label>
// <div class="d-flex justify-content-end w-100 align-items-center">
// ${calldataInput}
// <button id="deployAndRunLLTxSendTransaction" data-id="pluginManagerSettingsDeployAndRunLLTxSendTransaction" class="${css.instanceButton} p-0 w-50 btn border-warning text-warning" title="Send data to contract." onclick=${() => sendData()}>Transact</button>
// </div>
// </div>
// <div>
// ${llIError}
// </div>
// </div>
// `
// function sendData () {
// function setLLIError (text) {
// llIError.innerText = text
// }
// setLLIError('')
// const fallback = txHelper.getFallbackInterface(contractABI)
// const receive = txHelper.getReceiveInterface(contractABI)
// const args = {
// funABI: fallback || receive,
// address: address,
// contractName: contractName,
// contractABI: contractABI
// }
// const amount = document.querySelector('#value').value
// if (amount !== '0') {
// // check for numeric and receive/fallback
// if (!helper.isNumeric(amount)) {
// return setLLIError('Value to send should be a number')
// } else if (!receive && !(fallback && fallback.stateMutability === 'payable')) {
// return setLLIError("In order to receive Ether transfer the contract should have either 'receive' or payable 'fallback' function")
// }
// }
// let calldata = calldataInput.value
// if (calldata) {
// if (calldata.length < 4 && helper.is0XPrefixed(calldata)) {
// return setLLIError('The calldata should be a valid hexadecimal value with size of at least one byte.')
// } else {
// if (helper.is0XPrefixed(calldata)) {
// calldata = calldata.substr(2, calldata.length)
// }
// if (!helper.isHexadecimal(calldata)) {
// return setLLIError('The calldata should be a valid hexadecimal value.')
// }
// }
// if (!fallback) {
// return setLLIError("'Fallback' function is not defined")
// }
// }
// if (!receive && !fallback) return setLLIError('Both \'receive\' and \'fallback\' functions are not defined')
// // we have to put the right function ABI:
// // if receive is defined and that there is no calldata => receive function is called
// // if fallback is defined => fallback function is called
// if (receive && !calldata) args.funABI = receive
// else if (fallback) args.funABI = fallback
// if (!args.funABI) return setLLIError('Please define a \'Fallback\' function to send calldata and a either \'Receive\' or payable \'Fallback\' to send ethers')
// self.runTransaction(false, args, null, calldataInput.value, null)
// }
// contractActionsWrapper.appendChild(lowLevelInteracions)
// return instance
const toggleClass = () => {
setToggleExpander(!toggleExpander)
}
return (
<div className={`udapp_instance udapp_run-instance border-dark ${toggleExpander ? 'udapp_hidesub' : ''}`} id={`instance${props.instance.address}`} data-shared="universalDappUiInstance">
<div className="udapp_title alert alert-secondary">
<button data-id="universalDappUiTitleExpander" className="btn udapp_titleExpander" onClick={toggleClass}>
<i className={`fas ${toggleExpander ? 'fa-angle-right' : 'fa-angle-down'}`} aria-hidden="true"></i>
</button>
<div className="input-group udapp_nameNbuts">
<div className="udapp_titleText input-group-prepend">
<span className="input-group-text udapp_spanTitleText">
{props.instance.name} at {shortenAddress(props.instance)} ({context})
</span>
</div>
<div className="btn-group">
<button className="btn p-1 btn-secondary">${copyToClipboard(() => address)}</button>
</div>
</div>
</div>
</div>
)
}

@ -1,3 +1,5 @@
import { ContractData } from '../types'
interface Action {
type: string
payload: any
@ -61,7 +63,15 @@ export interface RunTabState {
maxPriorityFee: string,
baseFeePerGas: string,
txFeeContent: string,
gasPrice: string
gasPrice: string,
instances: {
instanceList: {
contractData: ContractData,
address: string,
name: string
}[],
error: string
}
}
export const runTabInitialState: RunTabState = {
@ -138,7 +148,11 @@ export const runTabInitialState: RunTabState = {
maxPriorityFee: '1',
baseFeePerGas: '',
txFeeContent: '',
gasPrice: ''
gasPrice: '',
instances: {
instanceList: [],
error: null
}
}
export const runTabReducer = (state: RunTabState = runTabInitialState, action: Action) => {
@ -518,6 +532,40 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
}
}
case 'ADD_INSTANCE': {
const payload: { contractData: ContractData, address: string, name: string } = action.payload
return {
...state,
instances: {
...state.instances,
instanceList: [...state.instances.instanceList, payload]
}
}
}
case 'REMOVE_INSTANCE': {
const payload: number = action.payload
return {
...state,
instances: {
...state.instances,
instanceList: state.instances.instanceList.filter((instance, index) => index !== payload)
}
}
}
case 'CLEAR_INSTANCES': {
return {
...state,
instances: {
instanceList: [],
error: null
}
}
}
default:
return state
}

@ -20,7 +20,7 @@ import {
updateBaseFeePerGas, updateConfirmSettings,
updateGasPrice, updateGasPriceStatus,
updateMaxFee, updateMaxPriorityFee,
updateTxFeeContent
updateTxFeeContent, clearInstances
} from './actions'
import './css/run-tab.css'
import { PublishToStorage } from '@remix-ui/publish-to-storage'
@ -191,7 +191,7 @@ export function RunTabUI (props: RunTabProps) {
maxPriorityFee={runTab.maxPriorityFee}
/>
<RecorderUI />
<InstanceContainerUI />
<InstanceContainerUI instances={runTab.instances} clearInstances={clearInstances} />
</div>
</div>
<ModalDialog id='fileSystem' { ...focusModal } handleHide={ handleHideModal } />

@ -182,7 +182,15 @@ export interface RecorderProps {
}
export interface InstanceContainerProps {
instances: {
instanceList: {
contractData: ContractData,
address: string,
name: string
}[],
error: string
},
clearInstances: () => void
}
export interface Modal {
@ -229,3 +237,11 @@ export interface MainnetProps {
maxFee: string,
maxPriorityFee: string
}
export interface UdappProps {
instance: {
contractData: ContractData,
address: string,
name: string
}
}

Loading…
Cancel
Save