Merge pull request #2262 from ethereum/ui_for_auto_exec

UI for auto exec
flakyhunt
yann300 3 years ago committed by GitHub
commit 1e2ffc39cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/remix-ide-e2e/src/tests/libraryDeployment.test.ts
  2. 8
      apps/remix-ide/src/app.js
  3. 3
      apps/remix-ide/src/app/panels/layout.ts
  4. 93
      apps/remix-ide/src/app/tabs/compile-and-run.ts
  5. 62
      apps/remix-ide/src/app/tabs/intelligent-script-executor.ts
  6. 12
      apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css
  7. 14
      apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
  8. 9
      apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css
  9. 12
      apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css
  10. 9
      apps/remix-ide/src/assets/css/themes/remix-black_undtds.css
  11. 9
      apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css
  12. 9
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  13. 9
      apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css
  14. 9
      apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css
  15. 2
      apps/remix-ide/src/remixAppManager.js
  16. 5
      apps/solidity-compiler/src/app/compiler-api.ts
  17. 1
      libs/remix-lib/src/types/ICompilerApi.ts
  18. 80
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  19. 5
      libs/remix-ui/solidity-compiler/src/lib/css/style.css
  20. 1
      libs/remix-ui/workspace/src/lib/templates/examples.ts

@ -41,7 +41,7 @@ module.exports = {
.clickLaunchIcon('settings') .clickLaunchIcon('settings')
.click('*[data-id="settingsTabGenerateContractMetadataLabel"]') .click('*[data-id="settingsTabGenerateContractMetadataLabel"]')
.clickLaunchIcon('solidity') .clickLaunchIcon('solidity')
.click('#compileTabView button[title="Compile"]') // that should generate the JSON artefact .click('#compileTabView button[data-id="compilerContainerCompileBtn"]') // that should generate the JSON artefact
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.verifyContracts(['test']) .verifyContracts(['test'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')

@ -5,7 +5,7 @@ import { RemixAppManager } from './remixAppManager'
import { ThemeModule } from './app/tabs/theme-module' import { ThemeModule } from './app/tabs/theme-module'
import { NetworkModule } from './app/tabs/network-module' import { NetworkModule } from './app/tabs/network-module'
import { Web3ProviderModule } from './app/tabs/web3-provider' import { Web3ProviderModule } from './app/tabs/web3-provider'
import { IntelligentScriptExecutor } from './app/tabs/intelligent-script-executor' import { CompileAndRun } from './app/tabs/compile-and-run'
import { SidePanel } from './app/components/side-panel' import { SidePanel } from './app/components/side-panel'
import { HiddenPanel } from './app/components/hidden-panel' import { HiddenPanel } from './app/components/hidden-panel'
import { VerticalIcons } from './app/components/vertical-icons' import { VerticalIcons } from './app/components/vertical-icons'
@ -184,7 +184,7 @@ class AppComponent {
name: 'offsettolinecolumnconverter' name: 'offsettolinecolumnconverter'
}) })
// ----------------- run script after each compilation results ----------- // ----------------- run script after each compilation results -----------
const intelligentScriptExecutor = new IntelligentScriptExecutor() const compileAndRun = new CompileAndRun()
// -------------------Terminal---------------------------------------- // -------------------Terminal----------------------------------------
makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl)) makeUdapp(blockchain, compilersArtefacts, domEl => terminal.logHtml(domEl))
const terminal = new Terminal( const terminal = new Terminal(
@ -227,7 +227,7 @@ class AppComponent {
contextualListener, contextualListener,
terminal, terminal,
web3Provider, web3Provider,
intelligentScriptExecutor, compileAndRun,
fetchAndCompile, fetchAndCompile,
dGitProvider, dGitProvider,
storagePlugin, storagePlugin,
@ -352,7 +352,7 @@ class AppComponent {
await this.appManager.activatePlugin(['settings', 'config']) await this.appManager.activatePlugin(['settings', 'config'])
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['settings'])
await this.appManager.activatePlugin(['walkthrough','storage', 'search','intelligentScriptExecutor']) await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun'])
this.appManager.on( this.appManager.on(
'filePanel', 'filePanel',

@ -75,9 +75,6 @@ export class Layout extends Plugin {
} else if (e.code === 'KeyA') { } else if (e.code === 'KeyA') {
// Ctrl+Shift+A // Ctrl+Shift+A
this.call('menuicons', 'select', 'pluginManager') this.call('menuicons', 'select', 'pluginManager')
} else if (e.code === 'KeyS') {
// Ctrl+Shift+S
this.call('menuicons', 'select', 'settings')
} }
e.preventDefault() e.preventDefault()
} }

@ -0,0 +1,93 @@
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
declare global {
interface Window {
_paq: any
}
}
const _paq = window._paq = window._paq || []
export const profile = {
name: 'compileAndRun',
displayName: 'Compile and Run',
description: 'after each compilation, run the script defined in Natspec.',
methods: ['runScriptAfterCompilation'],
version: packageJson.version,
kind: 'none'
}
type listener = (event: KeyboardEvent) => void
export class CompileAndRun extends Plugin {
executionListener: listener
targetFileName: string
constructor () {
super(profile)
this.executionListener = async (e) => {
// ctrl+e or command+e
const file = await this.call('fileManager', 'file')
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.keyCode === 83 && file !== '') {
if (file.endsWith('.sol')) {
e.preventDefault()
this.targetFileName = file
await this.call('solidity', 'compile', file)
_paq.push(['trackEvent', 'ScriptExecutor', 'compile_solidity'])
} else if (file.endsWith('.js') || file.endsWith('.ts')) {
e.preventDefault()
this.runScript(file, false)
_paq.push(['trackEvent', 'ScriptExecutor', 'run_script'])
}
}
}
}
runScriptAfterCompilation (fileName: string) {
this.targetFileName = fileName
_paq.push(['trackEvent', 'ScriptExecutor', 'request_run_script'])
}
async runScript (fileName, clearAllInstances) {
await this.call('terminal', 'log', `running ${fileName} ...`)
try {
const exists = await this.call('fileManager', 'exists', fileName)
if (!exists) {
await this.call('terminal', 'log', `${fileName} does not exist.`)
return
}
const content = await this.call('fileManager', 'readFile', fileName)
if (clearAllInstances) {
await this.call('udapp', 'clearAllInstances')
}
await this.call('scriptRunner', 'execute', content)
} catch (e) {
this.call('notification', 'toast', e.message || e)
}
}
onActivation () {
window.document.addEventListener('keydown', this.executionListener)
this.on('compilerMetadata', 'artefactsUpdated', async (fileName, contract) => {
if (this.targetFileName === contract.file) {
if (contract.object && contract.object.devdoc['custom:dev-run-script']) {
this.targetFileName = null
const file = contract.object.devdoc['custom:dev-run-script']
if (file) {
this.runScript(file, true)
_paq.push(['trackEvent', 'ScriptExecutor', 'run_script_after_compile'])
} else {
this.call('notification', 'toast', 'You have not set a script to run. Set it with @custom:dev-run-script NatSpec tag.')
}
} else {
this.call('notification', 'toast', 'You have not set a script to run. Set it with @custom:dev-run-script NatSpec tag.')
}
}
})
}
onDeactivation () {
window.document.removeEventListener('keydown', this.executionListener)
this.off('compilerMetadata', 'artefactsUpdated')
}
}

@ -1,62 +0,0 @@
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
export const profile = {
name: 'intelligentScriptExecutor',
displayName: 'Intelligent Script Executor',
description: 'after each compilation, run the script defined in Natspec.',
methods: [],
version: packageJson.version,
kind: 'none'
}
type listener = (event: KeyboardEvent) => void
export class IntelligentScriptExecutor extends Plugin {
executionListener: listener
targetFileName: string
constructor () {
super(profile)
this.executionListener = async (e) => {
// ctrl+e or command+e
const file = await this.call('fileManager', 'file')
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.keyCode === 83 && file !== '') {
if (file.endsWith('.sol')) {
e.preventDefault()
this.targetFileName = file
await this.call('solidity', 'compile', file)
} else if (file.endsWith('.js') || file.endsWith('.ts')) {
e.preventDefault()
this.runScript(file, false)
}
}
}
}
async runScript (fileName, clearAllInstances) {
await this.call('terminal', 'log', `running ${fileName} ...`)
const content = await this.call('fileManager', 'readFile', fileName)
if (clearAllInstances) {
await this.call('udapp', 'clearAllInstances')
}
await this.call('scriptRunner', 'execute', content)
}
onActivation () {
window.document.addEventListener('keydown', this.executionListener)
this.on('compilerMetadata', 'artefactsUpdated', async (fileName, contract) => {
if (this.targetFileName === contract.file && contract.object && contract.object.devdoc['custom:dev-run-script']) {
this.targetFileName = null
const file = contract.object.devdoc['custom:dev-run-script']
if (file) this.runScript(file, true)
}
})
}
onDeactivation () {
window.document.removeEventListener('keydown', this.executionListener)
this.off('compilerMetadata', 'artefactsUpdated')
}
}

@ -30,6 +30,7 @@
--warning:#dd5600; --warning:#dd5600;
--danger:#c71c22; --danger:#c71c22;
--light:#f8f9fa; --light:#f8f9fa;
--text:#343a40;
--dark:#343a40; --dark:#343a40;
--body-bg: #fff; --body-bg: #fff;
--text-bg-mark: #fcf8e3; --text-bg-mark: #fcf8e3;
@ -5186,12 +5187,11 @@ a.close.disabled {
border-left-color:#000 border-left-color:#000
} }
.tooltip-inner { .tooltip-inner {
max-width:200px; padding: .25rem .5rem;
padding:.25rem .5rem; color: var(--text);
color:#fff; text-align: center;
text-align:center; background-color: var(--light);
background-color:#000; border-radius: .25rem
border-radius:.25rem
} }
.popover { .popover {
position:absolute; position:absolute;

@ -32,6 +32,7 @@
--warning:#f80; --warning:#f80;
--danger:#c00; --danger:#c00;
--light:#222; --light:#222;
--text:#adafae;
--dark:#adafae; --dark:#adafae;
--body-bg: #060606; --body-bg: #060606;
--text-bg-mark: #fcf8e3; --text-bg-mark: #fcf8e3;
@ -5189,13 +5190,12 @@ a.close.disabled {
border-left-color:#282828 border-left-color:#282828
} }
.tooltip-inner { .tooltip-inner {
max-width:200px; padding: .25rem .5rem;
padding:.25rem .5rem; color: var(--text);
color:#fff; text-align: center;
text-align:center; background-color: var(--light);
background-color:#282828; border-radius: .25rem
border-radius:.25rem }
}
.popover { .popover {
position:absolute; position:absolute;
top:0; top:0;

@ -30,6 +30,7 @@
--warning:#f39c12; --warning:#f39c12;
--danger:#e74c3c; --danger:#e74c3c;
--light:#ecf0f1; --light:#ecf0f1;
--text:#7b8a8b;
--dark:#7b8a8b; --dark:#7b8a8b;
--body-bg: #fff; --body-bg: #fff;
--text-bg-mark: #fcf8e3; --text-bg-mark: #fcf8e3;
@ -4226,8 +4227,12 @@ a.close.disabled {
left:0; border-width:.4rem 0 .4rem .4rem; border-left-color:#000 left:0; border-width:.4rem 0 .4rem .4rem; border-left-color:#000
} }
.tooltip-inner { .tooltip-inner {
max-width:200px; padding:.25rem .5rem; color:#fff; text-align:center; background-color:#000; border-radius:.25rem padding: .25rem .5rem;
} color: var(--text);
text-align: center;
background-color: var(--light);
border-radius: .25rem
}
.popover { .popover {
position:absolute; top:0; left:0; z-index:1060; display:block; max-width:276px; font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; font-style:normal; font-weight:400; line-height:1.5; text-align:left; text-align:start; text-decoration:none; text-shadow:none; text-transform:none; letter-spacing:normal; word-break:normal; word-spacing:normal; white-space:normal; line-break:auto; font-size:.825rem; word-wrap:break-word; background-color:#fff; background-clip:padding-box; border:1px solid rgba(0,0,0,.2); border-radius:.3rem position:absolute; top:0; left:0; z-index:1060; display:block; max-width:276px; font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; font-style:normal; font-weight:400; line-height:1.5; text-align:left; text-align:start; text-decoration:none; text-shadow:none; text-transform:none; letter-spacing:normal; word-break:normal; word-spacing:normal; white-space:normal; line-break:auto; font-size:.825rem; word-wrap:break-word; background-color:#fff; background-clip:padding-box; border:1px solid rgba(0,0,0,.2); border-radius:.3rem
} }

@ -30,6 +30,7 @@
--info:#3399f3; --info:#3399f3;
--warning:#d47500; --warning:#d47500;
--danger:#cd0200; --danger:#cd0200;
--text:#eee;
--light:#eee; --light:#eee;
--dark:#333; --dark:#333;
--body-bg:#fff; --body-bg:#fff;
@ -5187,12 +5188,11 @@ a.close.disabled {
border-left-color:#000 border-left-color:#000
} }
.tooltip-inner { .tooltip-inner {
max-width:200px; padding: .25rem .5rem;
padding:.25rem .5rem; color: var(--text);
color:#fff; text-align: center;
text-align:center; background-color: var(--light);
background-color:#000; border-radius: .25rem
border-radius:.25rem
} }
.popover { .popover {
position:absolute; position:absolute;

@ -5240,12 +5240,11 @@ a.close.disabled {
border-left-color: #000; border-left-color: #000;
} }
.tooltip-inner { .tooltip-inner {
max-width: 200px; padding: .25rem .5rem;
padding: 3px 8px; color: var(--text);
color: #d5d5d5;
text-align: center; text-align: center;
background-color: #000; background-color: var(--light);
border-radius: 2px; border-radius: .25rem
} }
.popover { .popover {
position: absolute; position: absolute;

@ -5701,12 +5701,11 @@ a.close.disabled {
} }
.tooltip-inner { .tooltip-inner {
max-width: 200px; padding: .25rem .5rem;
padding: 0.25rem 0.5rem; color: var(--text);
color: #fff;
text-align: center; text-align: center;
background-color: #000; background-color: var(--light);
border-radius: 0.25rem; border-radius: .25rem
} }
.popover { .popover {

@ -5236,12 +5236,11 @@ a.close.disabled {
border-left-color: #000; border-left-color: #000;
} }
.tooltip-inner { .tooltip-inner {
max-width: 200px; padding: .25rem .5rem;
padding: 3px 8px; color: var(--text);
color: #fff;
text-align: center; text-align: center;
background-color: #000; background-color: var(--light);
border-radius: 2px; border-radius: .25rem
} }
.popover { .popover {
position: absolute; position: absolute;

@ -5697,12 +5697,11 @@ a.close.disabled {
} }
.tooltip-inner { .tooltip-inner {
max-width: 200px; padding: .25rem .5rem;
padding: 0.25rem 0.5rem; color: var(--text);
color: #fff;
text-align: center; text-align: center;
background-color: #000; background-color: var(--light);
border-radius: 0.25rem; border-radius: .25rem
} }
.popover { .popover {

@ -5703,12 +5703,11 @@ a.close.disabled {
} }
.tooltip-inner { .tooltip-inner {
max-width: 200px; padding: .25rem .5rem;
padding: 0.25rem 0.5rem; color: var(--text);
color: #eeede9;
text-align: center; text-align: center;
background-color: #000; background-color: var(--light);
border-radius: 0.25rem; border-radius: .25rem
} }
.popover { .popover {

@ -8,7 +8,7 @@ const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', '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-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'hardhat-provider', 'intelligentScriptExecutor', 'search'] 'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'hardhat-provider', 'compileAndRun', 'search']
const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd) const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)

@ -97,6 +97,10 @@ export const CompilerApiMixin = (Base) => class extends Base {
return this.call('contentImport', 'resolveAndSave', url) return this.call('contentImport', 'resolveAndSave', url)
} }
runScriptAfterCompilation (fileName: string) {
this.call('compileAndRun', 'runScriptAfterCompilation', fileName)
}
compileWithHardhat (configFile) { compileWithHardhat (configFile) {
return this.call('hardhat', 'compile', configFile) return this.call('hardhat', 'compile', configFile)
} }
@ -330,6 +334,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
e.preventDefault() e.preventDefault()
if(await this.getAppParameter('hardhat-compilation')) this.compileTabLogic.runCompiler('hardhat') if(await this.getAppParameter('hardhat-compilation')) this.compileTabLogic.runCompiler('hardhat')
else if(await this.getAppParameter('truffle-compilation')) this.compileTabLogic.runCompiler('truffle') else if(await this.getAppParameter('truffle-compilation')) this.compileTabLogic.runCompiler('truffle')
else this.compileTabLogic.runCompiler(undefined)
} }
} }
window.document.addEventListener('keydown', this.data.eventHandlers.onKeyDown) window.document.addEventListener('keydown', this.data.eventHandlers.onKeyDown)

@ -37,6 +37,7 @@ export interface ICompilerApi {
readFile: (file: string) => Promise<string> readFile: (file: string) => Promise<string>
open: (file: string) => void open: (file: string) => void
saveCurrentFile: () => void saveCurrentFile: () => void
runScriptAfterCompilation: (fileName: string) => void,
logToTerminal: (log: terminalLog) => void logToTerminal: (log: terminalLog) => void

@ -8,6 +8,7 @@ import { compilerReducer, compilerInitialState } from './reducers/compiler'
import { resetEditorMode, listenToEvents } from './actions/compiler' import { resetEditorMode, listenToEvents } from './actions/compiler'
import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line import { OverlayTrigger, Tooltip } from 'react-bootstrap' // eslint-disable-line
import { getValidLanguage } from '@remix-project/remix-solidity' import { getValidLanguage } from '@remix-project/remix-solidity'
import { CopyToClipboard } from '@remix-ui/clipboard'
import './css/style.css' import './css/style.css'
@ -332,6 +333,19 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
compileTabLogic.runCompiler(externalCompType) compileTabLogic.runCompiler(externalCompType)
} }
const compileAndRun = () => {
const currentFile = api.currentFile
if (!isSolFileSelected()) return
_setCompilerVersionFromPragma(currentFile)
let externalCompType
if (hhCompilation) externalCompType = 'hardhat'
else if (truffleCompilation) externalCompType = 'truffle'
api.runScriptAfterCompilation(currentFile)
compileTabLogic.runCompiler(externalCompType)
}
const _updateVersionSelector = (version, customUrl = '') => { const _updateVersionSelector = (version, customUrl = '') => {
// update selectedversion of previous one got filtered out // update selectedversion of previous one got filtered out
let selectedVersion = version let selectedVersion = version
@ -523,7 +537,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
onChangeRuns(settings.runs) onChangeRuns(settings.runs)
} }
return ( return (
<section> <section>
<article> <article>
<header className='remixui_compilerSection border-bottom'> <header className='remixui_compilerSection border-bottom'>
@ -596,7 +610,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<label className="form-check-label custom-control-label" htmlFor="enableHardhat">Enable Hardhat Compilation</label> <label className="form-check-label custom-control-label" htmlFor="enableHardhat">Enable Hardhat Compilation</label>
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/hardhat.html#enable-hardhat-compilation' target={'_blank'}> <a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/hardhat.html#enable-hardhat-compilation' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={ <OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip"> <Tooltip className="text-nowrap" id="overlay-tooltip-hardhat">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Hardhat Compilation</span> <span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Hardhat Compilation</span>
</Tooltip> </Tooltip>
}> }>
@ -612,7 +626,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<label className="form-check-label custom-control-label" htmlFor="enableTruffle">Enable Truffle Compilation</label> <label className="form-check-label custom-control-label" htmlFor="enableTruffle">Enable Truffle Compilation</label>
<a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/' target={'_blank'}> <a className="mt-1 text-nowrap" href='https://remix-ide.readthedocs.io/en/latest/' target={'_blank'}>
<OverlayTrigger placement={'right'} overlay={ <OverlayTrigger placement={'right'} overlay={
<Tooltip className="text-nowrap" id="overlay-tooltip"> <Tooltip className="text-nowrap" id="overlay-tooltip-truffle">
<span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Truffle Compilation</span> <span className="p-1 pr-3" style={{ backgroundColor: 'black', minWidth: '230px' }}>Learn how to use Truffle Compilation</span>
</Tooltip> </Tooltip>
}> }>
@ -621,12 +635,62 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
</a> </a>
</div> </div>
} }
<button id="compileBtn" data-id="compilerContainerCompileBtn" className="btn btn-primary d-block w-100 text-break remixui_disabled mt-3" title="Compile" onClick={compile} disabled={disableCompileButton}> <div>
<span> <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}>
{ <i ref={compileIcon} className="fas fa-sync remixui_iconbtn" aria-hidden="true"></i> } <OverlayTrigger overlay={
Compile { typeof state.compiledFileName === 'string' ? extractNameFromKey(state.compiledFileName) || '<no file selected>' : '<no file selected>' } <Tooltip id="overlay-tooltip-compile">
</span> <div className="text-left">
<div><b>Ctrl+S</b> for compiling</div>
</div>
</Tooltip>
}>
<span>
{ <i ref={compileIcon} className="fas fa-sync remixui_iconbtn" aria-hidden="true"></i> }
Compile { typeof state.compiledFileName === 'string' ? extractNameFromKey(state.compiledFileName) || '<no file selected>' : '<no file selected>' }
</span>
</OverlayTrigger>
</button> </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}>
<OverlayTrigger overlay={
<Tooltip id="overlay-tooltip-compile-run">
<div className="text-left">
<div><b>Ctrl+Shift+S</b> for compiling and script execution</div>
</div>
</Tooltip>
}>
<span>
Compile and Run script
</span>
</OverlayTrigger>
</button>
<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>
</Tooltip>
}>
<a href="https://remix-ide.readthedocs.io/en/latest/running_js_scripts.html#compile-a-contract-and-run-a-script-on-the-fly" target="_blank" ><i className="pl-2 ml-2 mt-3 mb-1 fas fa-info text-dark"></i></a>
</OverlayTrigger>
<CopyToClipboard tip="Copy tag to use in contract NatSpec" getContent={() => '@custom:dev-run-script file_path'} direction='top'>
<button className="btn remixui_copyButton ml-2 mt-3 mb-1 text-dark">
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
</button>
</CopyToClipboard>
</div>
</div>
</header> </header>
</article> </article>
</section> </section>

@ -171,6 +171,11 @@
-o-animation: spin 2s infinite linear; -o-animation: spin 2s infinite linear;
-webkit-animation: spin 2s infinite linear; -webkit-animation: spin 2s infinite linear;
} }
.remixui_solidityCompileAndRunButton {
width: 94%;
}
@keyframes spin { @keyframes spin {
0% { transform: rotate(0deg); } 0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); } 100% { transform: rotate(360deg); }

@ -7,6 +7,7 @@ pragma solidity >=0.7.0 <0.9.0;
/** /**
* @title Storage * @title Storage
* @dev Store & retrieve value in a variable * @dev Store & retrieve value in a variable
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
*/ */
contract Storage { contract Storage {

Loading…
Cancel
Save