pull/4877/head
Your Name 5 months ago
commit ccd38c444a
  1. 10
      apps/remix-ide-e2e/src/tests/etherscan_api.test.ts
  2. 17
      apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts
  3. 169
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  4. 3
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  5. 8
      libs/ghaction-helper/package.json
  6. 8
      libs/remix-analyzer/package.json
  7. 6
      libs/remix-astwalker/package.json
  8. 12
      libs/remix-debug/package.json
  9. 4
      libs/remix-lib/package.json
  10. 7
      libs/remix-simulator/package.json
  11. 6
      libs/remix-solidity/package.json
  12. 10
      libs/remix-tests/package.json
  13. 18
      libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
  14. 15
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  15. 2
      libs/remix-ui/helper/src/lib/components/custom-dropdown.tsx
  16. 2
      libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx
  17. 4
      libs/remix-ui/workspace/src/lib/css/remix-ui-workspace.css
  18. 201
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  19. 4
      libs/remix-url-resolver/package.json
  20. 4
      libs/remix-ws-templates/package.json
  21. 4
      libs/remixd/package.json

@ -6,7 +6,7 @@ declare global {
interface Window { testplugin: { name: string, url: string }; } interface Window { testplugin: { name: string, url: string }; }
} }
module.exports = { const tests = {
'@disabled': true, '@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) { before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, null) init(browser, done, null)
@ -58,6 +58,14 @@ module.exports = {
} }
} }
const branch = process.env.CIRCLE_BRANCH;
const isMasterBranch = branch === 'master';
module.exports = {
...(branch ? (isMasterBranch ? tests : {}) : tests),
};
const verifiedContract = ` const verifiedContract = `
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0

@ -25,7 +25,7 @@ const checkAlerts = function (browser: NightwatchBrowser){
}) })
} }
module.exports = { const tests = {
'@disabled': true, '@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) { before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done) init(browser, done)
@ -50,10 +50,10 @@ module.exports = {
.pause(5000) .pause(5000)
.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { .switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser browser
.waitForElementVisible('*[data-testid="page-container-footer-next"]') .waitForElementVisible('*[data-testid="page-container-footer-next"]', 60000)
.click('*[data-testid="page-container-footer-next"]') // this connects the metamask account to remix .click('*[data-testid="page-container-footer-next"]') // this connects the metamask account to remix
.pause(2000) .pause(2000)
.waitForElementVisible('*[data-testid="page-container-footer-next"]') .waitForElementVisible('*[data-testid="page-container-footer-next"]', 60000)
.click('*[data-testid="page-container-footer-next"]') .click('*[data-testid="page-container-footer-next"]')
// .waitForElementVisible('*[data-testid="popover-close"]') // .waitForElementVisible('*[data-testid="popover-close"]')
// .click('*[data-testid="popover-close"]') // .click('*[data-testid="popover-close"]')
@ -162,7 +162,7 @@ module.exports = {
.perform((done) => { .perform((done) => {
browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser browser
.waitForElementPresent('[data-testid="page-container-footer-next"]') .waitForElementPresent('[data-testid="page-container-footer-next"]', 60000)
.click('[data-testid="page-container-footer-next"]') // approve the tx .click('[data-testid="page-container-footer-next"]') // approve the tx
.switchBrowserTab(0) // back to remix .switchBrowserTab(0) // back to remix
.waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000)
@ -177,7 +177,7 @@ module.exports = {
.perform((done) => { // call delegate .perform((done) => { // call delegate
browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser browser
.waitForElementPresent('[data-testid="page-container-footer-next"]') .waitForElementPresent('[data-testid="page-container-footer-next"]', 60000)
.click('[data-testid="page-container-footer-next"]') // approve the tx .click('[data-testid="page-container-footer-next"]') // approve the tx
.switchBrowserTab(0) // back to remix .switchBrowserTab(0) // back to remix
.waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000) .waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000)
@ -232,6 +232,13 @@ module.exports = {
} }
} }
const branch = process.env.CIRCLE_BRANCH;
const isMasterBranch = branch === 'master';
module.exports = {
...(branch ? (isMasterBranch ? tests : {}) : tests),
};
const localsCheck = { const localsCheck = {
to: { to: {
value: '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB', value: '0x4B0897B0513FDC7C541B6D9D7E929C4E5364D2DB',

@ -2,6 +2,10 @@
import { NightwatchBrowser } from 'nightwatch' import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init' import init from '../helpers/init'
const branch = process.env.CIRCLE_BRANCH;
const isMasterBranch = branch === 'master';
const runMasterTests: boolean = (branch ? (isMasterBranch ? true : false) : true)
module.exports = { module.exports = {
'@disabled': true, '@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) { before: function (browser: NightwatchBrowser, done: VoidFunction) {
@ -209,26 +213,27 @@ module.exports = {
}, },
'Should run a script which log transaction and block using web3.js and ethers #group7': function (browser: NightwatchBrowser) { 'Should run a script which log transaction and block using web3.js and ethers #group7': function (browser: NightwatchBrowser) {
browser if (runMasterTests)
.clickLaunchIcon('udapp') browser
.switchEnvironment('basic-http-provider') .clickLaunchIcon('udapp')
.waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]') .switchEnvironment('basic-http-provider')
.execute(() => { .waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]')
(document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus() .execute(() => {
}, [], () => { }) (document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus()
.setValue('[data-id="modalDialogCustomPromp"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9') }, [], () => { })
.modalFooterOKClick('basic-http-provider') .setValue('[data-id="modalDialogCustomPromp"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9')
.clickLaunchIcon('filePanel') .modalFooterOKClick('basic-http-provider')
.openFile('README.txt') .clickLaunchIcon('filePanel')
.addFile('scripts/log_tx_block.js', { content: scriptBlockAndTransaction }) .openFile('README.txt')
.pause(1000) .addFile('scripts/log_tx_block.js', { content: scriptBlockAndTransaction })
.executeScriptInTerminal('remix.execute(\'scripts/log_tx_block.js\')') .pause(1000)
// check if the input of the transaction is being logged (web3 call) .executeScriptInTerminal('remix.execute(\'scripts/log_tx_block.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x2b0006fa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e9e0000000000000000000000000000000000000000000000000000000000004ea373ded44d6900b8b479935bee9c82176261653e334586e0fd282f569357c0777bd9d084474837ac94bf96f2e26590222a2b8e46545657c7cf06ce2833d267bd6f131b5b3fd36cb1ca3e07cf422224df0766d1a677bbdb7ee4cc0d634efa5367a302a94dac422a16b9b8d5c10fe0555924f8189f6b498bef507b1d32e7915bd4df184f51e6d79ae6a1b11d5745ce7d625cecc3bd0dc50af4f999ffb927225f5e5c019b499f5e1fdcbc70c45df61df76013d1b0d45cdf6a267dac1b4620c0db2efd251f6548509c9c69f5bd9d1ee38ac0df0c73be2774f7d2e1fb7ef5129010f29d091e3c48aed0f035fc29804c99927d33ff2a19ff526979355ac50b2542bc5d8f2d41e4f850d5981e0420807469e828b03173b96b757fbaeacda335e11b3ab8b02a48456fab35d41ca26abde751d5fca8ef5e7ba5295278b6e46ce2aab6c10b3d185a6137d3e5c28bb8dd3a797feaf35520fcb949ea074e1869e0011ef01f8162135e44bb797d3d6215ff74ffbee972c97264fc15d11c840e6a7e796dc1a418572f6dbcc842594a558e1a9e3cb7a159284e16fec758bbc303d13edc28fb6d8bb110c3a398e4ded1748da9854eb84679ad0c99bc59bea7956b521db3ed0a9057510cc11365858704989690f0d891af81b213b1f2e91e41e4998a467656eac87e7025ac2840c17f2b106df7d32a0139036bdf5d87344ca37e9ce770e0dbeb5e021d03a7d496a6695eb06d3de9258b43f3883ce155767962b52083504b19d6d609090a2f96e9724902bf1adbf57359ac1dda48a8ffe596b8d95cac1429378769a6ec2ff1c8a9c0bc343b0a6468f36696bfb202cde9f6cd5241b814096d777751b44f0cc2ac9e7ba142227e8d5f2dd8da62573953540da1abce82c59287b2f7a87a111851758c2505d8c1ded6c42a49fc5577451ee56126d2275da490baa645c3bcac0c31dabee7aa35e6cdffb56ac0d952c2583c6f50f906dfb96f5a98c49a5919031cff880bffbe371a50162a7bd0fa0398a5898eaf6ad6db868a7d807846a3592325bb4207d67ad96bac76435368962ba8944d0201c2f620fb29373a6f35c815d101af98111e9b4cc61e8ae77fc63ce375068328ec8d05b49486666fb0f756f99d2fe747c95b2a553965f304a324879393897315d310841f0a200cd156f6ca4ed2', 120000) // check if the input of the transaction is being logged (web3 call)
// check if the logsBloom is being logged (web3 call) .waitForElementContainsText('*[data-id="terminalJournal"]', '0x2b0006fa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e9e0000000000000000000000000000000000000000000000000000000000004ea373ded44d6900b8b479935bee9c82176261653e334586e0fd282f569357c0777bd9d084474837ac94bf96f2e26590222a2b8e46545657c7cf06ce2833d267bd6f131b5b3fd36cb1ca3e07cf422224df0766d1a677bbdb7ee4cc0d634efa5367a302a94dac422a16b9b8d5c10fe0555924f8189f6b498bef507b1d32e7915bd4df184f51e6d79ae6a1b11d5745ce7d625cecc3bd0dc50af4f999ffb927225f5e5c019b499f5e1fdcbc70c45df61df76013d1b0d45cdf6a267dac1b4620c0db2efd251f6548509c9c69f5bd9d1ee38ac0df0c73be2774f7d2e1fb7ef5129010f29d091e3c48aed0f035fc29804c99927d33ff2a19ff526979355ac50b2542bc5d8f2d41e4f850d5981e0420807469e828b03173b96b757fbaeacda335e11b3ab8b02a48456fab35d41ca26abde751d5fca8ef5e7ba5295278b6e46ce2aab6c10b3d185a6137d3e5c28bb8dd3a797feaf35520fcb949ea074e1869e0011ef01f8162135e44bb797d3d6215ff74ffbee972c97264fc15d11c840e6a7e796dc1a418572f6dbcc842594a558e1a9e3cb7a159284e16fec758bbc303d13edc28fb6d8bb110c3a398e4ded1748da9854eb84679ad0c99bc59bea7956b521db3ed0a9057510cc11365858704989690f0d891af81b213b1f2e91e41e4998a467656eac87e7025ac2840c17f2b106df7d32a0139036bdf5d87344ca37e9ce770e0dbeb5e021d03a7d496a6695eb06d3de9258b43f3883ce155767962b52083504b19d6d609090a2f96e9724902bf1adbf57359ac1dda48a8ffe596b8d95cac1429378769a6ec2ff1c8a9c0bc343b0a6468f36696bfb202cde9f6cd5241b814096d777751b44f0cc2ac9e7ba142227e8d5f2dd8da62573953540da1abce82c59287b2f7a87a111851758c2505d8c1ded6c42a49fc5577451ee56126d2275da490baa645c3bcac0c31dabee7aa35e6cdffb56ac0d952c2583c6f50f906dfb96f5a98c49a5919031cff880bffbe371a50162a7bd0fa0398a5898eaf6ad6db868a7d807846a3592325bb4207d67ad96bac76435368962ba8944d0201c2f620fb29373a6f35c815d101af98111e9b4cc61e8ae77fc63ce375068328ec8d05b49486666fb0f756f99d2fe747c95b2a553965f304a324879393897315d310841f0a200cd156f6ca4ed2', 120000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x0fbbd94c448fe6949f848380a1d145a974f386624b4b10aa40f9afb212b3ddeb', 120000) // hash of 4757766 // check if the logsBloom is being logged (web3 call)
// check if the logsBloom is being logged (ethers.js call) .waitForElementContainsText('*[data-id="terminalJournal"]', '0x0fbbd94c448fe6949f848380a1d145a974f386624b4b10aa40f9afb212b3ddeb', 120000) // hash of 4757766
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x9db899cb75888a630ba50a1644c243b83d2eb38525eb828a06a5e8bb5663c0b0', 120000) // hash of 4757767 // check if the logsBloom is being logged (ethers.js call)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x9db899cb75888a630ba50a1644c243b83d2eb38525eb828a06a5e8bb5663c0b0', 120000) // hash of 4757767
}, },
'Should listen on all transactions #group8': function (browser: NightwatchBrowser) { 'Should listen on all transactions #group8': function (browser: NightwatchBrowser) {
@ -291,46 +296,48 @@ module.exports = {
}, },
'Should connect to mainnet fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) { 'Should connect to mainnet fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) {
browser if (runMasterTests)
.clickLaunchIcon('udapp') browser
.switchEnvironment('vm-mainnet-fork') .clickLaunchIcon('udapp')
.waitForElementPresent({ .switchEnvironment('vm-mainnet-fork')
locateStrategy: 'css selector', .waitForElementPresent({
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', locateStrategy: 'css selector',
timeout: 240000 selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
}) timeout: 240000
.executeScriptInTerminal(`web3.eth.getCode('0x180587b00c8642e2c7ac3a758712d97e6f7bdcc7')`) // mainnet contract })
.waitForElementContainsText('*[data-id="terminalJournal"]', '0x608060405260043610601f5760003560e01c80635c60da1b14603157602b565b36602b576029605f565b005b6029605f565b348015603c57600080fd5b5060436097565b6040516001600160a01b03909116815260200160405180910390f35b609560917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60d1565b565b600060c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b90565b3660008037600080366000845af43d6000803e80801560ef573d6000f35b3d6000fdfea2646970667358221220969dbb4b1d8aec2bb348e26488dc1a33b6bcf0190f567d161312ab7ca9193d8d64736f6c63430008110033', 120000) .executeScriptInTerminal(`web3.eth.getCode('0x180587b00c8642e2c7ac3a758712d97e6f7bdcc7')`) // mainnet contract
.click('*[data-id="terminalClearConsole"]') .waitForElementContainsText('*[data-id="terminalJournal"]', '0x608060405260043610601f5760003560e01c80635c60da1b14603157602b565b36602b576029605f565b005b6029605f565b348015603c57600080fd5b5060436097565b6040516001600160a01b03909116815260200160405180910390f35b609560917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b60d1565b565b600060c97f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b90565b3660008037600080366000845af43d6000803e80801560ef573d6000f35b3d6000fdfea2646970667358221220969dbb4b1d8aec2bb348e26488dc1a33b6bcf0190f567d161312ab7ca9193d8d64736f6c63430008110033', 120000)
.click('*[data-id="terminalClearConsole"]')
}, },
'Should connect to the sepolia fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) { 'Should connect to the sepolia fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) {
browser if (runMasterTests)
.switchEnvironment('vm-custom-fork') browser
.waitForElementVisible('[data-id="vm-custom-fork-modal-footer-ok-react"]') .switchEnvironment('vm-custom-fork')
.execute(() => { .waitForElementVisible('[data-id="vm-custom-fork-modal-footer-ok-react"]')
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus() .execute(() => {
}, [], () => { }) (document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkNodeUrl"]') as any).focus()
.clearValue('*[data-id="CustomForkNodeUrl"]').pause(1000).setValue('*[data-id="CustomForkNodeUrl"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9') }, [], () => { })
.execute(() => { .clearValue('*[data-id="CustomForkNodeUrl"]').pause(1000).setValue('*[data-id="CustomForkNodeUrl"]', 'https://go.getblock.io/ee42d0a88f314707be11dd799b122cb9')
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkBlockNumber"]') as any).focus() .execute(() => {
}, [], () => { }) (document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkBlockNumber"]') as any).focus()
.clearValue('*[data-id="CustomForkBlockNumber"]').setValue('*[data-id="CustomForkBlockNumber"]', 'latest') }, [], () => { })
.execute(() => { .clearValue('*[data-id="CustomForkBlockNumber"]').setValue('*[data-id="CustomForkBlockNumber"]', 'latest')
(document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkEvmType"]') as any).focus() .execute(() => {
}, [], () => { }) (document.querySelector('*[data-id="vm-custom-forkModalDialogContainer-react"] input[data-id="CustomForkEvmType"]') as any).focus()
.click('*[data-id="CustomForkEvmType"] [value="cancun"]') }, [], () => { })
.pause(5000) .click('*[data-id="CustomForkEvmType"] [value="cancun"]')
.modalFooterOKClick('vm-custom-fork') .pause(5000)
.waitForElementPresent({ .modalFooterOKClick('vm-custom-fork')
locateStrategy: 'css selector', .waitForElementPresent({
selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]', locateStrategy: 'css selector',
timeout: 240000 selector: 'select[data-id="runTabSelectAccount"] option[value="0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]',
}) timeout: 240000
.pause(5000) })
.executeScriptInTerminal(`web3.eth.getCode('0x75F509A4eDA030470272DfBAf99A47D587E76709')`) // sepolia contract .pause(5000)
.waitForElementContainsText('*[data-id="terminalJournal"]', byteCodeInSepolia, 120000) .executeScriptInTerminal(`web3.eth.getCode('0x75F509A4eDA030470272DfBAf99A47D587E76709')`) // sepolia contract
.click('*[data-id="terminalClearConsole"]') .waitForElementContainsText('*[data-id="terminalJournal"]', byteCodeInSepolia, 120000)
.click('*[data-id="terminalClearConsole"]')
}, },
'Should run a free function while being connected to mainnet #group9': function (browser: NightwatchBrowser) { 'Should run a free function while being connected to mainnet #group9': function (browser: NightwatchBrowser) {
@ -354,29 +361,31 @@ module.exports = {
console.log(resolver.addr(node)); console.log(resolver.addr(node));
} }
` `
browser if (runMasterTests) {
// .clickLaunchIcon('udapp') browser
.switchEnvironment('vm-mainnet-fork') // .clickLaunchIcon('udapp')
.clickLaunchIcon('filePanel') .switchEnvironment('vm-mainnet-fork')
.addFile('test_mainnet.sol', { content: script }) .clickLaunchIcon('filePanel')
.addFile('test_mainnet.sol', { content: script })
const path = "//*[@class='view-line' and contains(.,'resolveENS') and contains(.,'view')]//span//span[contains(.,'(')]"
const pathRunFunction = `//li//*[@aria-label='Run the free function "resolveENS"']` const path = "//*[@class='view-line' and contains(.,'resolveENS') and contains(.,'view')]//span//span[contains(.,'(')]"
browser.waitForElementVisible('#editorView') const pathRunFunction = `//li//*[@aria-label='Run the free function "resolveENS"']`
//.waitForElementPresent(pathRunFunction) browser.waitForElementVisible('#editorView')
.pause(10000) // the parser need to parse the code //.waitForElementPresent(pathRunFunction)
.useXpath() .pause(10000) // the parser need to parse the code
.scrollToLine(16) .useXpath()
.click(path) .scrollToLine(16)
.perform(function () { .click(path)
const actions = this.actions({ async: true }); .perform(function () {
return actions const actions = this.actions({ async: true });
.keyDown(this.Keys.SHIFT) return actions
.keyDown(this.Keys.ALT) .keyDown(this.Keys.SHIFT)
.sendKeys('r') .keyDown(this.Keys.ALT)
}) .sendKeys('r')
.useCss() })
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 120000) .useCss()
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', 120000)
}
}, },
'Should run free function which logs in the terminal #group10': function (browser: NightwatchBrowser) { 'Should run free function which logs in the terminal #group10': function (browser: NightwatchBrowser) {

@ -141,5 +141,6 @@
"filePanel.movingFolderFailed": "Moving Folder Failed", "filePanel.movingFolderFailed": "Moving Folder Failed",
"filePanel.movingFolderFailedMsg": "Unexpected error while moving folder: {src}", "filePanel.movingFolderFailedMsg": "Unexpected error while moving folder: {src}",
"filePanel.workspaceActions": "Workspace actions", "filePanel.workspaceActions": "Workspace actions",
"filePanel.saveCodeSample": "This code-sample workspace will not be persisted. Click here to save it." "filePanel.saveCodeSample": "This code-sample workspace will not be persisted. Click here to save it.",
"filePanel.updateSubmodules": "Update all submodules of repository. Click to pull dependencies."
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/ghaction-helper", "name": "@remix-project/ghaction-helper",
"version": "0.1.30", "version": "0.1.32",
"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.36", "@remix-project/remix-solidity": "^0.5.38",
"@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.50", "@remix-project/remix-simulator": "^0.2.52",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986" "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-analyzer", "name": "@remix-project/remix-analyzer",
"version": "0.5.59", "version": "0.5.61",
"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.80", "@remix-project/remix-astwalker": "^0.0.82",
"@remix-project/remix-lib": "^0.5.57", "@remix-project/remix-lib": "^0.5.59",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986", "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
"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.80", "version": "0.0.82",
"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.57", "@remix-project/remix-lib": "^0.5.59",
"@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": "326585ffcef3a8846f2a1badf10beab1f73ee986", "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
"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.50", "version": "0.5.52",
"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.80", "@remix-project/remix-astwalker": "^0.0.82",
"@remix-project/remix-lib": "^0.5.57", "@remix-project/remix-lib": "^0.5.59",
"@remix-project/remix-simulator": "^0.2.50", "@remix-project/remix-simulator": "^0.2.52",
"@remix-project/remix-solidity": "^0.5.36", "@remix-project/remix-solidity": "^0.5.38",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986", "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
"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.57", "version": "0.5.59",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986", "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-simulator", "name": "@remix-project/remix-simulator",
"version": "0.2.50", "version": "0.2.52",
"description": "Ethereum IDE and tools for the web", "description": "Ethereum IDE and tools for the web",
"contributors": [ "contributors": [
{ {
@ -22,7 +22,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-lib": "^0.5.57", "@metamask/eth-sig-util": "^7.0.2",
"@remix-project/remix-lib": "^0.5.59",
"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 +71,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": "326585ffcef3a8846f2a1badf10beab1f73ee986", "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
"types": "./src/index.d.ts" "types": "./src/index.d.ts"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-solidity", "name": "@remix-project/remix-solidity",
"version": "0.5.36", "version": "0.5.38",
"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.57", "@remix-project/remix-lib": "^0.5.59",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986" "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-tests", "name": "@remix-project/remix-tests",
"version": "0.2.50", "version": "0.2.52",
"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.57", "@remix-project/remix-lib": "^0.5.59",
"@remix-project/remix-simulator": "^0.2.50", "@remix-project/remix-simulator": "^0.2.52",
"@remix-project/remix-solidity": "^0.5.36", "@remix-project/remix-solidity": "^0.5.38",
"@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": "326585ffcef3a8846f2a1badf10beab1f73ee986" "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
} }

@ -4,6 +4,7 @@ import { CompletionTimer } from './completionTimer';
import axios, { AxiosResponse } from 'axios' import axios, { AxiosResponse } from 'axios'
import { slice } from 'lodash'; import { slice } from 'lodash';
import { activateService } from '@remixproject/plugin-utils';
const _paq = (window._paq = window._paq || []) const _paq = (window._paq = window._paq || [])
const controller = new AbortController(); const controller = new AbortController();
@ -14,6 +15,9 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
props: EditorUIProps props: EditorUIProps
monaco: any monaco: any
completionEnabled: boolean completionEnabled: boolean
task: string
currentCompletion
constructor(props: any, monaco: any) { constructor(props: any, monaco: any) {
this.props = props this.props = props
this.monaco = monaco this.monaco = monaco
@ -28,6 +32,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
const lineRange = model.getFullModelRange().setStartPosition(lineNumber, 1).setEndPosition(lineNumber + 1, 1); const lineRange = model.getFullModelRange().setStartPosition(lineNumber, 1).setEndPosition(lineNumber + 1, 1);
return model.getValueInRange(lineRange); return model.getValueInRange(lineRange);
} }
// get text before the position of the completion // get text before the position of the completion
const word = model.getValueInRange({ const word = model.getValueInRange({
startLineNumber: 1, startLineNumber: 1,
@ -65,6 +70,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
// use the code generation model, only take max 1000 word as context // use the code generation model, only take max 1000 word as context
this.props.plugin.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Solcoder - generating code for following comment: ' + ask.replace('///', '') }) this.props.plugin.call('terminal', 'log', { type: 'aitypewriterwarning', value: 'Solcoder - generating code for following comment: ' + ask.replace('///', '') })
this.task = 'code_generation'
const data = await this.props.plugin.call('solcoder', 'code_generation', word) const data = await this.props.plugin.call('solcoder', 'code_generation', word)
const parsedData = data[0].trimStart() //JSON.parse(data).trimStart() const parsedData = data[0].trimStart() //JSON.parse(data).trimStart()
@ -103,15 +109,15 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
if (word.replace(/ +$/, '').endsWith('\n')){ if (word.replace(/ +$/, '').endsWith('\n')){
// Code insertion // Code insertion
try { try {
this.task = 'code_insertion'
const output = await this.props.plugin.call('solcoder', 'code_insertion', word, word_after) const output = await this.props.plugin.call('solcoder', 'code_insertion', word, word_after)
const generatedText = output[0] // no need to clean it. should already be const generatedText = output[0] // no need to clean it. should already be
const item: monacoTypes.languages.InlineCompletion = { const item: monacoTypes.languages.InlineCompletion = {
insertText: generatedText insertText: generatedText
}; };
this.completionEnabled = false this.completionEnabled = false
const handleCompletionTimer = new CompletionTimer(5000, () => { this.completionEnabled = true }); const handleCompletionTimer = new CompletionTimer(1000, () => { this.completionEnabled = true });
handleCompletionTimer.start() handleCompletionTimer.start()
return { return {
@ -127,6 +133,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
let result let result
try { try {
// Code completion // Code completion
this.task = 'code_completion'
const output = await this.props.plugin.call('solcoder', 'code_completion', word) const output = await this.props.plugin.call('solcoder', 'code_completion', word)
const generatedText = output[0] const generatedText = output[0]
let clean = generatedText let clean = generatedText
@ -168,14 +175,15 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
} }
handleItemDidShow?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, updatedInsertText: string): void { handleItemDidShow?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, updatedInsertText: string): void {
this.currentCompletion = { 'item':item, 'task':this.task }
_paq.push(['trackEvent', 'ai', 'solcoder', this.task + '_did_show'])
} }
handlePartialAccept?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, acceptedCharacters: number): void { handlePartialAccept?(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>, item: monacoTypes.languages.InlineCompletion, acceptedCharacters: number): void {
_paq.push(['trackEvent', 'ai', 'solcoder', this.task + '_partial_accept'])
} }
freeInlineCompletions(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>): void { freeInlineCompletions(completions: monacoTypes.languages.InlineCompletions<monacoTypes.languages.InlineCompletion>): void {
} }
groupId?: string; groupId?: string;
yieldsToGroupIds?: string[]; yieldsToGroupIds?: string[];
toString?(): string { toString?(): string {

@ -368,6 +368,8 @@ export const EditorUI = (props: EditorUIProps) => {
} }
}, [props.currentFile, props.isDiff]) }, [props.currentFile, props.isDiff])
const inlineCompletionProvider = new RemixInLineCompletionProvider(props, monacoRef.current)
const convertToMonacoDecoration = (decoration: lineText | sourceAnnotation | sourceMarker, typeOfDecoration: string) => { const convertToMonacoDecoration = (decoration: lineText | sourceAnnotation | sourceMarker, typeOfDecoration: string) => {
if (typeOfDecoration === 'sourceAnnotationsPerFile') { if (typeOfDecoration === 'sourceAnnotationsPerFile') {
decoration = decoration as sourceAnnotation decoration = decoration as sourceAnnotation
@ -700,6 +702,17 @@ export const EditorUI = (props: EditorUIProps) => {
} }
}) })
editor.onDidChangeModelContent((e) => {
if (inlineCompletionProvider.currentCompletion) {
const changes = e.changes;
// Check if the change matches the current completion
if (changes.some(change => change.text === inlineCompletionProvider.currentCompletion.item.insertText)) {
_paq.push(['trackEvent', 'ai', 'solcoder', inlineCompletionProvider.currentCompletion.task + '_accepted'])
inlineCompletionProvider.currentCompletion = null;
}
}
});
// add context menu items // add context menu items
const zoominAction = { const zoominAction = {
id: 'zoomIn', id: 'zoomIn',
@ -1003,7 +1016,7 @@ export const EditorUI = (props: EditorUIProps) => {
monacoRef.current.languages.registerReferenceProvider('remix-solidity', new RemixReferenceProvider(props, monaco)) monacoRef.current.languages.registerReferenceProvider('remix-solidity', new RemixReferenceProvider(props, monaco))
monacoRef.current.languages.registerHoverProvider('remix-solidity', new RemixHoverProvider(props, monaco)) monacoRef.current.languages.registerHoverProvider('remix-solidity', new RemixHoverProvider(props, monaco))
monacoRef.current.languages.registerCompletionItemProvider('remix-solidity', new RemixCompletionProvider(props, monaco)) monacoRef.current.languages.registerCompletionItemProvider('remix-solidity', new RemixCompletionProvider(props, monaco))
monacoRef.current.languages.registerInlineCompletionsProvider('remix-solidity', new RemixInLineCompletionProvider(props, monaco)) monacoRef.current.languages.registerInlineCompletionsProvider('remix-solidity', inlineCompletionProvider)
monaco.languages.registerCodeActionProvider('remix-solidity', new RemixCodeActionProvider(props, monaco)) monaco.languages.registerCodeActionProvider('remix-solidity', new RemixCodeActionProvider(props, monaco))
loadTypes(monacoRef.current) loadTypes(monacoRef.current)

@ -29,7 +29,7 @@ export const CustomToggle = React.forwardRef(
className={className.replace('dropdown-toggle', '')} className={className.replace('dropdown-toggle', '')}
> >
<div className="d-flex"> <div className="d-flex">
<div className="mr-auto text-nowrap overflow-hidden">{children}</div> <div className="mr-auto text-nowrap text-truncate overflow-hidden">{children}</div>
{icon && ( {icon && (
<div className="pr-1"> <div className="pr-1">
<i className={`${icon} pr-1`}></i> <i className={`${icon} pr-1`}></i>

@ -12,7 +12,7 @@ function HomeTabFeatured() {
const themeFilter = useContext(ThemeContext) const themeFilter = useContext(ThemeContext)
return ( return (
<div className="pt-1 pl-2 h-100" id="hTFeaturedeSection"> <div className="pt-1 pl-2" id="hTFeaturedeSection">
<div className="mb-2 remix_ui-carousel-container"> <div className="mb-2 remix_ui-carousel-container">
<div className="w-100 d-flex flex-column rounded-3 remix_ui-carouselbox"> <div className="w-100 d-flex flex-column rounded-3 remix_ui-carouselbox">
<ThemeContext.Provider value={themeFilter}> <ThemeContext.Provider value={themeFilter}>

@ -77,6 +77,10 @@
background: var(--custom-select); background: var(--custom-select);
} }
.branches-dropdown {
max-width: 16rem;
}
.custom-dropdown-items a { .custom-dropdown-items a {
border-radius: .25rem; border-radius: .25rem;
text-transform: none; text-transform: none;

@ -1345,102 +1345,119 @@ export function Workspace() {
</div> </div>
</div> </div>
</div> </div>
{selectedWorkspace && ( { selectedWorkspace && (
<div className={`bg-light border-top ${selectedWorkspace.isGitRepo && currentBranch ? 'd-block' : 'd-none'}`} data-id="workspaceGitPanel"> <div className={`bg-light border-top ${selectedWorkspace.isGitRepo && currentBranch ? 'd-block' : 'd-none'}`} data-id="workspaceGitPanel">
<div className="d-flex justify-space-between p-1"> <div className="d-flex justify-content-between p-1">
<div className="mr-auto text-uppercase text-dark pt-2 px-1">GIT</div> <div className="text-uppercase text-dark pt-1 px-1">GIT</div>
{selectedWorkspace.hasGitSubmodules? { selectedWorkspace.hasGitSubmodules?
<div className="pt-1 mr-1"> <CustomTooltip
{global.fs.browser.isRequestingCloning ? <div style={{ height: 30, minWidth: 165 }} className='btn btn-sm border text-muted small'><i className="fad fa-spinner fa-spin"></i> updating submodules</div> : placement="top"
<div style={{ height: 30, minWidth: 165 }} onClick={updateSubModules} data-id='updatesubmodules' className={`btn btn-sm border small ${highlightUpdateSubmodules ? 'text-warning' : 'text-muted'}`}>update submodules</div>} tooltipId="updateSubmodules"
</div> tooltipClasses="text-nowrap"
: null} tooltipText={<FormattedMessage id="filePanel.updateSubmodules" />}
<div className="pt-1 mr-1" data-id="workspaceGitBranchesDropdown"> >
<Dropdown style={{ height: 30, minWidth: 80 }} onToggle={toggleBranches} show={showBranches} drop={'up'}> <div className="pr-1">
<Dropdown.Toggle { global.fs.browser.isRequestingCloning ? <button style={{ height: 30, minWidth: "9rem" }} className='btn btn-sm border text-dark'>
as={CustomToggle} <i className="fad fa-spinner fa-spin"></i>
id="dropdown-custom-components" Updating submodules
className="btn btn-light btn-block w-100 d-inline-block border border-dark form-control h-100 p-0 pl-2 pr-2 text-dark" </button> :
icon={null} <button style={{ height: 30, minWidth: "9rem" }} onClick={updateSubModules} data-id='updatesubmodules' className={`btn btn-sm border ${highlightUpdateSubmodules ? 'text-warning' : 'text-dark'}`}>
> Update submodules
{global.fs.browser.isRequestingCloning ? <i className="fad fa-spinner fa-spin"></i> : (currentBranch && currentBranch.name) || '-none-'} </button> }
</Dropdown.Toggle> </div>
</CustomTooltip>
<Dropdown.Menu as={CustomMenu} className="custom-dropdown-items branches-dropdown"> : null
<div data-id="custom-dropdown-menu"> }
<div className="d-flex text-dark" style={{ fontSize: 14, fontWeight: 'bold' }}> <CustomTooltip
<span className="mt-2 ml-2 mr-auto"> placement="right"
<FormattedMessage id="filePanel.switchBranches" /> tooltipId="branchesDropdown"
</span> tooltipClasses="text-nowrap"
<div tooltipText={'Current branch: ' + currentBranch || 'Branches'}
className="pt-2 pr-2" >
onClick={() => { <div className="pt-0 mr-2" data-id="workspaceGitBranchesDropdown">
toggleBranches(false) <Dropdown style={{ height: 30, maxWidth: "6rem", minWidth: "6rem" }} onToggle={toggleBranches} show={showBranches} drop={'up'}>
}} <Dropdown.Toggle
> as={CustomToggle}
<i className="fa fa-close"></i> id="dropdown-custom-components"
className="btn btn-sm btn-light d-inline-block border border-dark form-control h-100 p-0 pl-2 pr-2 text-dark"
icon={null}
>
{global.fs.browser.isRequestingCloning ? <i className="fad fa-spinner fa-spin"></i> : currentBranch.name || '-none-'}
</Dropdown.Toggle>
<Dropdown.Menu as={CustomMenu} className="custom-dropdown-items branches-dropdown">
<div data-id="custom-dropdown-menu">
<div className="d-flex text-dark" style={{ fontSize: 14, fontWeight: 'bold' }}>
<span className="mt-2 ml-2 mr-auto">
<FormattedMessage id="filePanel.switchBranches" />
</span>
<div
className="pt-2 pr-2"
onClick={() => {
toggleBranches(false)
}}
>
<i className="fa fa-close"></i>
</div>
</div> </div>
</div> <div className="border-top py-2">
<div className="border-top py-2"> <input
<input className="form-control border checkout-input bg-light"
className="form-control border checkout-input bg-light" placeholder={intl.formatMessage({
placeholder={intl.formatMessage({ id: 'filePanel.findOrCreateABranch'
id: 'filePanel.findOrCreateABranch' })}
})} style={{ minWidth: 225 }}
style={{ minWidth: 225 }} onChange={handleBranchFilterChange}
onChange={handleBranchFilterChange} data-id="workspaceGitInput"
data-id="workspaceGitInput" />
/> </div>
</div> <div className="border-top" style={{ maxHeight: 120, overflowY: 'scroll' }} data-id="custom-dropdown-items">
<div className="border-top" style={{ maxHeight: 120, overflowY: 'scroll' }} data-id="custom-dropdown-items"> {filteredBranches.length > 0 ? (
{filteredBranches.length > 0 ? ( filteredBranches.map((branch, index) => {
filteredBranches.map((branch, index) => { return (
return ( <Dropdown.Item
<Dropdown.Item key={index}
key={index} onClick={() => {
onClick={() => { switchToBranch(branch)
switchToBranch(branch) }}
}} title={intl.formatMessage({ id: `filePanel.switchToBranch${branch.remote ? 'Title1' : 'Title2'}` })}
title={intl.formatMessage({ id: `filePanel.switchToBranch${branch.remote ? 'Title1' : 'Title2'}` })} >
> <div data-id={`workspaceGit-${branch.remote ? `${branch.remote}/${branch.name}` : branch.name}`}>
<div data-id={`workspaceGit-${branch.remote ? `${branch.remote.name}/${branch.name}` : branch.name}`}> {currentBranch.name === branch.name && !branch.remote ? (
{currentBranch && currentBranch.name === branch.name && !branch.remote ? ( <span>
<span> &#10003; <i className="far fa-code-branch"></i>
&#10003; <i className="far fa-code-branch"></i> <span className="pl-1">{branch.name}</span>
<span className="pl-1">{branch.name}</span> </span>
</span> ) : (
) : ( <span className="pl-3">
<span className="pl-3"> <i className={`far ${branch.remote ? 'fa-cloud' : 'fa-code-branch'}`}></i>
<i className={`far ${branch.remote ? 'fa-cloud' : 'fa-code-branch'}`}></i> <span className="pl-1">{branch.remote ? `${branch.remote}/${branch.name}` : branch.name}</span>
<span className="pl-1">{branch.remote ? `${branch.remote.name}/${branch.name}` : branch.name}</span> </span>
</span> )}
)} </div>
</div> </Dropdown.Item>
</Dropdown.Item> )
) })
}) ) : (
) : ( <Dropdown.Item onClick={switchToNewBranch}>
<Dropdown.Item onClick={switchToNewBranch}> <div className="pl-1 pr-1" data-id="workspaceGitCreateNewBranch">
<div className="pl-1 pr-1" data-id="workspaceGitCreateNewBranch"> <i className="fas fa-code-branch pr-2"></i>
<i className="fas fa-code-branch pr-2"></i> <span>
<span> <FormattedMessage id="filePanel.createBranch" />: {branchFilter} from '{currentBranch.name}'
<FormattedMessage id="filePanel.createBranch" />: {branchFilter} from '{currentBranch && currentBranch.name}' </span>
</span> </div>
</div> </Dropdown.Item>
</Dropdown.Item> )}
</div>
{(selectedWorkspace.branches || []).length > 4 && (
<button className="btn btn-sm w-100" style={{ cursor: "pointer" }} onClick={showAllBranches}>
<FormattedMessage id="filePanel.viewAllBranches" />
</button>
)} )}
</div> </div>
{(selectedWorkspace.branches || []).length > 4 && ( </Dropdown.Menu>
<div className="text-center border-top pt-2"> </Dropdown>
<label style={{ fontSize: 12, cursor: 'pointer' }} onClick={showAllBranches}> </div>
<FormattedMessage id="filePanel.viewAllBranches" /> </CustomTooltip>
</label>
</div>
)}
</div>
</Dropdown.Menu>
</Dropdown>
</div>
</div> </div>
</div> </div>
)} )}

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-url-resolver", "name": "@remix-project/remix-url-resolver",
"version": "0.0.79", "version": "0.0.81",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986" "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remix-ws-templates", "name": "@remix-project/remix-ws-templates",
"version": "1.0.44", "version": "1.0.46",
"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": "326585ffcef3a8846f2a1badf10beab1f73ee986" "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
} }

@ -1,6 +1,6 @@
{ {
"name": "@remix-project/remixd", "name": "@remix-project/remixd",
"version": "0.6.33", "version": "0.6.34",
"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",
@ -27,11 +27,11 @@
}, },
"homepage": "https://github.com/ethereum/remix-project#readme", "homepage": "https://github.com/ethereum/remix-project#readme",
"dependencies": { "dependencies": {
"@remix-project/remix-solidity": "^0.5.36",
"@remixproject/plugin": "0.3.33", "@remixproject/plugin": "0.3.33",
"@remixproject/plugin-api": "0.3.33", "@remixproject/plugin-api": "0.3.33",
"@remixproject/plugin-utils": "0.3.33", "@remixproject/plugin-utils": "0.3.33",
"@remixproject/plugin-ws": "0.3.33", "@remixproject/plugin-ws": "0.3.33",
"@remix-project/remix-solidity": "^0.5.36",
"axios": "1.6.0", "axios": "1.6.0",
"chokidar": "^2.1.8", "chokidar": "^2.1.8",
"commander": "^9.4.1", "commander": "^9.4.1",

Loading…
Cancel
Save