@ -1,25 +1,34 @@
// eslint-disable-next-line no-use-before-define
// eslint-disable-next-line no-use-before-define
import React , { useEffect , useRef , useState } from 'react'
import React , { Ref , 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 { ButtonGroup , Dropdown } from 'react-bootstrap'
import { DeployButton } from './deployButton'
import { MultiDeployInput } from './multiDeployInput'
import { DeployInput } from './deployInput'
const txFormat = remixLib . execution . txFormat
const txFormat = remixLib . execution . txFormat
export function ContractGUI ( props : ContractGUIProps ) {
export function ContractGUI ( props : ContractGUIProps ) {
const [ title , setTitle ] = useState < string > ( '' )
const [ title , setTitle ] = useState < string > ( '' )
const [ basicInput , setBasicInput ] = useState < string > ( '' )
const [ basicInput , setBasicInput ] = useState < string > ( '' )
// const [toggleContainer, setToggleContainer] = useState<boolean>(false)
const [ toggleContainer , setToggleContainer ] = useState < boolean > ( false )
const [ buttonOptions , setButtonOptions ] = useState < {
const [ buttonOptions , setButtonOptions ] = useState < {
title : string ,
title : string ,
content : string ,
content : string ,
classList : string ,
classList : string ,
dataId : string
dataId : string ,
} > ( { title : '' , content : '' , classList : '' , dataId : '' } )
widthClass : string
const [ selectedDeployIndex , setSelectedDeployIndex ] = useState < number [ ] > ( [ ] )
} > ( { title : '' , content : '' , classList : '' , dataId : '' , widthClass : '' } )
const [ selectedDeployIndex , setSelectedDeployIndex ] = useState < number > ( null )
const [ showOptions , setShowOptions ] = useState < boolean > ( false )
const [ showOptions , setShowOptions ] = useState < boolean > ( false )
const [ hasArgs , setHasArgs ] = useState < boolean > ( false )
const [ hasArgs , setHasArgs ] = useState < boolean > ( false )
const [ isMultiField , setIsMultiField ] = useState < boolean > ( false )
const [ isMultiField , setIsMultiField ] = useState < boolean > ( false )
const [ deployInputs , setDeployInputs ] = useState < {
internalType? : string ,
name : string ,
type : string
} [ ] > ( [ ] )
const [ deployPlaceholder , setDeployPlaceholder ] = useState < string > ( '' )
const multiFields = useRef < Array < HTMLInputElement | null > > ( [ ] )
const multiFields = useRef < Array < HTMLInputElement | null > > ( [ ] )
const basicInputRef = useRef < HTMLInputElement > ( )
const basicInputRef = useRef < HTMLInputElement > ( )
@ -36,13 +45,6 @@ export function ContractGUI (props: ContractGUIProps) {
if ( basicInputRef . current ) basicInputRef . current . value = ''
if ( basicInputRef . current ) basicInputRef . current . value = ''
multiFields . current . filter ( ( el ) = > el !== null && el !== undefined ) . forEach ( ( el ) = > el . value = '' )
multiFields . current . filter ( ( el ) = > el !== null && el !== undefined ) . forEach ( ( el ) = > el . value = '' )
multiFields . current = [ ]
multiFields . current = [ ]
const hasArgs = ( props . funcABI . inputs && props . funcABI . inputs . length > 0 ) ||
( props . funcABI . type === 'fallback' ) ||
( props . funcABI . type === 'receive' ) ||
( props . isDeploy && props . initializerOptions && props . initializerOptions . inputs && ( props . initializerOptions . inputs . inputs . length > 0 ) )
setHasArgs ( hasArgs )
} , [ props . title , props . funcABI ] )
} , [ props . title , props . funcABI ] )
useEffect ( ( ) = > {
useEffect ( ( ) = > {
@ -52,7 +54,8 @@ export function ContractGUI (props: ContractGUIProps) {
title : title + ' - call' ,
title : title + ' - call' ,
content : 'call' ,
content : 'call' ,
classList : 'btn-info' ,
classList : 'btn-info' ,
dataId : title + ' - call'
dataId : title + ' - call' ,
widthClass : props.widthClass
} )
} )
} else if ( props . funcABI . stateMutability === 'payable' || props . funcABI . payable ) {
} else if ( props . funcABI . stateMutability === 'payable' || props . funcABI . payable ) {
// // transact. stateMutability = payable
// // transact. stateMutability = payable
@ -60,7 +63,8 @@ export function ContractGUI (props: ContractGUIProps) {
title : title + ' - transact (payable)' ,
title : title + ' - transact (payable)' ,
content : 'transact' ,
content : 'transact' ,
classList : 'btn-danger' ,
classList : 'btn-danger' ,
dataId : title + ' - transact (payable)'
dataId : title + ' - transact (payable)' ,
widthClass : props.widthClass
} )
} )
} else {
} else {
// // transact. stateMutability = nonpayable
// // transact. stateMutability = nonpayable
@ -68,13 +72,59 @@ export function ContractGUI (props: ContractGUIProps) {
title : title + ' - transact (not payable)' ,
title : title + ' - transact (not payable)' ,
content : 'transact' ,
content : 'transact' ,
classList : 'btn-warning' ,
classList : 'btn-warning' ,
dataId : title + ' - transact (not payable)'
dataId : title + ' - transact (not payable)' ,
widthClass : props.widthClass
} )
} )
}
}
} , [ props . lookupOnly , props . funcABI , title ] )
} , [ props . lookupOnly , props . funcABI , title ] )
const getContentOnCTC = ( ) = > {
useEffect ( ( ) = > {
const multiString = getMultiValsString ( )
if ( props . deployOption && props . deployOption [ selectedDeployIndex ] ) {
if ( props . deployOption [ selectedDeployIndex ] . title === 'Deploy with Proxy' ) {
if ( props . initializerOptions ) {
setDeployInputs ( props . initializerOptions . inputs . inputs )
setDeployPlaceholder ( props . initializerOptions . initializeInputs )
setHasArgs ( true )
if ( props . initializerOptions . inputs . inputs . length > 1 ) setIsMultiField ( true )
else setIsMultiField ( false )
} else {
setDeployInputs ( [ ] )
setDeployPlaceholder ( '' )
setHasArgs ( false )
setIsMultiField ( false )
}
} else {
if ( props . funcABI ) {
setDeployInputs ( props . funcABI . inputs )
setDeployPlaceholder ( props . inputs )
setHasArgs ( true )
if ( props . funcABI . inputs . length > 1 ) setIsMultiField ( true )
else setIsMultiField ( false )
} else {
setDeployInputs ( [ ] )
setDeployPlaceholder ( '' )
setHasArgs ( false )
setIsMultiField ( false )
}
}
} else {
if ( props . funcABI ) {
setDeployInputs ( props . funcABI . inputs )
setDeployPlaceholder ( props . inputs )
setHasArgs ( true )
if ( props . funcABI . inputs . length > 1 ) setIsMultiField ( true )
else setIsMultiField ( false )
} else {
setDeployInputs ( [ ] )
setDeployPlaceholder ( '' )
setHasArgs ( false )
setIsMultiField ( false )
}
}
} , [ selectedDeployIndex , props . funcABI , props . initializerOptions ] )
const getContentOnCTC = ( fields : HTMLInputElement [ ] ) = > {
const multiString = getMultiValsString ( fields )
// copy-to-clipboard icon is only visible for method requiring input params
// copy-to-clipboard icon is only visible for method requiring input params
if ( ! multiString ) {
if ( ! multiString ) {
return 'cannot encode empty arguments'
return 'cannot encode empty arguments'
@ -94,31 +144,21 @@ export function ContractGUI (props: ContractGUIProps) {
}
}
}
}
useEffect ( ( ) = > {
const switchMethodViewOn = ( ) = > {
if ( props . initializerOptions ) {
setToggleContainer ( true )
if ( props . initializerOptions . inputs . inputs . length > 1 ) setIsMultiField ( true )
makeMultiVal ( )
else setIsMultiField ( false )
}
} else if ( props . funcABI ) {
if ( props . funcABI . inputs . length > 1 ) setIsMultiField ( true )
else setIsMultiField ( false )
} else setIsMultiField ( false )
} , [ props . initializerOptions , props . funcABI ] )
// const switchMethodViewOn = () => {
// setToggleContainer(true)
// makeMultiVal()
// }
const switchMethodViewOff = ( ) = > {
const switchMethodViewOff = ( ) = > {
// setToggleContainer(false)
setToggleContainer ( false )
let multiValString = getMultiValsString ( )
const multiValString = getMultiValsString ( multiFields . current )
multiValString = multiValString . replace ( /["]+/g , '' )
if ( multiValString ) setBasicInput ( multiValString )
if ( multiValString ) setBasicInput ( multiValString )
}
}
const getMultiValsString = ( ) = > {
const getMultiValsString = ( fields : HTMLInputElement [ ] ) = > {
const valArray = multiFields . current
const valArray = fields
console . log ( 'valArray: ' , valArray )
let ret = ''
let ret = ''
const valArrayTest = [ ]
const valArrayTest = [ ]
@ -154,7 +194,6 @@ export function ContractGUI (props: ContractGUIProps) {
inputString = inputString . replace ( /(^|,\s+|,)(\d+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted number by quoted number
inputString = inputString . replace ( /(^|,\s+|,)(\d+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted number by quoted number
inputString = inputString . replace ( /(^|,\s+|,)(0[xX][0-9a-fA-F]+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted hex string by quoted hex string
inputString = inputString . replace ( /(^|,\s+|,)(0[xX][0-9a-fA-F]+)(\s+,|,|$)/g , '$1"$2"$3' ) // replace non quoted hex string by quoted hex string
inputString = JSON . stringify ( [ inputString ] )
inputString = JSON . stringify ( [ inputString ] )
const inputJSON = JSON . parse ( inputString )
const inputJSON = JSON . parse ( inputString )
const multiInputs = multiFields . current
const multiInputs = multiFields . current
@ -167,8 +206,9 @@ export function ContractGUI (props: ContractGUIProps) {
}
}
const handleActionClick = ( ) = > {
const handleActionClick = ( ) = > {
const deployMode = selectedDeployIndex . map ( index = > props . deployOption [ i ndex] . title )
const deployMode = selectedDeployIndex !== null ? [ props . deployOption [ selectedDeployI ndex ] . title ] : [ ]
console . log ( 'basicInput: ' , basicInput )
props . clickCallBack ( props . funcABI . inputs , basicInput , deployMode )
props . clickCallBack ( props . funcABI . inputs , basicInput , deployMode )
}
}
@ -178,9 +218,10 @@ export function ContractGUI (props: ContractGUIProps) {
setBasicInput ( value )
setBasicInput ( value )
}
}
const handleMultiValsSubmit = ( ) = > {
const handleMultiValsSubmit = ( fields : HTMLInputElement [ ] ) = > {
const valsString = getMultiValsString ( )
console . log ( 'fields: ' , fields )
const deployMode = selectedDeployIndex . map ( index = > props . deployOption [ index ] . title )
const valsString = getMultiValsString ( fields )
const deployMode = selectedDeployIndex !== null ? [ props . deployOption [ selectedDeployIndex ] . title ] : [ ]
if ( valsString ) {
if ( valsString ) {
props . clickCallBack ( props . funcABI . inputs , valsString , deployMode )
props . clickCallBack ( props . funcABI . inputs , valsString , deployMode )
@ -190,12 +231,9 @@ export function ContractGUI (props: ContractGUIProps) {
}
}
const setSelectedDeploy = ( index : number ) = > {
const setSelectedDeploy = ( index : number ) = > {
const indexes = selectedDeployIndex . slice ( )
setSelectedDeployIndex ( index !== selectedDeployIndex ? index : null )
const existingIndex = indexes . findIndex ( value = > value === index )
if ( basicInputRef . current ) basicInputRef . current . value = ''
setBasicInput ( '' )
if ( existingIndex > - 1 ) indexes . splice ( existingIndex , 1 )
else indexes . push ( index )
setSelectedDeployIndex ( indexes )
}
}
const toggleOptions = ( ) = > {
const toggleOptions = ( ) = > {
@ -204,101 +242,67 @@ export function ContractGUI (props: ContractGUIProps) {
return (
return (
< div className = { ` udapp_contractProperty ${ hasArgs ? 'udapp_hasArgs' : '' } ` } >
< div className = { ` udapp_contractProperty ${ hasArgs ? 'udapp_hasArgs' : '' } ` } >
< div className = "udapp_contractActionsContainerSingle pt-2" style = { { display : 'flex' } } >
{
{
props . isDeploy ? ! isMultiField ?
props . isDeploy && ! isMultiField && ( props . deployOption || [ ] ) . length > 0 ?
< DeployInput
< Dropdown as = { ButtonGroup } show = { showOptions } >
buttonOptions = { buttonOptions }
< button onClick = { handleActionClick } title = { buttonOptions . title } className = { ` udapp_instanceButton ${ props . widthClass } btn btn-sm ${ buttonOptions . classList } ` } data - id = { buttonOptions . dataId } > Deploy < / button >
funcABI = { props . initializerOptions ? props.initializerOptions.inputs : props.funcABI }
< Dropdown.Toggle split id = "dropdown-split-basic" className = { ` btn btn-sm dropdown-toggle dropdown-toggle-split ${ buttonOptions . classList } ` } style = { { maxWidth : 25 , minWidth : 0 , height : 32 } } onClick = { toggleOptions } / >
inputs = { deployPlaceholder }
< Dropdown.Menu className = "deploy-items border-0" >
handleBasicInput = { handleBasicInput }
{
basicInputRef = { basicInputRef }
( props . deployOption ) . map ( ( { title , active } , index ) = > < Dropdown.Item onClick = { ( ) = > setSelectedDeploy ( index ) } key = { index } > { selectedDeployIndex . includes ( index ) ? < span > & # 10003 ; { title } < / span > : < span className = "pl-3" > { title } < / span > } < / Dropdown.Item > )
selectedIndex = { selectedDeployIndex }
}
setSelectedIndex = { setSelectedDeploy }
< / Dropdown.Menu >
handleActionClick = { handleActionClick }
< / Dropdown > :
deployOptions = { props . deployOption }
! isMultiField ?
/ > : < M u l t i D e p l o y I n p u t
< button onClick = { handleActionClick } title = { buttonOptions . title } className = { ` udapp_instanceButton ${ props . widthClass } btn btn-sm ${ buttonOptions . classList } ` } data - id = { buttonOptions . dataId } >
buttonOptions = { buttonOptions }
{ title }
selectedIndex = { selectedDeployIndex }
< / button > : null
setSelectedIndex = { setSelectedDeploy }
}
handleMultiValsSubmit = { handleMultiValsSubmit }
{
inputs = { deployInputs }
props . isDeploy && ! isMultiField && props . initializerOptions ?
getMultiValsString = { getMultiValsString }
< input
deployOptions = { props . deployOption }
className = "form-control"
/ > :
data - id = { props . initializerOptions . inputs . type === 'fallback' || props . initializerOptions . inputs . type === 'receive' ? ` '( ${ props . initializerOptions . inputs . type } ') ` : 'multiParamManagerBasicInputField' }
< >
placeholder = { props . initializerOptions . initializeInputs }
< div className = "udapp_contractActionsContainerSingle pt-2" style = { { display : toggleContainer ? 'none' : 'flex' } } >
title = { props . initializerOptions . inputs . type === 'fallback' || props . initializerOptions . inputs . type === 'receive' ? ` '( ${ props . initializerOptions . inputs . type } ') ` : props . initializerOptions . initializeInputs }
< button onClick = { handleActionClick } title = { buttonOptions . title } className = { ` udapp_instanceButton ${ props . widthClass } btn btn-sm ${ buttonOptions . classList } ` } data - id = { buttonOptions . dataId } > { title } < / button >
onChange = { handleBasicInput }
< input
ref = { basicInputRef }
className = "form-control"
style = { { visibility : ! ( ( props . initializerOptions . inputs . inputs && props . initializerOptions . inputs . inputs . length > 0 ) || ( props . initializerOptions . inputs . type === 'fallback' ) || ( props . initializerOptions . inputs . type === 'receive' ) ) ? 'hidden' : 'visible' } }
data - id = { props . funcABI . type === 'fallback' || props . funcABI . type === 'receive' ? ` '( ${ props . funcABI . type } ') ` : 'multiParamManagerBasicInputField' }
/ >
placeholder = { props . inputs }
: ! isMultiField && props . funcABI ?
title = { props . funcABI . type === 'fallback' || props . funcABI . type === 'receive' ? ` '( ${ props . funcABI . type } ') ` : props . inputs }
< input
onChange = { handleBasicInput }
className = "form-control"
ref = { basicInputRef }
data - id = { props . funcABI . type === 'fallback' || props . funcABI . type === 'receive' ? ` '( ${ props . funcABI . type } ') ` : 'multiParamManagerBasicInputField' }
style = { { visibility : ! ( ( props . funcABI . inputs && props . funcABI . inputs . length > 0 ) || ( props . funcABI . type === 'fallback' ) || ( props . funcABI . type === 'receive' ) ) ? 'hidden' : 'visible' } } / >
placeholder = { props . inputs }
< i
title = { props . funcABI . type === 'fallback' || props . funcABI . type === 'receive' ? ` '( ${ props . funcABI . type } ') ` : props . inputs }
className = "fas fa-angle-down udapp_methCaret"
onChange = { handleBasicInput }
onClick = { switchMethodViewOn }
ref = { basicInputRef }
title = { title }
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 ) ? 'hidden' : 'visible' } } > < / i >
/ > : n u l l
< / div >
}
< div className = "udapp_contractActionsContainerMulti" style = { { display : toggleContainer ? 'flex' : 'none' } } >
< / div >
< div className = "udapp_contractActionsContainerMultiInner text-dark" >
{ isMultiField && props . isDeploy && props . initializerOptions ?
< div onClick = { switchMethodViewOff } className = "udapp_multiHeader" >
< div className = "udapp_contractActionsContainerMulti" style = { { display : 'flex' } } >
< div className = "udapp_multiTitle run-instance-multi-title" > { title } < / div >
< div className = "udapp_contractActionsContainerMultiInner text-dark" >
< i className = 'fas fa-angle-up udapp_methCaret' > < / i >
< div className = "udapp_multiHeader" >
< div className = "udapp_multiTitle run-instance-multi-title" > { title } < / div >
< / div >
< div >
{ props . initializerOptions . inputs . inputs . map ( ( inp , index ) = > {
return (
< div className = "udapp_multiArg" key = { index } >
< label htmlFor = { inp . name } > { inp . name } : < / label >
< input ref = { el = > { multiFields . current [ index ] = el } } className = "form-control" placeholder = { inp . type } title = { inp . name } data - id = { ` multiParamManagerInput ${ inp . name } ` } / >
< / div > )
} ) }
< / div >
< div className = "udapp_group udapp_multiArg" >
{ /* <CopyToClipboard tip='Encode values of input fields & copy to clipboard' icon='fa-clipboard' direction={'left'} getContent={getContentOnCTC} /> */ }
{
( props . deployOption || [ ] ) . length > 0 ?
< Dropdown as = { ButtonGroup } show = { showOptions } >
< button onClick = { handleMultiValsSubmit } title = { buttonOptions . title } className = { ` udapp_instanceButton ${ props . widthClass } btn btn-sm ${ buttonOptions . classList } ` } data - id = { buttonOptions . dataId } > Deploy < / button >
< Dropdown.Toggle split id = "dropdown-split-basic" className = { ` btn btn-sm dropdown-toggle dropdown-toggle-split ${ buttonOptions . classList } ` } style = { { maxWidth : 25 , minWidth : 0 , height : 32 } } onClick = { toggleOptions } / >
< Dropdown.Menu className = "deploy-items border-0" >
{
( props . deployOption ) . map ( ( { title , active } , index ) = > < Dropdown.Item onClick = { ( ) = > setSelectedDeploy ( index ) } key = { index } > { selectedDeployIndex . includes ( index ) ? < span > & # 10003 ; { title } < / span > : < span className = "pl-3" > { title } < / span > } < / Dropdown.Item > )
}
< / Dropdown.Menu >
< / Dropdown > :
< button onClick = { handleMultiValsSubmit } title = { buttonOptions . title } data - id = { buttonOptions . dataId } className = { ` udapp_instanceButton ${ buttonOptions . classList } ` } > { title } < / button >
}
< / div >
< / div >
< / div >
< / div > :
< div >
isMultiField && props . funcABI ?
{ props . funcABI . inputs . map ( ( inp , index ) = > {
< div className = "udapp_contractActionsContainerMulti" style = { { display : 'flex' } } >
return (
< div className = "udapp_contractActionsContainerMultiInner text-dark" >
< div className = "udapp_multiArg" key = { index } >
< div className = "udapp_multiHeader" >
< label htmlFor = { inp . name } > { inp . name } : < / label >
< div className = "udapp_multiTitle run-instance-multi-title" > { title } < / div >
< input ref = { el = > { multiFields . current [ index ] = el } } className = "form-control" placeholder = { inp . type } title = { inp . name } data - id = { ` multiParamManagerInput ${ inp . name } ` } / >
< / div >
< / div > )
< div >
} ) }
{ props . funcABI . inputs . map ( ( inp , index ) = > {
return (
< div className = "udapp_multiArg" key = { index } >
< label htmlFor = { inp . name } > { inp . name } : < / label >
< input ref = { el = > { multiFields . current [ index ] = el } } className = "form-control" placeholder = { inp . type } title = { inp . name } data - id = { ` multiParamManagerInput ${ inp . name } ` } / >
< / div > )
} ) }
< / div >
< div className = "udapp_group udapp_multiArg" >
< CopyToClipboard tip = 'Encode values of input fields & copy to clipboard' icon = 'fa-clipboard' direction = { 'left' } getContent = { getContentOnCTC } / >
< button onClick = { handleMultiValsSubmit } title = { buttonOptions . title } data - id = { buttonOptions . dataId } className = { ` udapp_instanceButton ${ buttonOptions . classList } ` } > { buttonOptions . content } < / button >
< / div >
< / div >
< / div >
< / div > : null
< div className = "udapp_group udapp_multiArg" >
}
< CopyToClipboard tip = 'Encode values of input fields & copy to clipboard' icon = 'fa-clipboard' direction = { 'left' } getContent = { ( ) = > getContentOnCTC ( multiFields . current ) } / >
< button onClick = { ( ) = > handleMultiValsSubmit ( multiFields . current ) } title = { buttonOptions . title } data - id = { buttonOptions . dataId } className = { ` udapp_instanceButton ${ buttonOptions . classList } ` } > { buttonOptions . content } < / button >
< / div >
< / div >
< / div >
< / >
}
< / div >
< / div >
)
)
}
}