pull/1218/head
filip mertens 4 years ago
commit 71bb22ce5b
  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. 7
      apps/remix-ide/src/blockchain/execution-context.js
  7. 14
      apps/remix-ide/src/lib/helper.js
  8. 4
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx

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

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

@ -232,9 +232,10 @@ class FileManager extends Plugin {
await this._handleExists(dest, `Cannot paste content into ${dest}. Path does not exist.`) 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.`) await this._handleIsDir(dest, `Cannot paste content into ${dest}. Path is not directory.`)
const content = await this.readFile(src) 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) { } catch (e) {
throw new Error(e) throw new Error(e)
} }
@ -262,7 +263,8 @@ class FileManager extends Plugin {
async inDepthCopy (src, dest, count = 0) { async inDepthCopy (src, dest, count = 0) {
const content = await this.readdir(src) 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) await this.mkdir(copiedFolderPath)

@ -4,6 +4,7 @@ import * as packageJson from '../../../../../package.json'
var yo = require('yo-yo') var yo = require('yo-yo')
var modalDialog = require('../ui/modaldialog') var modalDialog = require('../ui/modaldialog')
var modalDialogCustom = require('../ui/modal-dialog-custom') var modalDialogCustom = require('../ui/modal-dialog-custom')
var copyToClipboard = require('../ui/copy-to-clipboard')
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
@ -130,22 +131,27 @@ export class RemixdHandle extends WebsocketPlugin {
} }
function remixdDialog () { function remixdDialog () {
const commandText = 'remixd -s absolute-path-to-the-shared-folder --remix-ide your-remix-ide-URL-instance'
return yo` return yo`
<div class=${css.dialog}> <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>
<div class=${css.dialogParagraph}>If you have looked at the Remixd docs and just need remixd command, <br> here it is: <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><b>remixd -s absolute-path-to-the-shared-folder --remix-ide your-remix-ide-URL-instance</b> <br>To see that a connection has been made, check that there is a localhost section in the Files Explorer
</div> </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> <div class=${css.dialogParagraph}>Please make sure your system is secured enough (port 65520 should not be opened nor forwarded).
so please make sure your system is secured enough (port 65520 neither opened nor forwarded). This feature is still in Alpha, so we recommend you to keep a copy of the shared folder.
</div> </div>
<div class=${css.dialogParagraph}> <div class=${css.dialogParagraph}>
<h6 class="text-danger"> <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> 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> </h6>
</div> </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> </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

@ -145,7 +145,6 @@ export class ExecutionContext {
if (context === 'web3') { if (context === 'web3') {
confirmCb(cb) confirmCb(cb)
} }
if (this.customNetWorks[context]) { if (this.customNetWorks[context]) {
var network = this.customNetWorks[context] var network = this.customNetWorks[context]
this.setProviderFromEndpoint(network.provider, network.name, (error) => { this.setProviderFromEndpoint(network.provider, network.name, (error) => {
@ -189,14 +188,16 @@ export class ExecutionContext {
const oldProvider = web3.currentProvider const oldProvider = web3.currentProvider
web3.setProvider(endpoint) web3.setProvider(endpoint)
web3.eth.net.isListening((err, isConnected) => { web3.eth.net.isListening((err, isConnected) => {
if (!err && isConnected) { if (!err && isConnected === true) {
this.executionContext = context this.executionContext = context
this._updateBlockGasLimit() this._updateBlockGasLimit()
this.event.trigger('contextChanged', [context]) this.event.trigger('contextChanged', [context])
this.event.trigger('web3EndpointChanged') this.event.trigger('web3EndpointChanged')
cb() cb()
} else if (isConnected === 'canceled') {
web3.setProvider(oldProvider)
cb()
} else { } else {
web3.setProvider(oldProvider) 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.') 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 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) { checkSpecialChars (name) {
return name.match(/[:*?"<>\\'|]/) != null return name.match(/[:*?"<>\\'|]/) != null
}, },

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

Loading…
Cancel
Save