Merge pull request #2470 from ethereum/configUpdates

added Berlin, fixed config file logic
pull/2471/head
yann300 2 years ago committed by GitHub
commit 207ced474b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      apps/remix-ide-e2e/src/commands/verifyContracts.ts
  2. 38
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  3. 1
      apps/remix-ide-e2e/src/tests/compiler_api.test.ts
  4. 6
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  5. 3
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  6. 2
      apps/remix-ide-e2e/src/types/index.d.ts
  7. 26
      apps/remix-ide/src/app/editor/editor.js
  8. 4
      apps/remix-ide/src/app/tabs/compile-tab.js
  9. 55
      apps/solidity-compiler/src/app/compiler-api.ts
  10. 1
      libs/remix-lib/src/types/ICompilerApi.ts
  11. 2
      libs/remix-ui/editor/src/lib/remix-plugin-types.ts
  12. 128
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  13. 10
      libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts
  14. 17
      libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx
  15. 4
      libs/remix-ui/solidity-compiler/src/lib/types/index.ts
  16. 1
      libs/remix-ui/workspace/src/lib/css/remix-ui-workspace.css
  17. 6
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  18. 2
      package.json

@ -2,7 +2,7 @@ import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
class VerifyContracts extends EventEmitter {
command (this: NightwatchBrowser, compiledContractNames: string[], opts = { wait: 1000, version: null }): NightwatchBrowser {
command (this: NightwatchBrowser, compiledContractNames: string[], opts = { wait: 1000, version: null, runs: '200' }): NightwatchBrowser {
this.api.perform((done) => {
verifyContracts(this.api, compiledContractNames, opts, () => {
done()
@ -13,13 +13,13 @@ class VerifyContracts extends EventEmitter {
}
}
function verifyContracts (browser: NightwatchBrowser, compiledContractNames: string[], opts: { wait: number, version?: string }, callback: VoidFunction) {
function verifyContracts (browser: NightwatchBrowser, compiledContractNames: string[], opts: { wait: number, version?: string, runs?: string }, callback: VoidFunction) {
browser
.clickLaunchIcon('solidity')
.pause(opts.wait)
.pause(5000)
.waitForElementPresent('*[data-id="compiledContracts"] option', 60000)
.perform((done) => {
.perform(async (done) => {
if (opts.version) {
browser
.click('*[data-id="compilation-details"]')
@ -36,10 +36,28 @@ function verifyContracts (browser: NightwatchBrowser, compiledContractNames: str
done()
callback()
})
} else {
compiledContractNames.forEach((name) => {
browser.waitForElementContainsText('[data-id="compiledContracts"]', name, 60000)
} if (opts.runs) {
browser
.click('*[data-id="compilation-details"]')
.waitForElementVisible('*[data-id="remixui_treeviewitem_metadata"]')
.pause(2000)
.click('*[data-id="remixui_treeviewitem_metadata"]')
.waitForElementVisible('*[data-id="treeViewDivtreeViewItemsettings"]')
.pause(2000)
.click('*[data-id="treeViewDivtreeViewItemsettings"]')
.waitForElementVisible('*[data-id="treeViewDivtreeViewItemoptimizer"]')
.click('*[data-id="treeViewDivtreeViewItemoptimizer"]')
.waitForElementVisible('*[data-id="treeViewDivruns"]')
.assert.containsText('*[data-id="treeViewDivruns"]', `${opts.runs}`)
.click('[data-id="workspacesModalDialog-modal-footer-ok-react"]')
.perform(() => {
done()
callback()
})
} else {
for (const index in compiledContractNames) {
await browser.waitForElementContainsText('[data-id="compiledContracts"]', compiledContractNames[index], 60000)
}
done()
callback()
}

@ -122,6 +122,24 @@ module.exports = {
})
// Test in Udapp UI , treeViewDiv0 shows returned value on method click
.assert.containsText('*[data-id="treeViewDiv0"]', 'bytes32: winnerName_ 0x48656c6c6f20576f726c64210000000000000000000000000000000000000000')
},
'Compile Ballot using config file': function (browser: NightwatchBrowser) {
browser
.addFile('cf.json', {content: configFile})
.clickLaunchIcon('solidity')
.waitForElementVisible('*[data-id="scConfigExpander"]')
.click('*[data-id="scConfigExpander"]')
.waitForElementVisible('*[data-id="scFileConfiguration"]', 10000)
.click('*[data-id="scFileConfiguration"]')
.waitForElementVisible('*[data-id="scConfigChangeFilePath"]', 10000)
.click('*[data-id="scConfigChangeFilePath"]')
.waitForElementVisible('*[data-id="scConfigFilePathInput"]', 10000)
.clearValue('*[data-id="scConfigFilePathInput"]')
.setValue('*[data-id="scConfigFilePathInput"]', 'cf.json')
.sendKeys('*[data-id$="scConfigFilePathInput"]', browser.Keys.ENTER)
.openFile('Untitled.sol')
.verifyContracts(['Ballot'], {wait: 2000, runs: '300'})
.end()
}
}
@ -190,6 +208,7 @@ const stateCheck = {
immutable: false
}
}
const ballotABI = `[
{
"inputs": [
@ -356,3 +375,22 @@ const ballotABI = `[
"type": "function"
}
]`
const configFile = `
{
"language": "Solidity",
"settings": {
"optimizer": {
"enabled": true,
"runs": 300
},
"outputSelection": {
"*": {
"": ["ast"],
"*": ["abi", "metadata", "devdoc", "userdoc", "storageLayout", "evm.legacyAssembly", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "evm.gasEstimates", "evm.assembly"]
}
},
"evmVersion": "byzantium"
}
}
`

@ -168,3 +168,4 @@ contract DoesNotCompile {
function fStackLimit(uint u1, uint u2, uint u3, uint u4, uint u5, uint u6, uint u7, uint u8, uint u9, uint u10, uint u11, uint u12) public {
}
}`

@ -231,7 +231,6 @@ module.exports = {
'Should get current files #group7': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:readdir', {
'compiler_config.json': { isDirectory: false },
contracts: { isDirectory: true },
scripts: { isDirectory: true },
tests: { isDirectory: true },
@ -286,15 +285,12 @@ module.exports = {
'Should create empty workspace #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, ['emptyworkspace', true])
await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'emptyworkspace', isLocalhost: false, absolutePath: '.workspaces/emptyworkspace' }, null, null)
await clickAndCheckLog(browser, 'fileManager:readdir', {
'compiler_config.json': { isDirectory: false }
}, null, '/')
await clickAndCheckLog(browser, 'fileManager:readdir', {}, null, '/')
},
'Should create workspace #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:createWorkspace', null, null, 'testspace')
await clickAndCheckLog(browser, 'filePanel:getCurrentWorkspace', { name: 'testspace', isLocalhost: false, absolutePath: '.workspaces/testspace' }, null, null)
await clickAndCheckLog(browser, 'fileManager:readdir', {
'compiler_config.json': { isDirectory: false },
contracts: { isDirectory: true },
scripts: { isDirectory: true },
tests: { isDirectory: true },

@ -107,8 +107,7 @@ module.exports = {
const fileList = document.querySelector('*[data-id="treeViewUltreeViewMenu"]')
return fileList.getElementsByTagName('li').length;
}, [], function(result){
// check there are no files in FE except config file
browser.assert.equal(result.value, 1, 'Incorrect number of files');
browser.assert.equal(result.value, 0, 'Incorrect number of files');
});
},

@ -11,7 +11,7 @@ declare module 'nightwatch' {
testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser,
setEditorValue(value: string, callback?: () => void): NightwatchBrowser,
addFile(name: string, content: NightwatchContractContent): NightwatchBrowser,
verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string }): NightwatchBrowser,
verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string, runs?: string }): NightwatchBrowser,
selectAccount(account?: string): NightwatchBrowser,
clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser,
testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser,

@ -167,6 +167,32 @@ class Editor extends Plugin {
}
})
this.on('fileManager', 'noFileSelected', async () => {
this.currentFile = null
this.renderComponent()
})
this.on('fileManager', 'currentFileChanged', async (name) => {
if (name.endsWith('.ts')) {
// extract the import, resolve their content
// and add the imported files to Monaco through the `addModel`
// so Monaco can provide auto completion
let content = await this.call('fileManager', 'readFile', name)
const paths = name.split('/')
paths.pop()
const fromPath = paths.join('/') // get current execution context path
for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) {
let path = match[2]
if (path.startsWith('./') || path.startsWith('../')) path = resolve(fromPath, path)
if (path.startsWith('/')) path = path.substring(1)
if (!path.endsWith('.ts')) path = path + '.ts'
if (await this.call('fileManager', 'exists', path)) {
content = await this.call('fileManager', 'readFile', path)
this.emit('addModel', content, 'typescript', path, false)
}
}
}
})
this.on('fileManager', 'noFileSelected', async () => {
this.currentFile = null
this.renderComponent()

@ -56,6 +56,10 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
this.renderComponent()
}
onFileRemoved () {
this.renderComponent()
}
onNoFileSelected () {
this.renderComponent()
}

@ -19,6 +19,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
onCurrentFileChanged: (fileName: string) => void
// onResetResults: () => void
onSetWorkspace: (isLocalhost: boolean, workspaceName: string) => void
onFileRemoved: (path: string) => void
onNoFileSelected: () => void
onCompilationFinished: (compilationDetails: { contractMap: { file: string } | Record<string, any>, contractsDetails: Record<string, any> }) => void
onSessionSwitched: () => void
@ -240,6 +241,10 @@ export const CompilerApiMixin = (Base) => class extends Base {
if (this.onSetWorkspace) this.onSetWorkspace(workspace.isLocalhost, workspace.name)
})
this.on('fileManager', 'fileRemoved', (path) => {
if (this.onFileRemoved) this.onFileRemoved(path)
})
this.on('remixd', 'rootFolderChanged', () => {
this.resetResults()
if (this.onSetWorkspace) this.onSetWorkspace(true, 'localhost')
@ -282,23 +287,20 @@ export const CompilerApiMixin = (Base) => class extends Base {
type: 'warning'
})
} else this.statusChanged({ key: 'succeed', title: 'compilation successful', type: 'success' })
// Store the contracts
this.compilationDetails.contractsDetails = {}
this.compiler.visitContracts((contract) => {
this.compilationDetails.contractsDetails[contract.name] = parseContracts(
contract.name,
contract.object,
this.compiler.getSource(contract.file)
)
})
} else {
const count = (data.errors ? data.errors.filter(error => error.severity === 'error').length : 0 + (data.error ? 1 : 0))
this.statusChanged({ key: count, title: `compilation failed with ${count} error${count > 1 ? 's' : ''}`, type: 'error' })
}
// Update contract Selection
this.compilationDetails.contractMap = {}
if (success) this.compiler.visitContracts((contract) => { this.compilationDetails.contractMap[contract.name] = contract })
this.compilationDetails.target = source.target
// Store the contracts and Update contract Selection
if (success) {
this.compilationDetails = await this.visitsContractApi(source, data)
} else {
this.compilationDetails = {
contractMap: {},
contractsDetails: {},
target: source.target
}
}
if (this.onCompilationFinished) this.onCompilationFinished(this.compilationDetails)
// set annotations
if (data.errors) {
@ -342,4 +344,31 @@ export const CompilerApiMixin = (Base) => class extends Base {
}
window.document.addEventListener('keydown', this.data.eventHandlers.onKeyDown)
}
async visitsContractApi (source, data): Promise<{ contractMap: { file: string } | Record<string, any>, contractsDetails: Record<string, any>, target?: string }> {
return new Promise((resolve) => {
if (!data.contracts || (data.contracts && Object.keys(data.contracts).length === 0)) {
return resolve({
contractMap: {},
contractsDetails: {},
target: source.target
})
}
const contractMap = {}
const contractsDetails = {}
this.compiler.visitContracts((contract) => {
contractMap[contract.name] = contract
contractsDetails[contract.name] = parseContracts(
contract.name,
contract.object,
this.compiler.getSource(contract.file)
)
})
return resolve({
contractMap,
contractsDetails,
target: source.target
})
})
}
}

@ -25,6 +25,7 @@ export interface ICompilerApi {
onCurrentFileChanged: (fileName: string) => void
// onResetResults: () => void,
onSetWorkspace: (isLocalhost: boolean, workspaceName: string) => void
onFileRemoved: (path: string) => void
onNoFileSelected: () => void
onCompilationFinished: (contractsDetails: any, contractMap: any) => void
onSessionSwitched: () => void

@ -226,7 +226,7 @@ declare interface CondensedCompilationInput {
optimize: boolean
/** e.g: 0.6.8+commit.0bbfe453 */
version: string
evmVersion?: 'istanbul' | 'petersburg' | 'constantinople' | 'byzantium' | 'spuriousDragon' | 'tangerineWhistle' | 'homestead'
evmVersion?: 'berlin' | 'istanbul' | 'petersburg' | 'constantinople' | 'byzantium' | 'spuriousDragon' | 'tangerineWhistle' | 'homestead'
}
declare interface ContentImport {

@ -12,6 +12,7 @@ import { CopyToClipboard } from '@remix-ui/clipboard'
import { configFileContent } from './compilerConfiguration'
import './css/style.css'
const defaultPath = "compiler_config.json"
declare global {
interface Window {
@ -22,11 +23,23 @@ declare global {
const _paq = window._paq = window._paq || [] //eslint-disable-line
export const CompilerContainer = (props: CompilerContainerProps) => {
const { api, compileTabLogic, tooltip, modal, compiledFileName, updateCurrentVersion, configurationSettings, isHardhatProject, isTruffleProject, workspaceName } = props // eslint-disable-line
const {
api,
compileTabLogic,
tooltip,
modal,
compiledFileName,
updateCurrentVersion,
configurationSettings,
isHardhatProject,
isTruffleProject,
workspaceName,
configFilePath,
setConfigFilePath,
} = props // eslint-disable-line
const [state, setState] = useState({
hideWarnings: false,
autoCompile: false,
configFilePath: "compiler_config.json",
useFileConfiguration: false,
matomoAutocompileOnce: true,
optimize: false,
@ -40,7 +53,8 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
compiledFileName: '',
includeNightlies: false,
language: 'Solidity',
evmVersion: ''
evmVersion: '',
createFileOnce: true
})
const [showFilePathInput, setShowFilePathInput] = useState<boolean>(false)
const [toggleExpander, setToggleExpander] = useState<boolean>(false)
@ -53,17 +67,27 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const [compilerContainer, dispatch] = useReducer(compilerReducer, compilerInitialState)
useEffect(() => {
api.setAppParameter('configFilePath', "/compiler_config.json")
api.fileExists("/compiler_config.json").then((exists) => {
if (!exists) createNewConfigFile()
else {
// what to do? discuss
if (workspaceName) {
api.setAppParameter('configFilePath', defaultPath)
if (state.useFileConfiguration) {
api.fileExists(defaultPath).then((exists) => {
if (!exists && state.useFileConfiguration) createNewConfigFile()
})
}
})
api.setAppParameter('configFilePath', "/compiler_config.json")
setShowFilePathInput(false)
setShowFilePathInput(false)
}
}, [workspaceName])
useEffect(() => {
if (state.useFileConfiguration) {
api.fileExists(defaultPath).then((exists) => {
if (!exists) createNewConfigFile()
})
setToggleExpander(true)
}
}, [state.useFileConfiguration])
useEffect(() => {
const listener = (event) => {
if (configFilePathInput.current !== event.target) {
@ -106,8 +130,10 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
const hideWarnings = await api.getAppParameter('hideWarnings') as boolean || false
const includeNightlies = await api.getAppParameter('includeNightlies') as boolean || false
const useFileConfiguration = await api.getAppParameter('useFileConfiguration') as boolean || false
let configFilePath = await api.getAppParameter('configFilePath')
if (!configFilePath || configFilePath == '') configFilePath = "/compiler_config.json"
let configFilePathSaved = await api.getAppParameter('configFilePath')
if (!configFilePathSaved || configFilePathSaved == '') configFilePathSaved = defaultPath
setConfigFilePath(configFilePathSaved)
setState(prevState => {
const params = api.getCompilerParameters()
@ -122,7 +148,6 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
autoCompile: autocompile,
includeNightlies: includeNightlies,
useFileConfiguration: useFileConfiguration,
configFilePath: configFilePath,
optimize: optimize,
runs: runs,
evmVersion: (evmVersion !== null) && (evmVersion !== 'null') && (evmVersion !== undefined) && (evmVersion !== 'undefined') ? evmVersion : 'default',
@ -181,7 +206,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
useEffect(() => {
compileTabLogic.setUseFileConfiguration(state.useFileConfiguration)
if (state.useFileConfiguration) compileTabLogic.setConfigFilePath(state.configFilePath)
if (state.useFileConfiguration) compileTabLogic.setConfigFilePath(configFilePath)
}, [state.useFileConfiguration])
useEffect(() => {
@ -191,6 +216,16 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
}, [configurationSettings])
const toggleConfigType = () => {
if (state.useFileConfiguration)
if (state.createFileOnce) {
api.fileExists(defaultPath).then((exists) => {
if (!exists || state.useFileConfiguration ) createNewConfigFile()
})
setState(prevState => {
return { ...prevState, createFileOnce: false }
})
}
setState(prevState => {
api.setAppParameter('useFileConfiguration', !state.useFileConfiguration)
return { ...prevState, useFileConfiguration: !state.useFileConfiguration }
@ -198,18 +233,17 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
}
const openFile = async () => {
api.open(state.configFilePath)
api.open(configFilePath)
}
const createNewConfigFile = async () => {
let filePath = configFilePathInput.current && configFilePathInput.current.value !== '' ? configFilePathInput.current.value : state.configFilePath
let filePath = configFilePathInput.current && configFilePathInput.current.value !== '' ? configFilePathInput.current.value : configFilePath
if (filePath === '') filePath = defaultPath
if (!filePath.endsWith('.json')) filePath = filePath + '.json'
await api.writeFile(filePath, configFileContent)
api.setAppParameter('configFilePath', filePath)
setState(prevState => {
return { ...prevState, configFilePath: filePath }
})
setConfigFilePath(filePath)
compileTabLogic.setConfigFilePath(filePath)
setShowFilePathInput(false)
}
@ -220,9 +254,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
if (await api.fileExists(configFilePathInput.current.value)) {
api.setAppParameter('configFilePath', configFilePathInput.current.value)
setState(prevState => {
return { ...prevState, configFilePath: configFilePathInput.current.value }
})
setConfigFilePath(configFilePathInput.current.value)
compileTabLogic.setConfigFilePath(configFilePathInput.current.value)
setShowFilePathInput(false)
@ -394,6 +426,9 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
compileIcon.current.classList.remove('remixui_spinningIcon')
compileIcon.current.classList.remove('remixui_bouncingIcon')
if (!state.autoCompile || (state.autoCompile && state.matomoAutocompileOnce)) {
if (state.useFileConfiguration)
_paq.push(['trackEvent', 'compiler', 'compiled_with_config_file'])
_paq.push(['trackEvent', 'compiler', 'compiled_with_version', _retrieveVersion()])
if (state.autoCompile && state.matomoAutocompileOnce) {
setState(prevState => {
@ -750,36 +785,38 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
</div>
<div className="d-flex pb-1 remixui_compilerConfig custom-control custom-radio">
<input className="custom-control-input" type="radio" name="configradio" value="file" onChange={toggleConfigType} checked={state.useFileConfiguration} id="scFileConfig" />
<label className="form-check-label custom-control-label" htmlFor="scFileConfig">Use configuration file</label>
<label className="form-check-label custom-control-label" htmlFor="scFileConfig" data-id="scFileConfiguration">Use configuration file</label>
</div>
<div className={`pt-2 ml-4 ml-2 align-items-start justify-content-between d-flex`}>
{ (!showFilePathInput && state.useFileConfiguration) && <span
title="Click to open the config file."
onClick={openFile}
className="py-2 text-primary remixui_compilerConfigPath"
>{state.configFilePath}</span> }
{ (!showFilePathInput&& !state.useFileConfiguration) && <span className="py-2 text-secondary">{state.configFilePath}</span> }
onClick={configFilePath === '' ? () => {} : openFile}
className="py-2 remixui_compilerConfigPath"
>{configFilePath === '' ? 'No file selected.' : configFilePath}</span> }
{ (!showFilePathInput && !state.useFileConfiguration) && <span className="py-2 text-secondary">{configFilePath}</span> }
<input
ref={configFilePathInput}
className={`py-0 my-0 form-control ${showFilePathInput ? "d-flex" : "d-none"}`}
placeholder={"Enter the new path"}
title="If the file you entered does not exist you will be able to create one in the next step."
disabled={!state.useFileConfiguration}
data-id="scConfigFilePathInput"
onKeyPress={event => {
if (event.key === 'Enter') {
handleConfigPathChange()
}
}}
/>
{ !showFilePathInput && <button disabled={!state.useFileConfiguration} className="btn-secondary" onClick={() => {setShowFilePathInput(true)}}>Change</button> }
{ !showFilePathInput && <button disabled={!state.useFileConfiguration} data-id="scConfigChangeFilePath" className="btn-secondary" onClick={() => {setShowFilePathInput(true)}}>Change</button> }
</div>
</div>
<div className="px-4">
<button id="compileBtn" data-id="compilerContainerCompileBtn" className="btn btn-primary btn-block d-block w-100 text-break remixui_disabled mb-1 mt-3" onClick={compile} disabled={disableCompileButton}>
<button id="compileBtn" data-id="compilerContainerCompileBtn" className="btn btn-primary btn-block d-block w-100 text-break remixui_disabled mb-1 mt-3" onClick={compile} disabled={(configFilePath === '' && state.useFileConfiguration) || disableCompileButton}>
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile">
<div className="text-left">
<div><b>Ctrl+S</b> for compiling</div>
{ !(configFilePath === '' && state.useFileConfiguration) && <div><b>Ctrl+S</b> for compiling</div> }
{ (configFilePath === '' && state.useFileConfiguration) && <div> No config file selected</div> }
</div>
</Tooltip>
}>
@ -790,11 +827,12 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
</OverlayTrigger>
</button>
<div className='d-flex align-items-center'>
<button id="compileAndRunBtn" data-id="compilerContainerCompileAndRunBtn" className="btn btn-secondary btn-block d-block w-100 text-break remixui_solidityCompileAndRunButton d-inline-block remixui_disabled mb-1 mt-3" onClick={compileAndRun} disabled={disableCompileButton}>
<button id="compileAndRunBtn" data-id="compilerContainerCompileAndRunBtn" className="btn btn-secondary btn-block d-block w-100 text-break remixui_solidityCompileAndRunButton d-inline-block remixui_disabled mb-1 mt-3" onClick={compileAndRun} disabled={(configFilePath === '' && state.useFileConfiguration) || disableCompileButton}>
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile-run">
<div className="text-left">
<div><b>Ctrl+Shift+S</b> for compiling and script execution</div>
{ !(configFilePath === '' && state.useFileConfiguration) && <div><b>Ctrl+Shift+S</b> for compiling and script execution</div> }
{ (configFilePath === '' && state.useFileConfiguration) && <div> No config file selected</div> }
</div>
</Tooltip>
}>
@ -806,18 +844,18 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile-run-doc">
<div className="text-left p-2">
<div>Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:</div>
<pre>
<code>
/**<br />
* @title ContractName<br />
* @dev ContractDescription<br />
* @custom:dev-run-script file_path<br />
*/<br />
contract ContractName {'{}'}<br />
</code>
</pre>
Click to know more
<div>Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:</div>
<pre>
<code>
/**<br />
* @title ContractName<br />
* @dev ContractDescription<br />
* @custom:dev-run-script file_path<br />
*/<br />
contract ContractName {'{}'}<br />
</code>
</pre>
Click to know more
</div>
</Tooltip>
}>

@ -24,7 +24,7 @@ export class CompileTabLogic {
constructor (public api: ICompilerApi, public contentImport) {
this.event = new EventEmitter()
this.compiler = new Compiler((url, cb) => api.resolveContentAndSave(url).then((result) => cb(null, result)).catch((error) => cb(error.message)))
this.evmVersions = ['default', 'london', 'istanbul', 'petersburg', 'constantinople', 'byzantium', 'spuriousDragon', 'tangerineWhistle', 'homestead']
this.evmVersions = ['default', 'berlin', 'london', 'istanbul', 'petersburg', 'constantinople', 'byzantium', 'spuriousDragon', 'tangerineWhistle', 'homestead']
}
init () {
@ -106,9 +106,11 @@ export class CompileTabLogic {
const sources = { [target]: { content } }
this.event.emit('removeAnnotations')
this.event.emit('startingCompilation')
this.api.readFile(this.configFilePath).then( contentConfig => {
this.compiler.set('configFileContent', contentConfig)
})
if (this.configFilePath) {
this.api.readFile(this.configFilePath).then( contentConfig => {
this.compiler.set('configFileContent', contentConfig)
})
}
// setTimeout fix the animation on chrome... (animation triggered by 'staringCompilation')
setTimeout(() => { this.compiler.compile(sources, target); resolve(true) }, 100)
}).catch((error) => {

@ -15,6 +15,7 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
isTruffleProject: false,
workspaceName: '',
currentFile,
configFilePath: 'compiler_config.json',
loading: false,
compileTabLogic: null,
compiler: null,
@ -71,6 +72,13 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
return { ...prevState, currentFile, isHardhatProject: isHardhat, workspaceName: workspaceName, isTruffleProject: isTruffle }
})
}
api.onFileRemoved = (path: string) => {
if (path === state.configFilePath)
setState(prevState => {
return { ...prevState, configFilePath: '' }
})
}
api.onNoFileSelected = () => {
setState(prevState => {
@ -103,6 +111,13 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
setBadgeStatus({ ...badgeStatus, [currentFile]: data })
}
const setConfigFilePath = (path: string) => {
setState(prevState => {
return { ...prevState, configFilePath: path }
})
}
const toast = (message: string) => {
setState(prevState => {
return { ...prevState, toasterMsg: message }
@ -162,6 +177,8 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
compiledFileName={currentFile}
updateCurrentVersion={updateCurrentVersion}
configurationSettings={configurationSettings}
configFilePath={state.configFilePath}
setConfigFilePath={setConfigFilePath}
/>
{ contractsFile[currentFile] && contractsFile[currentFile].contractsDetails && <ContractSelection api={api} contractsDetails={contractsFile[currentFile].contractsDetails} contractList={contractsFile[currentFile].contractList} modal={modal} /> }
{ compileErrors[currentFile] &&

@ -16,7 +16,9 @@ export interface CompilerContainerProps {
modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void,
compiledFileName: string,
updateCurrentVersion: any,
configurationSettings: ConfigurationSettings
configurationSettings: ConfigurationSettings,
configFilePath: string,
setConfigFilePath: (path: string) => void
}
export interface ContractSelectionProps {
api: ICompilerApi,

@ -13,6 +13,7 @@
padding-left : 6px;
padding-right : 6px;
padding-top : 6px;
overflow-y : auto;
}
.remixui_fileExplorerTree {
cursor : default;

@ -228,9 +228,9 @@ export function Workspace () {
</div>
</header>
</div>
<div className='remixui_fileExplorerTree'>
<div>
<div className='pl-2 remixui_treeview' data-id='filePanelFileExplorerTree'>
<div className='h-100 remixui_fileExplorerTree'>
<div className='h-100'>
<div className='pl-2 h-100 remixui_treeview' data-id='filePanelFileExplorerTree'>
{ (global.fs.mode === 'browser') && (currentWorkspace !== NO_WORKSPACE) &&
<FileExplorer
name={currentWorkspace}

@ -60,7 +60,7 @@
"minify": "uglifyjs --in-source-map inline --source-map-inline -c warnings=false",
"build:production": "NODE_ENV=production nx build remix-ide --skip-nx-cache",
"serve:production": "npx http-server ./dist/apps/remix-ide",
"select_test": "sh apps/remix-ide-e2e/src/select_tests.sh",
"select_test": "bash apps/remix-ide-e2e/src/select_tests.sh",
"group_test": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/${npm_config_test}_group${npm_config_group}.test.js --env=${npm_config_env}",
"nightwatch_parallel": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js --env=chrome,firefox",
"nightwatch_local_firefox": "yarn run build:e2e && nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js --env=firefox",

Loading…
Cancel
Save