fixed capital letters on ask

pull/4809/head
Stéphane Tetsing 6 months ago
commit c5f52d9fb4
  1. 2
      .github/workflows/pr-reminder.yml
  2. 79
      apps/remix-ide-e2e/src/tests/layout.test.ts
  3. 10
      apps/remix-ide-e2e/src/tests/url.test.ts
  4. 27
      apps/remix-ide/src/app.js
  5. 7
      apps/remix-ide/src/app/components/panel.ts
  6. 84
      apps/remix-ide/src/app/components/pinned-panel.tsx
  7. 33
      apps/remix-ide/src/app/components/side-panel.tsx
  8. 24
      apps/remix-ide/src/app/panels/layout.ts
  9. 6
      apps/remix-ide/src/app/plugins/contractFlattener.tsx
  10. 2
      apps/remix-ide/src/app/tabs/locales/en/panel.json
  11. 1
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  12. 10
      apps/remix-ide/src/app/tabs/locales/es/panel.json
  13. 1
      apps/remix-ide/src/app/tabs/locales/es/udapp.json
  14. 10
      apps/remix-ide/src/app/tabs/locales/fr/panel.json
  15. 1
      apps/remix-ide/src/app/tabs/locales/fr/udapp.json
  16. 10
      apps/remix-ide/src/app/tabs/locales/it/panel.json
  17. 1
      apps/remix-ide/src/app/tabs/locales/it/udapp.json
  18. 10
      apps/remix-ide/src/app/tabs/locales/ru/panel.json
  19. 1
      apps/remix-ide/src/app/tabs/locales/ru/udapp.json
  20. 10
      apps/remix-ide/src/app/tabs/locales/zh/panel.json
  21. 1
      apps/remix-ide/src/app/tabs/locales/zh/udapp.json
  22. 26
      apps/remix-ide/src/app/tabs/state-logger.js
  23. 2
      apps/remix-ide/src/assets/fontawesome/css/all.css
  24. BIN
      apps/remix-ide/src/assets/fontawesome/webfonts/custom-icons.ttf
  25. BIN
      apps/remix-ide/src/assets/fontawesome/webfonts/custom-icons.woff2
  26. 4
      apps/remix-ide/src/remixAppManager.js
  27. 8
      libs/ghaction-helper/package.json
  28. 8
      libs/remix-analyzer/package.json
  29. 6
      libs/remix-astwalker/package.json
  30. 12
      libs/remix-debug/package.json
  31. 4
      libs/remix-lib/package.json
  32. 39
      libs/remix-simulator/bin/ethsim
  33. 6
      libs/remix-simulator/package.json
  34. 1
      libs/remix-simulator/src/index.ts
  35. 6
      libs/remix-simulator/src/provider.ts
  36. 56
      libs/remix-simulator/src/server.ts
  37. 6
      libs/remix-solidity/package.json
  38. 10
      libs/remix-tests/package.json
  39. 80
      libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
  40. 56
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  41. 4
      libs/remix-ui/app/src/lib/remix-app/style/remix-app.css
  42. 20
      libs/remix-ui/debugger-ui/src/lib/api/debugger-api.ts
  43. 2
      libs/remix-ui/editor/src/lib/providers/completion/completionGlobals.ts
  44. 3
      libs/remix-ui/panel/src/lib/main/main-panel.tsx
  45. 48
      libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
  46. 18
      libs/remix-ui/panel/src/lib/plugins/panel-plugin.tsx
  47. 7
      libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx
  48. 1
      libs/remix-ui/panel/src/lib/types/index.ts
  49. 7
      libs/remix-ui/run-tab/src/lib/actions/events.ts
  50. 11
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  51. 6
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  52. 2
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  53. 15
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  54. 3
      libs/remix-ui/run-tab/src/lib/types/index.ts
  55. 2
      libs/remix-ui/search/src/lib/components/Search.tsx
  56. 1
      libs/remix-ui/search/src/lib/context/context.tsx
  57. 2
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  58. 59
      libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities.ts
  59. 4
      libs/remix-url-resolver/package.json
  60. 4
      libs/remix-ws-templates/package.json
  61. 2
      libs/remixd/package.json
  62. 4
      package.json

@ -14,4 +14,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
freeze-date: '2024-05-20T18:00:00Z' freeze-date: '2024-06-03T18:00:00Z'

@ -0,0 +1,79 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Should pin solidity compiler plugin to the right and switch focus for left side panel to the file-explorer': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('[data-id="movePluginToRight"]')
.click('[data-id="movePluginToRight"]')
.waitForElementVisible('[data-id="movePluginToLeft"]')
.waitForElementVisible('.pinned-panel h6[data-id="sidePanelSwapitTitle"]')
.assert.containsText('.sidepanel h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER')
.assert.containsText('.pinned-panel h6[data-id="sidePanelSwapitTitle"]', 'SOLIDITY COMPILER')
},
'Should unpin and focus on solidity compiler in the left side panel': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('[data-id="movePluginToLeft"]')
.click('[data-id="movePluginToLeft"]')
.waitForElementVisible('[data-id="movePluginToRight"]')
.assert.containsText('.sidepanel h6[data-id="sidePanelSwapitTitle"]', 'SOLIDITY COMPILER')
.waitForElementNotVisible('.pinned-panel h6[data-id="sidePanelSwapitTitle"]')
},
'Should pin a plugin while a another plugin is already pinned': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('[data-id="movePluginToRight"]')
.click('[data-id="movePluginToRight"]')
.waitForElementVisible('[data-id="movePluginToLeft"]')
.waitForElementVisible('.pinned-panel h6[data-id="sidePanelSwapitTitle"]')
.assert.containsText('.pinned-panel h6[data-id="sidePanelSwapitTitle"]', 'SOLIDITY COMPILER')
.clickLaunchIcon('udapp')
.click('[data-id="movePluginToRight"]')
.waitForElementVisible('[data-id="movePluginToLeft"]')
.assert.containsText('.pinned-panel h6[data-id="sidePanelSwapitTitle"]', 'DEPLOY & RUN TRANSACTIONS')
.assert.containsText('.sidepanel h6[data-id="sidePanelSwapitTitle"]', 'SOLIDITY COMPILER')
},
'Should pin a pinned plugin to the right after reloading the page': function (browser: NightwatchBrowser) {
browser.refreshPage()
.waitForElementVisible('.pinned-panel h6[data-id="sidePanelSwapitTitle"]')
.assert.containsText('.pinned-panel h6[data-id="sidePanelSwapitTitle"]', 'DEPLOY & RUN TRANSACTIONS')
},
'Should maintain logged state of udapp plugin after pinning and unpinning': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.click('*[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/1_Storage.sol')
.pause(5000)
.waitForElementPresent('*[data-id="Deploy - transact (not payable)"]')
.click('*[data-id="Deploy - transact (not payable)"]')
.waitForElementPresent('#instance0xd9145CCE52D386f254917e481eB44e9943F39138')
.clickInstance(0)
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '10' })
.clickFunction('retrieve - call')
.click('[data-id="movePluginToLeft"]')
.waitForElementVisible('[data-id="movePluginToRight"]')
.clickInstance(0)
.waitForElementContainsText('[data-id="treeViewLi0"]', 'uint256: 10')
},
'Should maintain logged state of search plugin after pinning and unpinning': function (browser: NightwatchBrowser) {
browser.clickLaunchIcon('search')
.waitForElementVisible('*[id="search_input"]')
.waitForElementVisible('*[id="search_include"]')
.setValue('*[id="search_include"]', ', *.*').pause(2000)
.setValue('*[id="search_input"]', 'read').sendKeys('*[id="search_input"]', browser.Keys.ENTER)
.pause(1000)
.waitForElementContainsText('*[data-id="search_results"]', '3_BALLOT.SOL', 60000)
.waitForElementContainsText('*[data-id="search_results"]', 'contracts', 60000)
.waitForElementContainsText('*[data-id="search_results"]', 'README.TXT', 60000)
.click('[data-id="movePluginToRight"]')
.waitForElementContainsText('*[data-id="search_results"]', '3_BALLOT.SOL')
.waitForElementContainsText('*[data-id="search_results"]', 'contracts')
.waitForElementContainsText('*[data-id="search_results"]', 'README.TXT')
}
}
const sources = []

@ -70,7 +70,7 @@ module.exports = {
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content && content.indexOf( browser.assert.ok(content && content.indexOf(
'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol') !== -1, 'https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol') !== -1,
'code has not been loaded') 'code has not been loaded')
}) })
}, },
@ -87,7 +87,7 @@ module.exports = {
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content && content.indexOf( browser.assert.ok(content && content.indexOf(
'proposals.length = _numProposals;') !== -1, 'proposals.length = _numProposals;') !== -1,
'url has not been loaded') 'url has not been loaded')
}) })
}, },
@ -121,8 +121,8 @@ module.exports = {
}) })
}, },
//Disabled due to failure from blockscout api
'Should load Blockscout verified contracts from URL "address" and "blockscout" params (multiple sources)': function (browser: NightwatchBrowser) { 'Should load Blockscout verified contracts from URL "address" and "blockscout" params (multiple sources)': '' + function (browser: NightwatchBrowser) {
browser browser
.url('http://127.0.0.1:8080/#address=0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9&blockscout=eth.blockscout.com') .url('http://127.0.0.1:8080/#address=0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9&blockscout=eth.blockscout.com')
.refreshPage() .refreshPage()
@ -162,7 +162,7 @@ module.exports = {
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content && content.indexOf( browser.assert.ok(content && content.indexOf(
'proposals.length = _numProposals;') !== -1, 'proposals.length = _numProposals;') !== -1,
'code has been loaded') 'code has been loaded')
}) })
.url('http://127.0.0.1:8080') // refresh without loading the code sample .url('http://127.0.0.1:8080') // refresh without loading the code sample
.currentWorkspaceIs('default_workspace') .currentWorkspaceIs('default_workspace')

@ -7,8 +7,10 @@ import {LocaleModule} from './app/tabs/locale-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 {CompileAndRun} from './app/tabs/compile-and-run' import {CompileAndRun} from './app/tabs/compile-and-run'
import {PluginStateLogger} from './app/tabs/state-logger'
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 {PinnedPanel} from './app/components/pinned-panel'
import {VerticalIcons} from './app/components/vertical-icons' import {VerticalIcons} from './app/components/vertical-icons'
import {LandingPage} from './app/ui/landing-page/landing-page' import {LandingPage} from './app/ui/landing-page/landing-page'
import {MainPanel} from './app/components/main-panel' import {MainPanel} from './app/components/main-panel'
@ -297,7 +299,8 @@ class AppComponent {
this.layout = new Layout() this.layout = new Layout()
const permissionHandler = new PermissionHandlerPlugin() const permissionHandler = new PermissionHandlerPlugin()
// ----------------- run script after each compilation results -----------
const pluginStateLogger = new PluginStateLogger()
this.engine.register([ this.engine.register([
permissionHandler, permissionHandler,
@ -347,6 +350,7 @@ class AppComponent {
solidityScript, solidityScript,
templates, templates,
solcoder, solcoder,
pluginStateLogger
]) ])
//---- fs plugin //---- fs plugin
@ -378,13 +382,14 @@ class AppComponent {
this.menuicons = new VerticalIcons() this.menuicons = new VerticalIcons()
this.sidePanel = new SidePanel() this.sidePanel = new SidePanel()
this.hiddenPanel = new HiddenPanel() this.hiddenPanel = new HiddenPanel()
this.pinnedPanel = new PinnedPanel()
const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine) const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine)
const filePanel = new FilePanel(appManager) const filePanel = new FilePanel(appManager)
const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport) const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport)
this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager) this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager)
this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, filePanel, pluginManagerComponent, this.settings]) this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, filePanel, pluginManagerComponent, this.settings, this.pinnedPanel])
// CONTENT VIEWS & DEFAULT PLUGINS // CONTENT VIEWS & DEFAULT PLUGINS
const openZeppelinProxy = new OpenZeppelinProxy(blockchain) const openZeppelinProxy = new OpenZeppelinProxy(blockchain)
@ -462,10 +467,12 @@ class AppComponent {
'compilerArtefacts', 'compilerArtefacts',
'network', 'network',
'web3Provider', 'web3Provider',
'offsetToLineColumnConverter' 'offsetToLineColumnConverter',
'pluginStateLogger'
]) ])
await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await this.appManager.activatePlugin(['pinnedPanel'])
await this.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['home'])
await this.appManager.activatePlugin(['settings', 'config']) await this.appManager.activatePlugin(['settings', 'config'])
await this.appManager.activatePlugin([ await this.appManager.activatePlugin([
@ -560,6 +567,12 @@ class AppComponent {
} }
} }
} }
}).then(async () => {
const lastPinned = localStorage.getItem('pinnedPlugin')
if (lastPinned) {
this.appManager.call('sidePanel', 'pinView', JSON.parse(lastPinned))
}
}) })
.catch(console.error) .catch(console.error)
} }
@ -568,6 +581,14 @@ class AppComponent {
document.body.appendChild(loadedElement) document.body.appendChild(loadedElement)
}) })
this.appManager.on('pinnedPanel', 'pinnedPlugin', (pluginProfile) => {
localStorage.setItem('pinnedPlugin', JSON.stringify(pluginProfile))
})
this.appManager.on('pinnedPanel', 'unPinnedPlugin', () => {
localStorage.setItem('pinnedPlugin', '')
})
// activate solidity plugin // activate solidity plugin
this.appManager.activatePlugin(['solidity', 'udapp', 'deploy-libraries', 'link-libraries', 'openzeppelin-proxy']) this.appManager.activatePlugin(['solidity', 'udapp', 'deploy-libraries', 'link-libraries', 'openzeppelin-proxy'])
} }

@ -15,9 +15,11 @@ export class AbstractPanel extends HostPlugin {
} }
currentFocus (): string { currentFocus (): string {
return Object.values(this.plugins).find(plugin => { const activePlugin = Object.values(this.plugins).find(plugin => {
return plugin.active return plugin.active
}).profile.name })
return activePlugin ? activePlugin.profile.name : null
} }
addView (profile, view) { addView (profile, view) {
@ -26,6 +28,7 @@ export class AbstractPanel extends HostPlugin {
profile: profile, profile: profile,
view: view, view: view,
active: false, active: false,
pinned: false,
class: 'plugItIn active' class: 'plugItIn active'
} }
} }

@ -0,0 +1,84 @@
// eslint-disable-next-line no-use-before-define
import React from 'react'
import { AbstractPanel } from './panel'
import { PluginRecord, RemixPluginPanel } from '@remix-ui/panel'
import packageJson from '../../../../../package.json'
import { RemixUIPanelHeader } from '@remix-ui/panel'
import { PluginViewWrapper } from '@remix-ui/helper'
const pinnedPanel = {
name: 'pinnedPanel',
displayName: 'Pinned Panel',
description: 'Remix IDE pinned panel',
version: packageJson.version,
methods: ['addView', 'removeView', 'currentFocus', 'pinView', 'unPinView']
}
export class PinnedPanel extends AbstractPanel {
dispatch: React.Dispatch<any> = () => {}
loggedState: any
constructor() {
super(pinnedPanel)
}
onActivation() {
this.renderComponent()
this.on('sidePanel', 'pluginDisabled', (name) => {
if (this.plugins[name] && this.plugins[name].active) {
this.emit('unPinnedPlugin', name)
this.events.emit('unPinnedPlugin', name)
super.remove(name)
}
})
}
async pinView (profile, view) {
const activePlugin = this.currentFocus()
if (activePlugin === profile.name) throw new Error(`Plugin ${profile.name} already pinned`)
if (activePlugin) {
await this.call('sidePanel', 'unPinView', this.plugins[activePlugin].profile, this.plugins[activePlugin].view)
this.remove(activePlugin)
}
this.loggedState = await this.call('pluginStateLogger', 'getPluginState', profile.name)
this.addView(profile, view)
this.plugins[profile.name].pinned = true
this.plugins[profile.name].active = true
this.renderComponent()
this.events.emit('pinnedPlugin', profile)
this.emit('pinnedPlugin', profile)
}
async unPinView (profile) {
const activePlugin = this.currentFocus()
if (activePlugin !== profile.name) throw new Error(`Plugin ${profile.name} is not pinned`)
await this.call('sidePanel', 'unPinView', profile, this.plugins[profile.name].view)
super.remove(profile.name)
this.renderComponent()
this.events.emit('unPinnedPlugin', profile)
this.emit('unPinnedPlugin', profile)
}
setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
}
render() {
return (
<section className='panel pinned-panel'> <PluginViewWrapper plugin={this} /></section>
)
}
updateComponent(state: any) {
return <RemixPluginPanel header={<RemixUIPanelHeader plugins={state.plugins} pinView={this.pinView.bind(this)} unPinView={this.unPinView.bind(this)}></RemixUIPanelHeader>} plugins={state.plugins} pluginState={state.pluginState} />
}
renderComponent() {
this.dispatch({
plugins: this.plugins,
pluginState: this.loggedState
})
}
}

@ -12,12 +12,14 @@ const sidePanel = {
displayName: 'Side Panel', displayName: 'Side Panel',
description: 'Remix IDE side panel', description: 'Remix IDE side panel',
version: packageJson.version, version: packageJson.version,
methods: ['addView', 'removeView', 'currentFocus'] methods: ['addView', 'removeView', 'currentFocus', 'pinView', 'unPinView']
} }
export class SidePanel extends AbstractPanel { export class SidePanel extends AbstractPanel {
sideelement: any sideelement: any
loggedState: any
dispatch: React.Dispatch<any> = () => {} dispatch: React.Dispatch<any> = () => {}
constructor() { constructor() {
super(sidePanel) super(sidePanel)
this.sideelement = document.createElement('section') this.sideelement = document.createElement('section')
@ -56,10 +58,8 @@ export class SidePanel extends AbstractPanel {
} }
removeView(profile) { removeView(profile) {
if (this.plugins[profile.name].active) this.call('menuicons', 'select', 'filePanel') if (this.plugins[profile.name] && this.plugins[profile.name].active) this.call('menuicons', 'select', 'filePanel')
super.removeView(profile) super.removeView(profile)
this.emit('pluginDisabled', profile.name)
this.call('menuicons', 'unlinkContent', profile)
this.renderComponent() this.renderComponent()
} }
@ -69,6 +69,26 @@ export class SidePanel extends AbstractPanel {
this.renderComponent() this.renderComponent()
} }
async pinView (profile) {
await this.call('pinnedPanel', 'pinView', profile, this.plugins[profile.name].view)
if (this.plugins[profile.name].active) this.call('menuicons', 'select', 'filePanel')
super.remove(profile.name)
this.call('menuicons', 'unlinkContent', profile)
this.renderComponent()
}
async unPinView (profile, view) {
const activePlugin = this.currentFocus()
if (activePlugin === profile.name) throw new Error(`Plugin ${profile.name} already unpinned`)
this.loggedState = await this.call('pluginStateLogger', 'getPluginState', profile.name)
super.addView(profile, view)
this.plugins[activePlugin].active = false
this.plugins[profile.name].active = true
await this.call('menuicons', 'linkContent', profile)
this.showContent(profile.name)
}
/** /**
* Display content and update the header * Display content and update the header
* @param {String} name The name of the plugin to display * @param {String} name The name of the plugin to display
@ -93,12 +113,13 @@ export class SidePanel extends AbstractPanel {
} }
updateComponent(state: any) { updateComponent(state: any) {
return <RemixPluginPanel header={<RemixUIPanelHeader plugins={state.plugins}></RemixUIPanelHeader>} plugins={state.plugins} /> return <RemixPluginPanel header={<RemixUIPanelHeader plugins={state.plugins} pinView={this.pinView.bind(this)} unPinView={this.unPinView.bind(this)}></RemixUIPanelHeader>} plugins={state.plugins} pluginState={state.pluginState} />
} }
renderComponent() { renderComponent() {
this.dispatch({ this.dispatch({
plugins: this.plugins plugins: this.plugins,
pluginState: this.loggedState
}) })
} }
} }

@ -6,7 +6,7 @@ import { QueryParams } from '@remix-project/remix-lib'
const profile: Profile = { const profile: Profile = {
name: 'layout', name: 'layout',
description: 'layout', description: 'layout',
methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel', 'maximizeTerminal'] methods: ['minimize', 'maximiseSidePanel', 'resetSidePanel', 'maximizeTerminal', 'maximisePinnedPanel', 'resetPinnedPanel']
} }
interface panelState { interface panelState {
@ -74,6 +74,16 @@ export class Layout extends Plugin {
this.event.emit('resetsidepanel') this.event.emit('resetsidepanel')
} }
}) })
this.on('pinnedPanel', 'pinnedPlugin', async (name) => {
const current = await this.call('pinnedPanel', 'currentFocus')
if (this.maximised[current]) {
this.event.emit('maximisepinnedpanel')
} else {
this.event.emit('resetpinnedpanel')
}
})
document.addEventListener('keypress', e => { document.addEventListener('keypress', e => {
if (e.shiftKey && e.ctrlKey) { if (e.shiftKey && e.ctrlKey) {
if (e.code === 'KeyF') { if (e.code === 'KeyF') {
@ -110,6 +120,12 @@ export class Layout extends Plugin {
this.maximised[current] = true this.maximised[current] = true
} }
async maximisePinnedPanel () {
this.event.emit('maximisepinnedpanel')
const current = await this.call('pinnedPanel', 'currentFocus')
this.maximised[current] = true
}
async maximizeTerminal() { async maximizeTerminal() {
this.panels.terminal.minimized = false this.panels.terminal.minimized = false
this.event.emit('change', this.panels) this.event.emit('change', this.panels)
@ -121,4 +137,10 @@ export class Layout extends Plugin {
const current = await this.call('sidePanel', 'currentFocus') const current = await this.call('sidePanel', 'currentFocus')
this.maximised[current] = false this.maximised[current] = false
} }
async resetPinnedPanel () {
this.event.emit('resetpinnedpanel')
const current = await this.call('pinnedPanel', 'currentFocus')
this.maximised[current] = false
}
} }

@ -1,3 +1,4 @@
/* eslint-disable prefer-const */
import React from 'react' import React from 'react'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { customAction } from '@remixproject/plugin-api' import { customAction } from '@remixproject/plugin-api'
@ -57,11 +58,12 @@ export class ContractFlattener extends Plugin {
let sorted let sorted
let result let result
let sources let sources
let order: string[] = []
try { try {
dependencyGraph = getDependencyGraph(ast, filePath, input.settings.remappings) dependencyGraph = getDependencyGraph(ast, filePath, input.settings.remappings, order)
sorted = dependencyGraph.isEmpty() ? [filePath] : dependencyGraph.sort().reverse() sorted = dependencyGraph.isEmpty() ? [filePath] : dependencyGraph.sort().reverse()
sources = source.sources sources = source.sources
result = concatSourceFiles(sorted, sources) result = concatSourceFiles(sorted, sources, order)
} catch (err) { } catch (err) {
console.warn(err) console.warn(err)
} }

@ -4,6 +4,8 @@
"panel.documentation": "Documentation", "panel.documentation": "Documentation",
"panel.description": "Description", "panel.description": "Description",
"panel.maintainedByRemix": "Maintained by Remix", "panel.maintainedByRemix": "Maintained by Remix",
"panel.pinnedMsg": "Click to move plugin to the right side panel",
"panel.unPinnedMsg": "Click to return plugin to the left side panel",
"panel.maintainedExternally": "Not maintained by Remix", "panel.maintainedExternally": "Not maintained by Remix",
"panel.pluginInfo": "Plugin info", "panel.pluginInfo": "Plugin info",
"panel.linkToDoc": "Link to documentation", "panel.linkToDoc": "Link to documentation",

@ -123,6 +123,7 @@
"udapp.llIError6": "Both 'receive' and 'fallback' functions are not defined", "udapp.llIError6": "Both 'receive' and 'fallback' functions are not defined",
"udapp.llIError7": "Please define a 'Fallback' function to send calldata and a either 'Receive' or payable 'Fallback' to send ethers", "udapp.llIError7": "Please define a 'Fallback' function to send calldata and a either 'Receive' or payable 'Fallback' to send ethers",
"udapp.copy": "Copy", "udapp.copy": "Copy",
"udapp.copyAddress": "Copy Address",
"udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx",
"udapp.mainnetText1": "You are about to create a transaction on {name} Network. Confirm the details to send the info to your provider.", "udapp.mainnetText1": "You are about to create a transaction on {name} Network. Confirm the details to send the info to your provider.",

@ -1,10 +0,0 @@
{
"panel.author": "Autor",
"panel.maintainedBy": "Mantenido por",
"panel.documentation": "Documentación",
"panel.description": "Descripción",
"panel.maintainedByRemix": "Mantenido por Remix",
"panel.pluginInfo": "Información del Complemento",
"panel.linkToDoc": "Enlace a la documentación",
"panel.makeAnissue": "Crear un asunto"
}

@ -102,6 +102,7 @@
"udapp.llIError6": "Las funciones 'receive' y 'fallback' no están definidas", "udapp.llIError6": "Las funciones 'receive' y 'fallback' no están definidas",
"udapp.llIError7": "Por favor defina una función 'Fallback' para enviar calldata y un 'Receice' o payable 'Fallback' para enviar ethers", "udapp.llIError7": "Por favor defina una función 'Fallback' para enviar calldata y un 'Receice' o payable 'Fallback' para enviar ethers",
"udapp.copy": "Copiar", "udapp.copy": "Copiar",
"udapp.copyAddress": "Copy Address",
"udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx",
"udapp.mainnetText1": "Estás a punto de crear una transacción en la Red {name}. Confirma los detalles para enviar la información a tu proveedor.", "udapp.mainnetText1": "Estás a punto de crear una transacción en la Red {name}. Confirma los detalles para enviar la información a tu proveedor.",
"udapp.mainnetText2": "El proveedor para muchos usuarios es MetaMask. El proveedor le pedirá que firme la transacción antes de enviarla a la Red {name}.", "udapp.mainnetText2": "El proveedor para muchos usuarios es MetaMask. El proveedor le pedirá que firme la transacción antes de enviarla a la Red {name}.",

@ -1,10 +0,0 @@
{
"panel.author": "Auteur",
"panel.maintainedBy": "Maintenu par :",
"panel.documentation": "Documentation",
"panel.description": "Description",
"panel.maintainedByRemix": "Maintenu par Remix",
"panel.pluginInfo": "Informations sur l'extension",
"panel.linkToDoc": "Lien vers la documentation",
"panel.makeAnissue": "Faire un ticket"
}

@ -102,6 +102,7 @@
"udapp.llIError6": "Les fonctions 'receive' et 'fallback' ne sont pas définies", "udapp.llIError6": "Les fonctions 'receive' et 'fallback' ne sont pas définies",
"udapp.llIError7": "Définissez s'il vous plaît une fonction 'Fallback' pour envoyer des calldata et soit une fonction 'Receive' ou une fonction 'Fallback' payable pour envoyer des ethers", "udapp.llIError7": "Définissez s'il vous plaît une fonction 'Fallback' pour envoyer des calldata et soit une fonction 'Receive' ou une fonction 'Fallback' payable pour envoyer des ethers",
"udapp.copy": "Copier", "udapp.copy": "Copier",
"udapp.copyAddress": "Copy Address",
"udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx",
"udapp.mainnetText1": "Vous êtes sur le point de créer une transaction sur le réseau {name} . Confirmez les détails pour envoyer les informations à votre fournisseur.", "udapp.mainnetText1": "Vous êtes sur le point de créer une transaction sur le réseau {name} . Confirmez les détails pour envoyer les informations à votre fournisseur.",
"udapp.mainnetText2": "Le provider pour de nombreux utilisateurs est MetaMask. Le provider vous demandera de signer la transaction avant qu'elle ne soit envoyée au réseau {name}.", "udapp.mainnetText2": "Le provider pour de nombreux utilisateurs est MetaMask. Le provider vous demandera de signer la transaction avant qu'elle ne soit envoyée au réseau {name}.",

@ -1,10 +0,0 @@
{
"panel.author": "Autore",
"panel.maintainedBy": "Mantenuto Da",
"panel.documentation": "Documentazione",
"panel.description": "Descrizione",
"panel.maintainedByRemix": "Mantenuto da Remix",
"panel.pluginInfo": "Informazioni sul plugin",
"panel.linkToDoc": "Link alla documentazione",
"panel.makeAnissue": "Crea una Issue"
}

@ -102,6 +102,7 @@
"udapp.llIError6": "Le funzioni 'receive' e 'fallback' non sono definite", "udapp.llIError6": "Le funzioni 'receive' e 'fallback' non sono definite",
"udapp.llIError7": "Definisci una funzione 'Fallback' per inviare Calldata e una 'Receive' o 'Fallback' payable per inviare ETH", "udapp.llIError7": "Definisci una funzione 'Fallback' per inviare Calldata e una 'Receive' o 'Fallback' payable per inviare ETH",
"udapp.copy": "Copia", "udapp.copy": "Copia",
"udapp.copyAddress": "Copy Address",
"udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx",
"udapp.mainnetText1": "Stai per creare una transazione su {name} Network. Conferma i dettagli per inviare le informazioni al tuo provider.", "udapp.mainnetText1": "Stai per creare una transazione su {name} Network. Conferma i dettagli per inviare le informazioni al tuo provider.",
"udapp.mainnetText2": "Il provider per molti utenti è MetaMask. Il provider ti chiederà di firmare la transazione prima che venga inviata alla rete {name}.", "udapp.mainnetText2": "Il provider per molti utenti è MetaMask. Il provider ti chiederà di firmare la transazione prima che venga inviata alla rete {name}.",

@ -1,10 +0,0 @@
{
"panel.author": "Автор",
"panel.maintainedBy": "Поддерживается",
"panel.documentation": "Документация",
"panel.description": "Описание",
"panel.maintainedByRemix": "Поддерживается Remix",
"panel.pluginInfo": "Информация о плагине",
"panel.linkToDoc": "Ссылка на документацию",
"panel.makeAnissue": "Создать задачу"
}

@ -103,6 +103,7 @@
"udapp.llIError6": "Обе функции 'receive' и 'fallback' не определены", "udapp.llIError6": "Обе функции 'receive' и 'fallback' не определены",
"udapp.llIError7": "Пожалуйста, определите функцию 'Fallback' для отправки вызываемых данных или 'Receive' или оплачиваемую функцию 'Fallback' для отправки эфира", "udapp.llIError7": "Пожалуйста, определите функцию 'Fallback' для отправки вызываемых данных или 'Receive' или оплачиваемую функцию 'Fallback' для отправки эфира",
"udapp.copy": "Копировать", "udapp.copy": "Копировать",
"udapp.copyAddress": "Copy Address",
"udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx",
"udapp.mainnetText1": "Вы собираетесь создать транзакцию в сети {name}. Подтвердите данные для отправки информации вашему провайдеру.", "udapp.mainnetText1": "Вы собираетесь создать транзакцию в сети {name}. Подтвердите данные для отправки информации вашему провайдеру.",
"udapp.mainnetText2": "Провайдером для многих пользователей является MetaMask. Провайдер попросит вас подписать транзакцию перед отправкой ее в сеть {name}.", "udapp.mainnetText2": "Провайдером для многих пользователей является MetaMask. Провайдер попросит вас подписать транзакцию перед отправкой ее в сеть {name}.",

@ -1,10 +0,0 @@
{
"panel.author": "作者",
"panel.maintainedBy": "维护者",
"panel.documentation": "文档",
"panel.description": "描述",
"panel.maintainedByRemix": "由 Remix 维护",
"panel.pluginInfo": "插件信息",
"panel.linkToDoc": "文档链接",
"panel.makeAnissue": "提交 issue"
}

@ -102,6 +102,7 @@
"udapp.llIError6": "'receive' 和 'fallback' 函数都未定义", "udapp.llIError6": "'receive' 和 'fallback' 函数都未定义",
"udapp.llIError7": "定义一个 'Fallback' 函数来发送 calldata ,并且定义一个 'Receive' 或 可支付的 'Fallback' 来发送以太币", "udapp.llIError7": "定义一个 'Fallback' 函数来发送 calldata ,并且定义一个 'Receive' 或 可支付的 'Fallback' 来发送以太币",
"udapp.copy": "复制", "udapp.copy": "复制",
"udapp.copyAddress": "Copy Address",
"udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx", "udapp._comment_mainnet.tsx": "libs/remix-ui/run-tab/src/lib/components/mainnet.tsx",
"udapp.mainnetText1": "您即将在 {name} 网络上创建一笔交易。确认详细信息,将信息发送给您的 provider 。", "udapp.mainnetText1": "您即将在 {name} 网络上创建一笔交易。确认详细信息,将信息发送给您的 provider 。",
"udapp.mainnetText2": "许多用户的 provider 是 MetaMask。在将交易发送到 {name} 网络之前,provider 会要求您签署交易。", "udapp.mainnetText2": "许多用户的 provider 是 MetaMask。在将交易发送到 {name} 网络之前,provider 会要求您签署交易。",

@ -0,0 +1,26 @@
import { Plugin } from "@remixproject/engine"
import { EventEmitter } from 'events'
import * as packageJson from '../../../../../package.json'
const profile = {
name: 'pluginStateLogger',
events: [],
methods: ['logPluginState', 'getPluginState'],
version: packageJson.version,
}
export class PluginStateLogger extends Plugin {
constructor() {
super(profile)
this.events = new EventEmitter()
this.stateLogs = {}
}
logPluginState(name, state) {
this.stateLogs[name] = state
}
getPluginState(name) {
return this.stateLogs[name]
}
}

@ -19391,6 +19391,8 @@ readers do not read off random characters that represent icons */
.fak.fa-cairo::before, .fa-kit.fa-cairo::before { content: "\e000"; } .fak.fa-cairo::before, .fa-kit.fa-cairo::before { content: "\e000"; }
.fak.fa-circom::before, .fa-kit.fa-circom::before { content: "\e001"; } .fak.fa-circom::before, .fa-kit.fa-circom::before { content: "\e001"; }
.fak.fa-fa-dock-l::before, .fa-kit.fa-fa-dock-l::before { content: "\e007"; }
.fak.fa-fa-dock-r::before, .fa-kit.fa-fa-dock-r::before { content: "\e006"; }
.fak.fa-lexon::before, .fa-kit.fa-lexon::before { content: "\e004"; } .fak.fa-lexon::before, .fa-kit.fa-lexon::before { content: "\e004"; }
.fak.fa-solidity-mono::before, .fa-kit.fa-solidity-mono::before { content: "\e005"; } .fak.fa-solidity-mono::before, .fa-kit.fa-solidity-mono::before { content: "\e005"; }
.fak.fa-ts-logo::before, .fa-kit.fa-ts-logo::before { content: "\e003"; } .fak.fa-ts-logo::before, .fa-kit.fa-ts-logo::before { content: "\e003"; }

@ -76,7 +76,9 @@ let requiredModules = [ // services + layout views + system views
'doc-viewer', 'doc-viewer',
'doc-gen', 'doc-gen',
'remix-templates', 'remix-templates',
'solhint' 'solhint',
'pinnedPanel',
'pluginStateLogger'
] ]

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/ghaction-helper", "name": "@remix-project/ghaction-helper",
"version": "0.1.28", "version": "0.1.29",
"description": "Solidity Tests GitHub Action Helper", "description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -19,17 +19,17 @@
}, },
"homepage": "https://github.com/ethereum/remix-project#readme", "homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": { "devDependencies": {
"@remix-project/remix-solidity": "^0.5.34", "@remix-project/remix-solidity": "^0.5.35",
"@types/chai": "^4.3.4", "@types/chai": "^4.3.4",
"typescript": "^4.9.3" "typescript": "^4.9.3"
}, },
"dependencies": { "dependencies": {
"@ethereum-waffle/chai": "^3.4.4", "@ethereum-waffle/chai": "^3.4.4",
"@remix-project/remix-simulator": "^0.2.48", "@remix-project/remix-simulator": "^0.2.49",
"chai": "^4.3.7", "chai": "^4.3.7",
"ethers": "^5.7.2", "ethers": "^5.7.2",
"web3": "^4.1.1" "web3": "^4.1.1"
}, },
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e" "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-analyzer", "name": "@remix-project/remix-analyzer",
"version": "0.5.57", "version": "0.5.58",
"description": "Tool to perform static analysis on Solidity smart contracts", "description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": { "scripts": {
"test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts" "test": "./../../node_modules/.bin/ts-node --project ../../tsconfig.base.json --require tsconfig-paths/register ./../../node_modules/.bin/tape ./test/tests.ts"
@ -25,8 +25,8 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.78", "@remix-project/remix-astwalker": "^0.0.79",
"@remix-project/remix-lib": "^0.5.55", "@remix-project/remix-lib": "^0.5.56",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
"ethjs-util": "^0.1.6", "ethjs-util": "^0.1.6",
@ -50,6 +50,6 @@
"typescript": "^3.7.5" "typescript": "^3.7.5"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e", "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7",
"main": "./src/index.js" "main": "./src/index.js"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-astwalker", "name": "@remix-project/remix-astwalker",
"version": "0.0.78", "version": "0.0.79",
"description": "Tool to walk through Solidity AST", "description": "Tool to walk through Solidity AST",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -37,7 +37,7 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.55", "@remix-project/remix-lib": "^0.5.56",
"@types/tape": "^4.2.33", "@types/tape": "^4.2.33",
"async": "^2.6.2", "async": "^2.6.2",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -53,6 +53,6 @@
"tap-spec": "^5.0.0" "tap-spec": "^5.0.0"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e", "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-debug", "name": "@remix-project/remix-debug",
"version": "0.5.48", "version": "0.5.49",
"description": "Tool to debug Ethereum transactions", "description": "Tool to debug Ethereum transactions",
"contributors": [ "contributors": [
{ {
@ -26,10 +26,10 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-astwalker": "^0.0.78", "@remix-project/remix-astwalker": "^0.0.79",
"@remix-project/remix-lib": "^0.5.55", "@remix-project/remix-lib": "^0.5.56",
"@remix-project/remix-simulator": "^0.2.48", "@remix-project/remix-simulator": "^0.2.49",
"@remix-project/remix-solidity": "^0.5.34", "@remix-project/remix-solidity": "^0.5.35",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.2", "async": "^2.6.2",
"color-support": "^1.1.3", "color-support": "^1.1.3",
@ -69,6 +69,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e", "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-lib", "name": "@remix-project/remix-lib",
"version": "0.5.55", "version": "0.5.56",
"description": "Library to various Remix tools", "description": "Library to various Remix tools",
"contributors": [ "contributors": [
{ {
@ -55,6 +55,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e", "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -23,22 +23,37 @@ program
.command('start') .command('start')
.option('-p, --port [port]', 'specify port', 8545) .option('-p, --port [port]', 'specify port', 8545)
.option('-b, --ip [host]', 'specify host', '127.0.0.1') .option('-b, --ip [host]', 'specify host', '127.0.0.1')
.option('-c, --coinbase [coinbase]', 'specify coinbase', '0x0000000000000000000000000000000000000000')
.option('--rpc', 'run rpc server only', true) .option('--rpc', 'run rpc server only', true)
.option('--details', 'display payloads for every requests and their responses', false) .option('--details', 'display payloads for every requests and their responses', false)
.action((option) => { .option('-c, --coinbase [coinbase]', 'specify coinbase', '0x0000000000000000000000000000000000000000')
console.log('coinbase: ', option.coinbase) .option('-f, --fork [fork]', 'specify fork name')
.option('-n, --nodeUrl [nodeUrl]', 'specify node url')
.option('-bn, --blockNumber [blockNumber]', 'specify block Number')
.option('-s, --stateDb [stateDb]', 'specify state database')
.option('-bs, --blocks [blocks]', 'specify blocks')
.action((option, env) => {
env.outputHelp()
console.log('\n')
console.log('Usage:')
console.log('remix-simulator start')
console.log('remix-simulator start -n <node url> -f cancun -bn latest')
console.log('\n')
console.log('Command line options:')
console.log('port: ', option.port)
console.log('host: ', option.ip)
console.log('rpc: ', option.rpc) console.log('rpc: ', option.rpc)
console.log('details: ', option.details) console.log('details: ', option.details)
console.log('host: ', option.ip) console.log('\n')
console.log('port: ', option.port) console.log('Provider options:')
const Server = require('../src/server') console.log('coinbase: ', option.coinbase)
const server = new Server({ console.log('fork: ', option.fork)
coinbase: option.coinbase, console.log('nodeUrl: ', option.nodeUrl)
rpc: option.rpc, console.log('blockNumber: ', option.blockNumber)
logDetails: option.details console.log('stateDb: ', option.stateDb)
}) console.log('blocks: ', option.blocks)
server.start(option.ip, option.port) const { Server } = require('../src/server')
const server = new Server(option)
server.start(option)
}) })
program.parse(process.argv) program.parse(process.argv)

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-simulator", "name": "@remix-project/remix-simulator",
"version": "0.2.48", "version": "0.2.49",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -22,7 +22,7 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.55", "@remix-project/remix-lib": "^0.5.56",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^3.1.0", "async": "^3.1.0",
"body-parser": "^1.18.2", "body-parser": "^1.18.2",
@ -70,6 +70,6 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e", "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1 +1,2 @@
export { Provider, extend, JSONRPCRequestPayload, JSONRPCResponsePayload, JSONRPCResponseCallback } from './provider' export { Provider, extend, JSONRPCRequestPayload, JSONRPCResponsePayload, JSONRPCResponseCallback } from './provider'
export { Server } from './server'

@ -35,7 +35,7 @@ export type ProviderOptions = {
nodeUrl?: string, nodeUrl?: string,
blockNumber?: number | 'latest', blockNumber?: number | 'latest',
stateDb?: State, stateDb?: State,
logDetails?: boolean details?: boolean
blocks?: string[], blocks?: string[],
coinbase?: string coinbase?: string
} }
@ -90,12 +90,12 @@ export class Provider {
return return
} }
const method = this.methods[payload.method] const method = this.methods[payload.method]
if (this.options.logDetails) { if (this.options.details) {
info(payload) info(payload)
} }
if (method) { if (method) {
return method.call(method, payload, (err, result) => { return method.call(method, payload, (err, result) => {
if (this.options.logDetails) { if (this.options.details) {
info(err) info(err)
info(result) info(result)
} }

@ -1,26 +1,32 @@
import express from 'express'
import cors from 'cors' import cors from 'cors'
import bodyParser from 'body-parser' import bodyParser from 'body-parser'
import expressWs from 'express-ws' import { Provider, ProviderOptions } from './provider'
import { Provider } from './provider' import { log, error } from './utils/logs'
import { log } from './utils/logs'
const app = express()
class Server { export type CliOptions = {
rpc?: boolean,
port: number
ip: string
}
export class Server {
provider provider
rpcOnly
constructor (options) { constructor (options?: ProviderOptions) {
this.provider = new Provider(options) this.provider = new Provider(options)
this.provider.init().then(() => { this.provider.init().then(() => {
log('Provider initiated') log('Provider initiated')
log('Test accounts:')
log(Object.keys(this.provider.Accounts.accounts))
}).catch((error) => { }).catch((error) => {
log(error) log(error)
}) })
this.rpcOnly = options.rpc
} }
start (host, port) { async start (cliOptions: CliOptions) {
const expressWs = (await import('express-ws')).default
const express = (await import('express')).default
const app = express()
const wsApp = expressWs(app) const wsApp = expressWs(app)
app.use(cors()) app.use(cors())
@ -31,22 +37,39 @@ class Server {
res.send('Welcome to remix-simulator') res.send('Welcome to remix-simulator')
}) })
if (this.rpcOnly) { if (cliOptions.rpc) {
app.use((req, res) => { app.use((req, res) => {
if (req && req.body && (req.body.method === 'eth_sendTransaction' || req.body.method === 'eth_call')) {
log('Receiving call/transaction:')
log(req.body.params)
}
this.provider.sendAsync(req.body, (err, jsonResponse) => { this.provider.sendAsync(req.body, (err, jsonResponse) => {
if (err) { if (err) {
error(err)
return res.send(JSON.stringify({ error: err })) return res.send(JSON.stringify({ error: err }))
} }
if (req && req.body && (req.body.method === 'eth_sendTransaction' || req.body.method === 'eth_call')) {
log(jsonResponse)
}
res.send(jsonResponse) res.send(jsonResponse)
}) })
}) })
} else { } else {
wsApp.app.ws('/', (ws, req) => { wsApp.app.ws('/', (ws, req) => {
ws.on('message', (msg) => { ws.on('message', (msg) => {
this.provider.sendAsync(JSON.parse(msg.toString()), (err, jsonResponse) => { const body = JSON.parse(msg.toString())
if (body && (body.method === 'eth_sendTransaction' || body.method === 'eth_call')) {
log('Receiving call/transaction:')
log(body.params)
}
this.provider.sendAsync(body, (err, jsonResponse) => {
if (err) { if (err) {
error(err)
return ws.send(JSON.stringify({ error: err })) return ws.send(JSON.stringify({ error: err }))
} }
if (body && (body.method === 'eth_sendTransaction' || body.method === 'eth_call')) {
log(jsonResponse)
}
ws.send(JSON.stringify(jsonResponse)) ws.send(JSON.stringify(jsonResponse))
}) })
}) })
@ -57,13 +80,14 @@ class Server {
}) })
} }
app.listen(port, host, () => { app.listen(cliOptions.port, cliOptions.ip, () => {
log('Remix Simulator listening on ws://' + host + ':' + port) if (!cliOptions.rpc) {
if (!this.rpcOnly) { log('Remix Simulator listening on ws://' + cliOptions.ip + ':' + cliOptions.port)
log('http json-rpc is deprecated and disabled by default. To enable it use --rpc') log('http json-rpc is deprecated and disabled by default. To enable it use --rpc')
} else {
log('Remix Simulator listening on http://' + cliOptions.ip + ':' + cliOptions.port)
} }
}) })
} }
} }
module.exports = Server

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-solidity", "name": "@remix-project/remix-solidity",
"version": "0.5.34", "version": "0.5.35",
"description": "Tool to load and run Solidity compiler", "description": "Tool to load and run Solidity compiler",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -19,7 +19,7 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.55", "@remix-project/remix-lib": "^0.5.56",
"async": "^2.6.2", "async": "^2.6.2",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.0.0",
"ethers": "^5.4.2", "ethers": "^5.4.2",
@ -57,5 +57,5 @@
}, },
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme", "homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e" "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-tests", "name": "@remix-project/remix-tests",
"version": "0.2.48", "version": "0.2.49",
"description": "Tool to test Solidity smart contracts", "description": "Tool to test Solidity smart contracts",
"main": "src/index.js", "main": "src/index.js",
"types": "./src/index.d.ts", "types": "./src/index.d.ts",
@ -41,9 +41,9 @@
"@ethereumjs/tx": "5.3.0", "@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3", "@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0", "@ethereumjs/vm": "8.0.0",
"@remix-project/remix-lib": "^0.5.55", "@remix-project/remix-lib": "^0.5.56",
"@remix-project/remix-simulator": "^0.2.48", "@remix-project/remix-simulator": "^0.2.49",
"@remix-project/remix-solidity": "^0.5.34", "@remix-project/remix-solidity": "^0.5.35",
"@remix-project/remix-url-resolver": "^0.0.42", "@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.0", "async": "^2.6.0",
@ -89,5 +89,5 @@
"@ethereumjs/trie": "6.2.0" "@ethereumjs/trie": "6.2.0"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e" "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7"
} }

@ -9,6 +9,7 @@ interface IRemixDragBarUi {
minWidth: number minWidth: number
maximiseTrigger: number maximiseTrigger: number
resetTrigger: number resetTrigger: number
layoutPosition: 'left' | 'right'
} }
const DragBar = (props: IRemixDragBarUi) => { const DragBar = (props: IRemixDragBarUi) => {
@ -19,35 +20,61 @@ const DragBar = (props: IRemixDragBarUi) => {
const nodeRef = React.useRef(null) // fix for strictmode const nodeRef = React.useRef(null) // fix for strictmode
useEffect(() => { useEffect(() => {
setDragBarPosX(offset + (props.hidden ? 0 : props.refObject.current.offsetWidth)) if (props.hidden) {
setDragBarPosX(offset)
} else if (props.layoutPosition === 'left') {
setDragBarPosX(offset + props.refObject.current.offsetWidth)
} else if (props.layoutPosition === 'right') {
setDragBarPosX(offset)
}
}, [props.hidden, offset]) }, [props.hidden, offset])
useEffect(() => { useEffect(() => {
initialWidth.current = props.refObject.current.clientWidth initialWidth.current = props.refObject.current.clientWidth
if (props.maximiseTrigger > 0) { if (props.maximiseTrigger > 0) {
const width = 0.4 * window.innerWidth if (props.layoutPosition === 'left') {
if (width > props.refObject.current.offsetWidth) { const width = 0.4 * window.innerWidth
props.refObject.current.style.width = width + 'px'
setTimeout(() => { if (width > props.refObject.current.offsetWidth) {
setDragBarPosX(offset + width) props.refObject.current.style.width = width + 'px'
}, 300) setTimeout(() => {
setDragBarPosX(offset + width)
}, 300)
}
} else if (props.layoutPosition === 'right') {
const width = 0.4 * window.innerWidth
if (width > props.refObject.current.offsetWidth) {
props.refObject.current.style.width = width + 'px'
setTimeout(() => {
setDragBarPosX(window.innerWidth - width)
}, 300)
}
} }
} }
}, [props.maximiseTrigger]) }, [props.maximiseTrigger])
useEffect(() => { useEffect(() => {
if (props.maximiseTrigger > 0) { if (props.maximiseTrigger > 0) {
props.refObject.current.style.width = initialWidth.current + 'px' if (props.layoutPosition === 'left') {
setTimeout(() => { props.refObject.current.style.width = initialWidth.current + 'px'
setDragBarPosX(offset + initialWidth.current) setTimeout(() => {
}, 300) setDragBarPosX(offset + initialWidth.current)
}, 300)
} else if (props.layoutPosition === 'right') {
props.refObject.current.style.width = props.minWidth + 'px'
setTimeout(() => {
setDragBarPosX(window.innerWidth - props.minWidth)
}, 300)
}
} }
}, [props.resetTrigger]) }, [props.resetTrigger])
const handleResize = () => { const handleResize = () => {
if (!props.refObject.current) return if (!props.refObject.current) return
setOffSet(props.refObject.current.offsetLeft) setOffSet(props.refObject.current.offsetLeft)
setDragBarPosX(props.refObject.current.offsetLeft + props.refObject.current.offsetWidth) if (props.layoutPosition === 'left') setDragBarPosX(props.refObject.current.offsetLeft + props.refObject.current.offsetWidth)
else if (props.layoutPosition === 'right') setDragBarPosX(props.refObject.current.offsetLeft)
} }
useEffect(() => { useEffect(() => {
@ -59,15 +86,28 @@ const DragBar = (props: IRemixDragBarUi) => {
function stopDrag(data: any) { function stopDrag(data: any) {
setDragState(false) setDragState(false)
if (data.x < props.minWidth + offset) { if (props.layoutPosition === 'left') {
setDragBarPosX(offset) if (data.x < props.minWidth + offset) {
props.setHideStatus(true) setDragBarPosX(offset)
} else { props.setHideStatus(true)
props.refObject.current.style.width = data.x - offset + 'px' } else {
setTimeout(() => { props.refObject.current.style.width = data.x - offset + 'px'
setTimeout(() => {
props.setHideStatus(false)
setDragBarPosX(offset + props.refObject.current.offsetWidth)
}, 300)
}
} else if (props.layoutPosition === 'right') {
if (window.innerWidth - data.x < props.minWidth) {
setDragBarPosX(props.refObject.current.offsetLeft)
props.setHideStatus(false) props.setHideStatus(false)
setDragBarPosX(offset + props.refObject.current.offsetWidth) } else {
}, 300) props.refObject.current.style.width = (window.innerWidth - data.x) + 'px'
setTimeout(() => {
props.setHideStatus(false)
setDragBarPosX(props.refObject.current.offsetLeft)
}, 300)
}
} }
} }

@ -27,14 +27,18 @@ const RemixApp = (props: IRemixAppUi) => {
const [appReady, setAppReady] = useState<boolean>(false) const [appReady, setAppReady] = useState<boolean>(false)
const [showEnterDialog, setShowEnterDialog] = useState<boolean>(false) const [showEnterDialog, setShowEnterDialog] = useState<boolean>(false)
const [hideSidePanel, setHideSidePanel] = useState<boolean>(false) const [hideSidePanel, setHideSidePanel] = useState<boolean>(false)
const [maximiseTrigger, setMaximiseTrigger] = useState<number>(0) const [hidePinnedPanel, setHidePinnedPanel] = useState<boolean>(true)
const [resetTrigger, setResetTrigger] = useState<number>(0) const [maximiseLeftTrigger, setMaximiseLeftTrigger] = useState<number>(0)
const [resetLeftTrigger, setResetLeftTrigger] = useState<number>(0)
const [maximiseRightTrigger, setMaximiseRightTrigger] = useState<number>(0)
const [resetRightTrigger, setResetRightTrigger] = useState<number>(0)
const [online, setOnline] = useState<boolean>(true) const [online, setOnline] = useState<boolean>(true)
const [locale, setLocale] = useState<{ code: string; messages: any }>({ const [locale, setLocale] = useState<{ code: string; messages: any }>({
code: 'en', code: 'en',
messages: {} messages: {}
}) })
const sidePanelRef = useRef(null) const sidePanelRef = useRef(null)
const pinnedPanelRef = useRef(null)
useEffect(() => { useEffect(() => {
async function activateApp() { async function activateApp() {
@ -81,20 +85,41 @@ const RemixApp = (props: IRemixAppUi) => {
}) })
props.app.layout.event.on('maximisesidepanel', () => { props.app.layout.event.on('maximisesidepanel', () => {
setMaximiseTrigger((prev) => { setMaximiseLeftTrigger((prev) => {
return prev + 1 return prev + 1
}) })
}) })
props.app.layout.event.on('resetsidepanel', () => { props.app.layout.event.on('resetsidepanel', () => {
setResetTrigger((prev) => { setResetLeftTrigger((prev) => {
return prev + 1 return prev + 1
}) })
}) })
props.app.layout.event.on('maximisepinnedpanel', () => {
setMaximiseRightTrigger((prev) => {
return prev + 1
})
})
props.app.layout.event.on('resetpinnedpanel', () => {
setResetRightTrigger((prev) => {
return prev + 1
})
})
props.app.localeModule.events.on('localeChanged', (nextLocale) => { props.app.localeModule.events.on('localeChanged', (nextLocale) => {
setLocale(nextLocale) setLocale(nextLocale)
}) })
props.app.pinnedPanel.events.on('pinnedPlugin', () => {
setHidePinnedPanel(false)
})
props.app.pinnedPanel.events.on('unPinnedPlugin', () => {
setHidePinnedPanel(true)
})
setInterval(() => { setInterval(() => {
setOnline(window.navigator.onLine) setOnline(window.navigator.onLine)
}, 1000) }, 1000)
@ -166,19 +191,32 @@ const RemixApp = (props: IRemixAppUi) => {
{props.app.sidePanel.render()} {props.app.sidePanel.render()}
</div> </div>
<DragBar <DragBar
resetTrigger={resetTrigger} resetTrigger={resetLeftTrigger}
maximiseTrigger={maximiseTrigger} maximiseTrigger={maximiseLeftTrigger}
minWidth={285} minWidth={285}
refObject={sidePanelRef} refObject={sidePanelRef}
hidden={hideSidePanel} hidden={hideSidePanel}
setHideStatus={setHideSidePanel} setHideStatus={setHideSidePanel}
layoutPosition='left'
></DragBar> ></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className="mainpanel d-flex"> <div id="main-panel" data-id="remixIdeMainPanel" className="mainpanel d-flex">
<RemixUIMainPanel layout={props.app.layout}></RemixUIMainPanel> <RemixUIMainPanel layout={props.app.layout}></RemixUIMainPanel>
<CustomTooltip placement="bottom" tooltipId="overlay-tooltip-all-tabs" tooltipText={<FormattedMessage id="remixApp.scrollToSeeAllTabs" />}>
<div className="remix-ui-tabs_end remix-bg-opacity position-absolute position-fixed"></div>
</CustomTooltip>
</div> </div>
<div id="pinned-panel" ref={pinnedPanelRef} data-id="remixIdePinnedPanel" className={`flex-row-reverse pinnedpanel border-right border-left ${hidePinnedPanel ? 'd-none' : 'd-flex'}`}>
{props.app.pinnedPanel.render()}
</div>
{
!hidePinnedPanel &&
<DragBar
resetTrigger={resetRightTrigger}
maximiseTrigger={maximiseRightTrigger}
minWidth={331}
refObject={pinnedPanelRef}
hidden={hidePinnedPanel}
setHideStatus={setHidePinnedPanel}
layoutPosition='right'
></DragBar>
}
</div> </div>
<div>{props.app.hiddenPanel.render()}</div> <div>{props.app.hiddenPanel.render()}</div>
<AppDialogs></AppDialogs> <AppDialogs></AppDialogs>

@ -34,6 +34,10 @@ pre {
width : 320px; width : 320px;
transition : width 0.25s; transition : width 0.25s;
} }
.pinnedpanel {
width : 320px;
transition : width 0.25s;
}
.highlightcode { .highlightcode {
position : absolute; position : absolute;
z-index : 20; z-index : 20;

@ -183,14 +183,26 @@ export const DebuggerApiMixin = (Base) => class extends Base {
showMessage (title: string, message: string) {} showMessage (title: string, message: string) {}
onStartDebugging (debuggerBackend: any) { async onStartDebugging (debuggerBackend: any) {
this.call('layout', 'maximiseSidePanel') const pinnedPlugin = await this.call('pinnedPanel', 'currentFocus')
if (pinnedPlugin === 'debugger') {
this.call('layout', 'maximisePinnedPanel')
} else {
this.call('layout', 'maximiseSidePanel')
}
this.emit('startDebugging') this.emit('startDebugging')
this.debuggerBackend = debuggerBackend this.debuggerBackend = debuggerBackend
} }
onStopDebugging () { async onStopDebugging () {
this.call('layout', 'resetSidePanel') const pinnedPlugin = await this.call('pinnedPanel', 'currentFocus')
if (pinnedPlugin === 'debugger') {
this.call('layout', 'resetPinnedPanel')
} else {
this.call('layout', 'resetSidePanel')
}
this.emit('stopDebugging') this.emit('stopDebugging')
this.debuggerBackend = null this.debuggerBackend = null
} }

@ -524,7 +524,7 @@ export function GeCompletionUnits(range: monacoTypes.IRange, monaco): monacoType
if (unit !== 'years') { if (unit !== 'years') {
completionItem.detail = unit + ': time unit'; completionItem.detail = unit + ': time unit';
} else { } else {
completionItem.detail = 'DEPRECATED: ' + unit + ': time unit'; completionItem.detail = 'REMOVED in v0.5.0: ' + unit + ': time unit';
} }
completionItems.push(completionItem); completionItems.push(completionItem);
}); });

@ -30,7 +30,8 @@ const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
active: panel.active, active: panel.active,
view: panel.plugin.profile.name === 'tabs' ? panel.plugin.renderTabsbar() : panel.plugin.render(), view: panel.plugin.profile.name === 'tabs' ? panel.plugin.renderTabsbar() : panel.plugin.render(),
class: panel.plugin.profile.name + '-wrap ' + (panel.minimized ? 'minimized ' : ' ') + ((platform === appPlatformTypes.desktop)? 'desktop' : ''), class: panel.plugin.profile.name + '-wrap ' + (panel.minimized ? 'minimized ' : ' ') + ((platform === appPlatformTypes.desktop)? 'desktop' : ''),
minimized: panel.minimized minimized: panel.minimized,
pinned: panel.pinned
}) })
}) })
setPlugins(pluginPanels) setPlugins(pluginPanels)

@ -1,11 +1,13 @@
import React, {useEffect, useRef, useState} from 'react' // eslint-disable-line import React, {useEffect, useState} from 'react' // eslint-disable-line
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
import { PluginRecord } from '../types' import { PluginRecord } from '../types'
import './panel.css' import './panel.css'
import { CustomTooltip } from '@remix-ui/helper' import { CustomTooltip, RenderIf, RenderIfNot } from '@remix-ui/helper'
export interface RemixPanelProps { export interface RemixPanelProps {
plugins: Record<string, PluginRecord> plugins: Record<string, PluginRecord>,
pinView?: (profile: PluginRecord['profile'], view: PluginRecord['view']) => void,
unPinView?: (profile: PluginRecord['profile']) => void
} }
const RemixUIPanelHeader = (props: RemixPanelProps) => { const RemixUIPanelHeader = (props: RemixPanelProps) => {
const [plugin, setPlugin] = useState<PluginRecord>() const [plugin, setPlugin] = useState<PluginRecord>()
@ -25,6 +27,14 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
setToggleExpander(!toggleExpander) setToggleExpander(!toggleExpander)
} }
const pinPlugin = () => {
props.pinView && props.pinView(plugin.profile, plugin.view)
}
const unPinPlugin = () => {
props.unPinView && props.unPinView(plugin.profile)
}
const tooltipChild = <i className={`px-1 ml-2 pt-1 pb-2 ${!toggleExpander ? 'fas fa-angle-right' : 'fas fa-angle-down bg-light'}`} aria-hidden="true"></i> const tooltipChild = <i className={`px-1 ml-2 pt-1 pb-2 ${!toggleExpander ? 'fas fa-angle-right' : 'fas fa-angle-down bg-light'}`} aria-hidden="true"></i>
return ( return (
@ -34,21 +44,47 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
{plugin?.profile?.name && <FormattedMessage id={`${plugin.profile.name}.displayName`} defaultMessage={plugin?.profile?.displayName || plugin?.profile?.name} />} {plugin?.profile?.name && <FormattedMessage id={`${plugin.profile.name}.displayName`} defaultMessage={plugin?.profile?.displayName || plugin?.profile?.name} />}
</h6> </h6>
<div className="d-flex flex-row"> <div className="d-flex flex-row">
{
plugin && plugin.profile.name !== 'filePanel' && (
<RenderIfNot condition={plugin.profile.name === 'filePanel'}>
<RenderIf condition={plugin.pinned}>
<div className='d-flex' data-id="movePluginToLeft" onClick={unPinPlugin}>
<CustomTooltip placement="auto-end" tooltipId="unPinnedMsg" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="panel.unPinnedMsg" />}>
<i aria-hidden="true" className="mt-1 px-2 fas fa-solid fa-square-left"></i>
</CustomTooltip>
</div>
</RenderIf>
</RenderIfNot>
)
}
<div className="d-flex flex-row"> <div className="d-flex flex-row">
{plugin?.profile?.maintainedBy?.toLowerCase() === 'remix' ? ( {plugin?.profile?.maintainedBy?.toLowerCase() === 'remix' ? (
<CustomTooltip placement="right-end" tooltipId="maintainedByTooltip" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="panel.maintainedByRemix" />}> <CustomTooltip placement="auto-end" tooltipId="maintainedByTooltip" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="panel.maintainedByRemix" />}>
<i aria-hidden="true" className="text-success mt-1 px-1 fas fa-check"></i> <i aria-hidden="true" className="text-success mt-1 px-1 fas fa-check"></i>
</CustomTooltip>) </CustomTooltip>)
: (<CustomTooltip placement="right-end" tooltipId="maintainedExternally" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="panel.maintainedExternally" />}> : (<CustomTooltip placement="auto-end" tooltipId="maintainedExternally" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="panel.maintainedExternally" />}>
<i aria-hidden="true" className="mt-1 px-1 text-warning far fa-exclamation-circle"></i> <i aria-hidden="true" className="mt-1 px-1 text-warning far fa-exclamation-circle"></i>
</CustomTooltip>) </CustomTooltip>)
} }
</div> </div>
<div className="swapitHeaderInfoSection d-flex justify-content-between" data-id="swapitHeaderInfoSectionId" onClick={toggleClass}> <div className="swapitHeaderInfoSection d-flex justify-content-between" data-id="swapitHeaderInfoSectionId" onClick={toggleClass}>
<CustomTooltip placement="right-end" tooltipText={<FormattedMessage id="panel.pluginInfo" />} tooltipId="pluginInfoTooltip" tooltipClasses="text-nowrap"> <CustomTooltip placement="auto-end" tooltipText={<FormattedMessage id="panel.pluginInfo" />} tooltipId="pluginInfoTooltip" tooltipClasses="text-nowrap">
{tooltipChild} {tooltipChild}
</CustomTooltip> </CustomTooltip>
</div> </div>
{
plugin && plugin.profile.name !== 'filePanel' && (
<RenderIfNot condition={plugin.profile.name === 'filePanel'}>
<RenderIfNot condition={plugin.pinned}>
<div className='d-flex' data-id="movePluginToRight" onClick={pinPlugin}>
<CustomTooltip placement="auto-end" tooltipId="pinnedMsg" tooltipClasses="text-nowrap" tooltipText={<FormattedMessage id="panel.pinnedMsg" />}>
<i aria-hidden="true" className="mt-1 px-1 pl-2 fas fa-solid fa-square-right"></i>
</CustomTooltip>
</div>
</RenderIfNot>
</RenderIfNot>
)
}
</div> </div>
</div> </div>
<div className={`bg-light mx-3 mb-2 p-3 pt-1 border-bottom flex-column ${toggleExpander ? 'd-flex' : 'd-none'}`}> <div className={`bg-light mx-3 mb-2 p-3 pt-1 border-bottom flex-column ${toggleExpander ? 'd-flex' : 'd-none'}`}>

@ -3,7 +3,9 @@ import React, {forwardRef, useEffect, useRef, useState} from 'react' // eslint-d
import { PluginRecord } from '../types' import { PluginRecord } from '../types'
import './panel.css' import './panel.css'
interface panelPLuginProps { interface panelPLuginProps {
pluginRecord: PluginRecord pluginRecord: PluginRecord,
initialState?: any,
children?: any
} }
const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => { const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => {
@ -14,7 +16,19 @@ const RemixUIPanelPlugin = (props: panelPLuginProps, panelRef: any) => {
if (ref.current) { if (ref.current) {
if (props.pluginRecord.view) { if (props.pluginRecord.view) {
if (React.isValidElement(props.pluginRecord.view)) { if (React.isValidElement(props.pluginRecord.view)) {
setView(props.pluginRecord.view) let view = props.pluginRecord.view
if (props.initialState) {
view = React.Children.map((props.pluginRecord.view.props as any).children, child => {
if (React.isValidElement(child) && typeof child.type === 'function') {
// Safe to clone and pass `initialState`
return React.cloneElement(child, { ...props, initialState: props.initialState } as any)
}
return child
})
}
setView(view)
} else { } else {
ref.current.appendChild(props.pluginRecord.view) ref.current.appendChild(props.pluginRecord.view)
} }

@ -6,8 +6,9 @@ import { PluginRecord } from '../types'
/* eslint-disable-next-line */ /* eslint-disable-next-line */
export interface RemixPanelProps { export interface RemixPanelProps {
plugins: Record<string, PluginRecord> plugins: Record<string, PluginRecord>,
header: JSX.Element header: JSX.Element,
pluginState?: any,
} }
export function RemixPluginPanel(props: RemixPanelProps) { export function RemixPluginPanel(props: RemixPanelProps) {
@ -17,7 +18,7 @@ export function RemixPluginPanel(props: RemixPanelProps) {
<div className="pluginsContainer"> <div className="pluginsContainer">
<div className="plugins" id="plugins"> <div className="plugins" id="plugins">
{Object.values(props.plugins).map((pluginRecord) => { {Object.values(props.plugins).map((pluginRecord) => {
return <RemixUIPanelPlugin key={pluginRecord.profile.name} pluginRecord={pluginRecord} /> return <RemixUIPanelPlugin key={pluginRecord.profile.name} pluginRecord={pluginRecord} initialState={props.pluginState} />
})} })}
</div> </div>
</div> </div>

@ -4,6 +4,7 @@ export type PluginRecord = {
profile: Profile profile: Profile
view: any view: any
active: boolean active: boolean
pinned: boolean
class?: string class?: string
minimized?: boolean minimized?: boolean
} }

@ -12,8 +12,13 @@ import { getNetworkProxyAddresses } from "./deploy"
import { shortenAddress } from "@remix-ui/helper" import { shortenAddress } from "@remix-ui/helper"
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
let dispatch: React.Dispatch<any> = () => {}
export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch<any>) => { export const setEventsDispatch = (reducerDispatch: React.Dispatch<any>) => {
dispatch = reducerDispatch
}
export const setupEvents = (plugin: RunTab) => {
// This maintains current network state and update the pinned contracts list, // This maintains current network state and update the pinned contracts list,
// only when there is a change in provider or in chain id for same provider // only when there is a change in provider or in chain id for same provider
// as 'networkStatus' is triggered in each 10 seconds // as 'networkStatus' is triggered in each 10 seconds

@ -1,7 +1,7 @@
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
import React from 'react' import React from 'react'
import { RunTab } from '../types/run-tab' import { RunTab } from '../types/run-tab'
import { resetAndInit, setupEvents } from './events' import { resetAndInit, setupEvents, setEventsDispatch } from './events'
import { createNewBlockchainAccount, setExecutionContext, signMessageWithAddress } from './account' import { createNewBlockchainAccount, setExecutionContext, signMessageWithAddress } from './account'
import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt, import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt,
setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit, setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit,
@ -22,11 +22,14 @@ declare global {
const _paq = window._paq = window._paq || [] //eslint-disable-line const _paq = window._paq = window._paq || [] //eslint-disable-line
let plugin: RunTab, dispatch: React.Dispatch<any> = () => {} let plugin: RunTab, dispatch: React.Dispatch<any> = () => {}
export const initRunTab = (udapp: RunTab) => async (reducerDispatch: React.Dispatch<any>) => { export const initRunTab = (udapp: RunTab, resetEventsAndAccounts: boolean) => async (reducerDispatch: React.Dispatch<any>) => {
plugin = udapp plugin = udapp
dispatch = reducerDispatch dispatch = reducerDispatch
setupEvents(plugin, dispatch) setEventsDispatch(reducerDispatch)
resetAndInit(plugin) if (resetEventsAndAccounts) {
setupEvents(plugin)
resetAndInit(plugin)
}
} }
export const setAccountAddress = (account: string) => setAccount(dispatch, account) export const setAccountAddress = (account: string) => setAccount(dispatch, account)

@ -373,10 +373,12 @@ export function ContractGUI(props: ContractGUIProps) {
<button <button
type="button" type="button"
data-id={buttonOptions.dataId} data-id={buttonOptions.dataId}
className={`udapp_instanceButton btn ${buttonOptions.classList}`} className={`udapp_instanceButton btn ${buttonOptions.classList} text-center d-flex justify-content-center align-items-center`}
disabled={props.disabled || (props.inputs !== '' && basicInput === '')} disabled={props.disabled || (props.inputs !== '' && basicInput === '')}
> >
{buttonOptions.content} <div className="text-center d-flex justify-content-center align-items-center">
{buttonOptions.content}
</div>
</button> </button>
</div> </div>
</CustomTooltip> </CustomTooltip>

@ -267,7 +267,7 @@ export function UniversalDappUI(props: UdappProps) {
</span>) } </span>) }
</div> </div>
<div className="btn" style={{ padding: '0.15rem' }}> <div className="btn" style={{ padding: '0.15rem' }}>
<CopyToClipboard tip={intl.formatMessage({ id: 'udapp.copy' })} content={address} direction={'top'} /> <CopyToClipboard tip={intl.formatMessage({ id: 'udapp.copyAddress' })} content={address} direction={'top'} />
</div> </div>
{ props.isPinnedContract ? ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}> { props.isPinnedContract ? ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}>
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappUnpinTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextUnpin" />}> <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappUnpinTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextUnpin" />}>

@ -74,18 +74,25 @@ export function RunTabUI(props: RunTabProps) {
storage: null, storage: null,
contract: null contract: null
}) })
runTabInitialState.selectExEnv = plugin.blockchain.getProvider() const initialState = props.initialState || runTabInitialState
const [runTab, dispatch] = useReducer(runTabReducer, runTabInitialState)
initialState.selectExEnv = plugin.blockchain.getProvider()
const [runTab, dispatch] = useReducer(runTabReducer, initialState)
const REACT_API = { runTab } const REACT_API = { runTab }
const currentfile = plugin.config.get('currentFile') const currentfile = plugin.config.get('currentFile')
useEffect(() => { useEffect(() => {
initRunTab(plugin)(dispatch) if (!props.initialState) {
plugin.onInitDone() initRunTab(plugin, true)(dispatch)
plugin.onInitDone()
} else {
initRunTab(plugin, false)(dispatch)
}
}, [plugin]) }, [plugin])
useEffect(() => { useEffect(() => {
plugin.onReady(runTab) plugin.onReady(runTab)
plugin.call('pluginStateLogger', 'logPluginState', 'udapp', runTab)
}, [REACT_API]) }, [REACT_API])
useEffect(() => { useEffect(() => {

@ -5,7 +5,8 @@ import { RunTab } from './run-tab'
import { SolcInput, SolcOutput } from '@openzeppelin/upgrades-core' import { SolcInput, SolcOutput } from '@openzeppelin/upgrades-core'
import { LayoutCompatibilityReport } from '@openzeppelin/upgrades-core/dist/storage/report' import { LayoutCompatibilityReport } from '@openzeppelin/upgrades-core/dist/storage/report'
export interface RunTabProps { export interface RunTabProps {
plugin: RunTab plugin: RunTab,
initialState: RunTabState
} }
export interface Contract { export interface Contract {

@ -15,7 +15,7 @@ export const SearchTab = (props) => {
return ( return (
<> <>
<div className="search_plugin_search_tab pr-4 px-2 pb-4"> <div className="search_plugin_search_tab pr-4 px-2 pb-4">
<SearchProvider platform={platform} plugin={plugin}> <SearchProvider platform={platform} plugin={plugin} initialState={props.initialState}>
<FindContainer></FindContainer> <FindContainer></FindContainer>
<Include></Include> <Include></Include>
<Exclude></Exclude> <Exclude></Exclude>

@ -443,6 +443,7 @@ export const SearchProvider = ({ children = [], reducer = SearchReducer, initial
} }
})() })()
} }
plugin.call('pluginStateLogger', 'logPluginState', 'search', state)
}, [state.timeStamp]) }, [state.timeStamp])
return ( return (

@ -373,7 +373,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
// Load solc compiler version according to pragma in contract file // Load solc compiler version according to pragma in contract file
const _setCompilerVersionFromPragma = (filename: string) => { const _setCompilerVersionFromPragma = (filename: string) => {
if (!solJsonBinData.selectorList) return if (solJsonBinData && !solJsonBinData.selectorList) return
api.readFile(filename).then((data) => { api.readFile(filename).then((data) => {
if (!data) return if (!data) return
const pragmaArr = data.match(/(pragma solidity (.+?);)/g) const pragmaArr = data.match(/(pragma solidity (.+?);)/g)

@ -1,42 +1,49 @@
import type { CompilationSource, AstNode } from '@remix-project/remix-solidity' import type { CompilationSource, AstNode } from '@remix-project/remix-solidity'
const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+).*$/gm; const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+).*$/gm
const SPDX_SOLIDITY_REGEX = /^\s*\/\/ SPDX-License-Identifier:.*$/gm; const SPDX_SOLIDITY_REGEX = /^\s*\/\/ SPDX-License-Identifier:.*$/gm
const PRAGMA_SOLIDITY_REGEX = /^pragma experimental\s+.*$/gm
type Visited = { [key: string]: number } type Visited = { [key: string]: number }
export function getDependencyGraph(ast: { [name: string]: CompilationSource }, target: string, remappings: string[]) { export function getDependencyGraph(ast: { [name: string]: CompilationSource }, target: string, remappings: string[], order: string[]) {
const graph = tsort(); const graph = tsort()
const visited = {}; const visited = {}
visited[target] = 1; visited[target] = 1
_traverse(graph, visited, ast, target, remappings); _traverse(graph, visited, ast, target, remappings, order)
return graph; return graph
} }
export function concatSourceFiles(files: any[], sources: any) { export function concatSourceFiles(files: any[], sources: any, order: string[]) {
let concat = ''; let concat = ''
for (const file of files) { order.forEach((importName) => {
const source = sources[file].content; for (const file of files) {
const sourceWithoutImport = source.replace(IMPORT_SOLIDITY_REGEX, ''); if (file === importName) {
const sourceWithoutSPDX = sourceWithoutImport.replace(SPDX_SOLIDITY_REGEX, ''); const source = sources[file].content
concat += `\n// File: ${file}\n\n`; const sourceWithoutImport = source.replace(IMPORT_SOLIDITY_REGEX, '')
concat += sourceWithoutSPDX; const sourceWithoutSPDX = sourceWithoutImport.replace(SPDX_SOLIDITY_REGEX, '')
} const sourceWithoutDuplicatePragma = sourceWithoutSPDX.replace(PRAGMA_SOLIDITY_REGEX, '')
return concat; concat += `\n// File: ${file}\n\n`
concat += sourceWithoutDuplicatePragma
}
}
})
return concat
} }
function _traverse(graph: Graph, visited: Visited, ast: { [name: string]: CompilationSource }, name: string, remappings: string[]) { function _traverse(graph: Graph, visited: Visited, ast: { [name: string]: CompilationSource }, name: string, remappings: string[], order: string[]) {
let currentAst = null let currentAst = null
currentAst = ast[name].ast currentAst = ast[name].ast
const dependencies = _getDependencies(currentAst); const dependencies = _getDependencies(currentAst)
for (const dependency of dependencies) { for (const dependency of dependencies) {
const path = resolve(name, dependency, remappings); const path = resolve(name, dependency, remappings)
if (path in visited) { if (path in visited) {
// continue; // fixes wrong ordering of source in flattened file continue; // fixes wrong ordering of source in flattened file
} }
visited[path] = 1; visited[path] = 1
graph.add(name, path); graph.add(name, path)
_traverse(graph, visited, ast, path, remappings); _traverse(graph, visited, ast, path, remappings, order)
} }
order.push(name)
} }
function _getDependencies(ast: AstNode) { function _getDependencies(ast: AstNode) {
@ -191,4 +198,4 @@ export function normalizeContractPath(contractPath: string): string[] {
} }
const resultingPath = `${folders}${filename}` const resultingPath = `${folders}${filename}`
return [folders,resultingPath, filename] return [folders,resultingPath, filename]
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-url-resolver", "name": "@remix-project/remix-url-resolver",
"version": "0.0.77", "version": "0.0.78",
"description": "Solidity import url resolver engine", "description": "Solidity import url resolver engine",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -41,5 +41,5 @@
"typescript": "^3.1.6" "typescript": "^3.1.6"
}, },
"typings": "src/index.d.ts", "typings": "src/index.d.ts",
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e" "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-ws-templates", "name": "@remix-project/remix-ws-templates",
"version": "1.0.42", "version": "1.0.43",
"description": "Create a Remix IDE workspace using different templates", "description": "Create a Remix IDE workspace using different templates",
"main": "src/index.js", "main": "src/index.js",
"types": "src/index.d.ts", "types": "src/index.d.ts",
@ -24,5 +24,5 @@
"ethers": "^5.4.2", "ethers": "^5.4.2",
"web3": "^4.1.1" "web3": "^4.1.1"
}, },
"gitHead": "4f5c2cb88bc38099f71c5407265a23ab3bb7508e" "gitHead": "9a971b0c22009d7405ca158b0847faf0d91ce9a7"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remixd", "name": "@remix-project/remixd",
"version": "0.6.31", "version": "0.6.32",
"description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)", "description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)",
"main": "index.js", "main": "index.js",
"types": "./index.d.ts", "types": "./index.d.ts",

@ -1,10 +1,10 @@
{ {
"name": "remix-project", "name": "remix-project",
"version": "0.49.0-dev", "version": "0.50.0-dev",
"license": "MIT", "license": "MIT",
"description": "Ethereum Remix Monorepo", "description": "Ethereum Remix Monorepo",
"main": "index.js", "main": "index.js",
"defaultVersion": "soljson-v0.8.25+commit.b61c2a91.js", "defaultVersion": "soljson-v0.8.26+commit.8a97fa7a.js",
"keywords": [ "keywords": [
"ethereum", "ethereum",
"solidity", "solidity",

Loading…
Cancel
Save