diff --git a/apps/remix-ide-e2e/src/tests/plugin_api.ts b/apps/remix-ide-e2e/src/tests/plugin_api.ts index 8409cb935d..cf696f2bec 100644 --- a/apps/remix-ide-e2e/src/tests/plugin_api.ts +++ b/apps/remix-ide-e2e/src/tests/plugin_api.ts @@ -230,7 +230,13 @@ module.exports = { }, 'Should get current files #group7': async function (browser: NightwatchBrowser) { - await clickAndCheckLog(browser, 'fileManager:readdir', { contracts: { isDirectory: true }, scripts: { isDirectory: true }, tests: { isDirectory: true }, 'README.txt': { isDirectory: false } }, null, '/') + await clickAndCheckLog(browser, 'fileManager:readdir', { + 'compiler_config.json': { isDirectory: false }, + contracts: { isDirectory: true }, + scripts: { isDirectory: true }, + tests: { isDirectory: true }, + 'README.txt': { isDirectory: false } + }, null, '/') }, 'Should throw error on current file #group7': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'fileManager:getCurrentFile', 'Error from IDE : Error: No such file or directory No file selected', null, null) @@ -280,12 +286,20 @@ 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', {}, null, '/') + await clickAndCheckLog(browser, 'fileManager:readdir', { + 'compiler_config.json': { isDirectory: false } + }, 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', { contracts: { isDirectory: true }, scripts: { isDirectory: true }, tests: { isDirectory: true }, 'README.txt': { isDirectory: false } }, null, null) + await clickAndCheckLog(browser, 'fileManager:readdir', { + 'compiler_config.json': { isDirectory: false }, + contracts: { isDirectory: true }, + scripts: { isDirectory: true }, + tests: { isDirectory: true }, + 'README.txt': { isDirectory: false } + }, null, null) }, 'Should get all workspaces #group2': async function (browser: NightwatchBrowser) { await clickAndCheckLog(browser, 'filePanel:getWorkspaces', ['default_workspace', 'emptyworkspace', 'testspace'], null, null) diff --git a/apps/remix-ide-e2e/src/tests/recorder.test.ts b/apps/remix-ide-e2e/src/tests/recorder.test.ts index fc77f0ef0f..7e1c0859a7 100644 --- a/apps/remix-ide-e2e/src/tests/recorder.test.ts +++ b/apps/remix-ide-e2e/src/tests/recorder.test.ts @@ -17,7 +17,7 @@ module.exports = { .pause(5000) .clickLaunchIcon('udapp') .selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c') // this account will be used for this test suite - .click('[data-id="udapp_arrow"]') + .click('[data-id="udappRecorderTitleExpander"]') .click('[data-id="runtransaction"]') .clickInstance(0) .clickInstance(1) diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index e6233ae2e7..a201b4ea36 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -81,6 +81,7 @@ module.exports = { .refresh() .pause(5000) .clickLaunchIcon('solidity') + .click('*[data-id="scConfigExpander"]') .assert.containsText('#versionSelector option[data-id="selected"]', '0.7.4+commit.3f05b770') .assert.containsText('#evmVersionSelector option[data-id="selected"]', 'istanbul') .assert.containsText('#compilierLanguageSelector option[data-id="selected"]', 'Yul') @@ -96,6 +97,7 @@ module.exports = { .pause(5000) .clickLaunchIcon('solidity') .pause(5000) + .click('*[data-id="scConfigExpander"]') .assert.containsText('#versionSelector option[data-id="selected"]', 'custom') // default values .assert.containsText('#evmVersionSelector option[data-id="selected"]', 'default') diff --git a/apps/remix-ide-e2e/src/tests/workspace.test.ts b/apps/remix-ide-e2e/src/tests/workspace.test.ts index 092d939302..f5fea02e36 100644 --- a/apps/remix-ide-e2e/src/tests/workspace.test.ts +++ b/apps/remix-ide-e2e/src/tests/workspace.test.ts @@ -107,8 +107,8 @@ module.exports = { const fileList = document.querySelector('*[data-id="treeViewUltreeViewMenu"]') return fileList.getElementsByTagName('li').length; }, [], function(result){ - // check there are no files in FE - browser.assert.equal(result.value, 0, 'Incorrect number of files'); + // check there are no files in FE except config file + browser.assert.equal(result.value, 1, 'Incorrect number of files'); }); }, diff --git a/apps/remix-ide/src/app/panels/tab-proxy.js b/apps/remix-ide/src/app/panels/tab-proxy.js index 43e15f5af4..645b30ecce 100644 --- a/apps/remix-ide/src/app/panels/tab-proxy.js +++ b/apps/remix-ide/src/app/panels/tab-proxy.js @@ -215,6 +215,7 @@ export class TabProxy extends Plugin { } renameTab (oldName, newName) { + // The new tab is being added by FileManager this.removeTab(oldName) } diff --git a/apps/remix-ide/src/app/plugins/config.ts b/apps/remix-ide/src/app/plugins/config.ts index 3102d555df..b65f1ddfa7 100644 --- a/apps/remix-ide/src/app/plugins/config.ts +++ b/apps/remix-ide/src/app/plugins/config.ts @@ -18,7 +18,7 @@ export class ConfigPlugin extends Plugin { const queryParams = new QueryParams() const params = queryParams.get() const config = Registry.getInstance().get('config').api - let param = params[name] || config.get(name) || config.get('settings/' + name) + const param = params[name] || config.get(name) || config.get('settings/' + name) if (param === 'true') return true if (param === 'false') return false return param diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 96d79aba39..0868ef8689 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -7,7 +7,7 @@ const _paq = window._paq = window._paq || [] const requiredModules = [ // services + layout views + system views 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', - 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', + 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout', 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy', 'hardhat-provider', 'compileAndRun', 'search'] const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd) @@ -19,7 +19,8 @@ const sensitiveCalls = { } export function isNative(name) { - const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider'] + const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'solidity-logic', + 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification', 'hardhat-provider', 'ganache-provider'] return nativePlugins.includes(name) || requiredModules.includes(name) } diff --git a/apps/solidity-compiler/src/app/compiler-api.ts b/apps/solidity-compiler/src/app/compiler-api.ts index ade46d3223..8a5437359c 100644 --- a/apps/solidity-compiler/src/app/compiler-api.ts +++ b/apps/solidity-compiler/src/app/compiler-api.ts @@ -18,7 +18,7 @@ export const CompilerApiMixin = (Base) => class extends Base { onCurrentFileChanged: (fileName: string) => void // onResetResults: () => void - onSetWorkspace: (workspace: any) => void + onSetWorkspace: (isLocalhost: boolean, workspaceName: string) => void onNoFileSelected: () => void onCompilationFinished: (compilationDetails: { contractMap: { file: string } | Record, contractsDetails: Record }) => void onSessionSwitched: () => void @@ -237,12 +237,12 @@ export const CompilerApiMixin = (Base) => class extends Base { this.on('filePanel', 'setWorkspace', (workspace) => { this.resetResults() - if (this.onSetWorkspace) this.onSetWorkspace(workspace.isLocalhost) + if (this.onSetWorkspace) this.onSetWorkspace(workspace.isLocalhost, workspace.name) }) this.on('remixd', 'rootFolderChanged', () => { this.resetResults() - if (this.onSetWorkspace) this.onSetWorkspace(true) + if (this.onSetWorkspace) this.onSetWorkspace(true, 'localhost') }) this.on('editor', 'sessionSwitched', () => { diff --git a/apps/solidity-compiler/src/app/compiler.ts b/apps/solidity-compiler/src/app/compiler.ts index a58ff585a2..df64855ab9 100644 --- a/apps/solidity-compiler/src/app/compiler.ts +++ b/apps/solidity-compiler/src/app/compiler.ts @@ -6,31 +6,14 @@ import { CompilerApiMixin } from './compiler-api' import { ICompilerApi } from '@remix-project/remix-lib-ts' import { CompileTabLogic } from '@remix-ui/solidity-compiler' -const profile = { - name: 'solidity', - displayName: 'Solidity compiler', - icon: 'assets/img/solidity.webp', - description: 'Compile solidity contracts', - kind: 'compiler', - permission: true, - location: 'sidePanel', - documentation: 'https://remix-ide.readthedocs.io/en/latest/solidity_editor.html', - version: '0.0.1', - methods: ['getCompilationResult', 'compile', 'compileWithParameters', 'setCompilerConfig', 'compileFile', 'getCompilerState'] -} - -const defaultAppParameters = { - hideWarnings: false, - autoCompile: false, - includeNightlies: false -} - const defaultCompilerParameters = { runs: '200', optimize: false, version: 'soljson-v0.8.7+commit.e28d00a7', evmVersion: null, // compiler default - language: 'Solidity' + language: 'Solidity', + useFileConfiguration: false, + configFilePath: "compiler_config.json" } export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements ICompilerApi { constructor () { @@ -48,7 +31,9 @@ export class CompilerClientApi extends CompilerApiMixin(PluginClient) implements optimize: localStorage.getItem('optimize') === 'true', version: localStorage.getItem('version') || defaultCompilerParameters.version, evmVersion: localStorage.getItem('evmVersion') || defaultCompilerParameters.evmVersion, // default - language: localStorage.getItem('language') || defaultCompilerParameters.language + language: localStorage.getItem('language') || defaultCompilerParameters.language, + useFileConfiguration: localStorage.getItem('useFileConfiguration') === 'true', + configFilePath: localStorage.getItem('configFilePath') || defaultCompilerParameters.configFilePath } return params } diff --git a/libs/remix-lib/src/types/ICompilerApi.ts b/libs/remix-lib/src/types/ICompilerApi.ts index 8e43892fa0..f34d20f420 100644 --- a/libs/remix-lib/src/types/ICompilerApi.ts +++ b/libs/remix-lib/src/types/ICompilerApi.ts @@ -24,7 +24,7 @@ export interface ICompilerApi { onCurrentFileChanged: (fileName: string) => void // onResetResults: () => void, - onSetWorkspace: (workspace: any) => void + onSetWorkspace: (isLocalhost: boolean, workspaceName: string) => void onNoFileSelected: () => void onCompilationFinished: (contractsDetails: any, contractMap: any) => void onSessionSwitched: () => void diff --git a/libs/remix-solidity/src/compiler/compiler-input.ts b/libs/remix-solidity/src/compiler/compiler-input.ts index 59a650620e..44c03305e0 100644 --- a/libs/remix-solidity/src/compiler/compiler-input.ts +++ b/libs/remix-solidity/src/compiler/compiler-input.ts @@ -46,3 +46,9 @@ export function getValidLanguage (val: string): Language { } return null } + +export function compilerInputForConfigFile(sources: Source, opts) +{ + opts.sources = sources + return JSON.stringify(opts) +} diff --git a/libs/remix-solidity/src/compiler/compiler.ts b/libs/remix-solidity/src/compiler/compiler.ts index a10fa6fce2..f728748a9e 100644 --- a/libs/remix-solidity/src/compiler/compiler.ts +++ b/libs/remix-solidity/src/compiler/compiler.ts @@ -2,7 +2,7 @@ import { update } from 'solc/abi' import * as webworkify from 'webworkify-webpack' -import compilerInput from './compiler-input' +import compilerInput, { compilerInputForConfigFile } from './compiler-input' import EventManager from '../lib/eventManager' import txHelper from './helper' import { @@ -31,6 +31,8 @@ export class Compiler { language: 'Solidity', compilationStartTime: null, target: null, + useFileConfiguration: false, + configFileContent: '', lastCompilationResult: { data: null, source: null @@ -111,11 +113,17 @@ export class Compiler { return { error: 'Deferred import' } } let result: CompilationResult = {} - let input + let input = "" try { if (source && source.sources) { - const { optimize, runs, evmVersion, language } = this.state - input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) + const { optimize, runs, evmVersion, language, useFileConfiguration, configFileContent } = this.state + + if (useFileConfiguration) { + input = compilerInputForConfigFile(source.sources, JSON.parse(configFileContent)) + } else { + input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) + } + result = JSON.parse(compiler.compile(input, { import: missingInputsCallback })) } } catch (exception) { @@ -183,11 +191,17 @@ export class Compiler { return { error: 'Deferred import' } } let result: CompilationResult = {} - let input: string + let input = "" try { if (source && source.sources) { - const { optimize, runs, evmVersion, language } = this.state - input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) + const { optimize, runs, evmVersion, language, useFileConfiguration, configFileContent } = this.state + + if (useFileConfiguration) { + input = compilerInputForConfigFile(source.sources, JSON.parse(configFileContent)) + } else { + input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) + } + result = JSON.parse(remoteCompiler.compile(input, { import: missingInputsCallback })) } } catch (exception) { @@ -289,12 +303,26 @@ export class Compiler { this.state.compileJSON = (source: SourceWithTarget) => { if (source && source.sources) { - const { optimize, runs, evmVersion, language } = this.state + const { optimize, runs, evmVersion, language, useFileConfiguration, configFileContent } = this.state jobs.push({ sources: source }) + let input = "" + + try { + if (useFileConfiguration) { + input = compilerInputForConfigFile(source.sources, JSON.parse(configFileContent)) + } else { + input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) + } + } catch (exception) { + this.onCompilationFinished({ error: { formattedMessage: exception.message } }, [], source, "", this.state.currentVersion) + return + } + + this.state.worker.postMessage({ cmd: 'compile', job: jobs.length - 1, - input: compilerInput(source.sources, { optimize, runs, evmVersion, language }) + input: input }) } } diff --git a/libs/remix-solidity/src/compiler/types.ts b/libs/remix-solidity/src/compiler/types.ts index 76ed36ca17..c4e48dd2ff 100644 --- a/libs/remix-solidity/src/compiler/types.ts +++ b/libs/remix-solidity/src/compiler/types.ts @@ -164,6 +164,8 @@ export interface CompilerState { language: Language, compilationStartTime: number| null, target: string | null, + useFileConfiguration: boolean, + configFileContent: string, lastCompilationResult: { data: CompilationResult | null, source: SourceWithTarget | null | undefined diff --git a/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx b/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx index cca6777535..afc97b9dac 100644 --- a/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx @@ -11,8 +11,8 @@ export function InstanceContainerUI (props: InstanceContainerProps) { } return ( -
-
+
+ { instanceList.length > 0 ?
{ props.instances.instanceList.map((instance, index) => { return { - return ( -
{}}> -
-
{title}
-
-
-
{recorderCount}
-
-
-
-
-
-
-
- ) - } - + const [toggleExpander, setToggleExpander] = useState(false) const triggerRecordButton = () => { props.storeScenario(props.scenarioPrompt) } @@ -30,24 +12,35 @@ export function RecorderUI (props: RecorderProps) { props.runCurrentScenario(props.gasEstimationPrompt, props.passphrasePrompt, props.mainnetPrompt, props.logBuilder) } + const toggleClass = () => { + setToggleExpander(!toggleExpander) + } + return ( -
- - -
-
- All transactions (deployed contracts and function executions) in this environment can be saved and replayed in - another environment. e.g Transactions created in Javascript VM can be replayed in the Injected Web3. -
-
- - -
-
-
-
+
+
+
+ +
{props.count}
+
+
+ + + +
+
+
+
+ All transactions (deployed contracts and function executions) can be saved and replayed in + another environment. e.g Transactions created in Javascript VM can be replayed in the Injected Web3. +
+
+ + +
+
) } diff --git a/libs/remix-ui/run-tab/src/lib/css/card.css b/libs/remix-ui/run-tab/src/lib/css/card.css index 1decf7c720..65cba95c60 100644 --- a/libs/remix-ui/run-tab/src/lib/css/card.css +++ b/libs/remix-ui/run-tab/src/lib/css/card.css @@ -2,11 +2,4 @@ padding : 0 24px 16px; margin : 0; background : none; -} -.udapp_arrow { - font-weight : bold; - cursor : pointer; - font-size : 14px; -} -.udapp_arrow:hover { } \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/css/run-tab.css b/libs/remix-ui/run-tab/src/lib/css/run-tab.css index f5ec6c2e65..5ad8e6774c 100644 --- a/libs/remix-ui/run-tab/src/lib/css/run-tab.css +++ b/libs/remix-ui/run-tab/src/lib/css/run-tab.css @@ -60,6 +60,9 @@ text-align: center; padding: 0 14px 16px; } +.udapp_deployedContracts { + font-size: 1rem; +} .udapp_pendingTxsContainer { display: flex; flex-direction: column; @@ -70,9 +73,6 @@ .udapp_container { padding: 0 24px 16px; } -.udapp_recorderDescription { - margin: 0 15px 15px 0; - } .udapp_contractNames { width: 100%; border: 1px solid @@ -121,7 +121,14 @@ .udapp_ataddressinput { padding: .25rem; } -.udapp_create { +.udapp_recorderSection:hover { + cursor: pointer; +}.udapp_recorderSectionLabel:hover { + cursor: pointer; +} +.udapp_recorderSectionLabel { + cursor: pointer; + font-size: 1rem; } .udapp_input { font-size: 10px !important; diff --git a/libs/remix-ui/run-tab/src/lib/types/index.ts b/libs/remix-ui/run-tab/src/lib/types/index.ts index b3ac8ca28c..5f1d2fb496 100644 --- a/libs/remix-ui/run-tab/src/lib/types/index.ts +++ b/libs/remix-ui/run-tab/src/lib/types/index.ts @@ -227,7 +227,8 @@ export interface ContractGUIProps { clickCallBack: (inputs: { name: string, type: string }[], input: string) => void, widthClass?: string, evmBC: any, - lookupOnly: boolean + lookupOnly: boolean, + disabled?: boolean } export interface MainnetProps { network: Network, diff --git a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx index f1fc578600..17d3baa2d2 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx @@ -9,6 +9,7 @@ import { resetEditorMode, listenToEvents } from './actions/compiler' import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line import { getValidLanguage } from '@remix-project/remix-solidity' import { CopyToClipboard } from '@remix-ui/clipboard' +import { configFileContent } from './compilerConfiguration' import './css/style.css' @@ -21,10 +22,12 @@ 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 } = props // eslint-disable-line + const { api, compileTabLogic, tooltip, modal, compiledFileName, updateCurrentVersion, configurationSettings, isHardhatProject, isTruffleProject, workspaceName } = props // eslint-disable-line const [state, setState] = useState({ hideWarnings: false, autoCompile: false, + configFilePath: "compiler_config.json", + useFileConfiguration: false, matomoAutocompileOnce: true, optimize: false, compileTimeout: null, @@ -39,13 +42,43 @@ export const CompilerContainer = (props: CompilerContainerProps) => { language: 'Solidity', evmVersion: '' }) + const [showFilePathInput, setShowFilePathInput] = useState(false) + const [toggleExpander, setToggleExpander] = useState(false) const [disableCompileButton, setDisableCompileButton] = useState(false) const compileIcon = useRef(null) const promptMessageInput = useRef(null) + const configFilePathInput = useRef(null) const [hhCompilation, sethhCompilation] = useState(false) const [truffleCompilation, setTruffleCompilation] = useState(false) 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 + } + }) + api.setAppParameter('configFilePath', "/compiler_config.json") + setShowFilePathInput(false) + }, [workspaceName]) + + useEffect(() => { + const listener = (event) => { + if (configFilePathInput.current !== event.target) { + setShowFilePathInput(false) + return; + } + }; + document.addEventListener("mousedown", listener); + document.addEventListener("touchstart", listener); + return () => { + document.removeEventListener("mousedown", listener); + document.removeEventListener("touchstart", listener); + } + }) + useEffect(() => { fetchAllVersion((allversions, selectedVersion, isURL) => { setState(prevState => { @@ -72,6 +105,10 @@ export const CompilerContainer = (props: CompilerContainerProps) => { const autocompile = await api.getAppParameter('autoCompile') as boolean || false 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" + setState(prevState => { const params = api.getCompilerParameters() const optimize = params.optimize @@ -84,6 +121,8 @@ export const CompilerContainer = (props: CompilerContainerProps) => { hideWarnings: hideWarnings, autoCompile: autocompile, includeNightlies: includeNightlies, + useFileConfiguration: useFileConfiguration, + configFilePath: configFilePath, optimize: optimize, runs: runs, evmVersion: (evmVersion !== null) && (evmVersion !== 'null') && (evmVersion !== undefined) && (evmVersion !== 'undefined') ? evmVersion : 'default', @@ -140,12 +179,67 @@ export const CompilerContainer = (props: CompilerContainerProps) => { } }, [compilerContainer.editor.mode]) + useEffect(() => { + compileTabLogic.setUseFileConfiguration(state.useFileConfiguration) + if (state.useFileConfiguration) compileTabLogic.setConfigFilePath(state.configFilePath) + }, [state.useFileConfiguration]) + useEffect(() => { if (configurationSettings) { setConfiguration(configurationSettings) } }, [configurationSettings]) + const toggleConfigType = () => { + setState(prevState => { + api.setAppParameter('useFileConfiguration', !state.useFileConfiguration) + return { ...prevState, useFileConfiguration: !state.useFileConfiguration } + }) + } + + const openFile = async () => { + api.open(state.configFilePath) + } + + const createNewConfigFile = async () => { + let filePath = configFilePathInput.current && configFilePathInput.current.value !== '' ? configFilePathInput.current.value : state.configFilePath + if (!filePath.endsWith('.json')) filePath = filePath + '.json' + + await api.writeFile(filePath, configFileContent) + api.setAppParameter('configFilePath', filePath) + setState(prevState => { + return { ...prevState, configFilePath: filePath } + }) + compileTabLogic.setConfigFilePath(filePath) + setShowFilePathInput(false) + } + + const handleConfigPathChange = async () => { + if (configFilePathInput.current.value !== '') { + if (!configFilePathInput.current.value.endsWith('.json')) configFilePathInput.current.value += '.json' + + if (await api.fileExists(configFilePathInput.current.value)) { + api.setAppParameter('configFilePath', configFilePathInput.current.value) + setState(prevState => { + return { ...prevState, configFilePath: configFilePathInput.current.value } + }) + compileTabLogic.setConfigFilePath(configFilePathInput.current.value) + + setShowFilePathInput(false) + } else { + modal( + 'New configuration file', `The file "${configFilePathInput.current.value}" you entered does not exist. Do you want to create a new one?`, + 'Create', + async () => await createNewConfigFile(), + 'Cancel', + () => { + setShowFilePathInput(false) + } + ) + } + } + } + const _retrieveVersion = (version?) => { if (!version) version = state.selectedVersion if (version === 'builtin') version = state.defaultVersion @@ -537,14 +631,18 @@ export const CompilerContainer = (props: CompilerContainerProps) => { onChangeRuns(settings.runs) } + const toggleConfigurations = () => { + setToggleExpander(!toggleExpander) + } + return (
-
-
+
+
-
+
-
- - +
+ +
-
- - -
-
-

Compiler Configuration

-
- - -
-
-
- { handleOptimizeChange(e.target.checked) }} className="custom-control-input" id="optimize" type="checkbox" checked={state.optimize} /> - - onChangeRuns(e.target.value)} - disabled={!state.optimize} - /> -
-
-
- - -
+
+ +
{ isHardhatProject && @@ -635,7 +700,81 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
} +
+
+
+ +
+ + + +
+
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ { handleOptimizeChange(e.target.checked) }} disabled={state.useFileConfiguration} className="custom-control-input" id="optimize" type="checkbox" checked={state.optimize} /> + + onChangeRuns(e.target.value)} + disabled={!state.optimize || state.useFileConfiguration} + /> +
+
+
+
+ + +
+
+ { (!showFilePathInput && state.useFileConfiguration) && {state.configFilePath} } + { (!showFilePathInput&& !state.useFileConfiguration) && {state.configFilePath} } + { + if (event.key === 'Enter') { + handleConfigPathChange() + } + }} + /> + { !showFilePathInput && } +
+
+
-
-
Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:
-
-                      
-                      /**
- * @title ContractName
- * @dev ContractDescription
- * @custom:dev-run-script file_path
- */
- contract ContractName {'{}'}
-
-
- Click to know more -
- - }> - -
- '@custom:dev-run-script file_path'} direction='top'> - - -
-
-
+ +
+
Choose the script to execute right after compilation by adding the `dev-run-script` natspec tag, as in:
+
+                  
+                  /**
+ * @title ContractName
+ * @dev ContractDescription
+ * @custom:dev-run-script file_path
+ */
+ contract ContractName {'{}'}
+
+
+ Click to know more +
+
+ }> + + + '@custom:dev-run-script file_path'} direction='top'> + + +
+
) diff --git a/libs/remix-ui/solidity-compiler/src/lib/compilerConfiguration.tsx b/libs/remix-ui/solidity-compiler/src/lib/compilerConfiguration.tsx new file mode 100644 index 0000000000..d05e1ab21c --- /dev/null +++ b/libs/remix-ui/solidity-compiler/src/lib/compilerConfiguration.tsx @@ -0,0 +1,18 @@ +export const configFileContent = ` +{ + "language": "Solidity", + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "": ["ast"], + "*": ["abi", "metadata", "devdoc", "userdoc", "storageLayout", "evm.legacyAssembly", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "evm.gasEstimates", "evm.assembly"] + } + }, + "evmVersion": "byzantium" + } +} +` \ No newline at end of file diff --git a/libs/remix-ui/solidity-compiler/src/lib/css/style.css b/libs/remix-ui/solidity-compiler/src/lib/css/style.css index 9bc492311d..892dc26e0b 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/css/style.css +++ b/libs/remix-ui/solidity-compiler/src/lib/css/style.css @@ -72,6 +72,15 @@ .remixui_compilerSection { padding: 12px 24px 16px; } +.remixui_compilerConfigSection:hover { + cursor: pointer; +} +.remixui_compilerConfigSection { + font-size: 1rem; +} +.remixui_compilerConfigPath { + cursor: pointer; +} .remixui_compilerLabel { margin-bottom: 2px; font-size: 11px; diff --git a/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts b/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts index 05e47fcd17..e84f73a76c 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts +++ b/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts @@ -18,6 +18,8 @@ export class CompileTabLogic { public compilerImport public event public evmVersions: Array + public useFileConfiguration: boolean + public configFilePath: string constructor (public api: ICompilerApi, public contentImport) { this.event = new EventEmitter() @@ -52,12 +54,21 @@ export class CompileTabLogic { } } - setOptimize (newOptimizeValue) { + setOptimize (newOptimizeValue: boolean) { this.optimize = newOptimizeValue this.api.setCompilerParameters({ optimize: this.optimize }) this.compiler.set('optimize', this.optimize) } + setUseFileConfiguration (useFileConfiguration: boolean) { + this.useFileConfiguration = useFileConfiguration + this.compiler.set('useFileConfiguration', useFileConfiguration) + } + + setConfigFilePath (path) { + this.configFilePath = path + } + setRuns (runs) { this.runs = runs this.api.setCompilerParameters({ runs: this.runs }) @@ -95,6 +106,9 @@ 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) + }) // setTimeout fix the animation on chrome... (animation triggered by 'staringCompilation') setTimeout(() => { this.compiler.compile(sources, target); resolve(true) }, 100) }).catch((error) => { diff --git a/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx b/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx index 328e830113..33d56f3175 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx @@ -13,6 +13,7 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => { const [state, setState] = useState({ isHardhatProject: false, isTruffleProject: false, + workspaceName: '', currentFile, loading: false, compileTabLogic: null, @@ -63,11 +64,11 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => { }) } - api.onSetWorkspace = async (isLocalhost: boolean) => { + api.onSetWorkspace = async (isLocalhost: boolean, workspaceName: string) => { const isHardhat = isLocalhost && await compileTabLogic.isHardhatProject() const isTruffle = await compileTabLogic.isTruffleProject() setState(prevState => { - return { ...prevState, currentFile, isHardhatProject: isHardhat, isTruffleProject: isTruffle } + return { ...prevState, currentFile, isHardhatProject: isHardhat, workspaceName: workspaceName, isTruffleProject: isTruffle } }) } @@ -150,7 +151,18 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => { return ( <>
- + { contractsFile[currentFile] && contractsFile[currentFile].contractsDetails && } { compileErrors[currentFile] &&
diff --git a/libs/remix-ui/solidity-compiler/src/lib/types/index.ts b/libs/remix-ui/solidity-compiler/src/lib/types/index.ts index d9c5635ba9..37cffd4289 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/types/index.ts +++ b/libs/remix-ui/solidity-compiler/src/lib/types/index.ts @@ -11,6 +11,7 @@ export interface CompilerContainerProps { compileTabLogic: CompileTabLogic, isHardhatProject: boolean, isTruffleProject: boolean, + workspaceName: string, tooltip: (message: string | JSX.Element) => void, modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void, compiledFileName: string, @@ -45,4 +46,3 @@ export interface CompilationDetails { export interface ContractsFile { [currentFile: string]: CompilationDetails } - diff --git a/libs/remix-ui/solidity-compiler/tsconfig.json b/libs/remix-ui/solidity-compiler/tsconfig.json index d52e31ad74..3375d6822b 100644 --- a/libs/remix-ui/solidity-compiler/tsconfig.json +++ b/libs/remix-ui/solidity-compiler/tsconfig.json @@ -4,7 +4,7 @@ "jsx": "react", "allowJs": true, "esModuleInterop": true, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, }, "files": [], "include": [],