Merge branch 'master' of https://github.com/ethereum/remix-project into editorcontext

editorcontextDummy
filip mertens 2 years ago
commit 372f434f33
  1. 4
      apps/remix-ide-e2e/src/tests/recorder.test.ts
  2. 2
      apps/remix-ide/src/app/components/hidden-panel.tsx
  3. 2
      apps/remix-ide/src/app/components/main-panel.tsx
  4. 2
      apps/remix-ide/src/app/components/side-panel.tsx
  5. 2
      apps/remix-ide/src/app/components/vertical-icons.tsx
  6. 2
      apps/remix-ide/src/app/files/dgitProvider.js
  7. 5
      apps/remix-ide/src/app/panels/file-panel.js
  8. 2
      apps/remix-ide/src/app/panels/terminal.js
  9. 2
      apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx
  10. 3
      apps/remix-ide/src/app/tabs/analysis-tab.js
  11. 2
      apps/remix-ide/src/app/tabs/compile-and-run.ts
  12. 1
      apps/remix-ide/src/app/tabs/compile-tab.js
  13. 3
      apps/remix-ide/src/app/tabs/debugger-tab.js
  14. 2
      apps/remix-ide/src/app/tabs/external-http-provider.tsx
  15. 2
      apps/remix-ide/src/app/tabs/foundry-provider.tsx
  16. 2
      apps/remix-ide/src/app/tabs/ganache-provider.tsx
  17. 13
      apps/remix-ide/src/app/tabs/runTab/model/recorder.js
  18. 5
      apps/remix-ide/src/app/tabs/search.tsx
  19. 5
      apps/remix-ide/src/app/tabs/test-tab.js
  20. 3
      apps/remix-ide/src/app/udapp/run-tab.js
  21. 2
      apps/remix-ide/src/app/ui/landing-page/landing-page.js
  22. 8
      apps/remix-ide/src/blockchain/blockchain.js
  23. 3
      apps/remix-ide/src/remixAppManager.js
  24. 2
      apps/remix-ide/src/walkthroughService.js
  25. 12
      libs/remix-ui/helper/src/lib/helper-components.tsx
  26. 8
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  27. 6
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  28. 26
      libs/remix-ui/run-tab/src/lib/components/recorderCardUI.tsx
  29. 6
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  30. 1
      libs/remix-ui/run-tab/src/lib/types/index.ts
  31. 30
      libs/remix-ui/workspace/src/lib/actions/workspace.ts

@ -118,7 +118,7 @@ module.exports = {
}) })
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.perform((done) => { .perform((done) => {
browser.verifyCallReturnValue(addressRef, ['', '0:uint256: 350']) browser.verifyCallReturnValue(addressRef, ['0:uint256: 350'])
.perform(() => done()) .perform(() => done())
}) })
// change the init state and recompile the same contract. // change the init state and recompile the same contract.
@ -138,7 +138,7 @@ module.exports = {
}) })
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
.perform((done) => { .perform((done) => {
browser.verifyCallReturnValue(addressRef, ['', '0:uint256: 300']) browser.verifyCallReturnValue(addressRef, ['0:uint256: 300'])
.perform(() => done()) .perform(() => done())
}) })
.end() .end()

@ -8,7 +8,7 @@ import { PluginViewWrapper } from '@remix-ui/helper'
const profile = { const profile = {
name: 'hiddenPanel', name: 'hiddenPanel',
displayName: 'Hidden Panel', displayName: 'Hidden Panel',
description: '', description: 'Remix IDE hidden panel',
version: packageJson.version, version: packageJson.version,
methods: ['addView', 'removeView'] methods: ['addView', 'removeView']
} }

@ -7,7 +7,7 @@ import { PluginViewWrapper } from '@remix-ui/helper'
const profile = { const profile = {
name: 'mainPanel', name: 'mainPanel',
displayName: 'Main Panel', displayName: 'Main Panel',
description: '', description: 'Remix IDE main panel',
version: packageJson.version, version: packageJson.version,
methods: ['addView', 'removeView', 'showContent'] methods: ['addView', 'removeView', 'showContent']
} }

@ -10,7 +10,7 @@ import { PluginViewWrapper } from '@remix-ui/helper'
const sidePanel = { const sidePanel = {
name: 'sidePanel', name: 'sidePanel',
displayName: 'Side Panel', displayName: 'Side Panel',
description: '', description: 'Remix IDE side panel',
version: packageJson.version, version: packageJson.version,
methods: ['addView', 'removeView'] methods: ['addView', 'removeView']
} }

@ -10,7 +10,7 @@ import { PluginViewWrapper } from '@remix-ui/helper'
const profile = { const profile = {
name: 'menuicons', name: 'menuicons',
displayName: 'Vertical Icons', displayName: 'Vertical Icons',
description: '', description: 'Remix IDE vertical icons',
version: packageJson.version, version: packageJson.version,
methods: ['select', 'unlinkContent', 'linkContent'], methods: ['select', 'unlinkContent', 'linkContent'],
events: ['toggleContent', 'showContent'] events: ['toggleContent', 'showContent']

@ -18,7 +18,7 @@ const axios = require('axios')
const profile = { const profile = {
name: 'dGitProvider', name: 'dGitProvider',
displayName: 'Decentralized git', displayName: 'Decentralized git',
description: '', description: 'Decentralized git provider',
icon: 'assets/img/fileManager.webp', icon: 'assets/img/fileManager.webp',
version: '0.0.1', version: '0.0.1',
methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem'], methods: ['init', 'localStorageUsed', 'addremote', 'delremote', 'remotes', 'fetch', 'clone', 'export', 'import', 'status', 'log', 'commit', 'add', 'remove', 'rm', 'lsfiles', 'readblob', 'resolveref', 'branches', 'branch', 'checkout', 'currentbranch', 'push', 'pin', 'pull', 'pinList', 'unPin', 'setIpfsConfig', 'zip', 'setItem', 'getItem'],

@ -33,11 +33,12 @@ const profile = {
methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace'], methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace'],
events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'], events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'],
icon: 'assets/img/fileManager.webp', icon: 'assets/img/fileManager.webp',
description: ' - ', description: 'Remix IDE file explorer',
kind: 'fileexplorer', kind: 'fileexplorer',
location: 'sidePanel', location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/file_explorer.html', documentation: 'https://remix-ide.readthedocs.io/en/latest/file_explorer.html',
version: packageJson.version version: packageJson.version,
maintainedBy: 'Remix'
} }
module.exports = class Filepanel extends ViewPlugin { module.exports = class Filepanel extends ViewPlugin {
constructor (appManager) { constructor (appManager) {

@ -20,7 +20,7 @@ const profile = {
name: 'terminal', name: 'terminal',
methods: ['log', 'logHtml'], methods: ['log', 'logHtml'],
events: [], events: [],
description: ' - ', description: 'Remix IDE terminal',
version: packageJson.version version: packageJson.version
} }

@ -7,7 +7,7 @@ import { Profile } from '@remixproject/plugin-utils'
const profile = { const profile = {
name: 'permissionhandler', name: 'permissionhandler',
displayName: 'permissionhandler', displayName: 'permissionhandler',
description: 'permissionhandler', description: 'Plugin to handle permissions',
methods: ['askPermission'] methods: ['askPermission']
} }

@ -18,7 +18,8 @@ const profile = {
kind: 'analysis', kind: 'analysis',
location: 'sidePanel', location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/static_analysis.html', documentation: 'https://remix-ide.readthedocs.io/en/latest/static_analysis.html',
version: packageJson.version version: packageJson.version,
maintainedBy: 'Remix'
} }
class AnalysisTab extends ViewPlugin { class AnalysisTab extends ViewPlugin {

@ -10,7 +10,7 @@ const _paq = window._paq = window._paq || []
export const profile = { export const profile = {
name: 'compileAndRun', name: 'compileAndRun',
displayName: 'Compile and Run', displayName: 'Compile and Run',
description: 'after each compilation, run the script defined in Natspec.', description: 'After each compilation, run the script defined in Natspec.',
methods: ['runScriptAfterCompilation'], methods: ['runScriptAfterCompilation'],
version: packageJson.version, version: packageJson.version,
kind: 'none' kind: 'none'

@ -19,6 +19,7 @@ const profile = {
location: 'sidePanel', location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html', documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html',
version: packageJson.version, version: packageJson.version,
maintainedBy: 'Remix',
methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig', 'compileFile', 'getCompilerState'] methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig', 'compileFile', 'getCompilerState']
} }

@ -17,7 +17,8 @@ const profile = {
kind: 'debugging', kind: 'debugging',
location: 'sidePanel', location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/debugger.html', documentation: 'https://remix-ide.readthedocs.io/en/latest/debugger.html',
version: packageJson.version version: packageJson.version,
maintainedBy: 'Remix'
} }
export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {

@ -6,7 +6,7 @@ const profile = {
name: 'basic-http-provider', name: 'basic-http-provider',
displayName: 'External Http Provider', displayName: 'External Http Provider',
kind: 'provider', kind: 'provider',
description: '', description: 'External Http Provider',
methods: ['sendAsync'], methods: ['sendAsync'],
version: packageJson.version version: packageJson.version
} }

@ -10,7 +10,7 @@ const profile = {
name: 'foundry-provider', name: 'foundry-provider',
displayName: 'Foundry Provider', displayName: 'Foundry Provider',
kind: 'provider', kind: 'provider',
description: 'Anvil', description: 'Foundry Anvil provider',
methods: ['sendAsync'], methods: ['sendAsync'],
version: packageJson.version version: packageJson.version
} }

@ -10,7 +10,7 @@ const profile = {
name: 'ganache-provider', name: 'ganache-provider',
displayName: 'Ganache Provider', displayName: 'Ganache Provider',
kind: 'provider', kind: 'provider',
description: 'Ganache', description: 'Truffle Ganache provider',
methods: ['sendAsync'], methods: ['sendAsync'],
version: packageJson.version version: packageJson.version
} }

@ -13,7 +13,7 @@ const _paq = window._paq = window._paq || [] //eslint-disable-line
const profile = { const profile = {
name: 'recorder', name: 'recorder',
displayName: 'Recorder', displayName: 'Recorder',
description: '', description: 'Records transactions to save and run',
version: packageJson.version, version: packageJson.version,
methods: [ ] methods: [ ]
} }
@ -200,13 +200,16 @@ class Recorder extends Plugin {
*/ */
run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, newContractFn) { run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, newContractFn) {
this.setListen(false) this.setListen(false)
const liveMsg = liveMode ? ' in live mode' : '' const liveMsg = liveMode ? ' with updated contracts' : ''
logCallBack(`Running ${records.length} transaction(s)${liveMsg} ...`) logCallBack(`Running ${records.length} transaction(s)${liveMsg} ...`)
async.eachOfSeries(records, async (tx, index, cb) => { async.eachOfSeries(records, async (tx, index, cb) => {
if (liveMode && tx.record.type === 'constructor') { if (liveMode && tx.record.type === 'constructor') {
// resolve the bytecode using the contract name, this ensure getting the last compiled one. // resolve the bytecode and ABI using the contract name, this ensure getting the last compiled one.
const data = await this.call('compilerArtefacts', 'getArtefactsByContractName', tx.record.contractName) const data = await this.call('compilerArtefacts', 'getArtefactsByContractName', tx.record.contractName)
tx.record.bytecode = data.artefact.evm.bytecode.object tx.record.bytecode = data.artefact.evm.bytecode.object
const updatedABIKeccak = ethutil.bufferToHex(ethutil.keccakFromString(JSON.stringify(data.artefact.abi)))
abis[updatedABIKeccak] = data.artefact.abi
tx.record.abi = updatedABIKeccak
} }
var record = this.resolveAddress(tx.record, accounts, options) var record = this.resolveAddress(tx.record, accounts, options)
var abi = abis[tx.record.abi] var abi = abis[tx.record.abi]
@ -312,11 +315,11 @@ class Recorder extends Plugin {
abis = json.abis || {} abis = json.abis || {}
linkReferences = json.linkReferences || {} linkReferences = json.linkReferences || {}
} catch (e) { } catch (e) {
return cb('Invalid Scenario File. Please try again') return cb('Invalid scenario file. Please try again')
} }
if (!txArray.length) { if (!txArray.length) {
return return cb('No transactions found in scenario file')
} }
this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, (abi, address, contractName) => { this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, liveMode, (abi, address, contractName) => {

@ -8,11 +8,12 @@ const profile = {
methods: [''], methods: [''],
events: [], events: [],
icon: 'assets/img/search_icon.webp', icon: 'assets/img/search_icon.webp',
description: '', description: 'Find and replace in file explorer',
kind: '', kind: '',
location: 'sidePanel', location: 'sidePanel',
documentation: '', documentation: '',
version: packageJson.version version: packageJson.version,
maintainedBy: 'Remix'
} }
export class SearchPlugin extends ViewPlugin { export class SearchPlugin extends ViewPlugin {

@ -16,9 +16,10 @@ const profile = {
methods: ['testFromPath', 'testFromSource', 'setTestFolderPath', 'getTestlibs', 'createTestLibs'], methods: ['testFromPath', 'testFromSource', 'setTestFolderPath', 'getTestlibs', 'createTestLibs'],
events: [], events: [],
icon: 'assets/img/unitTesting.webp', icon: 'assets/img/unitTesting.webp',
description: 'Fast tool to generate unit tests for your contracts', description: 'Write and run unit tests for your contracts in Solidity',
location: 'sidePanel', location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/unittesting.html' documentation: 'https://remix-ide.readthedocs.io/en/latest/unittesting.html',
maintainedBy: 'Remix'
} }
module.exports = class TestTab extends ViewPlugin { module.exports = class TestTab extends ViewPlugin {

@ -12,11 +12,12 @@ const profile = {
name: 'udapp', name: 'udapp',
displayName: 'Deploy & run transactions', displayName: 'Deploy & run transactions',
icon: 'assets/img/deployAndRun.webp', icon: 'assets/img/deployAndRun.webp',
description: 'execute and save transactions', description: 'Execute, save and replay transactions',
kind: 'udapp', kind: 'udapp',
location: 'sidePanel', location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/run.html', documentation: 'https://remix-ide.readthedocs.io/en/latest/run.html',
version: packageJson.version, version: packageJson.version,
maintainedBy: 'Remix',
permission: true, permission: true,
events: ['newTransaction'], events: ['newTransaction'],
methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance', 'resolveContractAndAddInstance'] methods: ['createVMAccount', 'sendTransaction', 'getAccounts', 'pendingTransactionsCount', 'getSettings', 'setEnvironmentMode', 'clearAllInstances', 'addInstance', 'resolveContractAndAddInstance']

@ -9,7 +9,7 @@ const profile = {
displayName: 'Home', displayName: 'Home',
methods: [], methods: [],
events: [], events: [],
description: ' - ', description: 'Remix home tab ',
icon: 'assets/img/remixLogo.webp', icon: 'assets/img/remixLogo.webp',
location: 'mainPanel', location: 'mainPanel',
version: packageJson.version version: packageJson.version

@ -141,9 +141,9 @@ export class Blockchain extends Plugin {
async deployProxy (proxyData, implementationContractObject) { async deployProxy (proxyData, implementationContractObject) {
const proxyModal = { const proxyModal = {
id: 'confirmProxyDeployment', id: 'confirmProxyDeployment',
title: 'ERC1967', title: 'Confirm Deploy Proxy (ERC1967)',
message: `Confirm you want to deploy an ERC1967 proxy contract that is connected to your implementation. message: `Confirm you want to deploy an ERC1967 proxy contract that is connected to your implementation.
For more info on ERC1967, see https://docs.openzeppelin.com/contracts/4.x/api/proxy#ERC1967Proxy`, For more info on ERC1967, see: https://docs.openzeppelin.com/contracts/4.x/api/proxy#ERC1967Proxy`,
modalType: 'modal', modalType: 'modal',
okLabel: 'OK', okLabel: 'OK',
cancelLabel: 'Cancel', cancelLabel: 'Cancel',
@ -189,8 +189,8 @@ export class Blockchain extends Plugin {
async upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) { async upgradeProxy(proxyAddress, newImplAddress, data, newImplementationContractObject) {
const upgradeModal = { const upgradeModal = {
id: 'confirmProxyDeployment', id: 'confirmProxyDeployment',
title: 'ERC1967', title: 'Confirm Update Proxy (ERC1967)',
message: `Confirm you want to upgrade your contract to new implementation ${newImplAddress}.`, message: `Confirm you want to update your proxy contract with the new implementation contract's address: ${newImplAddress}.`,
modalType: 'modal', modalType: 'modal',
okLabel: 'OK', okLabel: 'OK',
cancelLabel: 'Cancel', cancelLabel: 'Cancel',

@ -8,7 +8,8 @@ const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', 'hardhat-provider', 'compileAndRun', 'search'] 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy',
'hardhat-provider', 'compileAndRun', 'search', 'recorder']
const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd) const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)

@ -5,7 +5,7 @@ const introJs = require('intro.js')
const profile = { const profile = {
name: 'walkthrough', name: 'walkthrough',
displayName: 'Walkthrough', displayName: 'Walkthrough',
description: '', description: 'Remix walkthrough for beginner',
version: packageJson.version, version: packageJson.version,
methods: ['start'] methods: ['start']
} }

@ -98,12 +98,20 @@ export const cancelUpgradeMsg = () => (
export const deployWithProxyMsg = () => ( export const deployWithProxyMsg = () => (
<div> <div>
NOTE: Deploy With Proxy will initiate two (2) transactions. The first is for the deployment of your implementation contract and the second will be a deployment of an ERC1967 proxy contract. <b>Deploy with Proxy</b> will initiate two (2) transactions:
<ol className="pl-3">
<li>Deploying the implementation contract</li>
<li>Deploying an ERC1967 proxy contract</li>
</ol>
</div> </div>
) )
export const upgradeWithProxyMsg = () => ( export const upgradeWithProxyMsg = () => (
<div> <div>
NOTE: Upgrade With Proxy will initiate two (2) transactions. The first is for the deployment of your implementation contract and the second will intiate a call to the upgradeTo function in your proxy contract. <b>Upgrade with Proxy</b> will initiate two (2) transactions:
<ol className="pl-3">
<li>Deploying the new implementation contract</li>
<li>Updating the proxy contract with the address of the new implementation contract</li>
</ol>
</div> </div>
) )

@ -160,8 +160,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const isProxyDeployment = (deployMode || []).find(mode => mode === 'Deploy with Proxy') const isProxyDeployment = (deployMode || []).find(mode => mode === 'Deploy with Proxy')
const isContractUpgrade = (deployMode || []).find(mode => mode === 'Upgrade with Proxy') const isContractUpgrade = (deployMode || []).find(mode => mode === 'Upgrade with Proxy')
if (isProxyDeployment || isContractUpgrade) { if (isProxyDeployment) {
props.modal('ERC1967', isProxyDeployment ? deployWithProxyMsg() : upgradeWithProxyMsg(), 'Proceed', () => { props.modal('Deploy Implementation & Proxy (ERC1967)', deployWithProxyMsg(), 'Proceed', () => {
props.createInstance(loadedContractData, props.gasEstimationPrompt, props.passphrasePrompt, props.publishToStorage, props.mainnetPrompt, isOverSizePrompt, args, deployMode)
}, 'Cancel', () => {})
} else if (isContractUpgrade) {
props.modal('Deploy Implementation & Update Proxy', upgradeWithProxyMsg(), 'Proceed', () => {
props.createInstance(loadedContractData, props.gasEstimationPrompt, props.passphrasePrompt, props.publishToStorage, props.mainnetPrompt, isOverSizePrompt, args, deployMode) props.createInstance(loadedContractData, props.gasEstimationPrompt, props.passphrasePrompt, props.publishToStorage, props.mainnetPrompt, isOverSizePrompt, args, deployMode)
}, 'Cancel', () => {}) }, 'Cancel', () => {})
} else { } else {

@ -273,7 +273,7 @@ export function ContractGUI (props: ContractGUIProps) {
className="m-0 form-check-label custom-control-label udapp_checkboxAlign" className="m-0 form-check-label custom-control-label udapp_checkboxAlign"
title="An ERC1967 proxy contract will be deployed along with the selected implementation contract." title="An ERC1967 proxy contract will be deployed along with the selected implementation contract."
> >
Deploy With Proxy Deploy with Proxy
</label> </label>
</div> </div>
<div> <div>
@ -314,9 +314,9 @@ export function ContractGUI (props: ContractGUIProps) {
htmlFor="upgradeImplementation" htmlFor="upgradeImplementation"
data-id="contractGUIUpgradeImplementationLabel" data-id="contractGUIUpgradeImplementationLabel"
className="m-0 form-check-label custom-control-label udapp_checkboxAlign" className="m-0 form-check-label custom-control-label udapp_checkboxAlign"
title="The implemetation address will be updated to a new address in the proxy contract." title="The implementation contract will be deployed and then the proxy contract will be updated with new implementation's address."
> >
Upgrade With Proxy Upgrade with Proxy
</label> </label>
</div> </div>
<span onClick={handleToggleUpgradeImp}> <span onClick={handleToggleUpgradeImp}>

@ -1,11 +1,12 @@
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
import React, {useRef, useState} from 'react' import React, {useRef, useState, useEffect} from 'react'
import { RecorderProps } from '../types' import { RecorderProps } from '../types'
import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line
export function RecorderUI (props: RecorderProps) { export function RecorderUI (props: RecorderProps) {
const inputLive = useRef<HTMLInputElement>() const inputLive = useRef<HTMLInputElement>()
const [toggleExpander, setToggleExpander] = useState<boolean>(false) const [toggleExpander, setToggleExpander] = useState<boolean>(false)
const [enableRunButton, setEnableRunButton] = useState<boolean>(true)
const triggerRecordButton = () => { const triggerRecordButton = () => {
props.storeScenario(props.scenarioPrompt) props.storeScenario(props.scenarioPrompt)
} }
@ -15,6 +16,11 @@ export function RecorderUI (props: RecorderProps) {
props.runCurrentScenario(liveMode, props.gasEstimationPrompt, props.passphrasePrompt, props.mainnetPrompt) props.runCurrentScenario(liveMode, props.gasEstimationPrompt, props.passphrasePrompt, props.mainnetPrompt)
} }
useEffect(() => {
if (props.currentFile.endsWith('.json')) setEnableRunButton(false)
else setEnableRunButton(true)
}, [props.currentFile])
const toggleClass = () => { const toggleClass = () => {
setToggleExpander(!toggleExpander) setToggleExpander(!toggleExpander)
} }
@ -43,24 +49,28 @@ export function RecorderUI (props: RecorderProps) {
<div className={`flex-column ${toggleExpander ? "d-flex" : "d-none"}`}> <div className={`flex-column ${toggleExpander ? "d-flex" : "d-none"}`}>
<div className="mb-1 mt-1 fmt-2 custom-control custom-checkbox mb-1"> <div className="mb-1 mt-1 fmt-2 custom-control custom-checkbox mb-1">
<input ref={inputLive} type="checkbox" id="livemode-recorder" className="custom-control-input custom-select" name="input-livemode"/> <input ref={inputLive} type="checkbox" id="livemode-recorder" className="custom-control-input custom-select" name="input-livemode"/>
<label className="form-check-label custom-control-label" data-id="runtabLivemodeInput" htmlFor="livemode-recorder">Use live mode (Run transactions against latest compiled contracts).</label> <OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="tooltip-livemode-recorder">
<span>If contracts are updated after recording transactions, checking this box<br/>will run recorded transactions with the latest copy of the compiled contracts</span>
</Tooltip>
}>
<label className="form-check-label custom-control-label" data-id="runtabLivemodeInput" htmlFor="livemode-recorder">Run transactions using the latest compilation result</label>
</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={'right'} overlay={
<Tooltip className="text-nowrap" id="tooltip-save-recorder"> <Tooltip className="text-nowrap" id="tooltip-save-recorder">
<span>Save {props.count} transaction(s) as scenario file. <span>Save {props.count} transaction{props.count === 1 ? '' : 's'} as scenario file</span>
</span>
</Tooltip> </Tooltip>
}> }>
<button className="btn btn-sm btn-info savetransaction udapp_recorder" onClick={triggerRecordButton}>Save</button> <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>
</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>Run transaction(s) from the current scenario file</span>
</span>
</Tooltip> </Tooltip>
}> }>
<button className="btn btn-sm btn-info runtransaction udapp_runTxs" data-id="runtransaction" onClick={handleClickRunButton}>Run</button> <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>
</OverlayTrigger> </OverlayTrigger>
</div> </div>
</div> </div>

@ -56,10 +56,11 @@ export function RunTabUI (props: RunTabProps) {
storage: null, storage: null,
contract: null contract: null
}) })
runTabInitialState.selectExEnv = props.plugin.blockchain.getProvider() runTabInitialState.selectExEnv = plugin.blockchain.getProvider()
runTabInitialState.selectExEnv = runTabInitialState.selectExEnv === 'vm' ? 'vm-london' : runTabInitialState.selectExEnv runTabInitialState.selectExEnv = runTabInitialState.selectExEnv === 'vm' ? 'vm-london' : runTabInitialState.selectExEnv
const [runTab, dispatch] = useReducer(runTabReducer, runTabInitialState) const [runTab, dispatch] = useReducer(runTabReducer, runTabInitialState)
const REACT_API = { runTab } const REACT_API = { runTab }
const currentfile = plugin.config.get('currentFile')
useEffect(() => { useEffect(() => {
initRunTab(plugin)(dispatch) initRunTab(plugin)(dispatch)
@ -249,6 +250,7 @@ export function RunTabUI (props: RunTabProps) {
runCurrentScenario={runScenario} runCurrentScenario={runScenario}
scenarioPrompt={scenarioPrompt} scenarioPrompt={scenarioPrompt}
count={runTab.recorder.transactionCount} count={runTab.recorder.transactionCount}
currentFile={currentfile}
/> />
<InstanceContainerUI <InstanceContainerUI
instances={runTab.instances} instances={runTab.instances}
@ -266,7 +268,7 @@ export function RunTabUI (props: RunTabProps) {
</div> </div>
<ModalDialog id='udappNotify' { ...focusModal } handleHide={ handleHideModal } /> <ModalDialog id='udappNotify' { ...focusModal } handleHide={ handleHideModal } />
<Toaster message={focusToaster} handleHide={handleToaster} /> <Toaster message={focusToaster} handleHide={handleToaster} />
<PublishToStorage id='udapp' api={props.plugin} resetStorage={resetStorage} storage={publishData.storage} contract={publishData.contract} /> <PublishToStorage id='udapp' api={plugin} resetStorage={resetStorage} storage={publishData.storage} contract={publishData.contract} />
</Fragment> </Fragment>
) )
} }

@ -173,6 +173,7 @@ export interface RecorderProps {
passphrasePrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element,
scenarioPrompt: (msg: string, defaultValue: string) => JSX.Element, scenarioPrompt: (msg: string, defaultValue: string) => JSX.Element,
count: number count: number
currentFile: string
} }
export interface InstanceContainerProps { export interface InstanceContainerProps {

@ -2,7 +2,7 @@ import React from 'react'
import { bufferToHex, keccakFromString } from 'ethereumjs-util' import { bufferToHex, keccakFromString } from 'ethereumjs-util'
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace } from './payload' import { addInputFieldSuccess, cloneRepositoryFailed, cloneRepositoryRequest, cloneRepositorySuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, hideNotification, setCurrentWorkspace, setDeleteWorkspace, setMode, setReadOnlyMode, setRenameWorkspace } from './payload'
import { checkSlash, checkSpecialChars, createNonClashingTitle } from '@remix-ui/helper' import { checkSlash, checkSpecialChars } from '@remix-ui/helper'
import { JSONStandardInput, WorkspaceTemplate } from '../types' import { JSONStandardInput, WorkspaceTemplate } from '../types'
import { QueryParams } from '@remix-project/remix-lib' import { QueryParams } from '@remix-project/remix-lib'
@ -333,11 +333,10 @@ export const cloneRepository = async (url: string) => {
const config = plugin.registry.get('config').api const config = plugin.registry.get('config').api
const token = config.get('settings/gist-access-token') const token = config.get('settings/gist-access-token')
const repoConfig = { url, token } const repoConfig = { url, token }
const urlArray = url.split('/')
let repoName = urlArray.length > 0 ? urlArray[urlArray.length - 1] : ''
try { try {
repoName = await createNonClashingTitle(repoName, plugin.fileManager) const repoName = await getRepositoryTitle(url)
await createWorkspace(repoName, 'blank', true, null, true) await createWorkspace(repoName, 'blank', true, null, true)
const promise = plugin.call('dGitProvider', 'clone', repoConfig, repoName, true) const promise = plugin.call('dGitProvider', 'clone', repoConfig, repoName, true)
@ -348,11 +347,11 @@ export const cloneRepository = async (url: string) => {
if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit') if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit')
await fetchWorkspaceDirectory(repoName) await fetchWorkspaceDirectory(repoName)
dispatch(cloneRepositorySuccess()) dispatch(cloneRepositorySuccess())
}).catch((e) => { }).catch(() => {
const cloneModal = { const cloneModal = {
id: 'cloneGitRepository', id: 'cloneGitRepository',
title: 'Clone Git Repository', title: 'Clone Git Repository',
message: 'An error occured: ' + e, message: 'An error occurred: Please check that you have the correct URL for the repo. If the repo is private, you need to add your github credentials (with the valid token permissions) in Settings plugin',
modalType: 'modal', modalType: 'modal',
okLabel: 'OK', okLabel: 'OK',
okFn: async () => { okFn: async () => {
@ -370,3 +369,22 @@ export const cloneRepository = async (url: string) => {
dispatch(displayPopUp('An error occured: ' + e)) dispatch(displayPopUp('An error occured: ' + e))
} }
} }
export const getRepositoryTitle = async (url: string) => {
const urlArray = url.split('/')
let name = urlArray.length > 0 ? urlArray[urlArray.length - 1] : ''
if (!name) name = 'Undefined'
let _counter
let exist = true
do {
const isDuplicate = await workspaceExists(name + (_counter || ''))
if (isDuplicate) _counter = (_counter || 0) + 1
else exist = false
} while (exist)
const counter = _counter || ''
return name + counter
}

Loading…
Cancel
Save