Commit 2e7a02fd authored by gxkai's avatar gxkai

chore: 与baas通讯

parent 61f0cf6b
......@@ -142,7 +142,6 @@ class App {
// setup storage
const configStorage = new Storage('config-v0.8:')
// load app config
const config = new Config(configStorage)
registry.put({ api: config, name: 'config' })
......@@ -157,8 +156,19 @@ class App {
registry.put({ api: self._components.filesProviders.workspace, name: 'fileproviders/workspace' })
registry.put({ api: self._components.filesProviders, name: 'fileproviders' })
migrateFileSystem(self._components.filesProviders.browser)
// 请求token
window.parent.postMessage({event: 'getToken'}, '\*')
window.addEventListener("message", this.handleListenMessage, false)
}
handleListenMessage(event$){
const {event,data: token} = event$.data
if (!event) return
// 接收token
if (event === 'giveToken') {
registry.put({api: token, name: 'baas-token'})
}
}
init () {
......@@ -507,7 +517,7 @@ class App {
}).catch(console.error)
} else {
// activate solidity plugin
appManager.activatePlugin(['solidity', 'udapp'])
appManager.activatePlugin(['solidity', 'udapp','debugger'])
}
})
......
......@@ -21,7 +21,7 @@ contract Storage {
}
/**
* @dev Return value
* @dev Return value
* @return value of 'number'
*/
function retrieve() public view returns (uint256){
......@@ -40,10 +40,10 @@ pragma solidity >=0.7.0 <0.9.0;
contract Owner {
address private owner;
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
......@@ -54,7 +54,7 @@ contract Owner {
require(msg.sender == owner, "Caller is not owner");
_;
}
/**
* @dev Set contract deployer as owner
*/
......@@ -73,7 +73,7 @@ contract Owner {
}
/**
* @dev Return owner address
* @dev Return owner address
* @return address of owner
*/
function getOwner() external view returns (address) {
......@@ -85,12 +85,12 @@ const ballot = `// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
/**
* @title Ballot
* @dev Implements voting process along with vote delegation
*/
contract Ballot {
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
......@@ -99,7 +99,7 @@ contract Ballot {
}
struct Proposal {
// If you can limit the length to a certain number of bytes,
// If you can limit the length to a certain number of bytes,
// always use one of bytes1 to bytes32 because they are much cheaper
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
......@@ -111,7 +111,7 @@ contract Ballot {
Proposal[] public proposals;
/**
/**
* @dev Create a new ballot to choose one of 'proposalNames'.
* @param proposalNames names of proposals
*/
......@@ -129,8 +129,8 @@ contract Ballot {
}));
}
}
/**
/**
* @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.
* @param voter address of voter
*/
......@@ -193,7 +193,7 @@ contract Ballot {
proposals[proposal].voteCount += sender.weight;
}
/**
/**
* @dev Computes the winning proposal taking all previous votes into account.
* @return winningProposal_ index of winning proposal in the proposals array
*/
......@@ -209,7 +209,7 @@ contract Ballot {
}
}
/**
/**
* @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then
* @return winnerName_ the name of the winner
*/
......@@ -228,21 +228,21 @@ import "remix_tests.sol"; // this import is automatically injected by Remix.
import "../contracts/3_Ballot.sol";
contract BallotTest {
bytes32[] proposalNames;
Ballot ballotToTest;
function beforeAll () public {
proposalNames.push(bytes32("candidate1"));
ballotToTest = new Ballot(proposalNames);
}
function checkWinningProposal () public {
ballotToTest.vote(0);
Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name");
}
function checkWinninProposalWithReturnValue () public view returns (bool) {
return ballotToTest.winningProposal() == 0;
}
......@@ -252,24 +252,24 @@ const deployWithWeb3 = `// Right click on the script name and hit "Run" to execu
(async () => {
try {
console.log('Running deployWithWeb3 script...')
const contractName = 'Storage' // Change this for other contract
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = \`browser/contracts/artifacts/\${contractName}.json\` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
const accounts = await web3.eth.getAccounts()
let contract = new web3.eth.Contract(metadata.abi)
contract = contract.deploy({
data: metadata.data.bytecode.object,
arguments: constructorArgs
})
const newContractInstance = await contract.send({
from: accounts[0],
gas: 1500000,
......@@ -285,24 +285,24 @@ const deployWithEthers = `// Right click on the script name and hit "Run" to exe
(async () => {
try {
console.log('Running deployWithEthers script...')
const contractName = 'Storage' // Change this for other contract
const constructorArgs = [] // Put constructor args (if any) here for your contract
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = \`browser/contracts/artifacts/\${contractName}.json\` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()
let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);
let contract = await factory.deploy(...constructorArgs);
console.log('Contract Address: ', contract.address);
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
console.log('Deployment successful.')
......@@ -313,7 +313,7 @@ const deployWithEthers = `// Right click on the script name and hit "Run" to exe
const readme = `REMIX EXAMPLE PROJECT
Remix example project is present when Remix loads very first time or there are no files existing in the File Explorer.
Remix example project is present when Remix loads very first time or there are no files existing in the File Explorer.
It contains 3 directories:
1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name.
......@@ -323,7 +323,7 @@ It contains 3 directories:
SCRIPTS
The 'scripts' folder contains example async/await scripts for deploying the 'Storage' contract.
For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required).
For the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required).
Scripts have full access to the web3.js and ethers.js libraries.
To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled.
......@@ -333,10 +333,10 @@ Output from script will appear in remix terminal.
module.exports = {
storage: { name: 'contracts/1_Storage.sol', content: storage },
owner: { name: 'contracts/2_Owner.sol', content: owner },
ballot: { name: 'contracts/3_Ballot.sol', content: ballot },
deployWithWeb3: { name: 'scripts/deploy_web3.js', content: deployWithWeb3 },
deployWithEthers: { name: 'scripts/deploy_ethers.js', content: deployWithEthers },
ballot_test: { name: 'tests/4_Ballot_test.sol', content: ballotTest },
readme: { name: 'README.txt', content: readme }
// owner: { name: 'contracts/2_Owner.sol', content: owner },
// ballot: { name: 'contracts/3_Ballot.sol', content: ballot },
// deployWithWeb3: { name: 'scripts/deploy_web3.js', content: deployWithWeb3 },
// deployWithEthers: { name: 'scripts/deploy_ethers.js', content: deployWithEthers },
// ballot_test: { name: 'tests/4_Ballot_test.sol', content: ballotTest },
// readme: { name: 'README.txt', content: readme }
}
......@@ -402,7 +402,6 @@ class FileManager extends Plugin {
this._deps.workspaceExplorer.event.on('fileRenamed', (oldName, newName, isFolder) => { this.fileRenamedEvent(oldName, newName, isFolder) })
this._deps.workspaceExplorer.event.on('fileRemoved', (path) => { this.fileRemovedEvent(path) })
this._deps.workspaceExplorer.event.on('fileAdded', (path) => { this.fileAddedEvent(path) })
this.getCurrentFile = this.file
this.getFile = this.readFile
this.getFolder = this.readdir
......@@ -515,7 +514,7 @@ class FileManager extends Plugin {
<span>
${this.currentRequest.from}
<span class="font-weight-bold text-warning">
is modifying
is modifying
</span>${path}
</span>
</div>
......
......@@ -281,7 +281,6 @@ class FileProvider {
window.remixFileSystem.readdir(path, (error, files) => {
var ret = {}
if (files) {
files.forEach(element => {
path = path.replace(/^\/|\/$/g, '') // remove first and last slash
......
......@@ -102,19 +102,19 @@ class SettingsUI {
title="Execution environment does not connect to any node, everything is local and in memory only."
value="vm-london" name="executionContext" fork="london"> JavaScript VM (London)
</option>
<option id="vm-mode-berlin" data-id="settingsVMBerlinMode"
title="Execution environment does not connect to any node, everything is local and in memory only."
value="vm-berlin" name="executionContext" fork="berlin" > JavaScript VM (Berlin)
</option>
<option id="injected-mode" data-id="settingsInjectedMode"
title="Execution environment has been provided by Metamask or similar provider."
value="injected" name="executionContext"> Injected Web3
</option>
<option id="web3-mode" data-id="settingsWeb3Mode"
title="Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse!
If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http."
value="web3" name="executionContext"> Web3 Provider
</option>
<!-- <option id="vm-mode-berlin" data-id="settingsVMBerlinMode"-->
<!-- title="Execution environment does not connect to any node, everything is local and in memory only."-->
<!-- value="vm-berlin" name="executionContext" fork="berlin" > JavaScript VM (Berlin)-->
<!-- </option>-->
<!-- <option id="injected-mode" data-id="settingsInjectedMode"-->
<!-- title="Execution environment has been provided by Metamask or similar provider."-->
<!-- value="injected" name="executionContext"> Injected Web3-->
<!-- </option>-->
<!-- <option id="web3-mode" data-id="settingsWeb3Mode"-->
<!-- title="Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse!-->
<!-- If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http."-->
<!-- value="web3" name="executionContext"> Web3 Provider-->
<!-- </option>-->
</select>
<a href="https://remix-ide.readthedocs.io/en/latest/run.html#run-setup" target="_blank"><i class="${css.infoDeployAction} ml-2 fas fa-info" title="check out docs to setup Environment"></i></a>
</div>
......@@ -274,12 +274,12 @@ class SettingsUI {
To run Remix & a local Geth test node, use this command: (see <a href="https://geth.ethereum.org/getting-started/dev-mode" target="_blank">Geth Docs on Dev mode</a>)
<div class="border p-1">geth --http --http.corsdomain="${window.origin}" --http.api web3,eth,debug,personal,net --vmdebug --datadir ${thePath} --dev console</div>
<br>
<br>
<br>
<b>WARNING:</b> It is not safe to use the --http.corsdomain flag with a wildcard: <b>--http.corsdomain *</b>
<br>
<br>For more info: <a href="https://remix-ide.readthedocs.io/en/latest/run.html#more-about-web3-provider" target="_blank">Remix Docs on Web3 Provider</a>
<br>
<br>
<br>
Web3 Provider Endpoint
</div>
`
......
import * as packageJson from '../../../../../../package.json'
import { ViewPlugin } from '@remixproject/engine-web'
import { migrateToWorkspace } from '../../../migrateFileSystem'
import JSZip from 'jszip'
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const globalRegistry = require('../../../global/registry')
const modalDialogCustom = require('../modal-dialog-custom')
const modalDialog = require('../modaldialog')
const tooltip = require('../tooltip')
const GistHandler = require('../../../lib/gist-handler')
const QueryParams = require('../../../lib/query-params.js')
const _paq = window._paq = window._paq || []
const css = csjs`
.text {
cursor: pointer;
font-weight: normal;
max-width: 300px;
user-select: none;
}
.text:hover {
cursor: pointer;
text-decoration: underline;
}
.homeContainer {
user-select: none;
overflow-y: hidden;
}
.mainContent {
overflow-y: auto;
flex-grow: 3;
}
.hpLogoContainer {
margin: 30px;
padding-right: 90px;
}
.mediaBadge {
font-size: 2em;
height: 2em;
width: 2em;
}
.mediaBadge:focus {
outline: none;
}
.image {
height: 1em;
width: 1em;
text-align: center;
}
.logoImg {
height: 10em;
}
.hpSections {
}
.rightPanel {
right: 0;
position: absolute;
z-index: 3;
}
.remixHomeMedia {
overflow-y: auto;
overflow-x: hidden;
max-height: 720px;
}
.panels {
box-shadow: 0px 0px 13px -7px;
}
.labelIt {
margin-bottom: 0;
}
.bigLabelSize {
font-size: 13px;
}
.seeAll {
margin-top: 7px;
white-space: nowrap;
}
.importFrom p {
margin-right: 10px;
}
.logoContainer img{
height: 150px;
opacity: 0.7;
}
.envLogo {
height: 16px;
}
.cursorStyle {
cursor: pointer;
}
.envButton {
width: 120px;
height: 70px;
}
.media {
overflow: hidden;
width: 400px;
transition: .5s ease-out;
z-index: 1000;
}
.migrationBtn {
width: 100px;
}
}
`
const profile = {
name: 'home',
displayName: 'Home',
methods: [],
events: [],
description: ' - ',
icon: 'assets/img/remixLogo.webp',
location: 'mainPanel',
version: packageJson.version
}
export class LandingPage extends ViewPlugin {
constructor (appManager, verticalIcons, fileManager, filePanel, contentImport) {
super(profile)
this.profile = profile
this.fileManager = fileManager
this.filePanel = filePanel
this.contentImport = contentImport
this.appManager = appManager
this.verticalIcons = verticalIcons
this.gistHandler = new GistHandler()
const themeQuality = globalRegistry.get('themeModule').api.currentTheme().quality
window.addEventListener('resize', () => this.adjustMediaPanel())
window.addEventListener('click', (e) => this.hideMediaPanel(e))
this.twitterFrame = yo`
<div class="px-2 ${css.media}">
<a class="twitter-timeline"
data-width="350"
data-theme="${themeQuality}"
data-chrome="nofooter noheader transparent"
data-tweet-limit="8"
href="https://twitter.com/EthereumRemix"
>
</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
`
this.badgeTwitter = yo`<button
class="btn-info p-2 m-1 border rounded-circle ${css.mediaBadge} fab fa-twitter"
id="remixIDEHomeTwitterbtn"
onclick=${(e) => this.showMediaPanel(e)}
></button>`
this.badgeMedium = yo`<button
class="btn-danger p-2 m-1 border rounded-circle ${css.mediaBadge} fab fa-medium"
id="remixIDEHomeMediumbtn"
onclick=${(e) => this.showMediaPanel(e)}
></button>`
this.twitterPanel = yo`
<div id="remixIDE_TwitterBlock" class="p-2 mx-0 mb-0 d-none ${css.remixHomeMedia}">
${this.twitterFrame}
</div>
`
this.mediumPanel = yo`
<div id="remixIDE_MediumBlock" class="p-2 mx-0 mb-0 d-none ${css.remixHomeMedia}">
<div id="medium-widget" class="p-3 ${css.media}">
<div
id="retainable-rss-embed"
data-rss="https://medium.com/feed/remix-ide"
data-maxcols="1"
data-layout="grid"
data-poststyle="external"
data-readmore="More..."
data-buttonclass="btn mb-3"
data-offset="-100"
>
- </div>
</div>
</div>
`
this.adjustMediaPanel()
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
this.onThemeChanged(theme.quality)
})
}
adjustMediaPanel () {
this.twitterPanel.style.maxHeight = Math.max(window.innerHeight - 150, 200) + 'px'
this.mediumPanel.style.maxHeight = Math.max(window.innerHeight - 150, 200) + 'px'
}
hideMediaPanel (e) {
const mediaPanelsTitle = document.getElementById('remixIDEMediaPanelsTitle')
const mediaPanels = document.getElementById('remixIDEMediaPanels')
if (!mediaPanelsTitle || !mediaPanels) return
if (!mediaPanelsTitle.contains(e.target) && !mediaPanels.contains(e.target)) {
this.mediumPanel.classList.remove('d-block')
this.mediumPanel.classList.add('d-none')
this.twitterPanel.classList.remove('d-block')
this.twitterPanel.classList.add('d-none')
}
}
onThemeChanged (themeQuality) {
const twitterFrame = yo`
<div class="px-2 ${css.media}">
<a class="twitter-timeline"
data-width="350"
data-theme="${themeQuality}"
data-chrome="nofooter noheader transparent"
data-tweet-limit="8"
href="https://twitter.com/EthereumRemix"
>
</a>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
`
yo.update(this.twitterFrame, twitterFrame)
const invertNum = (themeQuality === 'dark') ? 1 : 0
if (this.solEnv.getElementsByTagName('img')[0]) this.solEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.optimismEnv.getElementsByTagName('img')[0]) this.optimismEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.solhintEnv.getElementsByTagName('img')[0]) this.solhintEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.learnEthEnv.getElementsByTagName('img')[0]) this.learnEthEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.sourcifyEnv.getElementsByTagName('img')[0]) this.sourcifyEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.moreEnv.getElementsByTagName('img')[0]) this.moreEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
if (this.websiteIcon) this.websiteIcon.style.filter = `invert(${invertNum})`
}
showMediaPanel (e) {
if (e.target.id === 'remixIDEHomeTwitterbtn') {
this.mediumPanel.classList.remove('d-block')
this.mediumPanel.classList.add('d-none')
this.twitterPanel.classList.toggle('d-block')
_paq.push(['trackEvent', 'pluginManager', 'media', 'twitter'])
} else {
this.twitterPanel.classList.remove('d-block')
this.twitterPanel.classList.add('d-none')
this.mediumPanel.classList.toggle('d-block')
_paq.push(['trackEvent', 'pluginManager', 'media', 'medium'])
}
}
render () {
const load = (service, item, examples, info) => {
const contentImport = this.contentImport
const fileProviders = globalRegistry.get('fileproviders').api
const msg = yo`
<div class="p-2">
<span>Enter the ${item} you would like to load.</span>
<div>${info}</div>
<div>e.g ${examples.map((url) => { return yo`<div class="p-1"><a>${url}</a></div>` })}</div>
</div>`
const title = `Import from ${service}`
modalDialogCustom.prompt(title, msg, null, (target) => {
if (target !== '') {
contentImport.import(
target,
(loadingMsg) => { tooltip(loadingMsg) },
(error, content, cleanUrl, type, url) => {
if (error) {
modalDialogCustom.alert(title, error.message || error)
} else {
try {
fileProviders.workspace.addExternal(type + '/' + cleanUrl, content, url)
this.verticalIcons.select('filePanel')
} catch (e) {
modalDialogCustom.alert(title, e.message)
}
}
}
)
}
})
}
const startSolidity = async () => {
await this.appManager.activatePlugin(['solidity', 'udapp', 'solidityStaticAnalysis', 'solidityUnitTesting'])
this.verticalIcons.select('solidity')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solidity'])
}
const startOptimism = async () => {
await this.appManager.activatePlugin('optimism-compiler')
this.verticalIcons.select('optimism-compiler')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'optimism-compiler'])
}
const startSolhint = async () => {
await this.appManager.activatePlugin(['solidity', 'solhint'])
this.verticalIcons.select('solhint')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'solhint'])
}
const startLearnEth = async () => {
await this.appManager.activatePlugin(['solidity', 'LearnEth', 'solidityUnitTesting'])
this.verticalIcons.select('LearnEth')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'learnEth'])
}
const startSourceVerify = async () => {
await this.appManager.activatePlugin(['solidity', 'source-verification'])
this.verticalIcons.select('source-verification')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'source-verification'])
}
const startPluginManager = async () => {
await this.appManager.activatePlugin('pluginManager')
this.verticalIcons.select('pluginManager')
}
const startRestoreBackupZip = async () => {
await this.appManager.activatePlugin(['restorebackupzip'])
this.verticalIcons.select('restorebackupzip')
_paq.push(['trackEvent', 'pluginManager', 'userActivate', 'restorebackupzip'])
}
const createNewFile = () => {
this.call('filePanel', 'createNewFile')
}
const saveAs = (blob, name) => {
const node = document.createElement('a')
node.download = name
node.rel = 'noopener'
node.href = URL.createObjectURL(blob)
setTimeout(function () { URL.revokeObjectURL(node.href) }, 4E4) // 40s
setTimeout(function () {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
var evt = document.createEvent('MouseEvents')
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
20, false, false, false, false, 0, null)
node.dispatchEvent(evt)
}
}, 0) // 40s
}
const downloadFiles = async () => {
try {
tooltip('preparing files for download, please wait..')
const fileProviders = globalRegistry.get('fileproviders').api
const zip = new JSZip()
await fileProviders.browser.copyFolderToJson('/', ({ path, content }) => {
zip.file(`remixbackup${path}`, content)
})
zip.generateAsync({ type: 'blob' }).then(function (blob) {
saveAs(blob, 'remixbackup.zip')
}).catch((e) => {
tooltip(e.message)
})
} catch (e) {
tooltip(e.message)
}
}
const uploadFile = (target) => {
this.call('filePanel', 'uploadFile', target)
}
const connectToLocalhost = () => {
this.appManager.activatePlugin('remixd')
}
const importFromGist = () => {
this.gistHandler.loadFromGist({ gist: '' }, globalRegistry.get('filemanager').api)
this.verticalIcons.select('filePanel')
}
globalRegistry.get('themeModule').api.events.on('themeChanged', (theme) => {
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('remixLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('solidityLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('debuggerLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('learnEthLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('workshopLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('moreLogo'))
globalRegistry.get('themeModule').api.fixInvert(document.getElementById('solhintLogo'))
})
const createLargeButton = (imgPath, envID, envText, callback) => {
return yo`
<button
class="btn border-secondary d-flex mr-3 text-nowrap justify-content-center flex-column align-items-center ${css.envButton}"
data-id="landingPageStartSolidity"
onclick=${() => callback()}
>
<img class="m-2 align-self-center ${css.envLogo}" id=${envID} src="${imgPath}">
<label class="text-uppercase text-dark ${css.cursorStyle}">${envText}</label>
</button>
`
}
// main
this.solEnv = createLargeButton('assets/img/solidityLogo.webp', 'solidityLogo', 'Solidity', startSolidity)
// Featured
this.optimismEnv = createLargeButton('assets/img/optimismLogo.webp', 'optimismLogo', 'Optimism', startOptimism)
this.solhintEnv = createLargeButton('assets/img/solhintLogo.png', 'solhintLogo', 'Solhint linter', startSolhint)
this.learnEthEnv = createLargeButton('assets/img/learnEthLogo.webp', 'learnEthLogo', 'LearnEth', startLearnEth)
this.sourcifyEnv = createLargeButton('assets/img/sourcifyLogo.webp', 'sourcifyLogo', 'Sourcify', startSourceVerify)
this.moreEnv = createLargeButton('assets/img/moreLogo.webp', 'moreLogo', 'More', startPluginManager)
this.websiteIcon = yo`<img id='remixHhomeWebsite' class="mr-1 ${css.image}" src="${profile.icon}"></img>`
const themeQuality = globalRegistry.get('themeModule').api.currentTheme().quality
const invertNum = (themeQuality === 'dark') ? 1 : 0
this.solEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.optimismEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.solhintEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.learnEthEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.sourcifyEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.moreEnv.getElementsByTagName('img')[0].style.filter = `invert(${invertNum})`
this.websiteIcon.style.filter = `invert(${invertNum})`
const switchToPreviousVersion = () => {
const query = new QueryParams()
query.update({ appVersion: '0.7.7' })
_paq.push(['trackEvent', 'LoadingType', 'oldExperience_0.7.7'])
document.location.reload()
}
const migrate = async () => {
try {
setTimeout(() => {
tooltip('migrating workspace...')
}, 500)
const workspaceName = await migrateToWorkspace(this.fileManager, this.filePanel)
tooltip('done. ' + workspaceName + ' created.')
} catch (e) {
setTimeout(() => {
tooltip(e.message)
}, 1000)
}
}
const onAcceptDownloadn = async () => {
await downloadFiles()
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
migrate()
}
const onDownload = () => {
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
migrate()
}
const onCancel = () => {
const el = document.getElementById('modal-dialog')
el.parentElement.removeChild(el)
}
const migrateWorkspace = async () => {
modalDialog(
'File system Migration',
yo`
<span>Do you want to download your files to local device first?</span>
<div class="d-flex justify-content-around pt-3 mt-3 border-top">
<button class="btn btn-sm btn-primary" onclick=${async () => onAcceptDownloadn()}>Download and Migrate</button>
<button class="btn btn-sm btn-secondary ${css.migrationBtn}" onclick=${() => onDownload()}>Migrate</button>
<button class="btn btn-sm btn-secondary ${css.migrationBtn}" onclick=${() => onCancel()}>Cancel</button>
</div>
`,
{
label: '',
fn: null
},
{
label: '',
fn: null
}
)
}
const img = yo`<img class="m-4 ${css.logoImg}" src="assets/img/guitarRemiCroped.webp" onclick="${() => playRemi()}"></img>`
const playRemi = async () => { await document.getElementById('remiAudio').play() }
// to retrieve medium posts
document.body.appendChild(yo`<script src="https://www.twilik.com/assets/retainable/rss-embed/retainable-rss-embed.js"></script>`)
const container = yo`
<div class="${css.homeContainer} d-flex" data-id="landingPageHomeContainer">
<div class="${css.mainContent} bg-light">
<div class="d-flex justify-content-between">
<div class="d-flex flex-column">
<div class="border-bottom d-flex justify-content-between clearfix py-3 mb-4">
<div class="mx-4 w-100 d-flex">
${img}
<audio id="remiAudio" muted=false src="assets/audio/remiGuitar-single-power-chord-A-minor.wav"></audio>
<div class="w-80 pl-5 ml-5">
<h5 class="mb-1">Quicklinks</h5>
<a class="${css.text} mr-1" target="__blank" href="https://medium.com/remix-ide/migrating-files-to-workspaces-8e34737c751c?source=friends_link&sk=b75cfd9093aa23c78be13cce49e4a5e8">Guide </a>for migrating the old File System
<p class="font-weight-bold mb-0 py-1">Migration tools:</p>
<li class="pl-1">
<spam class="pl-0">
<u class="${css.text} pr-1" onclick=${() => migrateWorkspace()}>Basic migration</u>
</spam>
</li>
<li class="pl-1">
<u class="${css.text} pr-1" onclick=${() => downloadFiles()}>Download all Files</u>
as a backup zip
</li>
<li class="pl-1">
<u class="${css.text} pr-1" onclick=${() => startRestoreBackupZip()}>Restore files</u>from backup zip
</li>
<p class="font-weight-bold mb-0 mt-2">Help:</p>
<dir class="d-flex flex-column mt-1 pl-0">
<a class="${css.text} mx-1" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
<a class="${css.text} mx-1" target="__blank" href="https://github.com/ethereum/remix-project/issues">Report on Github</a>
</dir>
</div>
</div>
</div>
<div class="row ${css.hpSections} mx-4" data-id="landingPageHpSections">
<div class="ml-3">
<div class="plugins mb-5">
<h4>Featured Plugins</h4>
<div class="d-flex flex-row pt-2">
${this.solEnv}
${this.optimismEnv}
${this.learnEthEnv}
${this.solhintEnv}
${this.sourcifyEnv}
${this.moreEnv}
</div>
</div>
<div class="d-flex">
<div class="file">
<h4>File</h4>
<p class="mb-1">
<i class="mr-1 far fa-file"></i>
<span class="ml-1 mb-1 ${css.text}" onclick=${() => createNewFile()}>New File</span>
</p>
<p class="mb-1">
<i class="mr-1 far fa-file-alt"></i>
<label class="ml-1 ${css.labelIt} ${css.bigLabelSize} ${css.text}">
Open Files
<input title="open file" type="file" onchange="${(event) => {
event.stopPropagation()
uploadFile(event.target)
}
}" multiple />
</label>
</p>
<p class="mb-1">
<i class="far fa-hdd"></i>
<span class="ml-1 ${css.text}" onclick=${() => connectToLocalhost()}>Connect to Localhost</span>
</p>
<p class="mt-3 mb-0"><label>LOAD FROM:</label></p>
<div class="btn-group">
<button class="btn mr-1 btn-secondary" data-id="landingPageImportFromGistButton" onclick="${() => importFromGist()}">Gist</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Github', 'github URL', ['https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol', 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol'])}">GitHub</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Ipfs', 'ipfs URL', ['ipfs://<ipfs-hash>'])}">Ipfs</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Https', 'http/https raw content', ['https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol'])}">https</button>
</div><!-- end of btn-group -->
</div><!-- end of div.file -->
<div class="ml-4 pl-4">
<h4>Resources</h4>
<p class="mb-1">
<i class="mr-1 fas fa-book"></i>
<a class="${css.text}" target="__blank" href="https://remix-ide.readthedocs.io/en/latest/#">Documentation</a>
</p>
<p class="mb-1">
<i class="mr-1 fab fa-gitter"></i>
<a class="${css.text}" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
</p>
<p class="mb-1">
${this.websiteIcon}
<a class="${css.text}" target="__blank" href="https://remix-project.org">Featuring website</a>
</p>
<p class="mb-1">
<i class="fab fa-ethereum ${css.image}"></i>
<span class="${css.text}" onclick=${() => switchToPreviousVersion()}>Old experience</span>
</p>
</div>
</div>
</div>
</div><!-- end of hpSections -->
</div>
<div class="d-flex flex-column ${css.rightPanel}">
<div class="d-flex pr-3 py-2 align-self-end" id="remixIDEMediaPanelsTitle">
${this.badgeTwitter}
${this.badgeMedium}
</div>
<div class="mr-3 d-flex bg-light ${css.panels}" id="remixIDEMediaPanels">
${this.mediumPanel}
${this.twitterPanel}
</div>
</div>
</div>
</div>
</div>
`
return container
}
}
......@@ -467,117 +467,7 @@ export class LandingPage extends ViewPlugin {
// to retrieve medium posts
document.body.appendChild(yo`<script src="https://www.twilik.com/assets/retainable/rss-embed/retainable-rss-embed.js"></script>`)
const container = yo`
<div class="${css.homeContainer} d-flex" data-id="landingPageHomeContainer">
<div class="${css.mainContent} bg-light">
<div class="d-flex justify-content-between">
<div class="d-flex flex-column">
<div class="border-bottom d-flex justify-content-between clearfix py-3 mb-4">
<div class="mx-4 w-100 d-flex">
${img}
<audio id="remiAudio" muted=false src="assets/audio/remiGuitar-single-power-chord-A-minor.wav"></audio>
<div class="w-80 pl-5 ml-5">
<h5 class="mb-1">Quicklinks</h5>
<a class="${css.text} mr-1" target="__blank" href="https://medium.com/remix-ide/migrating-files-to-workspaces-8e34737c751c?source=friends_link&sk=b75cfd9093aa23c78be13cce49e4a5e8">Guide </a>for migrating the old File System
<p class="font-weight-bold mb-0 py-1">Migration tools:</p>
<li class="pl-1">
<spam class="pl-0">
<u class="${css.text} pr-1" onclick=${() => migrateWorkspace()}>Basic migration</u>
</spam>
</li>
<li class="pl-1">
<u class="${css.text} pr-1" onclick=${() => downloadFiles()}>Download all Files</u>
as a backup zip
</li>
<li class="pl-1">
<u class="${css.text} pr-1" onclick=${() => startRestoreBackupZip()}>Restore files</u>from backup zip
</li>
<p class="font-weight-bold mb-0 mt-2">Help:</p>
<dir class="d-flex flex-column mt-1 pl-0">
<a class="${css.text} mx-1" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
<a class="${css.text} mx-1" target="__blank" href="https://github.com/ethereum/remix-project/issues">Report on Github</a>
</dir>
</div>
</div>
</div>
<div class="row ${css.hpSections} mx-4" data-id="landingPageHpSections">
<div class="ml-3">
<div class="plugins mb-5">
<h4>Featured Plugins</h4>
<div class="d-flex flex-row pt-2">
${this.solEnv}
${this.optimismEnv}
${this.learnEthEnv}
${this.solhintEnv}
${this.sourcifyEnv}
${this.moreEnv}
</div>
</div>
<div class="d-flex">
<div class="file">
<h4>File</h4>
<p class="mb-1">
<i class="mr-1 far fa-file"></i>
<span class="ml-1 mb-1 ${css.text}" onclick=${() => createNewFile()}>New File</span>
</p>
<p class="mb-1">
<i class="mr-1 far fa-file-alt"></i>
<label class="ml-1 ${css.labelIt} ${css.bigLabelSize} ${css.text}">
Open Files
<input title="open file" type="file" onchange="${(event) => {
event.stopPropagation()
uploadFile(event.target)
}
}" multiple />
</label>
</p>
<p class="mb-1">
<i class="far fa-hdd"></i>
<span class="ml-1 ${css.text}" onclick=${() => connectToLocalhost()}>Connect to Localhost</span>
</p>
<p class="mt-3 mb-0"><label>LOAD FROM:</label></p>
<div class="btn-group">
<button class="btn mr-1 btn-secondary" data-id="landingPageImportFromGistButton" onclick="${() => importFromGist()}">Gist</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Github', 'github URL', ['https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol', 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol'])}">GitHub</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Ipfs', 'ipfs URL', ['ipfs://<ipfs-hash>'])}">Ipfs</button>
<button class="btn mx-1 btn-secondary" onclick="${() => load('Https', 'http/https raw content', ['https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol'])}">https</button>
</div><!-- end of btn-group -->
</div><!-- end of div.file -->
<div class="ml-4 pl-4">
<h4>Resources</h4>
<p class="mb-1">
<i class="mr-1 fas fa-book"></i>
<a class="${css.text}" target="__blank" href="https://remix-ide.readthedocs.io/en/latest/#">Documentation</a>
</p>
<p class="mb-1">
<i class="mr-1 fab fa-gitter"></i>
<a class="${css.text}" target="__blank" href="https://gitter.im/ethereum/remix">Gitter channel</a>
</p>
<p class="mb-1">
${this.websiteIcon}
<a class="${css.text}" target="__blank" href="https://remix-project.org">Featuring website</a>
</p>
<p class="mb-1">
<i class="fab fa-ethereum ${css.image}"></i>
<span class="${css.text}" onclick=${() => switchToPreviousVersion()}>Old experience</span>
</p>
</div>
</div>
</div>
</div><!-- end of hpSections -->
</div>
<div class="d-flex flex-column ${css.rightPanel}">
<div class="d-flex pr-3 py-2 align-self-end" id="remixIDEMediaPanelsTitle">
${this.badgeTwitter}
${this.badgeMedium}
</div>
<div class="mr-3 d-flex bg-light ${css.panels}" id="remixIDEMediaPanels">
${this.mediumPanel}
${this.twitterPanel}
</div>
</div>
</div>
</div>
</div>
<div></div>
`
return container
......
......@@ -19,7 +19,8 @@ if (typeof window !== 'undefined' && typeof window.ethereum !== 'undefined') {
export class ExecutionContext {
constructor () {
this.event = new EventManager()
this.executionContext = null
// @todo 关闭执行
this.executionContext = 'vm' // null
this.lastBlock = null
this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault
......
......@@ -25,7 +25,6 @@ export async function migrateToWorkspace (fileManager, filePanel) {
const browserProvider = fileManager.getProvider('browser')
const workspaceProvider = fileManager.getProvider('workspace')
const files = await browserProvider.copyFolderToJson('/')
if (Object.keys(files).length === 0) {
// we don't have any root file, only .workspaces
// don't need to create a workspace
......
{
"contracts...1_Storage.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Storage\n * @dev Store & retrieve value in a variable\n */\ncontract Storage {\n\n uint256 number;\n\n /**\n * @dev Store value in variable\n * @param num value to store\n */\n function store(uint256 num) public {\n number = num;\n }\n\n /**\n * @dev Return value \n * @return value of 'number'\n */\n function retrieve() public view returns (uint256){\n return number;\n }\n}"
},
"contracts...2_Owner.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/**\n * @title Owner\n * @dev Set & change owner\n */\ncontract Owner {\n\n address private owner;\n \n // event for EVM logging\n event OwnerSet(address indexed oldOwner, address indexed newOwner);\n \n // modifier to check if caller is owner\n modifier isOwner() {\n // If the first argument of 'require' evaluates to 'false', execution terminates and all\n // changes to the state and to Ether balances are reverted.\n // This used to consume all gas in old EVM versions, but not anymore.\n // It is often a good idea to use 'require' to check if functions are called correctly.\n // As a second argument, you can also provide an explanation about what went wrong.\n require(msg.sender == owner, \"Caller is not owner\");\n _;\n }\n \n /**\n * @dev Set contract deployer as owner\n */\n constructor() {\n owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor\n emit OwnerSet(address(0), owner);\n }\n\n /**\n * @dev Change owner\n * @param newOwner address of new owner\n */\n function changeOwner(address newOwner) public isOwner {\n emit OwnerSet(owner, newOwner);\n owner = newOwner;\n }\n\n /**\n * @dev Return owner address \n * @return address of owner\n */\n function getOwner() external view returns (address) {\n return owner;\n }\n}"
},
"contracts...3_Ballot.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\n\n/** \n * @title Ballot\n * @dev Implements voting process along with vote delegation\n */\ncontract Ballot {\n \n struct Voter {\n uint weight; // weight is accumulated by delegation\n bool voted; // if true, that person already voted\n address delegate; // person delegated to\n uint vote; // index of the voted proposal\n }\n\n struct Proposal {\n // If you can limit the length to a certain number of bytes, \n // always use one of bytes1 to bytes32 because they are much cheaper\n bytes32 name; // short name (up to 32 bytes)\n uint voteCount; // number of accumulated votes\n }\n\n address public chairperson;\n\n mapping(address => Voter) public voters;\n\n Proposal[] public proposals;\n\n /** \n * @dev Create a new ballot to choose one of 'proposalNames'.\n * @param proposalNames names of proposals\n */\n constructor(bytes32[] memory proposalNames) {\n chairperson = msg.sender;\n voters[chairperson].weight = 1;\n\n for (uint i = 0; i < proposalNames.length; i++) {\n // 'Proposal({...})' creates a temporary\n // Proposal object and 'proposals.push(...)'\n // appends it to the end of 'proposals'.\n proposals.push(Proposal({\n name: proposalNames[i],\n voteCount: 0\n }));\n }\n }\n \n /** \n * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.\n * @param voter address of voter\n */\n function giveRightToVote(address voter) public {\n require(\n msg.sender == chairperson,\n \"Only chairperson can give right to vote.\"\n );\n require(\n !voters[voter].voted,\n \"The voter already voted.\"\n );\n require(voters[voter].weight == 0);\n voters[voter].weight = 1;\n }\n\n /**\n * @dev Delegate your vote to the voter 'to'.\n * @param to address to which vote is delegated\n */\n function delegate(address to) public {\n Voter storage sender = voters[msg.sender];\n require(!sender.voted, \"You already voted.\");\n require(to != msg.sender, \"Self-delegation is disallowed.\");\n\n while (voters[to].delegate != address(0)) {\n to = voters[to].delegate;\n\n // We found a loop in the delegation, not allowed.\n require(to != msg.sender, \"Found loop in delegation.\");\n }\n sender.voted = true;\n sender.delegate = to;\n Voter storage delegate_ = voters[to];\n if (delegate_.voted) {\n // If the delegate already voted,\n // directly add to the number of votes\n proposals[delegate_.vote].voteCount += sender.weight;\n } else {\n // If the delegate did not vote yet,\n // add to her weight.\n delegate_.weight += sender.weight;\n }\n }\n\n /**\n * @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'.\n * @param proposal index of proposal in the proposals array\n */\n function vote(uint proposal) public {\n Voter storage sender = voters[msg.sender];\n require(sender.weight != 0, \"Has no right to vote\");\n require(!sender.voted, \"Already voted.\");\n sender.voted = true;\n sender.vote = proposal;\n\n // If 'proposal' is out of the range of the array,\n // this will throw automatically and revert all\n // changes.\n proposals[proposal].voteCount += sender.weight;\n }\n\n /** \n * @dev Computes the winning proposal taking all previous votes into account.\n * @return winningProposal_ index of winning proposal in the proposals array\n */\n function winningProposal() public view\n returns (uint winningProposal_)\n {\n uint winningVoteCount = 0;\n for (uint p = 0; p < proposals.length; p++) {\n if (proposals[p].voteCount > winningVoteCount) {\n winningVoteCount = proposals[p].voteCount;\n winningProposal_ = p;\n }\n }\n }\n\n /** \n * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then\n * @return winnerName_ the name of the winner\n */\n function winnerName() public view\n returns (bytes32 winnerName_)\n {\n winnerName_ = proposals[winningProposal()].name;\n }\n}\n"
},
"scripts...deploy_web3.js": {
"content": "// Right click on the script name and hit \"Run\" to execute\n(async () => {\n try {\n console.log('Running deployWithWeb3 script...')\n \n const contractName = 'Storage' // Change this for other contract\n const constructorArgs = [] // Put constructor args (if any) here for your contract\n \n // Note that the script needs the ABI which is generated from the compilation artifact.\n // Make sure contract is compiled and artifacts are generated\n const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path\n\n const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))\n const accounts = await web3.eth.getAccounts()\n \n let contract = new web3.eth.Contract(metadata.abi)\n \n contract = contract.deploy({\n data: metadata.data.bytecode.object,\n arguments: constructorArgs\n })\n \n const newContractInstance = await contract.send({\n from: accounts[0],\n gas: 1500000,\n gasPrice: '30000000000'\n })\n console.log('Contract deployed at address: ', newContractInstance.options.address)\n } catch (e) {\n console.log(e.message)\n }\n })()"
},
"scripts...deploy_ethers.js": {
"content": "// Right click on the script name and hit \"Run\" to execute\n(async () => {\n try {\n console.log('Running deployWithEthers script...')\n \n const contractName = 'Storage' // Change this for other contract\n const constructorArgs = [] // Put constructor args (if any) here for your contract\n\n // Note that the script needs the ABI which is generated from the compilation artifact.\n // Make sure contract is compiled and artifacts are generated\n const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path\n \n const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))\n // 'web3Provider' is a remix global variable object\n const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()\n \n let factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer);\n \n let contract = await factory.deploy(...constructorArgs);\n \n console.log('Contract Address: ', contract.address);\n \n // The contract is NOT deployed yet; we must wait until it is mined\n await contract.deployed()\n console.log('Deployment successful.')\n } catch (e) {\n console.log(e.message)\n }\n})()"
},
"tests...4_Ballot_test.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.7.0 <0.9.0;\nimport \"remix_tests.sol\"; // this import is automatically injected by Remix.\nimport \"../contracts/3_Ballot.sol\";\n\ncontract BallotTest {\n \n bytes32[] proposalNames;\n \n Ballot ballotToTest;\n function beforeAll () public {\n proposalNames.push(bytes32(\"candidate1\"));\n ballotToTest = new Ballot(proposalNames);\n }\n \n function checkWinningProposal () public {\n ballotToTest.vote(0);\n Assert.equal(ballotToTest.winningProposal(), uint(0), \"proposal at index 0 should be the winning proposal\");\n Assert.equal(ballotToTest.winnerName(), bytes32(\"candidate1\"), \"candidate1 should be the winner name\");\n }\n \n function checkWinninProposalWithReturnValue () public view returns (bool) {\n return ballotToTest.winningProposal() == 0;\n }\n}\n"
},
"README.txt": {
"content": "REMIX EXAMPLE PROJECT\n\nRemix example project is present when Remix loads very first time or there are no files existing in the File Explorer. \nIt contains 3 directories:\n\n1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name.\n2. 'scripts': Holds two scripts to deploy a contract. It is explained below.\n3. 'tests': Contains one test file for 'Ballot' contract with unit tests in Solidity.\n\nSCRIPTS\n\nThe 'scripts' folder contains example async/await scripts for deploying the 'Storage' contract.\nFor the deployment of any other contract, 'contractName' and 'constructorArgs' should be updated (along with other code if required). \nScripts have full access to the web3.js and ethers.js libraries.\n\nTo run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled.\n\nOutput from script will appear in remix terminal.\n"
}
}
......@@ -19,7 +19,7 @@ export interface RemixUiSettingsProps {
export const RemixUiSettings = (props: RemixUiSettingsProps) => {
const [, dispatch] = useReducer(settingReducer, initialState)
const [state, dispatchToast] = useReducer(toastReducer, toastInitialState)
const [tokenValue, setTokenValue] = useState('')
const [tokenValue, setTokenValue] = useState('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')
const [themeName, setThemeName] = useState('')
useEffect(() => {
......
......@@ -150,6 +150,72 @@ export const publishToGist = async (path?: string, type?: string) => {
}
}
export const publishToBaas = async (path?: string, type?: string) => {
// If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer.
const folder = path || '/'
const id = type === 'baas' ? extractNameFromKey(path).split('-')[1] : null
try {
const packaged = await packageGistFiles(folder)
// check for token
const config = plugin.registry.get('config').api
const accessToken = config.get('settings/gist-access-token')
if (!accessToken) {
dispatch(displayNotification('Authorize Token', 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.', 'Close', null, () => {}))
} else {
const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' +
queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist='
const gists = new Gists({ token: accessToken })
if (id) {
const originalFileList = await getOriginalFiles(id)
// Telling the GIST API to remove files
const updatedFileList = Object.keys(packaged)
const allItems = Object.keys(originalFileList)
.filter(fileName => updatedFileList.indexOf(fileName) === -1)
.reduce((acc, deleteFileName) => ({
...acc,
[deleteFileName]: null
}), originalFileList)
// adding new files
updatedFileList.forEach((file) => {
const _items = file.split('/')
const _fileName = _items[_items.length - 1]
allItems[_fileName] = packaged[file]
})
dispatch(displayPopUp('Saving gist (' + id + ') ...'))
gists.edit({
description: description,
public: true,
files: allItems,
id: id
}, (error, result) => {
handleGistResponse(error, result)
if (!error) {
for (const key in allItems) {
if (allItems[key] === null) delete allItems[key]
}
}
})
} else {
// id is not existing, need to create a new gist
dispatch(displayPopUp('Creating a new gist ...'))
gists.create({
description: description,
public: true,
files: packaged
}, (error, result) => {
handleGistResponse(error, result)
})
}
}
} catch (error) {
console.log(error)
dispatch(displayNotification('Publish to gist Failed', 'Failed to create gist: ' + error.message, 'Close', null, async () => {}))
}
}
export const clearPopUp = async () => {
dispatch(hidePopUp())
}
......@@ -260,7 +326,6 @@ const packageGistFiles = (directory) => {
const workspaceProvider = plugin.fileProviders.workspace
const isFile = workspaceProvider.isFile(directory)
const ret = {}
if (isFile) {
try {
workspaceProvider.get(directory, (error, content) => {
......
......@@ -6,7 +6,6 @@ import { checkSlash, checkSpecialChars } from '@remix-ui/helper'
const examples = require('../../../../../../apps/remix-ide/src/app/editor/examples')
const QueryParams = require('../../../../../../apps/remix-ide/src/lib/query-params')
const LOCALHOST = ' - connect to localhost - '
const NO_WORKSPACE = ' - none - '
const queryParams = new QueryParams()
......@@ -42,7 +41,6 @@ export const addInputField = async (type: 'file' | 'folder', path: string, cb?:
export const createWorkspace = async (workspaceName: string, isEmpty = false, cb?: (err: Error, result?: string | number | boolean | Record<string, any>) => void) => {
await plugin.fileManager.closeAllFiles()
const promise = createWorkspaceTemplate(workspaceName, 'default-template')
dispatch(createWorkspaceRequest(promise))
promise.then(async () => {
dispatch(createWorkspaceSuccess(workspaceName))
......@@ -72,7 +70,6 @@ export const createWorkspaceTemplate = async (workspaceName: string, template: '
export const loadWorkspacePreset = async (template: 'gist-template' | 'code-template' | 'default-template' = 'default-template') => {
const workspaceProvider = plugin.fileProviders.workspace
const params = queryParams.get()
switch (template) {
case 'code-template':
// creates a new workspace code-sample and loads code from url params.
......@@ -292,7 +289,6 @@ export const getWorkspaces = async (): Promise<string[]> | undefined => {
.map((folder) => folder.replace(workspacesPath + '/', '')))
})
})
plugin.setWorkspaces(workspaces)
return workspaces
} catch (e) {}
......
......@@ -5,7 +5,7 @@ import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileSystemContext } from '../contexts'
import { browserReducer, browserInitialState } from '../reducers/workspace'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, createNewFile, setFocusElement, createNewFolder, deletePath, renamePath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from '../actions'
import { initWorkspace, fetchDirectory, removeInputField, deleteWorkspace, clearPopUp, publishToGist, publishToBaas, createNewFile, setFocusElement, createNewFolder, deletePath, renamePath, copyFile, copyFolder, runScript, emitContextMenuEvent, handleClickFile, handleExpandPath, addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from '../actions'
import { Modal, WorkspaceProps } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Workspace } from '../remix-ui-workspace'
......@@ -67,6 +67,11 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await publishToGist(path, type)
}
// 上传到bass
const dispatchPublishToBaas = async (path?: string, type?: string) => {
await publishToBaas(path, type)
}
const dispatchUploadFile = async (target?: SyntheticEvent, targetFolder?: string) => {
await uploadFile(target, targetFolder)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment