Merge branch 'master' into targets2

pull/5370/head
bunsenstraat 4 years ago committed by GitHub
commit 5f58c9c139
  1. 4
      apps/remix-ide-e2e/src/tests/fileManager_api.spec.ts
  2. 5
      apps/remix-ide/src/app.js
  3. 8
      apps/remix-ide/src/app/files/fileManager.js
  4. 18
      apps/remix-ide/src/app/files/remixd-handle.js
  5. 71
      apps/remix-ide/src/app/tabs/hardhat-provider.js
  6. 51
      apps/remix-ide/src/app/ui/confirmDialog.js
  7. 7
      apps/remix-ide/src/blockchain/execution-context.js
  8. 14
      apps/remix-ide/src/lib/helper.js
  9. 4
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx

@ -147,8 +147,8 @@ const executeReadFile = `
const executeCopyFile = `
const run = async () => {
await remix.call('fileManager', 'copyFile', 'contracts/3_Ballot.sol', '/', 'new_contract.sol')
const result = await remix.call('fileManager', 'readFile', 'new_contract.sol')
await remix.call('fileManager', 'copyFile', 'contracts/3_Ballot.sol', '/', 'copy_contract.sol')
const result = await remix.call('fileManager', 'readFile', 'copy_contract.sol')
console.log(result)
}

@ -29,6 +29,7 @@ const { OffsetToLineColumnConverter } = require('./lib/offsetToLineColumnConvert
const QueryParams = require('./lib/query-params')
const Storage = remixLib.Storage
const RemixDProvider = require('./app/files/remixDProvider')
const HardhatProvider = require('./app/tabs/hardhat-provider')
const Config = require('./config')
const modalDialogCustom = require('./app/ui/modal-dialog-custom')
const modalDialog = require('./app/ui/modaldialog')
@ -274,6 +275,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const networkModule = new NetworkModule(blockchain)
// ----------------- represent the current selected web3 provider ----
const web3Provider = new Web3ProviderModule(blockchain)
const hardhatProvider = new HardhatProvider(blockchain)
// ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
registry.put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' })
@ -309,7 +311,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
contextualListener,
terminal,
web3Provider,
fetchAndCompile
fetchAndCompile,
hardhatProvider
])
// LAYOUT & SYSTEM VIEWS

@ -222,9 +222,10 @@ class FileManager extends Plugin {
await this._handleExists(dest, `Cannot paste content into ${dest}. Path does not exist.`)
await this._handleIsDir(dest, `Cannot paste content into ${dest}. Path is not directory.`)
const content = await this.readFile(src)
const copiedFileName = customName ? '/' + customName : '/' + `Copy_${helper.extractNameFromKey(src)}`
let copiedFilePath = dest + (customName ? '/' + customName : '/' + `Copy_${helper.extractNameFromKey(src)}`)
copiedFilePath = await helper.createNonClashingNameAsync(copiedFilePath, this)
await this.writeFile(dest + copiedFileName, content)
await this.writeFile(copiedFilePath, content)
} catch (e) {
throw new Error(e)
}
@ -252,7 +253,8 @@ class FileManager extends Plugin {
async inDepthCopy (src, dest, count = 0) {
const content = await this.readdir(src)
const copiedFolderPath = count === 0 ? dest + '/' + `Copy_${helper.extractNameFromKey(src)}` : dest + '/' + helper.extractNameFromKey(src)
let copiedFolderPath = count === 0 ? dest + '/' + `Copy_${helper.extractNameFromKey(src)}` : dest + '/' + helper.extractNameFromKey(src)
copiedFolderPath = await helper.createNonClashingDirNameAsync(copiedFolderPath, this)
await this.mkdir(copiedFolderPath)

@ -4,6 +4,7 @@ import * as packageJson from '../../../../../package.json'
var yo = require('yo-yo')
var modalDialog = require('../ui/modaldialog')
var modalDialogCustom = require('../ui/modal-dialog-custom')
var copyToClipboard = require('../ui/copy-to-clipboard')
var csjs = require('csjs-inject')
@ -130,22 +131,27 @@ export class RemixdHandle extends WebsocketPlugin {
}
function remixdDialog () {
const commandText = 'remixd -s absolute-path-to-the-shared-folder --remix-ide your-remix-ide-URL-instance'
return yo`
<div class=${css.dialog}>
<div class=${css.dialogParagraph}>Interact with your file system from Remix. <br>See the <a target="_blank" href="https://remix-ide.readthedocs.io/en/latest/remixd.html">Remixd tutorial</a> for more info.
<div class=${css.dialogParagraph}>
Access your file system from Remix IDE. Remixd the NPM module needs to be running in the background to use the Remixd plugin. For more info please check the <a target="_blank" href="https://remix-ide.readthedocs.io/en/latest/remixd.html">Remixd tutorial</a>.
</div>
<div class=${css.dialogParagraph}>If you are just looking for the remixd command here it is:
<br><br><b>remixd -s absolute-path-to-the-shared-folder --remix-ide your-remix-ide-URL-instance</b>
<span class="">${copyToClipboard(() => commandText)}</span>
</div>
<div class=${css.dialogParagraph}>If you have looked at the Remixd docs and just need remixd command, <br> here it is:
<br><b>remixd -s absolute-path-to-the-shared-folder --remix-ide your-remix-ide-URL-instance</b>
<div class=${css.dialogParagraph}>A connection will start a session between <em>${window.location.origin}</em> and your local file system <i>ws://127.0.0.1:65520</i>
<br>To see that a connection has been made, check that there is a localhost section in the Files Explorer
</div>
<div class=${css.dialogParagraph}>Connection will start a session between <em>${window.location.origin}</em> and your local file system <i>ws://127.0.0.1:65520</i>
so please make sure your system is secured enough (port 65520 neither opened nor forwarded).
<div class=${css.dialogParagraph}>Please make sure your system is secured enough (port 65520 should not be opened nor forwarded).
This feature is still in Alpha, so we recommend you to keep a copy of the shared folder.
</div>
<div class=${css.dialogParagraph}>
<h6 class="text-danger">
Before using, make sure you have the <b>latest remixd version</b>.<br><a target="_blank" href="https://remix-ide.readthedocs.io/en/latest/remixd.html#update-to-the-latest-remixd">Read here how to update it</a>
</h6>
</div>
<div class=${css.dialogParagraph}>This feature is still in Alpha, so we recommend you to keep a copy of the shared folder.</div>
</div>
`
}

@ -0,0 +1,71 @@
import * as packageJson from '../../../../../package.json'
import { Plugin } from '@remixproject/engine'
import Web3 from 'web3'
const yo = require('yo-yo')
const modalDialogCustom = require('../ui/modal-dialog-custom')
const profile = {
name: 'hardhat-provider',
displayName: 'Hardhat Provider',
kind: 'provider',
description: 'Hardhat provider',
methods: ['sendAsync'],
version: packageJson.version
}
export default class HardhatProvider extends Plugin {
constructor (blockchain) {
super(profile)
this.provider = null
this.blockchain = blockchain
}
onDeactivation () {
this.provider = null
}
hardhatProviderDialogBody () {
return yo`
<div class="">
Note: To run Hardhat network node on your system, go to hardhat project folder and run command:
<div class="border p-1">npx hardhat node</div>
<br>
For more info, visit: <a href="https://hardhat.org/getting-started/#connecting-a-wallet-or-dapp-to-hardhat-network" target="_blank">Hardhat Documentation</a>
<br><br>
Hardhat JSON-RPC Endpoint
</div>
`
}
sendAsync (data) {
return new Promise((resolve, reject) => {
if (!this.provider) {
modalDialogCustom.prompt('Hardhat node request', this.hardhatProviderDialogBody(), 'http://127.0.0.1:8545', (target) => {
this.provider = new Web3.providers.HttpProvider(target)
this.sendAsyncInternal(data, resolve, reject)
}, () => {
this.sendAsyncInternal(data, resolve, reject)
})
} else {
this.sendAsyncInternal(data, resolve, reject)
}
})
}
sendAsyncInternal (data, resolve, reject) {
if (this.provider) {
this.provider[this.provider.sendAsync ? 'sendAsync' : 'send'](data, (error, message) => {
if (error) {
this.provider = null
return reject(error)
}
resolve(message)
})
} else {
const result = data.method === 'net_listening' ? 'canceled' : []
resolve({ jsonrpc: '2.0', result: result, id: data.id })
}
}
}
module.exports = HardhatProvider

@ -26,21 +26,46 @@ function confirmDialog (tx, amount, gasEstimation, self, newGasPriceCb, initialP
var el = yo`
<div>
<div>You are creating a transaction on the main network. Click confirm if you are sure to continue.</div>
<div class=${css.txInfoBox}>
<div>From: ${tx.from}</div>
<div>To: ${tx.to ? tx.to : '(Contract Creation)'}</div>
<div>Amount: ${amount} Ether</div>
<div>Gas estimation: ${gasEstimation}</div>
<div>Gas limit: ${tx.gas}</div>
<div>Gas price: <input id='gasprice' oninput=${onGasPriceChange} /> Gwei <span> (visit <a target='_blank' href='https://ethgasstation.info'>ethgasstation.info</a> to get more info about gas price)</span></div>
<div>Max transaction fee:<span id='txfee'></span></div>
<div>Data:</div>
<div>You are about to create a transaction on the Main Network. Confirm the details to send the info to your provider.
<br>The provider for many users is MetaMask. The provider will ask you to sign the transaction before it is sent to the Main Network.</div>
<div class="mt-3 ${css.txInfoBox}">
<div>
<span class="text-dark mr-2">From:</span>
<span>${tx.from}</span>
</div>
<div>
<span class="text-dark mr-2">To:</span>
<span>${tx.to ? tx.to : '(Contract Creation)'}</span>
</div>
<div>
<span class="text-dark mr-2">Amount:</span>
<span>${amount} Ether</span>
</div>
<div>
<span class="text-dark mr-2">Gas estimation:</span>
<span>${gasEstimation}</span>
</div>
<div>
<span class="text-dark mr-2">Gas limit:</span>
<span>${tx.gas}</span>
</div>
<div>
<span class="text-dark mr-2">Max transaction fee:</span>
<span id='txfee'></span>
</div>
<div class="d-flex align-items-center my-1">
<span class="text-dark mr-2">Gas price:</span>
<input class="form-control mr-1" style='width: 40px; height: 28px;'id='gasprice' oninput=${onGasPriceChange} />
<span>Gwei (visit <a target='_blank' href='https://ethgasstation.info'>ethgasstation.info</a> for current gas price info.)</span>
</div>
<div class="d-flex align-items-center">
<span class="text-dark mr-2 mb-3">Data:</span>
<pre class=${css.wrapword}>${tx.data && tx.data.length > 50 ? tx.data.substring(0, 49) + '...' : tx.data} ${copyToClipboard(() => { return tx.data })}</pre>
</div>
<div class=${css.checkbox}>
<input id='confirmsetting' type="checkbox">
<i class="fas fa-exclamation-triangle" aria-hidden="true"></i> Do not ask for confirmation again. (the setting will not be persisted for the next page reload)
</div>
<div class="d-flex py-1 align-items-center custom-control custom-checkbox ${css.checkbox}">
<input class="form-check-input custom-control-input" id='confirmsetting' type="checkbox">
<label class="m-0 form-check-label custom-control-label">Do not show this warning again.</label>
</div>
</div>
`

@ -145,7 +145,6 @@ export class ExecutionContext {
if (context === 'web3') {
confirmCb(cb)
}
if (this.customNetWorks[context]) {
var network = this.customNetWorks[context]
this.setProviderFromEndpoint(network.provider, network.name, (error) => {
@ -189,14 +188,16 @@ export class ExecutionContext {
const oldProvider = web3.currentProvider
web3.setProvider(endpoint)
web3.eth.net.isListening((err, isConnected) => {
if (!err && isConnected) {
if (!err && isConnected === true) {
this.executionContext = context
this._updateBlockGasLimit()
this.event.trigger('contextChanged', [context])
this.event.trigger('web3EndpointChanged')
cb()
} else if (isConnected === 'canceled') {
web3.setProvider(oldProvider)
cb()
} else {
web3.setProvider(oldProvider)
cb('Not possible to connect to the Web3 provider. Make sure the provider is running, a connection is open (via IPC or RPC) or that the provider plugin is properly configured.')

@ -71,6 +71,20 @@ module.exports = {
return name + counter + prefix + '.' + ext
},
async createNonClashingDirNameAsync (name, fileManager) {
if (!name) name = 'Undefined'
let counter = ''
let exist = true
do {
const isDuplicate = await fileManager.exists(name + counter)
if (isDuplicate) counter = (counter | 0) + 1
else exist = false
} while (exist)
return name + counter
},
checkSpecialChars (name) {
return name.match(/[:*?"<>\\'|]/) != null
},

@ -763,10 +763,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
state.copyElement.map(({ key, type }) => {
type === 'file' ? copyFile(key, dest) : copyFolder(key, dest)
})
setState(prevState => {
return { ...prevState, copyElement: [] }
})
setCanPaste(false)
}
const label = (file: File) => {

Loading…
Cancel
Save