@@ -51,13 +83,13 @@ function StepDetailPage() {
{errorLoadingFile ? (
<>
-
{step.name}
+
{clonedStep.name}
{
dispatch({
type: 'remixide/displayFile',
- payload: step,
+ payload: clonedStep,
})
}}
>
@@ -68,13 +100,13 @@ function StepDetailPage() {
) : (
<>
- {step.name}
+ {clonedStep.name}
>
)}
- {step.markdown?.content}
+ {clonedStep.markdown?.content}
- {step.test?.content ? (
+ {clonedStep.test?.content ? (
<>
{errorLoadingFile ? (
@@ -83,7 +115,7 @@ function StepDetailPage() {
onClick={() => {
dispatch({
type: 'remixide/displayFile',
- payload: step,
+ payload: clonedStep,
})
}}
>
@@ -98,19 +130,19 @@ function StepDetailPage() {
onClick={() => {
dispatch({
type: 'remixide/testStep',
- payload: step,
+ payload: clonedStep,
})
}}
>
Check Answer
- {step.answer?.content && (
+ {clonedStep.answer?.content && (
{
dispatch({
type: 'remixide/showAnswer',
- payload: step,
+ payload: clonedStep,
})
}}
>
@@ -130,13 +162,13 @@ function StepDetailPage() {
>
Next
- {step.answer?.content && (
+ {clonedStep.answer?.content && (
{
dispatch({
type: 'remixide/showAnswer',
- payload: step,
+ payload: clonedStep,
})
}}
>
@@ -185,13 +217,13 @@ function StepDetailPage() {
) : (
<>
- {!errorLoadingFile && step.answer?.content && (
+ {!errorLoadingFile && clonedStep.answer?.content && (
{
dispatch({
type: 'remixide/showAnswer',
- payload: step,
+ payload: clonedStep,
})
}}
>
@@ -223,7 +255,7 @@ function StepDetailPage() {
)}
>
)}
- >
+
)
}
diff --git a/apps/learneth/src/redux/models/remixide.ts b/apps/learneth/src/redux/models/remixide.ts
index c16fd163e0..fe7491f650 100644
--- a/apps/learneth/src/redux/models/remixide.ts
+++ b/apps/learneth/src/redux/models/remixide.ts
@@ -84,7 +84,6 @@ const Model: ModelType = {
const { detail, selectedId } = yield select((state) => state.workshop)
const workshop = detail[selectedId]
- console.log('loading ', step, workshop)
path = `.learneth/${workshop.name}/${step.name}/${path}`
try {
@@ -138,14 +137,11 @@ const Model: ModelType = {
yield remixClient.call('fileManager', 'switchFile', `${path}`)
}
- console.log('testing ', step.test.content)
-
path = getFilePath(step.test.file)
path = `.learneth/${workshop.name}/${step.name}/${path}`
yield remixClient.call('fileManager', 'setFile', path, step.test.content)
const result = yield remixClient.call('solidityUnitTesting', 'testFromPath', path)
- console.log('result ', result);
if (!result) {
yield put({
@@ -196,7 +192,6 @@ const Model: ModelType = {
toast.info('loading answer into IDE')
try {
- console.log('loading ', step)
const content = step.answer.content
let path = getFilePath(step.answer.file)
diff --git a/apps/learneth/src/redux/models/workshop.ts b/apps/learneth/src/redux/models/workshop.ts
index 087d1e89e0..635503c657 100644
--- a/apps/learneth/src/redux/models/workshop.ts
+++ b/apps/learneth/src/redux/models/workshop.ts
@@ -23,7 +23,7 @@ const Model: ModelType = {
},
effects: {
*init(_, { put }) {
- const cache = localStorage.getItem('workshop.state')
+ const cache = null // don't use cache because remote might change
if (cache) {
const workshopState = JSON.parse(cache)
@@ -54,7 +54,6 @@ const Model: ModelType = {
const { list, detail } = yield select((state) => state.workshop)
const url = `${apiUrl}/clone/${encodeURIComponent(payload.name)}/${payload.branch}?${Math.random()}`
- console.log('loading ', url)
const { data } = yield axios.get(url)
const repoId = `${payload.name}-${payload.branch}`
@@ -90,7 +89,7 @@ const Model: ModelType = {
const key = stepKeysWithFile[k]
if (step[key]) {
try {
- step[key].content = (yield remixClient.call('contentImport', 'resolve', step[key].file)).content
+ step[key].content = null // we load this later
} catch (error) {
console.error(error)
}
diff --git a/apps/learneth/src/remix-client.ts b/apps/learneth/src/remix-client.ts
index 8ee04dce2a..4742970649 100644
--- a/apps/learneth/src/remix-client.ts
+++ b/apps/learneth/src/remix-client.ts
@@ -10,7 +10,6 @@ class RemixClient extends PluginClient {
}
startTutorial(name: any, branch: any, id: any): void {
- console.log('start tutorial', name, branch, id)
void router.navigate('/home')
store.dispatch({
type: 'workshop/loadRepo',
@@ -23,7 +22,6 @@ class RemixClient extends PluginClient {
}
addRepository(name: any, branch: any) {
- console.log('add repo', name, branch)
void router.navigate('/home')
store.dispatch({
type: 'workshop/loadRepo',
diff --git a/apps/remix-ide-e2e/src/commands/hideMetaMaskPopup.ts b/apps/remix-ide-e2e/src/commands/hideMetaMaskPopup.ts
new file mode 100644
index 0000000000..234a3a08cd
--- /dev/null
+++ b/apps/remix-ide-e2e/src/commands/hideMetaMaskPopup.ts
@@ -0,0 +1,34 @@
+import { NightwatchBrowser } from 'nightwatch'
+import EventEmitter from 'events'
+
+class HideMetaMaskPopup extends EventEmitter {
+ command(this: NightwatchBrowser) {
+ browser
+ .pause(5000)
+ .isVisible({
+ selector: 'button[data-testid="popover-close"]',
+ locateStrategy: 'css selector',
+ suppressNotFoundErrors: true,
+ timeout: 2000
+ }, (okVisible) => {
+ console.log('okVisible', okVisible)
+ if (!okVisible.value) {
+ console.log('popover not found')
+ } else {
+ console.log('popover found... closing')
+ browser.click('button[data-testid="popover-close"]')
+ }
+ })
+ .waitForElementNotPresent({
+ selector: 'button[data-testid="popover-close"]',
+ locateStrategy: 'css selector',
+ timeout: 2000
+ })
+ .perform((done) => {
+ done()
+ this.emit('complete')
+ })
+ }
+}
+
+module.exports = HideMetaMaskPopup
diff --git a/apps/remix-ide-e2e/src/commands/pinGrid.ts b/apps/remix-ide-e2e/src/commands/pinGrid.ts
new file mode 100644
index 0000000000..6c82922960
--- /dev/null
+++ b/apps/remix-ide-e2e/src/commands/pinGrid.ts
@@ -0,0 +1,20 @@
+import { NightwatchBrowser } from 'nightwatch'
+import EventEmitter from 'events'
+
+class pinGrid extends EventEmitter {
+ command (this: NightwatchBrowser, provider: string, status: boolean): NightwatchBrowser {
+ this.api.useCss().waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
+ .click('[data-id="settingsSelectEnvOptions"] button')
+ .waitForElementVisible(`[data-id="dropdown-item-another-chain"]`)
+ .click(`[data-id="dropdown-item-another-chain"]`)
+ .waitForElementVisible(`[data-id="${provider}-${status ? 'unpinned' : 'pinned'}"]`)
+ .click(`[data-id="${provider}-${status ? 'unpinned' : 'pinned'}"]`)
+ .perform((done) => {
+ done()
+ this.emit('complete')
+ })
+ return this
+ }
+}
+
+module.exports = pinGrid
diff --git a/apps/remix-ide-e2e/src/commands/selectFiles.ts b/apps/remix-ide-e2e/src/commands/selectFiles.ts
index d24ec1e42b..544f36ba3d 100644
--- a/apps/remix-ide-e2e/src/commands/selectFiles.ts
+++ b/apps/remix-ide-e2e/src/commands/selectFiles.ts
@@ -8,15 +8,14 @@ class SelectFiles extends EventEmitter {
browser.perform(function () {
const actions = this.actions({ async: true })
actions.keyDown(this.Keys.SHIFT)
- for(let i = 0; i < selectedElements.length; i++) {
+ for (let i = 0; i < selectedElements.length; i++) {
actions.click(selectedElements[i].value)
}
- return actions.contextClick(selectedElements[0].value)
+ return actions//.contextClick(selectedElements[0].value)
})
this.emit('complete')
return this
}
}
-
module.exports = SelectFiles
diff --git a/apps/remix-ide-e2e/src/commands/setupMetamask.ts b/apps/remix-ide-e2e/src/commands/setupMetamask.ts
index 768b9631bb..585473827c 100644
--- a/apps/remix-ide-e2e/src/commands/setupMetamask.ts
+++ b/apps/remix-ide-e2e/src/commands/setupMetamask.ts
@@ -16,6 +16,7 @@ class MetaMask extends EventEmitter {
function setupMetaMask(browser: NightwatchBrowser, passphrase: string, password: string, done: VoidFunction) {
const words = passphrase.split(' ')
+ console.log('setup metamask')
browser
.switchBrowserTab(1)
.waitForElementVisible('input[data-testid="onboarding-terms-checkbox"]')
@@ -49,6 +50,7 @@ function setupMetaMask(browser: NightwatchBrowser, passphrase: string, password:
.click('button[data-testid="pin-extension-next"]')
.waitForElementVisible('button[data-testid="pin-extension-done"]')
.click('button[data-testid="pin-extension-done"]')
+ .pause(5000)
.isVisible({
selector: 'button[data-testid="popover-close"]',
locateStrategy: 'css selector',
@@ -58,14 +60,22 @@ function setupMetaMask(browser: NightwatchBrowser, passphrase: string, password:
console.log('okVisible', okVisible)
if (!okVisible.value) {
console.log('popover not found')
- }else{
+ } else {
+ console.log('popover found... closing')
browser.click('button[data-testid="popover-close"]')
}
})
+ .waitForElementNotPresent({
+ selector: 'button[data-testid="popover-close"]',
+ locateStrategy: 'css selector',
+ timeout: 3000
+ })
+ .saveScreenshot('./reports/screenshots/metamask.png')
.click('[data-testid="network-display"]')
.click('.mm-modal-content label.toggle-button--off') // show test networks
.click('div[data-testid="Sepolia"]') // switch to sepolia
.perform(() => {
+ console.log('MetaMask setup complete')
done()
})
}
diff --git a/apps/remix-ide-e2e/src/githttpbackend/setup.sh b/apps/remix-ide-e2e/src/githttpbackend/setup.sh
index 5d2644ddb1..496428301f 100755
--- a/apps/remix-ide-e2e/src/githttpbackend/setup.sh
+++ b/apps/remix-ide-e2e/src/githttpbackend/setup.sh
@@ -1,7 +1,9 @@
cd /tmp/
rm -rf git/bare.git
+rm -rf git/bare2.git
rm -rf git
mkdir -p git
cd git
git clone --bare https://github.com/ethereum/awesome-remix bare.git
+git clone --bare https://github.com/ethereum/awesome-remix bare2.git
diff --git a/apps/remix-ide-e2e/src/tests/ballot.test.ts b/apps/remix-ide-e2e/src/tests/ballot.test.ts
index dbdef20903..c9fb7c27bc 100644
--- a/apps/remix-ide-e2e/src/tests/ballot.test.ts
+++ b/apps/remix-ide-e2e/src/tests/ballot.test.ts
@@ -97,12 +97,12 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-remixDefault"]')
+ .scrollAndClick('*[data-id="create-remixDefault"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_remix_default' })
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_remix_default')
+ .modalFooterOKClick('TemplatesSelection')
.pause(1000)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.addFile('contracts/lib/storage/src/Storage.sol', { content: storageContract})
diff --git a/apps/remix-ide-e2e/src/tests/circom.test.ts b/apps/remix-ide-e2e/src/tests/circom.test.ts
index 2f64844faa..ac14415ea9 100644
--- a/apps/remix-ide-e2e/src/tests/circom.test.ts
+++ b/apps/remix-ide-e2e/src/tests/circom.test.ts
@@ -13,13 +13,9 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
- .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=semaphore]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
- .pause(100)
+ .waitForElementPresent('*[data-id="create-semaphore"]')
+ .scrollAndClick('*[data-id="create-semaphore"]')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/semaphore.circom"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]')
@@ -155,12 +151,9 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
- .waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=hashchecker]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .waitForElementPresent('*[data-id="create-hashchecker"]')
+ .scrollAndClick('*[data-id="create-hashchecker"]')
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/calculate_hash.circom"]')
@@ -190,8 +183,8 @@ module.exports = {
.journalLastChildIncludes('newZkey')
.pause(25000)
.journalLastChildIncludes('setup done.')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/groth16/verification_key.json"]')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/groth16/zkey_final.txt"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/zk/keys/verification_key.json"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/zk/keys/zkey_final.txt"]')
},
'Should run groth16 zkproof script for hash checker #group5': function (browser: NightwatchBrowser) {
browser
@@ -210,8 +203,8 @@ module.exports = {
.journalLastChildIncludes('WITNESS CHECKING FINISHED SUCCESSFULLY')
.pause(2000)
.journalLastChildIncludes('zk proof validity')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/groth16/zk_verifier.sol"]')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/groth16/input.json"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/zk/build/zk_verifier.sol"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/zk/build/input.json"]')
},
'Should run plonk trusted setup script for hash checker #group6': function (browser: NightwatchBrowser) {
browser
@@ -228,8 +221,8 @@ module.exports = {
.journalLastChildIncludes('plonk setup')
.pause(10000)
.journalLastChildIncludes('setup done')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/plonk/verification_key.json"]')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/keys/plonk/zkey_final.txt"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/keys/verification_key.json"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/keys/zkey_final.txt"]')
},
'Should run plonk zkproof script for hash checker #group6': function (browser: NightwatchBrowser) {
browser
@@ -246,8 +239,8 @@ module.exports = {
.pause(5000)
.journalLastChildIncludes('zk proof validity')
.journalLastChildIncludes('proof done.')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/plonk/zk_verifier.sol"]')
- .waitForElementVisible('*[data-id="treeViewLitreeViewItemzk/build/plonk/input.json"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/build/zk_verifier.sol"]')
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/build/input.json"]')
}
}
diff --git a/apps/remix-ide-e2e/src/tests/dgit_github.test.ts b/apps/remix-ide-e2e/src/tests/dgit_github.test.ts
index 6c8f8cfa08..da38485359 100644
--- a/apps/remix-ide-e2e/src/tests/dgit_github.test.ts
+++ b/apps/remix-ide-e2e/src/tests/dgit_github.test.ts
@@ -101,8 +101,8 @@ module.exports = {
.click('*[data-id="remotes-panel"]')
.waitForElementVisible('*[data-id="remotes-panel-content"]')
- .click({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin"]',
+ .waitForElementVisible({
+ selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin-default"]',
locateStrategy: 'xpath'
})
.waitForElementVisible({
@@ -115,7 +115,8 @@ module.exports = {
})
.waitForElementVisible({
selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]',
- locateStrategy: 'xpath'
+ locateStrategy: 'xpath',
+ timeout: 10000
})
},
@@ -136,24 +137,24 @@ module.exports = {
},
'switch to branch links #group1': function (browser: NightwatchBrowser) {
browser
+ .click('*[data-id="branches-panel"]')
.waitForElementVisible({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-branch-links"]',
+ selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-branch-links"]',
locateStrategy: 'xpath'
})
.click({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-toggle-branch-links"]',
+ selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-branch-links"]',
locateStrategy: 'xpath'
})
.waitForElementVisible({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="branches-toggle-current-branch-links"]',
+ selector: '//*[@data-id="branches-panel-content-remote-branches"]//*[@data-id="branches-toggle-current-branch-links"]',
locateStrategy: 'xpath'
})
},
'check the local branches #group1': function (browser: NightwatchBrowser) {
browser
- .click('*[data-id="branches-panel"]')
.waitForElementVisible({
- selector: '//*[@data-id="branches-panel-content"]//*[@data-id="branches-toggle-current-branch-links"]',
+ selector: '//*[@data-id="branches-panel-content-local-branches"]//*[@data-id="branches-toggle-current-branch-links"]',
locateStrategy: 'xpath'
})
},
@@ -232,7 +233,7 @@ module.exports = {
locateStrategy: 'xpath'
})
.waitForElementVisible({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote"]',
+ selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]',
locateStrategy: 'xpath'
})
},
@@ -263,7 +264,7 @@ module.exports = {
}
})
},
- 'remove the remove #group2': function (browser: NightwatchBrowser) {
+ 'remove the remote #group2': function (browser: NightwatchBrowser) {
browser
.pause(1000)
.click('*[data-id="remotes-panel"]')
@@ -278,7 +279,7 @@ module.exports = {
})
.pause(1000)
.waitForElementNotPresent({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote"]',
+ selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-newremote-default"]',
locateStrategy: 'xpath'
})
},
diff --git a/apps/remix-ide-e2e/src/tests/dgit_local.test.ts b/apps/remix-ide-e2e/src/tests/dgit_local.test.ts
index 86d766a753..fc0ec93f98 100644
--- a/apps/remix-ide-e2e/src/tests/dgit_local.test.ts
+++ b/apps/remix-ide-e2e/src/tests/dgit_local.test.ts
@@ -24,14 +24,14 @@ module.exports = {
})
},
- 'run server #group1 #group2 #group3': function (browser: NightwatchBrowser) {
+ 'run server #group1 #group2 #group3 #group4': function (browser: NightwatchBrowser) {
browser.perform(async (done) => {
gitserver = await spawnGitServer('/tmp/')
console.log('working directory', process.cwd())
done()
})
},
- 'Update settings for git #group1 #group2 #group3': function (browser: NightwatchBrowser) {
+ 'Update settings for git #group1 #group2 #group3 #group4': function (browser: NightwatchBrowser) {
browser.
clickLaunchIcon('dgit')
.waitForElementVisible('*[data-id="initgit-btn"]')
@@ -42,7 +42,7 @@ module.exports = {
.modalFooterOKClick('github-credentials-error')
.pause(2000)
},
- 'clone a repo #group1 #group2 #group3': function (browser: NightwatchBrowser) {
+ 'clone a repo #group1 #group2 #group3 #group4': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="clone-panel"]')
.click('*[data-id="clone-panel"]')
@@ -56,10 +56,11 @@ module.exports = {
// GROUP 1
- 'check file added #group1 #group3': function (browser: NightwatchBrowser) {
+ 'check file added #group1 #group3 #group4': function (browser: NightwatchBrowser) {
browser.
addFile('test.txt', { content: 'hello world' }, 'README.md')
.clickLaunchIcon('dgit')
+ .pause(3000)
.click('*[data-id="sourcecontrol-panel"]')
.waitForElementVisible({
selector: "//*[@data-status='new-untracked' and @data-file='/test.txt']",
@@ -75,7 +76,7 @@ module.exports = {
.setValue('*[data-id="commitMessage"]', 'testcommit')
.click('*[data-id="commitButton"]')
},
- 'look at the commit #group1': function (browser: NightwatchBrowser) {
+ 'look at the commit #group1 #group4': function (browser: NightwatchBrowser) {
browser
.click('*[data-id="commits-panel"]')
.waitForElementPresent({
@@ -187,6 +188,7 @@ module.exports = {
'stage renamed file #group3': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('dgit')
+ .pause(3000)
.waitForElementVisible({
selector: "//*[@data-status='deleted-unstaged' and @data-file='/test.txt']",
locateStrategy: 'xpath'
@@ -228,6 +230,7 @@ module.exports = {
'create a branch #group2': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('dgit')
+ .pause(3000)
.click('*[data-id="branches-panel"]')
.waitForElementVisible('*[data-id="newbranchname"]')
.setValue('*[data-id="newbranchname"]', 'testbranch')
@@ -244,6 +247,7 @@ module.exports = {
'publish the branch #group2': function (browser: NightwatchBrowser) {
browser
.clickLaunchIcon('dgit')
+ .pause(3000)
.waitForElementVisible('*[data-id="sourcecontrol-panel"]')
.click('*[data-id="sourcecontrol-panel"]')
.pause(1000)
@@ -321,9 +325,97 @@ module.exports = {
},
'check if test file is gone #group2': function (browser: NightwatchBrowser) {
browser
+ .pause()
.clickLaunchIcon('filePanel')
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.txt"]')
- }
+ },
+ 'add second remote #group4': function (browser: NightwatchBrowser) {
+ browser
+ .pause(1000)
+ .click('*[data-id="remotes-panel"]')
+ .waitForElementVisible('*[data-id="add-manual-remoteurl"]')
+ .setValue('*[data-id="add-manual-remoteurl"]', 'http://localhost:6868/bare2.git')
+ .waitForElementVisible('*[data-id="add-manual-remotename"]')
+ .setValue('*[data-id="add-manual-remotename"]', 'origin2')
+ .waitForElementVisible('*[data-id="add-manual-remotebtn"]')
+ .click('*[data-id="add-manual-remotebtn"]')
+ },
+ 'check the buttons #group4': function (browser: NightwatchBrowser) {
+ browser
+ .waitForElementVisible('*[data-id="default-remote-check-origin"]')
+ .waitForElementVisible('*[data-id="set-as-default-origin2"]')
+ },
+ 'check the commands #group4': function (browser: NightwatchBrowser) {
+ browser
+ .click('*[data-id="commands-panel"]')
+ .waitForElementVisible({
+ selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]",
+ locateStrategy: 'xpath'
+ })
+ },
+ 'switch to origin2 #group4': function (browser: NightwatchBrowser) {
+ browser
+ .click('*[data-id="remotes-panel"]')
+ .waitForElementVisible('*[data-id="set-as-default-origin2"]')
+ .click('*[data-id="set-as-default-origin2"]')
+ },
+ 'check the commands for origin2 #group4': function (browser: NightwatchBrowser) {
+ browser
+ .click('*[data-id="commands-panel"]')
+ .waitForElementVisible({
+ selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin2')]",
+ locateStrategy: 'xpath'
+ })
+ },
+ 'sync the commit #group4': function (browser: NightwatchBrowser) {
+ browser
+ .pause(1000)
+ .waitForElementVisible('*[data-id="sourcecontrol-panel"]')
+ .click('*[data-id="sourcecontrol-panel"]')
+ .waitForElementVisible('*[data-id="syncButton"]')
+ .click('*[data-id="syncButton"]')
+ .waitForElementVisible('*[data-id="commitButton"]')
+ .click('*[data-id="commits-panel"]')
+ .waitForElementPresent({
+ selector: '//*[@data-id="commit-summary-testcommit-"]',
+ locateStrategy: 'xpath'
+ })
+ },
+ 'check the log #group4': async function (browser: NightwatchBrowser) {
+ const logs = await getGitLog('/tmp/git/bare2.git')
+ console.log(logs)
+ browser.assert.ok(logs.includes('testcommit'))
+ const logs2 = await getGitLog('/tmp/git/bare.git')
+ console.log(logs2)
+ browser.assert.fail(logs2.includes('testcommit'))
+ },
+ 'switch to origin #group4': function (browser: NightwatchBrowser) {
+ browser
+ .click('*[data-id="remotes-panel"]')
+ .waitForElementVisible('*[data-id="set-as-default-origin"]')
+ .click('*[data-id="set-as-default-origin"]')
+ },
+ 'check the commands for origin #group4': function (browser: NightwatchBrowser) {
+ browser
+ .click('*[data-id="commands-panel"]')
+ .waitForElementVisible({
+ selector: "//div[@id='commands-remote-origin-select']//div[contains(@class, 'singleValue') and contains(text(), 'origin')]",
+ locateStrategy: 'xpath'
+ })
+ },
+ 'check the commit ahead #group4': function (browser: NightwatchBrowser) {
+ browser
+ .pause(1000)
+ .waitForElementVisible('*[data-id="sourcecontrol-panel"]')
+ .click('*[data-id="sourcecontrol-panel"]')
+ .waitForElementVisible('*[data-id="syncButton"]')
+ // do not sync
+ .click('*[data-id="commits-panel"]')
+ .waitForElementPresent({
+ selector: '//*[@data-id="commit-summary-testcommit-ahead"]',
+ locateStrategy: 'xpath'
+ })
+ },
}
async function getBranches(path: string): Promise
{
@@ -360,10 +452,10 @@ async function getGitLog(path: string): Promise {
})
}
-async function cloneOnServer(repo: string, path: string) {
+async function cloneOnServer(repo: string, path: string, name: string = 'bare') {
console.log('cloning', repo, path)
return new Promise((resolve, reject) => {
- const git = spawn('rm -rf bare && git', ['clone', repo], { cwd: path, shell: true, detached: true });
+ const git = spawn(`rm -rf ${name} && git`, ['clone', repo], { cwd: path, shell: true, detached: true });
git.stdout.on('data', function (data) {
console.log('stdout data cloning', data.toString());
diff --git a/apps/remix-ide-e2e/src/tests/erc721.test.ts b/apps/remix-ide-e2e/src/tests/erc721.test.ts
index 373477f064..890a5e7fc3 100644
--- a/apps/remix-ide-e2e/src/tests/erc721.test.ts
+++ b/apps/remix-ide-e2e/src/tests/erc721.test.ts
@@ -17,14 +17,12 @@ module.exports = {
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
// create contract
+ .waitForElementPresent('*[data-id="create-hashchecker"]')
+ .scrollAndClick('*[data-id="create-ozerc721"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc721' })
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc721]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_erc721')
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
diff --git a/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts b/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts
index 1d31d6a9b5..214217af38 100644
--- a/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts
+++ b/apps/remix-ide-e2e/src/tests/file_explorer_multiselect.test.ts
@@ -2,6 +2,7 @@ import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
+ "@disabled": true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
@@ -10,11 +11,11 @@ module.exports = {
const selectedElements = []
browser
.openFile('contracts')
- .click({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]', locateStrategy: 'xpath' })
- .findElement({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]', locateStrategy: 'xpath' }, (el) => {
+ .click({ selector: '//*[@data-id="treeViewDivtreeViewItemcontracts/1_Storage.sol"]', locateStrategy: 'xpath' })
+ .findElement({ selector: '//*[@data-id="treeViewDivtreeViewItemcontracts/2_Owner.sol"]', locateStrategy: 'xpath' }, (el) => {
selectedElements.push(el)
})
- browser.findElement({ selector: '//*[@data-id="treeViewLitreeViewItemtests"]', locateStrategy: 'xpath' },
+ browser.findElement({ selector: '//*[@data-id="treeViewDivtreeViewItemtests"]', locateStrategy: 'xpath' },
(el: any) => {
selectedElements.push(el)
})
@@ -22,6 +23,74 @@ module.exports = {
.assert.visible('.bg-secondary[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]')
.assert.visible('.bg-secondary[data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]')
.assert.visible('.bg-secondary[data-id="treeViewLitreeViewItemtests"]')
- .end()
+ },
+ 'Should drag and drop multiple files in file explorer to tests folder #group1': function (browser: NightwatchBrowser) {
+ const selectedElements = []
+ if (browser.options.desiredCapabilities?.browserName === 'firefox') {
+ console.log('Skipping test for firefox')
+ browser.end()
+ return;
+ } else {
+ browser
+ .click({ selector: '//*[@data-id="treeViewUltreeViewMenu"]', locateStrategy: 'xpath' })
+ .click({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]', locateStrategy: 'xpath' })
+ .findElement({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]', locateStrategy: 'xpath' }, (el) => {
+ selectedElements.push(el)
+ })
+ browser.selectFiles(selectedElements)
+ .perform((done) => {
+ browser.findElement({ selector: '//*[@data-id="treeViewLitreeViewItemtests"]', locateStrategy: 'xpath' },
+ (el: any) => {
+ const id = (el as any).value.getId()
+ browser
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemtests"]')
+ .dragAndDrop('li[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]', id)
+ .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
+ .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemtests/1_Storage.sol"]')
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemtests/2_Owner.sol"]')
+ .waitForElementNotPresent('li[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]')
+ .waitForElementNotPresent('li[data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]')
+ .perform(() => done())
+ })
+ })
+ }
+ },
+ 'should drag and drop multiple files and folders in file explorer to contracts folder #group3': function (browser: NightwatchBrowser) {
+ const selectedElements = []
+ if (browser.options.desiredCapabilities?.browserName === 'firefox') {
+ console.log('Skipping test for firefox')
+ browser.end()
+ return;
+ } else {
+ browser
+ .clickLaunchIcon('filePanel')
+ .click({ selector: '//*[@data-id="treeViewLitreeViewItemtests"]', locateStrategy: 'xpath' })
+ .findElement({ selector: '//*[@data-id="treeViewDivtreeViewItemscripts"]', locateStrategy: 'xpath' }, (el) => {
+ selectedElements.push(el)
+ })
+ browser.findElement({ selector: '//*[@data-id="treeViewDivtreeViewItemREADME.txt"]', locateStrategy: 'xpath' },
+ (el: any) => {
+ selectedElements.push(el)
+ })
+ browser.selectFiles(selectedElements)
+ .perform((done) => {
+ browser.findElement({ selector: '//*[@data-id="treeViewLitreeViewItemcontracts"]', locateStrategy: 'xpath' },
+ (el: any) => {
+ const id = (el as any).value.getId()
+ browser
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts"]')
+ .dragAndDrop('li[data-id="treeViewLitreeViewItemtests"]', id)
+ .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
+ .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/tests"]', 5000)
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/README.txt"]', 5000)
+ .waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/scripts"]', 5000)
+ .waitForElementNotPresent('li[data-id="treeViewLitreeViewItemtests"]')
+ .waitForElementNotPresent('li[data-id="treeViewLitreeViewItemREADME.txt"]')
+ .perform(() => done())
+ })
+ })
+ }
}
}
diff --git a/apps/remix-ide-e2e/src/tests/grid.test.ts b/apps/remix-ide-e2e/src/tests/grid.test.ts
new file mode 100644
index 0000000000..5da7379328
--- /dev/null
+++ b/apps/remix-ide-e2e/src/tests/grid.test.ts
@@ -0,0 +1,36 @@
+'use strict'
+import { NightwatchBrowser } from 'nightwatch'
+import init from '../helpers/init'
+
+module.exports = {
+ before: function (browser: NightwatchBrowser, done: VoidFunction) {
+ init(browser, done, 'http://127.0.0.1:8080?plugins=solidity,udapp', false)
+ },
+ 'pin chain': function (browser: NightwatchBrowser) {
+ browser
+ .clickLaunchIcon('udapp')
+ .pinGrid('vm-custom-fork', true)
+ .waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
+ .click('[data-id="settingsSelectEnvOptions"] button')
+ .waitForElementVisible(`[data-id="dropdown-item-vm-custom-fork"]`)
+ .click('[data-id="settingsSelectEnvOptions"] button') // close the dropdown
+ .pinGrid('vm-sepolia-fork', true)
+ .waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
+ .click('[data-id="settingsSelectEnvOptions"] button')
+ .waitForElementVisible(`[data-id="dropdown-item-vm-sepolia-fork"]`)
+ .click('[data-id="settingsSelectEnvOptions"] button') // close the dropdown
+ },
+ 'unpin chain': function (browser: NightwatchBrowser) {
+ browser
+ .pinGrid('vm-custom-fork', false)
+ .waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
+ .click('[data-id="settingsSelectEnvOptions"] button')
+ .waitForElementNotPresent(`[data-id="dropdown-item-vm-custom-fork"]`)
+ .click('[data-id="settingsSelectEnvOptions"] button') // close the dropdown
+ .pinGrid('vm-sepolia-fork', false)
+ .waitForElementVisible('[data-id="settingsSelectEnvOptions"]')
+ .click('[data-id="settingsSelectEnvOptions"] button')
+ .waitForElementNotPresent(`[data-id="dropdown-item-vm-sepolia-fork"]`)
+ .click('[data-id="settingsSelectEnvOptions"] button') // close the dropdown
+ }
+}
\ No newline at end of file
diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts
index 20a252a729..446d5e4d13 100644
--- a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts
+++ b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts
@@ -11,7 +11,7 @@ const checkBrowserIsChrome = function (browser: NightwatchBrowser) {
return browser.browserName.indexOf('chrome') > -1
}
-const checkAlerts = function (browser: NightwatchBrowser){
+const checkAlerts = function (browser: NightwatchBrowser) {
browser.isVisible({
selector: '//*[contains(.,"not have enough")]',
locateStrategy: 'xpath',
@@ -38,7 +38,7 @@ const tests = {
'Should connect to Sepolia Test Network using MetaMask #group1': function (browser: NightwatchBrowser) {
if (!checkBrowserIsChrome(browser)) return
browser.waitForElementPresent('*[data-id="remixIdeSidePanel"]')
- .setupMetamask(passphrase, password)
+ .setupMetamask(passphrase, password)
.useCss().switchBrowserTab(0)
.refreshPage()
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
@@ -50,13 +50,14 @@ const tests = {
.pause(5000)
.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser
+ .hideMetaMaskPopup()
.waitForElementVisible('*[data-testid="page-container-footer-next"]', 60000)
.click('*[data-testid="page-container-footer-next"]') // this connects the metamask account to remix
.pause(2000)
.waitForElementVisible('*[data-testid="page-container-footer-next"]', 60000)
.click('*[data-testid="page-container-footer-next"]')
- // .waitForElementVisible('*[data-testid="popover-close"]')
- // .click('*[data-testid="popover-close"]')
+ // .waitForElementVisible('*[data-testid="popover-close"]')
+ // .click('*[data-testid="popover-close"]')
})
.switchBrowserTab(0) // back to remix
},
@@ -83,6 +84,7 @@ const tests = {
browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
checkAlerts(browser)
browser
+ .hideMetaMaskPopup()
.waitForElementPresent('[data-testid="page-container-footer-next"]')
.click('[data-testid="page-container-footer-next"]') // approve the tx
.switchBrowserTab(0) // back to remix
@@ -90,7 +92,7 @@ const tests = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000)
.perform(() => done())
})
- })
+ })
},
'Should run low level interaction (fallback function) on Sepolia Test Network using MetaMask #group1': function (browser: NightwatchBrowser) {
@@ -102,14 +104,15 @@ const tests = {
.perform((done) => {
browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser
+ .hideMetaMaskPopup()
.waitForElementPresent('[data-testid="page-container-footer-next"]')
.click('[data-testid="page-container-footer-next"]') // approve the tx
.switchBrowserTab(0) // back to remix
.waitForElementContainsText('*[data-id="terminalJournal"]', 'view on etherscan', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000)
.perform(() => done())
- })
- })
+ })
+ })
},
'Should connect to Ethereum Main Network using MetaMask #group1': function (browser: NightwatchBrowser) {
@@ -162,6 +165,8 @@ const tests = {
.perform((done) => {
browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser
+ .hideMetaMaskPopup()
+ .saveScreenshot('./reports/screenshots/metamask_4.png')
.waitForElementPresent('[data-testid="page-container-footer-next"]', 60000)
.click('[data-testid="page-container-footer-next"]') // approve the tx
.switchBrowserTab(0) // back to remix
@@ -169,7 +174,7 @@ const tests = {
.waitForElementContainsText('*[data-id="terminalJournal"]', 'from: 0x76a...2708f', 60000)
.perform(() => done())
})
- })
+ })
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)
.clearConsole()
.clickInstance(0)
@@ -177,6 +182,8 @@ const tests = {
.perform((done) => { // call delegate
browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => {
browser
+ .hideMetaMaskPopup()
+ .saveScreenshot('./reports/screenshots/metamask_5.png')
.waitForElementPresent('[data-testid="page-container-footer-next"]', 60000)
.click('[data-testid="page-container-footer-next"]') // approve the tx
.switchBrowserTab(0) // back to remix
@@ -199,11 +206,11 @@ const tests = {
*/
'Should debug Sepolia transaction with source highlighting MetaMask #group1': function (browser: NightwatchBrowser) {
if (!checkBrowserIsChrome(browser)) return
- let txhash
- browser.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
+ let txhash
+ browser.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('pluginManager') // load debugger and source verification
- // .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_sourcify"] button')
- // debugger already activated .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_debugger"] button')
+ // .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_sourcify"] button')
+ // debugger already activated .scrollAndClick('#pluginManager article[id="remixPluginManagerListItem_debugger"] button')
.clickLaunchIcon('udapp')
.perform((done) => {
browser.getLastTransactionHash((hash) => {
@@ -213,15 +220,17 @@ const tests = {
})
.perform((done) => {
browser
- .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
- .clickLaunchIcon('debugger')
- .setValue('*[data-id="debuggerTransactionInput"]', txhash) // debug tx
- .click('*[data-id="debuggerTransactionStartButton"]')
- .waitForElementVisible('*[data-id="treeViewDivto"]', 30000)
- .checkVariableDebug('soliditylocals', localsCheck)
- .perform(() => done())
+ .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
+ .clickLaunchIcon('debugger')
+ .setValue('*[data-id="debuggerTransactionInput"]', txhash) // debug tx
+ .saveScreenshot('./reports/screenshots/metamask_2.png')
+ .click('*[data-id="debuggerTransactionStartButton"]')
+ .saveScreenshot('./reports/screenshots/metamask_3.png')
+ .waitForElementVisible('*[data-id="treeViewDivto"]', 30000)
+ .checkVariableDebug('soliditylocals', localsCheck)
+ .perform(() => done())
})
-
+
},
'Call web3.eth.getAccounts() using Injected Provider (Metamask) #group1': function (browser: NightwatchBrowser) {
@@ -229,14 +238,14 @@ const tests = {
browser
.executeScriptInTerminal('web3.eth.getAccounts()')
.journalLastChildIncludes('["0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f"]')
- }
+ }
}
const branch = process.env.CIRCLE_BRANCH;
const isMasterBranch = branch === 'master';
module.exports = {
- ...(branch ? (isMasterBranch ? tests : {}) : tests),
+ ...{} //(branch ? (isMasterBranch ? tests : {}) : tests),
};
const localsCheck = {
@@ -250,7 +259,7 @@ const sources = [
{
'Greet.sol': {
content:
- `
+ `
pragma solidity ^0.8.0;
contract HelloWorld {
string public message;
diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
index c96f702339..91ef7d6a4f 100644
--- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
+++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
@@ -180,16 +180,17 @@ module.exports = {
// creating a new workspace
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-remixDefault"]')
+ .scrollAndClick('*[data-id="create-remixDefault"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .click('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]')
- .setValue('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_new')
+ .click('input[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('input[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_new')
.pause(2000)
- .getValue('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]', (result) => {
+ .getValue('input[data-id="modalDialogCustomPromptTextCreate"]', (result) => {
console.log(result)
browser.assert.equal(result.value, 'workspace_new')
})
- .waitForElementVisible('*[data-id="fileSystem-modal-footer-ok-react"]')
- .click('*[data-id="fileSystem-modal-footer-ok-react"]')
+ .modalFooterOKClick('TemplatesSelection')
.pause(3000)
.currentWorkspaceIs('workspace_new')
.waitForElementVisible('li[data-id="treeViewLitreeViewItem.deps/remix-tests/remix_tests.sol"]')
diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts
index e1335c856d..9d73831389 100644
--- a/apps/remix-ide-e2e/src/tests/terminal.test.ts
+++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts
@@ -313,6 +313,7 @@ module.exports = {
'Should connect to the sepolia fork and run web3.eth.getCode in the terminal #group9': function (browser: NightwatchBrowser) {
if (runMasterTests)
browser
+ .pinGrid('vm-custom-fork', true)
.switchEnvironment('vm-custom-fork')
.waitForElementVisible('[data-id="vm-custom-fork-modal-footer-ok-react"]')
.execute(() => {
diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts
index 316c239448..8a77f2e60c 100644
--- a/apps/remix-ide-e2e/src/tests/url.test.ts
+++ b/apps/remix-ide-e2e/src/tests/url.test.ts
@@ -336,5 +336,18 @@ module.exports = {
.waitForElementVisible('*[data-shared="tooltipPopup"]')
.waitForElementContainsText('*[data-shared="tooltipPopup"]', 'initiating fileManager and calling "open" ...')
.waitForElementContainsText('*[data-shared="tooltipPopup"]', 'initiating terminal and calling "log" ...')
+ },
+
+ 'Import Github folder from URL params #group4': function (browser: NightwatchBrowser) {
+ browser
+ .url('http://127.0.0.1:8080/#ghfolder=https://github.com/ethereum/remix-project/tree/master/apps/remix-ide/contracts/hardhat')
+ .refreshPage()
+ .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]', 40000)
+ .currentWorkspaceIs('code-sample')
+ .openFile('contracts')
+ .openFile('contracts/Lock.sol')
+ .getEditorValue((content) => {
+ browser.assert.ok(content.indexOf('contract Lock {') !== -1, 'content does contain "contract Lock {"')
+ })
}
}
diff --git a/apps/remix-ide-e2e/src/tests/workspace.test.ts b/apps/remix-ide-e2e/src/tests/workspace.test.ts
index d351b05ce1..094b35a080 100644
--- a/apps/remix-ide-e2e/src/tests/workspace.test.ts
+++ b/apps/remix-ide-e2e/src/tests/workspace.test.ts
@@ -38,12 +38,12 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-remixDefault"]')
+ .scrollAndClick('*[data-id="create-remixDefault"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_remix_default' })
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_remix_default')
+ .modalFooterOKClick('TemplatesSelection')
.pause(1000)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/1_Storage.sol"]')
@@ -110,14 +110,12 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-blank"]')
+ .scrollAndClick('*[data-id="create-blank"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_blank' })
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=blank]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_blank')
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementPresent('*[data-id="treeViewUltreeViewMenu"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.prettierrc.json"]')
@@ -133,14 +131,12 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-ozerc20"]')
+ .scrollAndClick('*[data-id="create-ozerc20"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc20' })
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc20]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_erc20')
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
@@ -194,14 +190,12 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-ozerc721"]')
+ .scrollAndClick('*[data-id="create-ozerc721"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc721' })
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc721]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_erc721')
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
@@ -255,14 +249,12 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-ozerc1155"]')
+ .scrollAndClick('*[data-id="create-ozerc1155"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_erc1155' })
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc1155]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_erc1155')
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
@@ -316,17 +308,10 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent(`*[data-id='create-ozerc1155{"upgradeable":"uups","mintable":true,"burnable":true,"pausable":true}']`)
+ .scrollAndClick(`*[data-id='create-ozerc1155{"upgradeable":"uups","mintable":true,"burnable":true,"pausable":true}']`)
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc1155]')
- .waitForElementPresent('*[data-id="ozCustomization"]')
- .click('*[data-id="featureTypeMintable"]')
- .click('*[data-id="featureTypeBurnable"]')
- .click('*[data-id="featureTypePausable"]')
- .click('*[data-id="upgradeTypeUups"]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
@@ -386,12 +371,10 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-hashchecker"]')
+ .scrollAndClick('*[data-id="create-hashchecker"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=hashchecker]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/calculate_hash.circom"]')
@@ -424,11 +407,12 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-remixDefault"]')
+ .scrollAndClick('*[data-id="create-remixDefault"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .click('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]')
- .setValue('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .click('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
+ .click('input[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('input[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.addFile('test.sol', { content: 'test' })
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest.sol"]')
@@ -438,11 +422,12 @@ module.exports = {
})
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-remixDefault"]')
+ .scrollAndClick('*[data-id="create-remixDefault"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .click('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]')
- .setValue('*[data-id="fileSystemModalDialogContainer-react"] input[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name_1')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .click('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
+ .click('input[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('input[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_name_1')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtests"]')
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItemtest.sol"]')
.switchWorkspace('workspace_name')
@@ -494,13 +479,12 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-ozerc1155"]')
+ .scrollAndClick('*[data-id="create-ozerc1155"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc1155]')
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'sometestworkspace' })
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'sometestworkspace')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.prettierrc.json"]')
@@ -521,14 +505,12 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-ozerc1155"]')
+ .scrollAndClick('*[data-id="create-ozerc1155"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc1155]')
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_db_test' })
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_db_test')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItem.prettierrc.json"]')
@@ -551,14 +533,12 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-uniswapV4HookBookMultiSigSwapHook"]')
+ .scrollAndClick('*[data-id="create-uniswapV4HookBookMultiSigSwapHook"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=uniswapV4HookBookMultiSigSwapHook]')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'multisig cookbook' })
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'multisig cookbook')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('[data-id="PermissionHandler-modal-footer-ok-react"]', 300000)
.click('[data-id="PermissionHandler-modal-footer-ok-react"]')
// click on lib to close it
diff --git a/apps/remix-ide-e2e/src/tests/workspace_git.test.ts b/apps/remix-ide-e2e/src/tests/workspace_git.test.ts
index e0fe581d9d..0661eb31ee 100644
--- a/apps/remix-ide-e2e/src/tests/workspace_git.test.ts
+++ b/apps/remix-ide-e2e/src/tests/workspace_git.test.ts
@@ -13,8 +13,9 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-remixDefault"]')
+ .scrollAndClick('*[data-id="create-remixDefault"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
.waitForElementVisible({
selector: "//*[@class='text-warning' and contains(.,'add username and email')]",
locateStrategy: 'xpath'
@@ -23,10 +24,10 @@ module.exports = {
selector: '//*[@data-id="initGitRepository"][@disabled]',
locateStrategy: 'xpath'
})
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_blank' })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_blank')
.click('[data-id="initGitRepositoryLabel"]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementNotPresent('*[data-id="treeViewLitreeViewItem.git"]')
@@ -47,15 +48,13 @@ module.exports = {
.waitForElementNotVisible('[data-id="workspaceGitPanel"]')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-blank"]')
+ .scrollAndClick('*[data-id="create-blank"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'workspace_blank' })
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=blank]')
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'workspace_blank')
.click('[data-id="initGitRepositoryLabel"]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('[data-id="workspaceGitPanel"]')
.waitForElementContainsText('[data-id="workspaceGitBranchesDropdown"]', 'main')
@@ -391,12 +390,10 @@ module.exports = {
browser
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-uniswapV4Template"]')
+ .scrollAndClick('*[data-id="create-uniswapV4Template"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=uniswapV4Template]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .modalFooterOKClick('TemplatesSelection')
.pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemsrc"]')
.openFile('src')
@@ -413,14 +410,12 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-ozerc20"]')
+ .scrollAndClick('*[data-id="create-ozerc20"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- // eslint-disable-next-line dot-notation
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=ozerc20]')
- .execute(function () { document.querySelector('*[data-id="modalDialogCustomPromptTextCreate"]')['value'] = 'new_workspace' })
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
+ .scrollAndClick('*[data-id="modalDialogCustomPromptTextCreate"]')
+ .setValue('*[data-id="modalDialogCustomPromptTextCreate"]', 'new_workspace')
+ .modalFooterOKClick('TemplatesSelection')
.waitForElementVisible('*[data-id="treeViewDivDraggableItemtests/MyToken_test.sol"]')
},
'Update settings for git #group5': function (browser: NightwatchBrowser) {
@@ -468,13 +463,11 @@ module.exports = {
.clickLaunchIcon('filePanel')
.click('*[data-id="workspacesMenuDropdown"]')
.click('*[data-id="workspacecreate"]')
+ .waitForElementPresent('*[data-id="create-uniswapV4Template"]')
+ .scrollAndClick('*[data-id="create-uniswapV4Template"]')
.waitForElementVisible('*[data-id="modalDialogCustomPromptTextCreate"]')
- .waitForElementVisible('[data-id="fileSystemModalDialogModalFooter-react"] > button')
- .click('select[id="wstemplate"]')
- .click('select[id="wstemplate"] option[value=uniswapV4Template]')
- .waitForElementPresent('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok')
- .execute(function () { (document.querySelector('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') as HTMLElement).click() })
- .pause(100)
+ .modalFooterOKClick('TemplatesSelection')
+ .pause(100)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemsrc"]')
.openFile('src')
.openFile('src/Counter.sol')
@@ -491,11 +484,11 @@ module.exports = {
.click('*[data-id="remotes-panel"]')
.waitForElementVisible('*[data-id="remotes-panel-content"]')
.click({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin"]',
+ selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin-default"]',
locateStrategy: 'xpath'
})
.waitForElementVisible({
- selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin" and contains(.,"v4-template")]',
+ selector: '//*[@data-id="remotes-panel-content"]//*[@data-id="remote-detail-origin-default" and contains(.,"v4-template")]',
locateStrategy: 'xpath'
})
},
diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts
index 33f14fb169..4a5b1831ee 100644
--- a/apps/remix-ide-e2e/src/types/index.d.ts
+++ b/apps/remix-ide-e2e/src/types/index.d.ts
@@ -48,6 +48,7 @@ declare module 'nightwatch' {
removeFile(path: string, workspace: string): NightwatchBrowser
switchBrowserWindow(url: string, windowName: string, cb: (browser: NightwatchBrowser, window?: NightwatchCallbackResult) => void): NightwatchBrowser
setupMetamask(passphrase: string, password: string): NightwatchBrowser
+ hideMetaMaskPopup(): NightwatchBrowser
signMessage(msg: string, callback: (hash: {value: string}, signature: {value: string}) => void): NightwatchBrowser
setSolidityCompilerVersion(version: string): NightwatchBrowser
clickElementAtPosition(cssSelector: string, index: number, opt?: {forceSelectIfUnselected: boolean}): NightwatchBrowser
@@ -69,6 +70,7 @@ declare module 'nightwatch' {
currentSelectedFileIs(name: string): NightwatchBrowser
switchWorkspace: (workspaceName: string) => NightwatchBrowser
switchEnvironment: (provider: string) => NightwatchBrowser
+ pinGrid: (provider: string, status: boolean) => NightwatchBrowser
connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser
waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser
hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser
diff --git a/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh b/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh
index 964da156b1..40cc0c0fb0 100755
--- a/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh
+++ b/apps/remix-ide/ci/deploy_from_travis_remix-alpha.sh
@@ -3,13 +3,13 @@
set -e
SHA=`git rev-parse --short --verify HEAD`
-cd dist/apps/remix-ide
-
# this gh action is used to deploy the build to the gh pages
mkdir dist/apps/remix-ide/.github
mkdir dist/apps/remix-ide/.github/workflows
cp apps/remix-ide/ci/gh-actions-deploy.yml dist/apps/remix-ide/.github/workflows
+cd dist/apps/remix-ide
+
git init
git checkout -b gh-pages
git config user.name "$COMMIT_AUTHOR"
diff --git a/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh b/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh
index 98f7af21c8..62b7a1d483 100755
--- a/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh
+++ b/apps/remix-ide/ci/deploy_from_travis_remix-beta.sh
@@ -3,13 +3,13 @@
set -e
SHA=`git rev-parse --short --verify HEAD`
-cd dist/apps/remix-ide
-
# this gh action is used to deploy the build to the gh pages
mkdir dist/apps/remix-ide/.github
mkdir dist/apps/remix-ide/.github/workflows
cp apps/remix-ide/ci/gh-actions-deploy.yml dist/apps/remix-ide/.github/workflows
+cd dist/apps/remix-ide
+
git init
git checkout -b gh-pages
git config user.name "$COMMIT_AUTHOR"
diff --git a/apps/remix-ide/ci/deploy_from_travis_remix-live.sh b/apps/remix-ide/ci/deploy_from_travis_remix-live.sh
index 0aadafc75c..b0b0a8bcce 100755
--- a/apps/remix-ide/ci/deploy_from_travis_remix-live.sh
+++ b/apps/remix-ide/ci/deploy_from_travis_remix-live.sh
@@ -3,13 +3,13 @@
set -e
SHA=`git rev-parse --short --verify HEAD`
-cd dist/apps/remix-ide
-
# this gh action is used to deploy the build to the gh pages
mkdir dist/apps/remix-ide/.github
mkdir dist/apps/remix-ide/.github/workflows
cp apps/remix-ide/ci/gh-actions-deploy.yml dist/apps/remix-ide/.github/workflows/gh-actions-deploy.yml
+cd dist/apps/remix-ide
+
git init
git checkout -b gh-pages
git config user.name "$COMMIT_AUTHOR"
diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js
index 52fed627a6..4c490aaf34 100644
--- a/apps/remix-ide/src/app.js
+++ b/apps/remix-ide/src/app.js
@@ -25,21 +25,22 @@ import { WalkthroughService } from './walkthroughService'
import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, FetchAndCompile, CompilerImports, GistHandler } from '@remix-project/core-plugin'
-import { Registry } from '@remix-project/remix-lib'
-import { ConfigPlugin } from './app/plugins/config'
-import { StoragePlugin } from './app/plugins/storage'
-import { Layout } from './app/panels/layout'
-import { NotificationPlugin } from './app/plugins/notification'
-import { Blockchain } from './blockchain/blockchain'
-import { MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider, CancunVMProvider } from './app/providers/vm-provider'
-import { MainnetForkVMProvider } from './app/providers/mainnet-vm-fork-provider'
-import { SepoliaForkVMProvider } from './app/providers/sepolia-vm-fork-provider'
-import { GoerliForkVMProvider } from './app/providers/goerli-vm-fork-provider'
-import { CustomForkVMProvider } from './app/providers/custom-vm-fork-provider'
-import { HardhatProvider } from './app/providers/hardhat-provider'
-import { GanacheProvider } from './app/providers/ganache-provider'
-import { FoundryProvider } from './app/providers/foundry-provider'
-import { ExternalHttpProvider } from './app/providers/external-http-provider'
+import {Registry} from '@remix-project/remix-lib'
+import {ConfigPlugin} from './app/plugins/config'
+import {StoragePlugin} from './app/plugins/storage'
+import {Layout} from './app/panels/layout'
+import {NotificationPlugin} from './app/plugins/notification'
+import {Blockchain} from './blockchain/blockchain'
+import {MergeVMProvider, LondonVMProvider, BerlinVMProvider, ShanghaiVMProvider, CancunVMProvider} from './app/providers/vm-provider'
+import {MainnetForkVMProvider} from './app/providers/mainnet-vm-fork-provider'
+import {SepoliaForkVMProvider} from './app/providers/sepolia-vm-fork-provider'
+import {GoerliForkVMProvider} from './app/providers/goerli-vm-fork-provider'
+import {CustomForkVMProvider} from './app/providers/custom-vm-fork-provider'
+import {HardhatProvider} from './app/providers/hardhat-provider'
+import {GanacheProvider} from './app/providers/ganache-provider'
+import {FoundryProvider} from './app/providers/foundry-provider'
+import {ExternalHttpProvider} from './app/providers/external-http-provider'
+import { EnvironmentExplorer } from './app/providers/environment-explorer'
import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
@@ -69,6 +70,8 @@ import { Matomo } from './app/plugins/matomo'
+import { TemplatesSelectionPlugin } from './app/plugins/templates-selection/templates-selection-plugin'
+
const isElectron = require('is-electron')
const remixLib = require('@remix-project/remix-lib')
@@ -293,6 +296,8 @@ class AppComponent {
const ganacheProvider = new GanacheProvider(blockchain)
const foundryProvider = new FoundryProvider(blockchain)
const externalHttpProvider = new ExternalHttpProvider(blockchain)
+
+ const environmentExplorer = new EnvironmentExplorer()
// ----------------- convert offset to line/column service -----------
const offsetToLineColumnConverter = new OffsetToLineColumnConverter()
Registry.getInstance().put({
@@ -329,6 +334,8 @@ class AppComponent {
// ----------------- run script after each compilation results -----------
const pluginStateLogger = new PluginStateLogger()
+ const templateSelection = new TemplatesSelectionPlugin()
+
this.engine.register([
permissionHandler,
this.layout,
@@ -367,6 +374,7 @@ class AppComponent {
ganacheProvider,
foundryProvider,
externalHttpProvider,
+ environmentExplorer,
this.walkthroughService,
search,
solidityumlgen,
@@ -379,7 +387,8 @@ class AppComponent {
solcoder,
git,
pluginStateLogger,
- matomo
+ matomo,
+ templateSelection
])
//---- fs plugin
@@ -533,7 +542,7 @@ class AppComponent {
])
await this.appManager.activatePlugin(['settings'])
- await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder', 'dgit'])
+ await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder', 'dgitApi', 'dgit'])
await this.appManager.activatePlugin(['solidity-script', 'remix-templates'])
if (isElectron()) {
diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js
index 92e0a637a9..9654f8abda 100644
--- a/apps/remix-ide/src/app/editor/editor.js
+++ b/apps/remix-ide/src/app/editor/editor.js
@@ -348,7 +348,6 @@ class Editor extends Plugin {
}
async openDiff(change) {
- console.log('openDiff', change)
const hashedPathModified = change.readonly ? change.path + change.hashModified : change.path
const hashedPathOriginal = change.path + change.hashOriginal
const session = await this._createSession(hashedPathModified, change.modified, this._getMode(change.path), change.readonly)
@@ -458,7 +457,6 @@ class Editor extends Plugin {
revealRange (startLineNumber, startColumn, endLineNumber, endColumn) {
if (!this.activated) return
this.emit('focus')
- console.log(startLineNumber, startColumn, endLineNumber, endColumn)
this.emit('revealRange', startLineNumber, startColumn, endLineNumber, endColumn)
}
diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts
index e232c2a132..2ff2d5a4d3 100644
--- a/apps/remix-ide/src/app/files/fileManager.ts
+++ b/apps/remix-ide/src/app/files/fileManager.ts
@@ -40,6 +40,7 @@ const errorMsg = {
const createError = (err) => {
return new Error(`${errorMsg[err.code]} ${err.message || ''}`)
}
+const _paq = (window._paq = window._paq || [])
class FileManager extends Plugin {
mode: string
openedFiles: any
@@ -215,6 +216,11 @@ class FileManager extends Plugin {
} else {
const ret = await this.setFileContent(path, data, options)
this.emit('fileAdded', path)
+ // Temporary solution to tracking scripts execution for zk in matomo
+ if (path === 'scripts/groth16/zk/keys/zkey_final.txt' && data) _paq.push(['trackEvent', 'circuit-compiler', 'script', 'groth16', 'zk trusted setup done'])
+ if (path === 'scripts/groth16/zk/build/zk_verifier.sol' && data) _paq.push(['trackEvent', 'circuit-compiler', 'script', 'groth16', 'zk proof done'])
+ if (path === 'scripts/plonk/zk/keys/zkey_final.txt' && data) _paq.push(['trackEvent', 'circuit-compiler', 'script', 'plonk', 'zk trusted setup done'])
+ if (path === 'scripts/plonk/zk/build/zk_verifier.sol' && data) _paq.push(['trackEvent', 'circuit-compiler', 'script', 'plonk', 'zk proof done'])
return ret
}
} catch (e) {
@@ -962,6 +968,12 @@ class FileManager extends Plugin {
return exists
}
+ /**
+ * Check if a file can be moved
+ * @param src source file
+ * @param dest destination file
+ * @returns {boolean} true if the file is allowed to be moved
+ */
async moveFileIsAllowed (src: string, dest: string) {
try {
src = this.normalize(src)
@@ -984,6 +996,12 @@ class FileManager extends Plugin {
}
}
+ /**
+ * Check if a folder can be moved
+ * @param src source folder
+ * @param dest destination folder
+ * @returns {boolean} true if the folder is allowed to be moved
+ */
async moveDirIsAllowed (src: string, dest: string) {
try {
src = this.normalize(src)
diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js
index 2260443663..2b3946bca1 100644
--- a/apps/remix-ide/src/app/panels/file-panel.js
+++ b/apps/remix-ide/src/app/panels/file-panel.js
@@ -189,7 +189,7 @@ module.exports = class Filepanel extends ViewPlugin {
if (err) reject(err)
else resolve(data || true)
})
- })
+ }, false)
}
renameWorkspace(oldName, workspaceName) {
diff --git a/apps/remix-ide/src/app/panels/layout.ts b/apps/remix-ide/src/app/panels/layout.ts
index 90896c2041..51149c3859 100644
--- a/apps/remix-ide/src/app/panels/layout.ts
+++ b/apps/remix-ide/src/app/panels/layout.ts
@@ -33,7 +33,9 @@ export class Layout extends Plugin {
maximised: { [key: string]: boolean }
constructor () {
super(profile)
- this.maximised = {}
+ this.maximised = {
+ 'dgit': true
+ }
this.event = new EventEmitter()
}
@@ -65,7 +67,6 @@ export class Layout extends Plugin {
this.event.emit('change', null)
})
this.on('tabs', 'openDiff', () => {
- console.log('openDiff')
this.panels.editor.active = true
this.panels.main.active = false
this.event.emit('change', null)
@@ -126,15 +127,15 @@ export class Layout extends Plugin {
}
async maximiseSidePanel () {
- this.event.emit('maximisesidepanel')
const current = await this.call('sidePanel', 'currentFocus')
this.maximised[current] = true
+ this.event.emit('maximisesidepanel')
}
async maximisePinnedPanel () {
- this.event.emit('maximisepinnedpanel')
const current = await this.call('pinnedPanel', 'currentFocus')
this.maximised[current] = true
+ this.event.emit('maximisepinnedpanel')
}
async maximizeTerminal() {
@@ -144,14 +145,14 @@ export class Layout extends Plugin {
}
async resetSidePanel () {
- this.event.emit('resetsidepanel')
const current = await this.call('sidePanel', 'currentFocus')
this.maximised[current] = false
+ this.event.emit('resetsidepanel')
}
async resetPinnedPanel () {
- this.event.emit('resetpinnedpanel')
const current = await this.call('pinnedPanel', 'currentFocus')
this.maximised[current] = false
+ this.event.emit('resetpinnedpanel')
}
}
diff --git a/apps/remix-ide/src/app/plugins/git.tsx b/apps/remix-ide/src/app/plugins/git.tsx
index 73331d87ed..6ffa0f0835 100644
--- a/apps/remix-ide/src/app/plugins/git.tsx
+++ b/apps/remix-ide/src/app/plugins/git.tsx
@@ -1,7 +1,7 @@
'use strict'
-import { ViewPlugin } from '@remixproject/engine-web';
+import { ViewPlugin } from '@remixproject/engine-web'
import React from 'react' // eslint-disable-line
-import { gitState, GitUI } from '@remix-ui/git';
+import { gitState, GitUI } from '@remix-ui/git'
import * as packageJson from '../../../../../package.json'
const profile = {
diff --git a/apps/remix-ide/src/app/plugins/matomo.ts b/apps/remix-ide/src/app/plugins/matomo.ts
index 9495d1ddd7..8aa8f61f70 100644
--- a/apps/remix-ide/src/app/plugins/matomo.ts
+++ b/apps/remix-ide/src/app/plugins/matomo.ts
@@ -11,7 +11,7 @@ const profile = {
version: '1.0.0'
}
-const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner']
+const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'dgit']
export class Matomo extends Plugin {
diff --git a/apps/remix-ide/src/app/plugins/remixGuide.tsx b/apps/remix-ide/src/app/plugins/remixGuide.tsx
index 2fa94f2466..2a4a79cdc2 100644
--- a/apps/remix-ide/src/app/plugins/remixGuide.tsx
+++ b/apps/remix-ide/src/app/plugins/remixGuide.tsx
@@ -123,6 +123,8 @@ export class RemixGuidePlugin extends ViewPlugin {
expandViewEl={
cell.expandViewElement
}
+ key={cell.title}
+ id={cell.title}
handleExpand={() => {
this.showVideo = true
this.videoID = cell.expandViewElement.videoID
diff --git a/apps/remix-ide/src/app/plugins/templates-selection/templates-selection-plugin.css b/apps/remix-ide/src/app/plugins/templates-selection/templates-selection-plugin.css
new file mode 100644
index 0000000000..f6e9f504f1
--- /dev/null
+++ b/apps/remix-ide/src/app/plugins/templates-selection/templates-selection-plugin.css
@@ -0,0 +1,12 @@
+.TSCellStyle {
+ min-height: 8.5rem;
+ max-width: 13rem;
+ min-width: 13rem;
+ max-height: 8.5rem;
+}
+
+.badgeForCell {
+ max-width: fit-content;
+ padding-right: 0.5rem;
+ font-size: smaller;
+}
diff --git a/apps/remix-ide/src/app/plugins/templates-selection/templates-selection-plugin.tsx b/apps/remix-ide/src/app/plugins/templates-selection/templates-selection-plugin.tsx
new file mode 100644
index 0000000000..6df97e60b6
--- /dev/null
+++ b/apps/remix-ide/src/app/plugins/templates-selection/templates-selection-plugin.tsx
@@ -0,0 +1,269 @@
+
+import React from 'react'
+import { FormattedMessage, useIntl } from 'react-intl'
+import { CustomTooltip } from "@remix-ui/helper"
+import { AppModal } from '@remix-ui/app'
+import { ViewPlugin } from '@remixproject/engine-web'
+import { PluginViewWrapper } from '@remix-ui/helper'
+import { RemixUIGridView } from '@remix-ui/remix-ui-grid-view'
+import { RemixUIGridSection } from '@remix-ui/remix-ui-grid-section'
+import { RemixUIGridCell } from '@remix-ui/remix-ui-grid-cell'
+import isElectron from 'is-electron'
+import type { TemplateGroup } from '@remix-ui/workspace'
+import './templates-selection-plugin.css'
+import { templates } from './templates'
+
+//@ts-ignore
+const _paq = (window._paq = window._paq || [])
+
+const profile = {
+ name: 'templateSelection',
+ displayName: 'Template Selection',
+ description: 'templateSelection',
+ location: 'mainPanel',
+ methods: [],
+ events: [],
+ maintainedBy: 'Remix',
+}
+
+export class TemplatesSelectionPlugin extends ViewPlugin {
+ templates: Array
+ dispatch: React.Dispatch = () => { }
+ constructor() {
+ super(profile)
+ }
+
+ async onActivation() {
+ this.handleThemeChange()
+ await this.call('tabs', 'focus', 'templateSelection')
+ this.renderComponent()
+ _paq.push(['trackEvent', 'plugin', 'activated', 'remixGuide'])
+ }
+
+ onDeactivation(): void {
+ }
+
+ private handleThemeChange() {
+ this.on('theme', 'themeChanged', (theme: any) => {
+ this.renderComponent()
+ })
+ }
+
+ setDispatch(dispatch: React.Dispatch): void {
+ this.dispatch = dispatch
+ this.renderComponent()
+ }
+
+ render() {
+ return (
+
+ )
+ }
+
+ renderComponent() {
+ this.dispatch({
+ ...this,
+ })
+ }
+
+ updateComponent() {
+ /*
+ This represents the different options available from the openzeppelin library.
+ const opts = {
+ // @ts-ignore: Object is possibly 'null'.
+ mintable: mintableCheckboxRef.current.checked,
+ // @ts-ignore: Object is possibly 'null'.
+ burnable: burnableCheckboxRef.current.checked,
+ // @ts-ignore: Object is possibly 'null'.
+ pausable: pausableCheckboxRef.current.checked,
+ // @ts-ignore: Object is possibly 'null'.
+ upgradeable: transparentRadioRef.current.checked ? transparentRadioRef.current.value : uupsRadioRef.current.checked ? uupsRadioRef.current.value : false
+ }
+ */
+ const createWorkspace = async (item) => {
+ const defaultName = await this.call('filePanel', 'getAvailableWorkspaceName', item.displayName)
+
+ const username = await this.call('settings', 'get', 'settings/github-user-name')
+ const email = await this.call('settings', 'get', 'settings/github-email')
+ const gitNotSet = !username || !email
+ let workspaceName = defaultName
+ let initGit = false
+ const modal: AppModal = {
+ id: 'TemplatesSelection',
+ title: window._intl.formatMessage({ id: !isElectron() ? 'filePanel.workspace.create': 'filePanel.workspace.create.desktop' }),
+ message: await createModalMessage(defaultName, gitNotSet, (value) => workspaceName = value, (value) => initGit = !!value),
+ okLabel: window._intl.formatMessage({ id: !isElectron() ? 'filePanel.ok':'filePanel.selectFolder' }),
+ }
+ const modalResult = await this.call('notification', 'modal', modal)
+ if (!modalResult) return
+ this.emit('createWorkspaceReducerEvent', workspaceName, item.value, item.opts, false, async (e, data) => {
+ if (e) {
+ const modal: AppModal = {
+ id: 'TemplatesSelection',
+ title: window._intl.formatMessage({ id: !isElectron() ? 'filePanel.workspace.create': 'filePanel.workspace.create.desktop' }),
+ message: e.message,
+ okLabel: window._intl.formatMessage({ id: 'filePanel.ok' }),
+ cancelLabel: window._intl.formatMessage({ id: 'filePanel.cancel' })
+ }
+ await this.call('notification', 'modal', modal)
+ console.error(e)
+ }
+
+ }, initGit)
+ }
+
+ const addToCurrentWorkspace = async (item) => {
+ this.emit('addTemplateToWorkspaceReducerEvent', item.value, item.opts, false, async (e, data) => {
+ if (e) {
+ const modal: AppModal = {
+ id: 'TemplatesSelection',
+ title: window._intl.formatMessage({ id: !isElectron() ? 'filePanel.workspace.create': 'filePanel.workspace.create.desktop' }),
+ message: e.message,
+ okLabel: window._intl.formatMessage({ id: 'filePanel.ok' }),
+ cancelLabel: window._intl.formatMessage({ id: 'filePanel.cancel' })
+ }
+ await this.call('notification', 'modal', modal)
+ console.error(e)
+ } else {
+ this.call('notification', 'toast', 'Files Added.')
+ }
+ })
+ }
+
+ return (
+
+ {
+ templates(window._intl).map(template => {
+ return
+ {template.items.map(item => {
+ return
+
+
+
+ {item.description && {item.description} }
+
+
+ {(item.opts && item.opts.upgradeable && item.opts.upgradeable === 'uupds') && Upgradeable-UUPS }
+ {(item.opts && item.opts.mintable) && mintable }
+ {(item.opts && item.opts.burnable) && burnable }
+ {(item.opts && item.opts.pausable) && pausable }
+
+
+
+ {(!template.IsArtefact || !item.isArtefact) &&
+ createWorkspace(item)}
+ className="btn btn-sm mr-2 border border-primary"
+ >
+ Create
+
+ }
+
+ addToCurrentWorkspace(item)}
+ className="btn btn-sm border"
+ >
+ Add to current
+
+
+
+
+
+ })}
+
+ })}
+
+ )
+ }
+}
+
+const createModalMessage = async (
+ defaultName: string,
+ gitConfigNotSet: boolean,
+ onChangeTemplateName: (name: string) => void,
+ onChangeInitGit: (name: string) => void) => {
+
+ return (
+ <>
+
+
+
+ onChangeTemplateName(e.target.value)}
+ onInput={(e) => onChangeTemplateName((e.target as any).value)}
+ />
+
+ onChangeInitGit(e.target.value)}
+ onInput={(e) => onChangeInitGit((e.target as any).value)}
+ />
+
+
+
+
+ {gitConfigNotSet ? (
+
+
+
+ ) : (
+ <>>
+ )}
+ >
+ )
+}
+
diff --git a/apps/remix-ide/src/app/plugins/templates-selection/templates.ts b/apps/remix-ide/src/app/plugins/templates-selection/templates.ts
new file mode 100644
index 0000000000..a42524a285
--- /dev/null
+++ b/apps/remix-ide/src/app/plugins/templates-selection/templates.ts
@@ -0,0 +1,357 @@
+
+export const templates = (intl) => {
+ return [
+ {
+ name: "Generic",
+ items: [
+ { value: "remixDefault", tagList: ["Solidity"], displayName: intl.formatMessage({ id: 'filePanel.basic' }), description: 'A default project' },
+ { value: "blank", displayName: intl.formatMessage({ id: 'filePanel.blank' }), IsArtefact: true, description: 'A blank project' }
+ ]
+ },
+ {
+ name: "OpenZeppelin",
+ items: [
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ tagList: ["ERC20", "Solidity"],
+ description: 'A simple ERC20 project'
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ tagList: ["ERC721", "Solidity"],
+ description: 'A simple ERC721 (aka NFT) project'
+ },
+ {
+ value: "ozerc1155",
+ tagList: ["Solidity"],
+ displayName: "ERC1155",
+ description: 'A simple ERC1155 (multi token) project'
+ },
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ tagList: ["Solidity"],
+ opts: {
+ mintable: true
+ }
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ tagList: ["Solidity", "ERC721"],
+ opts: {
+ mintable: true
+ }
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ tagList: ["Solidity"],
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ mintable: true
+ }
+ },
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ tagList: ["Solidity", "ERC20"],
+ opts: {
+ mintable: true,
+ burnable: true
+ },
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ opts: {
+ mintable: true,
+ burnable: true
+ },
+ tagList: ["ERC721", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ mintable: true,
+ burnable: true
+ },
+ tagList: ["ERC1155", "Solidity"]
+ },
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ opts: {
+ mintable: true,
+ pausable: true
+ },
+ tagList: ["ERC20", "Solidity"]
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ opts: {
+ mintable: true,
+ pausable: true
+ },
+ tagList: ["ERC721", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ tagList: ["ERC20"],
+ opts: {
+ mintable: true,
+ pausable: true
+ }
+ }
+ ]
+ },
+ {
+ name: "OpenZeppelin Proxy",
+ items: [
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ opts: {
+ upgradeable: 'uups'
+ },
+ tagList: ["ERC20", "Solidity"]
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ opts: {
+ upgradeable: 'uups'
+ },
+ tagList: ["ERC721", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ upgradeable: 'uups'
+ },
+ tagList: ["ERC1155", "Solidity"]
+ },
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true
+ },
+ tagList: ["ERC20", "Solidity"]
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true
+ },
+ tagList: ["ERC721", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true
+ },
+ tagList: ["ERC1155", "Solidity"]
+ },
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ burnable: true
+ },
+ tagList: ["ERC20", "Solidity"]
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ burnable: true
+ },
+ tagList: ["ERC721", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ burnable: true
+ },
+ tagList: ["ERC1155", "Solidity"]
+ },
+ {
+ value: "ozerc20",
+ displayName: "ERC20",
+ description: "A standard interface for fungible tokens",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ pausable: true
+ },
+ tagList: ["ERC20", "Solidity"]
+ },
+ {
+ value: "ozerc721",
+ displayName: "ERC721 (NFT)",
+ description: "Non-fungible Token Standard",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ pausable: true
+ },
+ tagList: ["ERC721", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ pausable: true
+ },
+ tagList: ["ERC1155", "Solidity"]
+ },
+ {
+ value: "ozerc1155",
+ displayName: "ERC1155",
+ description: "A standard interface for contracts that manage multiple token types",
+ opts: {
+ upgradeable: 'uups',
+ mintable: true,
+ burnable: true,
+ pausable: true
+ },
+ tagList: ["ERC1155", "Solidity"]
+ }
+ ]
+ },
+ {
+ name: "OxProject",
+ items: [
+ { value: "zeroxErc20", displayName: "ERC20", tagList: ["ERC20", "Solidity"], description: "A standard interface for fungible tokens by 0xProject" }
+ ]
+ },
+ {
+ name: "Gnosis Safe",
+ items: [
+ { value: "gnosisSafeMultisig", tagList: ["Solidity"], displayName: intl.formatMessage({ id: 'filePanel.multiSigWallet' }), description: 'Deploy or Customize the Gnosis Safe.' }
+ ]
+ },
+ {
+ name: "Circom ZKP",
+ items: [
+ { value: "semaphore", tagList: ["ZKP"], displayName: intl.formatMessage({ id: 'filePanel.semaphore' }), description: 'Run a ZK Semaphore circom circuit.' },
+ { value: "hashchecker", tagList: ["ZKP"], displayName: intl.formatMessage({ id: 'filePanel.hashchecker' }), description: 'Run a ZK Hash checker circom circuit.' },
+ { value: "rln", tagList: ["ZKP"], displayName: intl.formatMessage({ id: 'filePanel.rln' }), description: 'Run a Rate Limiting Nullifier circom circuit.' }
+ ]
+ },
+ {
+ name: "Generic ZKP",
+ items: [
+ {
+ value: "sindriScripts",
+ tagList: ["ZKP"],
+ displayName: intl.formatMessage({ id: 'filePanel.addscriptsindri' }),
+ description: 'Use the Sindri API to compile and generate proof.'
+ },
+ ],
+ },
+ {
+ name: "Uniswap V4",
+ items: [
+ { value: "uniswapV4Template",
+ displayName: intl.formatMessage({ id: 'filePanel.uniswapV4Template' }),
+ description: 'Use an Uniswap hook'
+ },
+ {
+ value: "breakthroughLabsUniswapv4Hooks",
+ displayName: intl.formatMessage({ id: 'filePanel.breakthroughLabsUniswapv4Hooks' }),
+ description: 'Use an Uniswap hook developed by Breakthrough Labs'
+ },
+ {
+ value: "uniswapV4HookBookMultiSigSwapHook",
+ displayName: intl.formatMessage({ id: 'filePanel.uniswapV4HookBookMultiSigSwapHook' }),
+ description: 'Use a MultiSigSwapHook developed by Breakthrough Labs'
+ }
+ ]
+ },
+ {
+ name: "Solidity CREATE2",
+ items: [
+ {
+ value: "contractCreate2Factory",
+ tagList: ["Solidity"],
+ displayName: intl.formatMessage({ id: 'filePanel.addcreate2solidityfactory' }),
+ description: 'Factory for deploying a Contract using the CREATE2 opcode.'
+ },
+ {
+ value: "contractDeployerScripts",
+ displayName: intl.formatMessage({ id: 'filePanel.addscriptdeployer' }),
+ description: 'Script for deploying a Contract using the CREATE2 opcode.'
+ }
+ ]
+ },
+ {
+ name: "Contract Verification",
+ items: [
+ {
+ value: "etherscanScripts",
+ displayName: intl.formatMessage({ id: 'filePanel.addscriptetherscan' }),
+ description: 'Script for verifying a Contract in Etherscan.'
+ },
+ ],
+ },
+ {
+ name: 'Github Actions',
+ items: [
+ { value: "runJsTestAction",
+ displayName: intl.formatMessage({ id: 'filePanel.tssoltestghaction' }),
+ description: 'A Mocha Chai Test Workflow in a GitHub CI.'
+ },
+ { value: "runSolidityUnittestingAction",
+ displayName: intl.formatMessage({ id: 'filePanel.solghaction' }),
+ description: 'Run a Solidity Unittest Workflow in a GitHub CI.'
+ },
+ {
+ value: "runSlitherAction",
+ displayName: intl.formatMessage({ id: 'filePanel.slitherghaction' }),
+ description: 'Run a Slither Security Analysis in a GitHub CI.'
+ }
+ ],
+ IsArtefact: true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/remix-ide/src/app/providers/environment-explorer.tsx b/apps/remix-ide/src/app/providers/environment-explorer.tsx
new file mode 100644
index 0000000000..8e5fe87011
--- /dev/null
+++ b/apps/remix-ide/src/app/providers/environment-explorer.tsx
@@ -0,0 +1,207 @@
+import React from 'react' // eslint-disable-line
+import { ViewPlugin } from '@remixproject/engine-web'
+import { PluginViewWrapper } from '@remix-ui/helper'
+import { RemixUIGridView } from '@remix-ui/remix-ui-grid-view'
+import { RemixUIGridSection } from '@remix-ui/remix-ui-grid-section'
+import { RemixUIGridCell } from '@remix-ui/remix-ui-grid-cell'
+import './style/environment-explorer.css'
+import type { Provider } from '../../blockchain/blockchain'
+
+import * as packageJson from '../../../../../package.json'
+
+const _paq = (window._paq = window._paq || [])
+
+const profile = {
+ name: 'environmentExplorer',
+ displayName: 'Environment Explorer',
+ icon: 'assets/img/EnvironmentExplorerLogo.webp',
+ description: 'Customize the Environments list in Deploy & Run',
+ location: 'mainPanel',
+ documentation: 'https://remix-ide.readthedocs.io/en/latest/run.html',
+ version: packageJson.version,
+ maintainedBy: 'Remix',
+ permission: true,
+ events: [],
+ methods: []
+}
+
+type ProvidersSection = `Injected` | 'Remix VMs' | 'Externals'
+
+export class EnvironmentExplorer extends ViewPlugin {
+ providers: { [key in ProvidersSection]: Provider[] }
+ providersFlat: { [key: string]: Provider }
+ pinnedProviders: string[]
+ dispatch: React.Dispatch = () => {}
+
+ constructor() {
+ super(profile)
+ this.providersFlat = {}
+ this.providers = {
+ 'Injected': [],
+ 'Remix VMs': [],
+ 'Externals': []
+ }
+ }
+
+ async onActivation(): Promise {
+ this.providersFlat = await this.call('blockchain', 'getAllProviders')
+ this.pinnedProviders = await this.call('blockchain', 'getPinnedProviders')
+ this.renderComponent()
+ }
+
+ addProvider (provider: Provider) {
+ if (provider.isInjected) {
+ this.providers['Injected'].push(provider)
+ } else if (provider.isVM) {
+ this.providers['Remix VMs'].push(provider)
+ } else {
+ this.providers['Externals'].push(provider)
+ }
+ }
+
+ setDispatch(dispatch: React.Dispatch): void {
+ this.dispatch = dispatch
+ this.renderComponent()
+ }
+ render() {
+ return (
+
+ )
+ }
+
+ renderComponent() {
+ this.dispatch({
+ ...this
+ })
+ }
+
+ updateComponent(state: any) {
+ this.providers = {
+ 'Injected': [],
+ 'Remix VMs': [],
+ 'Externals': []
+ }
+ for (const [key, provider] of Object.entries(this.providersFlat)) {
+ this.addProvider(provider)
+ }
+ return (
+
+
+ {this.providers['Injected'].map(provider => {
+ return {
+ if (pinned) {
+ this.emit('providerPinned', provider.name, provider)
+ this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
+ return true
+ }
+ const providerName = await this.call('blockchain', 'getProvider')
+ if (providerName !== provider.name) {
+ this.emit('providerUnpinned', provider.name, provider)
+ this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
+ return true
+ } else {
+ this.call('notification', 'toast', 'Cannot unpin the current selected provider')
+ return false
+ }
+ }}
+ >
+ {provider.description}
+
+ })}
+
+ {this.providers['Remix VMs'].map(provider => {
+ return {
+ if (pinned) {
+ this.emit('providerPinned', provider.name, provider)
+ this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
+ return true
+ }
+ const providerName = await this.call('blockchain', 'getProvider')
+ if (providerName !== provider.name) {
+ this.emit('providerUnpinned', provider.name, provider)
+ this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
+ return true
+ } else {
+ this.call('notification', 'toast', 'Cannot unpin the current selected provider')
+ return false
+ }
+ }}
+ >
+ {provider.description}
+
+ })}
+ {this.providers['Externals'].map(provider => {
+ return {
+ if (pinned) {
+ this.emit('providerPinned', provider.name, provider)
+ this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
+ return true
+ }
+ const providerName = await this.call('blockchain', 'getProvider')
+ if (providerName !== provider.name) {
+ this.emit('providerUnpinned', provider.name, provider)
+ this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
+ return true
+ } else {
+ this.call('notification', 'toast', 'Cannot unpin the current selected provider')
+ return false
+ }
+ }}
+ >
+ {provider.description}
+
+ })}
+
+ )
+ }
+}
diff --git a/apps/remix-ide/src/app/providers/style/environment-explorer.css b/apps/remix-ide/src/app/providers/style/environment-explorer.css
new file mode 100644
index 0000000000..b5770fba42
--- /dev/null
+++ b/apps/remix-ide/src/app/providers/style/environment-explorer.css
@@ -0,0 +1,5 @@
+.EECellStyle {
+ min-height: 6rem;
+ max-width: 12rem;
+ min-width: 10rem;
+}
diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js
index 837e8d97ba..35306c87d1 100644
--- a/apps/remix-ide/src/app/udapp/run-tab.js
+++ b/apps/remix-ide/src/app/udapp/run-tab.js
@@ -129,6 +129,42 @@ export class RunTab extends ViewPlugin {
async onInitDone() {
const udapp = this // eslint-disable-line
+ const descriptions = {
+ 'vm-cancun': 'Deploy to the in-browser virtual machine running the Cancun fork.',
+ 'vm-shanghai': 'Deploy to the in-browser virtual machine running the Shanghai fork.',
+ 'vm-paris': 'Deploy to the in-browser virtual machine running the Paris fork.',
+ 'vm-london': 'Deploy to the in-browser virtual machine running the London fork.',
+ 'vm-berlin': 'Deploy to the in-browser virtual machine running the Berlin fork.',
+ 'vm-mainnet-fork': 'Deploy to a fork of the Ethereum mainnet in the in-browser virtual machine.',
+ 'vm-sepolia-fork': 'Deploy to a fork of the Sepolia testnet in the in-browser virtual machine.',
+ 'vm-custom-fork': 'Deploy to a fork of a custom network in the in-browser virtual machine.',
+ 'walletconnect': 'Deploy using WalletConnect.',
+ 'basic-http-provider': 'Deploy to a Custom local network.',
+ 'hardhat-provider': 'Deploy to the local Hardhat dev chain.',
+ 'ganache-provider': 'Deploy to the local Ganache dev chain.',
+ 'foundry-provider': 'Deploy to the local Foundry dev chain.',
+ 'injected-MetaMask': 'Deploy through the Metamask browser extension.',
+ 'injected-Brave Wallet': 'Deploy through the Brave Wallet extension.',
+ 'injected-Brave': 'Deploy through the Brave browser extension.',
+ 'injected-metamask-optimism': 'Deploy to Optimism through the Metamask browser extension.',
+ 'injected-metamask-arbitrum': 'Deploy to Arbitrum through the Metamask browser extension.',
+ 'injected-metamask-sepolia': 'Deploy to the Sepolia testnet through the Metamask browser extension.',
+ 'injected-metamask-ephemery': 'Deploy to the Ephemery testnet through the Metamask browser extension.'
+ }
+
+ const logos = {
+ 'injected-metamask-optimism': ['assets/img/optimism-ethereum-op-logo.png', 'assets/img/metamask.png'],
+ 'injected-metamask-arbitrum': ['assets/img/arbitrum-arb-logo.png', 'assets/img/metamask.png'],
+ 'injected-metamask-sepolia': ['assets/img/metamask.png'],
+ 'injected-metamask-ephemery': ['assets/img/metamask.png'],
+ 'injected-MetaMask': ['assets/img/metamask.png'],
+ 'injected-Brave Wallet': ['assets/img/brave.png'],
+ 'injected-Trust Wallet': ['assets/img/trust-wallet.png'],
+ 'hardhat-provider': ['assets/img/hardhat.png'],
+ 'walletconnect': ['assets/img/Walletconnect-logo.png'],
+ 'foundry-provider': ['assets/img/foundry.png']
+ }
+
const addProvider = async (position, name, displayName, isInjected, isVM, fork = '', dataId = '', title = '') => {
await this.call('blockchain', 'addProvider', {
position,
@@ -136,6 +172,8 @@ export class RunTab extends ViewPlugin {
dataId,
name,
displayName,
+ description: descriptions[name] || displayName,
+ logos: logos[name],
fork,
isInjected,
isVM,
@@ -167,15 +205,15 @@ export class RunTab extends ViewPlugin {
await addProvider(0, name, displayName, true, false, false)
if (event.detail.info.name === 'MetaMask') {
- await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism', '0xa', ['https://mainnet.optimism.io'])
- await addCustomInjectedProvider(8, event, 'injected-metamask-arbitrum', 'L2 - Arbitrum', '0xa4b1', ['https://arb1.arbitrum.io/rpc'])
- await addCustomInjectedProvider(5, event, 'injected-metamask-sepolia', 'Testnet - Sepolia', '0xaa36a7', [],
+ await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism - ' + event.detail.info.name, '0xa', ['https://mainnet.optimism.io'])
+ await addCustomInjectedProvider(8, event, 'injected-metamask-arbitrum', 'L2 - Arbitrum - ' + event.detail.info.name, '0xa4b1', ['https://arb1.arbitrum.io/rpc'])
+ await addCustomInjectedProvider(5, event, 'injected-metamask-sepolia', 'Sepolia Testnet - ' + event.detail.info.name, '0xaa36a7', [],
{
"name": "Sepolia ETH",
"symbol": "ETH",
"decimals": 18
})
- await addCustomInjectedProvider(9, event, 'injected-metamask-ephemery', 'Ephemery Testnet', '', ['https://otter.bordel.wtf/erigon', 'https://eth.ephemeral.zeus.fyi'],
+ await addCustomInjectedProvider(9, event, 'injected-metamask-ephemery', 'Ephemery Testnet - ' + event.detail.info.name, '', ['https://otter.bordel.wtf/erigon', 'https://eth.ephemeral.zeus.fyi'],
{
"name": "Ephemery ETH",
"symbol": "ETH",
@@ -192,7 +230,7 @@ export class RunTab extends ViewPlugin {
}
}
- // VM
+ // VM
const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.'
await addProvider(1, 'vm-cancun', 'Remix VM (Cancun)', false, true, 'cancun', 'settingsVMCancunMode', titleVM)
await addProvider(50, 'vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM)
diff --git a/apps/remix-ide/src/assets/img/EnvironmentExplorerLogo.webp b/apps/remix-ide/src/assets/img/EnvironmentExplorerLogo.webp
new file mode 100644
index 0000000000..8fc0b06788
Binary files /dev/null and b/apps/remix-ide/src/assets/img/EnvironmentExplorerLogo.webp differ
diff --git a/apps/remix-ide/src/assets/img/Walletconnect-logo.png b/apps/remix-ide/src/assets/img/Walletconnect-logo.png
new file mode 100644
index 0000000000..ea0ca5810d
Binary files /dev/null and b/apps/remix-ide/src/assets/img/Walletconnect-logo.png differ
diff --git a/apps/remix-ide/src/assets/img/arbitrum-arb-logo.png b/apps/remix-ide/src/assets/img/arbitrum-arb-logo.png
new file mode 100644
index 0000000000..a7ee4623d6
Binary files /dev/null and b/apps/remix-ide/src/assets/img/arbitrum-arb-logo.png differ
diff --git a/apps/remix-ide/src/assets/img/brave.png b/apps/remix-ide/src/assets/img/brave.png
new file mode 100644
index 0000000000..a55721b1d2
Binary files /dev/null and b/apps/remix-ide/src/assets/img/brave.png differ
diff --git a/apps/remix-ide/src/assets/img/foundry.png b/apps/remix-ide/src/assets/img/foundry.png
new file mode 100644
index 0000000000..21863acc13
Binary files /dev/null and b/apps/remix-ide/src/assets/img/foundry.png differ
diff --git a/apps/remix-ide/src/assets/img/hardhat.png b/apps/remix-ide/src/assets/img/hardhat.png
new file mode 100644
index 0000000000..e29c2cdaea
Binary files /dev/null and b/apps/remix-ide/src/assets/img/hardhat.png differ
diff --git a/apps/remix-ide/src/assets/img/metamask.png b/apps/remix-ide/src/assets/img/metamask.png
new file mode 100644
index 0000000000..96081fe838
Binary files /dev/null and b/apps/remix-ide/src/assets/img/metamask.png differ
diff --git a/apps/remix-ide/src/assets/img/optimism-ethereum-op-logo.png b/apps/remix-ide/src/assets/img/optimism-ethereum-op-logo.png
new file mode 100644
index 0000000000..cb31c98074
Binary files /dev/null and b/apps/remix-ide/src/assets/img/optimism-ethereum-op-logo.png differ
diff --git a/apps/remix-ide/src/assets/img/trust-wallet.png b/apps/remix-ide/src/assets/img/trust-wallet.png
new file mode 100644
index 0000000000..87ac7a80de
Binary files /dev/null and b/apps/remix-ide/src/assets/img/trust-wallet.png differ
diff --git a/apps/remix-ide/src/blockchain/blockchain.tsx b/apps/remix-ide/src/blockchain/blockchain.tsx
index bbe6d302f1..00a64273f0 100644
--- a/apps/remix-ide/src/blockchain/blockchain.tsx
+++ b/apps/remix-ide/src/blockchain/blockchain.tsx
@@ -23,7 +23,7 @@ const profile = {
name: 'blockchain',
displayName: 'Blockchain',
description: 'Blockchain - Logic',
- methods: ['getCode', 'getTransactionReceipt', 'addProvider', 'removeProvider', 'getCurrentFork', 'getAccounts', 'web3VM', 'web3', 'getProvider', 'getCurrentNetworkStatus'],
+ methods: ['getCode', 'getTransactionReceipt', 'addProvider', 'removeProvider', 'getCurrentFork', 'getAccounts', 'web3VM', 'web3', 'getProvider', 'getCurrentNetworkStatus', 'getAllProviders', 'getPinnedProviders'],
version: packageJson.version
}
@@ -44,6 +44,24 @@ export type Transaction = {
timestamp?: number
}
+export type Provider = {
+ options: { [key: string]: string }
+ dataId: string
+ name: string
+ displayName: string
+ logo?: string,
+ logos?: string[],
+ fork: string
+ description?: string
+ isInjected: boolean
+ isVM: boolean
+ title: string
+ init: () => Promise
+ provider:{
+ sendAsync: (payload: any) => Promise
+ }
+}
+
export class Blockchain extends Plugin {
active: boolean
event: EventManager
@@ -62,6 +80,7 @@ export class Blockchain extends Plugin {
providers: {[key: string]: VMProvider | InjectedProvider | NodeProvider}
transactionContextAPI: TransactionContextAPI
registeredPluginEvents: string[]
+ pinnedProviders: string[]
// NOTE: the config object will need to be refactored out in remix-lib
constructor(config: Config) {
@@ -93,6 +112,7 @@ export class Blockchain extends Plugin {
this.networkcallid = 0
this.networkStatus = { network: { name: ' - ', id: ' - ' } }
this.registeredPluginEvents = []
+ this.pinnedProviders = ['vm-cancun', 'vm-shanghai', 'vm-mainnet-fork', 'vm-london', 'vm-berlin', 'vm-paris', 'walletconnect', 'injected-MetaMask', 'basic-http-provider', 'ganache-provider', 'hardhat-provider', 'foundry-provider']
this.setupEvents()
this.setupProviders()
}
@@ -116,6 +136,14 @@ export class Blockchain extends Plugin {
})
}
})
+
+ this.on('environmentExplorer', 'providerPinned', (name, provider) => {
+ this.emit('shouldAddProvidertoUdapp', name, provider)
+ })
+
+ this.on('environmentExplorer', 'providerUnpinned', (name, provider) => {
+ this.emit('shouldRemoveProviderFromUdapp', name, provider)
+ })
}
onDeactivation() {
@@ -136,12 +164,12 @@ export class Blockchain extends Plugin {
})
})
- this.executionContext.event.register('addProvider', (network) => {
- this._triggerEvent('addProvider', [network])
+ this.executionContext.event.register('providerAdded', (network) => {
+ this._triggerEvent('providerAdded', [network])
})
- this.executionContext.event.register('removeProvider', (name) => {
- this._triggerEvent('removeProvider', [name])
+ this.executionContext.event.register('providerRemoved', (name) => {
+ this._triggerEvent('providerRemoved', [name])
})
setInterval(() => {
@@ -504,7 +532,11 @@ export class Blockchain extends Plugin {
}
changeExecutionContext(context, confirmCb, infoCb, cb) {
- return this.executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
+ if (context.context === 'item-another-chain') {
+ this.call('manager', 'activatePlugin', 'environmentExplorer').then(() => this.call('tabs', 'focus', 'environmentExplorer'))
+ } else {
+ return this.executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
+ }
}
detectNetwork(cb) {
@@ -611,7 +643,8 @@ export class Blockchain extends Plugin {
this.executionContext.listenOnLastBlock()
}
- addProvider(provider) {
+ addProvider(provider: Provider) {
+ if (this.pinnedProviders.includes(provider.name)) this.emit('shouldAddProvidertoUdapp', provider.name, provider)
this.executionContext.addProvider(provider)
}
@@ -619,6 +652,14 @@ export class Blockchain extends Plugin {
this.executionContext.removeProvider(name)
}
+ getAllProviders() {
+ return this.executionContext.getAllProviders()
+ }
+
+ getPinnedProviders() {
+ return this.pinnedProviders
+ }
+
// TODO : event should be triggered by Udapp instead of TxListener
/** Listen on New Transaction. (Cannot be done inside constructor because txlistener doesn't exist yet) */
startListening(txlistener) {
diff --git a/apps/remix-ide/src/blockchain/execution-context.js b/apps/remix-ide/src/blockchain/execution-context.js
index b54b8d371b..fd127fb20c 100644
--- a/apps/remix-ide/src/blockchain/execution-context.js
+++ b/apps/remix-ide/src/blockchain/execution-context.js
@@ -123,10 +123,13 @@ export class ExecutionContext {
addProvider (network) {
if (network && network.name && !this.customNetWorks[network.name]) {
this.customNetWorks[network.name] = network
- this.event.trigger('addProvider', [network])
}
}
+ getAllProviders () {
+ return this.customNetWorks
+ }
+
internalWeb3 () {
return web3
}
diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js
index 95696ae8c3..92f76e950e 100644
--- a/apps/remix-ide/src/remixAppManager.js
+++ b/apps/remix-ide/src/remixAppManager.js
@@ -82,11 +82,12 @@ let requiredModules = [ // services + layout views + system views
'pinnedPanel',
'pluginStateLogger',
'remixGuide',
- 'matomo'
+ 'environmentExplorer',
+ 'templateSelection',
+ 'matomo',
+ 'walletconnect'
]
-
-
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither']
@@ -133,7 +134,9 @@ export function isNative(name) {
'circuit-compiler',
'compilationDetails',
'vyperCompilationDetails',
- 'remixGuide',
+ //'remixGuide',
+ 'environmentExplorer',
+ 'templateSelection',
'walletconnect'
]
return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name)
@@ -389,7 +392,16 @@ class PluginLoader {
constructor() {
const queryParams = new QueryParams()
- this.donotAutoReload = ['remixd'] // that would be a bad practice to force loading some plugins at page load.
+ // some plugins should not be activated at page load.
+ this.donotAutoReload = [
+ 'remixd',
+ 'environmentExplorer',
+ 'templateSelection',
+ 'compilationDetails',
+ 'walletconnect',
+ 'dapp-draft',
+ 'solidityumlgen'
+ ]
this.loaders = {}
this.loaders.localStorage = {
set: (plugin, actives) => {
diff --git a/apps/remix-ide/src/remixEngine.js b/apps/remix-ide/src/remixEngine.js
index ba321480ed..e4977c43f2 100644
--- a/apps/remix-ide/src/remixEngine.js
+++ b/apps/remix-ide/src/remixEngine.js
@@ -28,6 +28,8 @@ export class RemixEngine extends Engine {
if (name === 'fileManager') return { queueTimeout: 60000 * 20 }
if (name === 'solcoder') return { queueTimeout: 60000 * 2 }
if (name === 'cookbookdev') return { queueTimeout: 60000 * 3 }
+ if (name === 'contentImport') return { queueTimeout: 60000 * 3 }
+
return { queueTimeout: 10000 }
}
diff --git a/libs/ghaction-helper/package.json b/libs/ghaction-helper/package.json
index 2290c89071..c3f69e6aff 100644
--- a/libs/ghaction-helper/package.json
+++ b/libs/ghaction-helper/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/ghaction-helper",
- "version": "0.1.32",
+ "version": "0.1.33",
"description": "Solidity Tests GitHub Action Helper",
"main": "src/index.js",
"scripts": {
@@ -19,17 +19,17 @@
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"devDependencies": {
- "@remix-project/remix-solidity": "^0.5.38",
+ "@remix-project/remix-solidity": "^0.5.39",
"@types/chai": "^4.3.4",
"typescript": "^4.9.3"
},
"dependencies": {
"@ethereum-waffle/chai": "^3.4.4",
- "@remix-project/remix-simulator": "^0.2.52",
+ "@remix-project/remix-simulator": "^0.2.53",
"chai": "^4.3.7",
"ethers": "^5.7.2",
"web3": "^4.1.1"
},
"types": "./src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c"
}
\ No newline at end of file
diff --git a/libs/remix-analyzer/package.json b/libs/remix-analyzer/package.json
index 6550d471ce..0aaf874b51 100644
--- a/libs/remix-analyzer/package.json
+++ b/libs/remix-analyzer/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-analyzer",
- "version": "0.5.61",
+ "version": "0.5.62",
"description": "Tool to perform static analysis on Solidity smart contracts",
"scripts": {
"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/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
- "@remix-project/remix-astwalker": "^0.0.82",
- "@remix-project/remix-lib": "^0.5.59",
+ "@remix-project/remix-astwalker": "^0.0.83",
+ "@remix-project/remix-lib": "^0.5.60",
"async": "^2.6.2",
"ethers": "^5.4.2",
"ethjs-util": "^0.1.6",
@@ -50,6 +50,6 @@
"typescript": "^3.7.5"
},
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c",
"main": "./src/index.js"
}
\ No newline at end of file
diff --git a/libs/remix-api/src/lib/plugins/layout-api.ts b/libs/remix-api/src/lib/plugins/layout-api.ts
new file mode 100644
index 0000000000..cb53309219
--- /dev/null
+++ b/libs/remix-api/src/lib/plugins/layout-api.ts
@@ -0,0 +1,13 @@
+import { IFilePanel } from '@remixproject/plugin-api'
+import { StatusEvents } from '@remixproject/plugin-utils'
+
+export interface ILayoutApi {
+ events:{
+ } & StatusEvents
+ methods: {
+ maximisePinnedPanel: () => void
+ maximiseSidePanel: () => void
+ resetPinnedPanel: () => void
+ resetSidePanel: () => void
+ }
+}
diff --git a/libs/remix-api/src/lib/plugins/matomo-api.ts b/libs/remix-api/src/lib/plugins/matomo-api.ts
new file mode 100644
index 0000000000..9bd368f17c
--- /dev/null
+++ b/libs/remix-api/src/lib/plugins/matomo-api.ts
@@ -0,0 +1,10 @@
+import { IFilePanel } from '@remixproject/plugin-api'
+import { StatusEvents } from '@remixproject/plugin-utils'
+
+export interface IMatomoApi {
+ events:{
+ } & StatusEvents
+ methods: {
+ track: (data: string[]) => void
+ }
+}
diff --git a/libs/remix-api/src/lib/plugins/pinned-panel-api.ts b/libs/remix-api/src/lib/plugins/pinned-panel-api.ts
new file mode 100644
index 0000000000..db3aacf199
--- /dev/null
+++ b/libs/remix-api/src/lib/plugins/pinned-panel-api.ts
@@ -0,0 +1,11 @@
+import { IFilePanel } from '@remixproject/plugin-api'
+import { StatusEvents } from '@remixproject/plugin-utils'
+
+export interface IPinnedPanelApi {
+ events:{
+
+ } & StatusEvents
+ methods: {
+ currentFocus(): Promise
+ }
+}
diff --git a/libs/remix-api/src/lib/plugins/sidePanel-api.ts b/libs/remix-api/src/lib/plugins/sidePanel-api.ts
new file mode 100644
index 0000000000..7f7ccdfd19
--- /dev/null
+++ b/libs/remix-api/src/lib/plugins/sidePanel-api.ts
@@ -0,0 +1,11 @@
+import { IFilePanel } from '@remixproject/plugin-api'
+import { StatusEvents } from '@remixproject/plugin-utils'
+
+export interface ISidePanelApi {
+ events:{
+ focusChanged: (name: string) => void;
+ } & StatusEvents
+ methods: {
+
+ }
+}
diff --git a/libs/remix-api/src/lib/remix-api.ts b/libs/remix-api/src/lib/remix-api.ts
index c2805a602d..71b3536910 100644
--- a/libs/remix-api/src/lib/remix-api.ts
+++ b/libs/remix-api/src/lib/remix-api.ts
@@ -9,6 +9,10 @@ import { INotificationApi } from "./plugins/notification-api"
import { ISettings } from "./plugins/settings-api"
import { IExtendedTerminalApi } from "./plugins/terminal-api"
import { IFilePanelApi } from "./plugins/filePanel-api"
+import { ISidePanelApi } from "./plugins/sidePanel-api"
+import { IPinnedPanelApi } from "./plugins/pinned-panel-api"
+import { ILayoutApi } from "./plugins/layout-api"
+import { IMatomoApi } from "./plugins/matomo-api"
export interface ICustomRemixApi extends IRemixApi {
dgitApi: IGitApi
@@ -21,6 +25,10 @@ export interface ICustomRemixApi extends IRemixApi {
terminal: IExtendedTerminalApi
fs: IFs
filePanel: IFilePanelApi
+ sidePanel: ISidePanelApi
+ pinnedPanel: IPinnedPanelApi
+ layout: ILayoutApi
+ matomo: IMatomoApi
}
export declare type CustomRemixApi = Readonly
\ No newline at end of file
diff --git a/libs/remix-astwalker/package.json b/libs/remix-astwalker/package.json
index a6a82f6cac..6a1cfb3fe3 100644
--- a/libs/remix-astwalker/package.json
+++ b/libs/remix-astwalker/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-astwalker",
- "version": "0.0.82",
+ "version": "0.0.83",
"description": "Tool to walk through Solidity AST",
"main": "src/index.js",
"scripts": {
@@ -37,7 +37,7 @@
"@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
- "@remix-project/remix-lib": "^0.5.59",
+ "@remix-project/remix-lib": "^0.5.60",
"@types/tape": "^4.2.33",
"async": "^2.6.2",
"ethers": "^5.4.2",
@@ -53,6 +53,6 @@
"tap-spec": "^5.0.0"
},
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c",
"types": "./src/index.d.ts"
}
\ No newline at end of file
diff --git a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts
index 54f99a2984..df715721d2 100644
--- a/libs/remix-core-plugin/src/lib/compiler-content-imports.ts
+++ b/libs/remix-core-plugin/src/lib/compiler-content-imports.ts
@@ -1,12 +1,12 @@
'use strict'
import { Plugin } from '@remixproject/engine'
-import { RemixURLResolver } from '@remix-project/remix-url-resolver'
+import { RemixURLResolver, githubFolderResolver } from '@remix-project/remix-url-resolver'
const profile = {
name: 'contentImport',
displayName: 'content import',
version: '0.0.1',
- methods: ['resolve', 'resolveAndSave', 'isExternalUrl']
+ methods: ['resolve', 'resolveAndSave', 'isExternalUrl', 'resolveGithubFolder']
}
export type ResolvedImport = {
@@ -212,4 +212,10 @@ export class CompilerImports extends Plugin {
throw new Error(e)
}
}
+
+ async resolveGithubFolder (url) {
+ const ghFolder = {}
+ await githubFolderResolver(url, ghFolder, 3)
+ return ghFolder
+ }
}
diff --git a/libs/remix-debug/package.json b/libs/remix-debug/package.json
index 72b01e0e9c..5a86998144 100644
--- a/libs/remix-debug/package.json
+++ b/libs/remix-debug/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-debug",
- "version": "0.5.52",
+ "version": "0.5.53",
"description": "Tool to debug Ethereum transactions",
"contributors": [
{
@@ -26,10 +26,10 @@
"@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
- "@remix-project/remix-astwalker": "^0.0.82",
- "@remix-project/remix-lib": "^0.5.59",
- "@remix-project/remix-simulator": "^0.2.52",
- "@remix-project/remix-solidity": "^0.5.38",
+ "@remix-project/remix-astwalker": "^0.0.83",
+ "@remix-project/remix-lib": "^0.5.60",
+ "@remix-project/remix-simulator": "^0.2.53",
+ "@remix-project/remix-solidity": "^0.5.39",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"color-support": "^1.1.3",
@@ -69,6 +69,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-debug#readme",
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c",
"types": "./src/index.d.ts"
}
\ No newline at end of file
diff --git a/libs/remix-lib/package.json b/libs/remix-lib/package.json
index dffc187d0a..c5d8136421 100644
--- a/libs/remix-lib/package.json
+++ b/libs/remix-lib/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-lib",
- "version": "0.5.59",
+ "version": "0.5.60",
"description": "Library to various Remix tools",
"contributors": [
{
@@ -55,6 +55,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-lib#readme",
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c",
"types": "./src/index.d.ts"
-}
+}
\ No newline at end of file
diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts
index bbb19bceb4..621e1c475a 100644
--- a/libs/remix-lib/src/execution/txRunnerWeb3.ts
+++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts
@@ -49,8 +49,6 @@ export class TxRunnerWeb3 {
const receipt = await tryTillReceiptAvailable(resp, this.getWeb3())
tx = await tryTillTxAvailable(resp, this.getWeb3())
currentDateTime = new Date();
- const end = currentDateTime.getTime() / 1000
- console.log('tx duration', end - start)
resolve({
receipt,
tx,
diff --git a/libs/remix-simulator/package.json b/libs/remix-simulator/package.json
index 8a9a1a0bbc..6b45fba53a 100644
--- a/libs/remix-simulator/package.json
+++ b/libs/remix-simulator/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-simulator",
- "version": "0.2.52",
+ "version": "0.2.53",
"description": "Ethereum IDE and tools for the web",
"contributors": [
{
@@ -23,7 +23,7 @@
"@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
"@metamask/eth-sig-util": "^7.0.2",
- "@remix-project/remix-lib": "^0.5.59",
+ "@remix-project/remix-lib": "^0.5.60",
"ansi-gray": "^0.1.1",
"async": "^3.1.0",
"body-parser": "^1.18.2",
@@ -71,6 +71,6 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-simulator#readme",
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55",
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c",
"types": "./src/index.d.ts"
}
\ No newline at end of file
diff --git a/libs/remix-solidity/package.json b/libs/remix-solidity/package.json
index 7a61d805e6..85218ddd77 100644
--- a/libs/remix-solidity/package.json
+++ b/libs/remix-solidity/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-solidity",
- "version": "0.5.38",
+ "version": "0.5.39",
"description": "Tool to load and run Solidity compiler",
"main": "src/index.js",
"types": "src/index.d.ts",
@@ -19,7 +19,7 @@
"@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
- "@remix-project/remix-lib": "^0.5.59",
+ "@remix-project/remix-lib": "^0.5.60",
"async": "^2.6.2",
"eslint-scope": "^5.0.0",
"ethers": "^5.4.2",
@@ -57,5 +57,5 @@
},
"homepage": "https://github.com/ethereum/remix-project/tree/master/libs/remix-solidity#readme",
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c"
}
\ No newline at end of file
diff --git a/libs/remix-tests/package.json b/libs/remix-tests/package.json
index f9db3aae99..c0926f75f4 100644
--- a/libs/remix-tests/package.json
+++ b/libs/remix-tests/package.json
@@ -1,6 +1,6 @@
{
"name": "@remix-project/remix-tests",
- "version": "0.2.52",
+ "version": "0.2.53",
"description": "Tool to test Solidity smart contracts",
"main": "src/index.js",
"types": "./src/index.d.ts",
@@ -41,9 +41,9 @@
"@ethereumjs/tx": "5.3.0",
"@ethereumjs/util": "9.0.3",
"@ethereumjs/vm": "8.0.0",
- "@remix-project/remix-lib": "^0.5.59",
- "@remix-project/remix-simulator": "^0.2.52",
- "@remix-project/remix-solidity": "^0.5.38",
+ "@remix-project/remix-lib": "^0.5.60",
+ "@remix-project/remix-simulator": "^0.2.53",
+ "@remix-project/remix-solidity": "^0.5.39",
"@remix-project/remix-url-resolver": "^0.0.42",
"ansi-gray": "^0.1.1",
"async": "^2.6.0",
@@ -89,5 +89,5 @@
"@ethereumjs/trie": "6.2.0"
},
"typings": "src/index.d.ts",
- "gitHead": "35e1469e94bb370f5427d4ab230fcbd47c665e55"
+ "gitHead": "cc2850c7fb3f1e50b0d65437a74ccae19c74b87c"
}
\ No newline at end of file
diff --git a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
index 0c57ebaffb..009cb410b6 100644
--- a/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
+++ b/libs/remix-ui/app/src/lib/remix-app/components/dragbar/dragbar.tsx
@@ -41,7 +41,6 @@ const DragBar = (props: IRemixDragBarUi) => {
}, [props.hidden, offset])
useEffect(() => {
- initialWidth.current = props.refObject.current.clientWidth
if (props.maximiseTrigger > 0) {
if (props.layoutPosition === 'left') {
const width = 0.4 * window.innerWidth
@@ -106,6 +105,7 @@ const DragBar = (props: IRemixDragBarUi) => {
setTimeout(() => {
props.setHideStatus(false)
setDragBarPosX(offset + props.refObject.current.offsetWidth)
+ initialWidth.current = props.refObject.current.clientWidth
}, 300)
}
} else if (props.layoutPosition === 'right') {
@@ -117,9 +117,11 @@ const DragBar = (props: IRemixDragBarUi) => {
setTimeout(() => {
props.setHideStatus(false)
setDragBarPosX(props.refObject.current.offsetLeft)
+ initialWidth.current = props.refObject.current.clientWidth
}, 300)
}
}
+
}
function startDrag() {
diff --git a/libs/remix-ui/clipboard/src/lib/copy-to-clipboard/copy-to-clipboard.tsx b/libs/remix-ui/clipboard/src/lib/copy-to-clipboard/copy-to-clipboard.tsx
index b4a4b5f66a..2ae17389e6 100644
--- a/libs/remix-ui/clipboard/src/lib/copy-to-clipboard/copy-to-clipboard.tsx
+++ b/libs/remix-ui/clipboard/src/lib/copy-to-clipboard/copy-to-clipboard.tsx
@@ -14,9 +14,10 @@ interface ICopyToClipboard {
title?: string
children?: JSX.Element
getContent?: () => any
+ callback?: () => void
}
export const CopyToClipboard = (props: ICopyToClipboard) => {
- const { tip = 'Copy', icon = 'fa-copy', direction = 'right', getContent, children, ...otherProps } = props
+ const { tip = 'Copy', icon = 'fa-copy', direction = 'right', getContent, children, callback, ...otherProps } = props
let { content } = props
const [message, setMessage] = useState(tip)
@@ -29,6 +30,7 @@ export const CopyToClipboard = (props: ICopyToClipboard) => {
if (typeof content !== 'string') {
content = JSON.stringify(content, null, '\t')
}
+ callback && callback()
copy(content)
setMessage('Copied')
} catch (e) {
diff --git a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
index 6c0b67e705..6baeaec1fc 100644
--- a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
+++ b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
@@ -117,7 +117,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
};
this.completionEnabled = false
- const handleCompletionTimer = new CompletionTimer(1000, () => { this.completionEnabled = true });
+ const handleCompletionTimer = new CompletionTimer(100, () => { this.completionEnabled = true });
handleCompletionTimer.start()
return {
@@ -150,7 +150,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
// handle the completion timer by locking suggestions request for 2 seconds
this.completionEnabled = false
- const handleCompletionTimer = new CompletionTimer(2000, () => { this.completionEnabled = true });
+ const handleCompletionTimer = new CompletionTimer(100, () => { this.completionEnabled = true });
handleCompletionTimer.start()
return {
diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
index 686c014383..658eb20fba 100644
--- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
+++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
@@ -699,6 +699,7 @@ export const EditorUI = (props: EditorUIProps) => {
}
props.plugin.call('notification', 'alert', modalContent)
pasteCodeRef.current = true
+ _paq.push(['trackEvent', 'editor', 'onDidPaste', 'more_than_10_lines'])
}
})
diff --git a/libs/remix-ui/git/src/components/branchHeader.tsx b/libs/remix-ui/git/src/components/branchHeader.tsx
index debb86bd5a..91647687c0 100644
--- a/libs/remix-ui/git/src/components/branchHeader.tsx
+++ b/libs/remix-ui/git/src/components/branchHeader.tsx
@@ -33,7 +33,7 @@ export const BranchHeader = () => {
}
}
}
- }, [context.currentBranch, context.commits, context.branches, context.remotes, context.currentHead])
+ }, [context.currentBranch, context.commits, context.branches, context.remotes, context.currentHead, context.defaultRemote])
useEffect(() => {
if (context.fileStatusResult) {
@@ -43,6 +43,14 @@ export const BranchHeader = () => {
}
}, [context.fileStatusResult, context.modified, context.allchangesnotstaged, context.untracked, context.deleted])
+ const getName = () => {
+ const url = context.currentBranch?.remote?.url
+ if (!url) return
+ const regex = /https:\/\/github\.com\/[^/]+\/([^/]+)(?:\.git)?/;
+ const match = url.match(regex)
+ return match ? match[1] : null
+ }
+
const showDetachedWarningText = async () => {
await pluginActions.showAlert({
message: `You are in 'detached HEAD' state. This means you are not on a branch because you checkout a tag or a specific commit. If you want to commit changes, you will need to create a new branch.`,
@@ -50,21 +58,50 @@ export const BranchHeader = () => {
})
}
+ const Heading = () => {
+ return (
+
+
+
+ {getName() ? (
+
+ {getName() ?? ''}
+ {context.currentBranch && context.currentBranch.remote && context.currentBranch.remote.name ? ` on ${context.currentBranch.remote.name}` : ''}
+
+ ) : null
+ }
+ {context.currentBranch && context.currentBranch.name ?
+
+ {context.currentBranch && context.currentBranch.name}{changed?'*':''}
+ : null}
+ {(latestCommit && latestCommit.commit && latestCommit.commit.message) ?
+
+ {latestCommit ?
+ latestCommit.commit && latestCommit.commit.message ? `"${latestCommit.commit.message}"` : '' : null}
+
+ : null}
+ {isDetached ?
+
+ {isDetached ?
+ <>You are in a detached state > : null}
+
+ : null}
+ {context.storage.enabled ?
+
+ {context.storage.used} MB used
+ ({context.storage.percentUsed} %)
+
+ : null}
+
+
+
+ )
+ }
+
return (<>
-
-
- {changed ? '*' : ''}{context.currentBranch && context.currentBranch.name}
-
- {latestCommit ?
-
- {latestCommit.commit && latestCommit.commit.message ? latestCommit.commit.message : ''}
-
: null}
- {isDetached ?
-
- You are in a detached state
-
: null}
+
>)
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/buttons/commitmessage.tsx b/libs/remix-ui/git/src/components/buttons/commitmessage.tsx
index 17fc807a79..e5726df46c 100644
--- a/libs/remix-ui/git/src/components/buttons/commitmessage.tsx
+++ b/libs/remix-ui/git/src/components/buttons/commitmessage.tsx
@@ -126,7 +126,7 @@ export const CommitMessage = () => {
return (
<>
-
+
await commit()} >
@@ -144,4 +144,4 @@ export const CommitMessage = () => {
>
);
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/buttons/gituibutton.tsx b/libs/remix-ui/git/src/components/buttons/gituibutton.tsx
index 7556829c13..ee8c68a11b 100644
--- a/libs/remix-ui/git/src/components/buttons/gituibutton.tsx
+++ b/libs/remix-ui/git/src/components/buttons/gituibutton.tsx
@@ -1,5 +1,6 @@
import React, { useContext } from 'react'
import { gitPluginContext } from '../gitui'
+import { CustomTooltip } from '@remix-ui/helper';
interface ButtonWithContextProps {
onClick: React.MouseEventHandler;
@@ -7,18 +8,31 @@ interface ButtonWithContextProps {
disabledCondition?: boolean; // Optional additional disabling condition
// You can add other props if needed, like 'type', 'className', etc.
[key: string]: any; // Allow additional props to be passed
+ tooltip?: string;
}
// This component extends a button, disabling it when loading is true
-const GitUIButton = ({ children, disabledCondition = false, ...rest }:ButtonWithContextProps) => {
+const GitUIButton = ({ children, disabledCondition = false, ...rest }: ButtonWithContextProps) => {
const { loading } = React.useContext(gitPluginContext)
const isDisabled = loading || disabledCondition
- return (
-
- {children}
-
- );
+
+ if (rest.tooltip) {
+
+ return (
+
+
+ {children}
+
+
+ );
+ } else {
+ return (
+
+ {children}
+
+ );
+ }
};
export default GitUIButton;
\ No newline at end of file
diff --git a/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx b/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx
index 64d36df050..628e57f0fb 100644
--- a/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx
+++ b/libs/remix-ui/git/src/components/buttons/sourceControlBase.tsx
@@ -44,7 +44,10 @@ export const SourceControlBase = (props: SourceControlButtonsProps) => {
}, [context.branchDifferences, context.currentBranch, branch, remote])
const setDefaultRemote = () => {
-
+ if (context.defaultRemote) {
+ setRemote(context.defaultRemote)
+ return
+ }
if (context.remotes.length > 0) {
// find remote called origin
const origin = context.remotes.find(remote => remote.name === 'origin')
diff --git a/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx b/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx
index 22879e9a94..c8273914bc 100644
--- a/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx
+++ b/libs/remix-ui/git/src/components/buttons/sourcecontrolbuttons.tsx
@@ -5,9 +5,11 @@ import React, { useEffect, useState } from "react"
import { FormattedMessage } from "react-intl"
import { gitActionsContext } from "../../state/context"
import { branch, remote } from "@remix-api"
+import { gitMatomoEventTypes } from "../../types"
import { gitPluginContext } from "../gitui"
import GitUIButton from "./gituibutton"
import { syncStateContext } from "./sourceControlBase"
+import { sendToMatomo } from "../../lib/pluginActions"
export const SourceControlButtons = () => {
const context = React.useContext(gitPluginContext)
@@ -51,6 +53,7 @@ export const SourceControlButtons = () => {
}
const refresh = async() => {
+ await sendToMatomo(gitMatomoEventTypes.REFRESH)
await actions.getFileStatusMatrix(null)
await actions.gitlog()
}
diff --git a/libs/remix-ui/git/src/components/github/branchselect.tsx b/libs/remix-ui/git/src/components/github/branchselect.tsx
index e272f266f9..1e87e195e9 100644
--- a/libs/remix-ui/git/src/components/github/branchselect.tsx
+++ b/libs/remix-ui/git/src/components/github/branchselect.tsx
@@ -38,7 +38,7 @@ export const BranchSelect = (props: BranchySelectProps) => {
return (<>{branchOptions && branchOptions.length ?
selectRemoteBranch(e)}
theme={selectTheme}
diff --git a/libs/remix-ui/git/src/components/github/devicecode.tsx b/libs/remix-ui/git/src/components/github/devicecode.tsx
index cd611efe4d..85922441fd 100644
--- a/libs/remix-ui/git/src/components/github/devicecode.tsx
+++ b/libs/remix-ui/git/src/components/github/devicecode.tsx
@@ -4,6 +4,8 @@ import { gitPluginContext } from "../gitui";
import axios from "axios";
import { CopyToClipboard } from "@remix-ui/clipboard";
import { Card } from "react-bootstrap";
+import { sendToMatomo } from "../../lib/pluginActions";
+import { gitMatomoEventTypes } from "../../types";
export const GetDeviceCode = () => {
const context = React.useContext(gitPluginContext)
@@ -13,7 +15,7 @@ export const GetDeviceCode = () => {
const [authorized, setAuthorized] = React.useState(false)
const getDeviceCodeFromGitHub = async () => {
-
+ await sendToMatomo(gitMatomoEventTypes.GETGITHUBDEVICECODE)
setAuthorized(false)
// Send a POST request
const response = await axios({
@@ -36,6 +38,7 @@ export const GetDeviceCode = () => {
}
const connectApp = async () => {
+ await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUB)
// poll https://github.com/login/oauth/access_token
const accestokenresponse = await axios({
method: 'post',
@@ -56,13 +59,17 @@ export const GetDeviceCode = () => {
if (response.access_token) {
setAuthorized(true)
+ await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUBSUCCESS)
await pluginActions.saveToken(response.access_token)
await actions.loadGitHubUserFromToken()
+ } else {
+ await sendToMatomo(gitMatomoEventTypes.CONNECTTOGITHUBFAIL)
}
}
const disconnect = async () => {
+ await sendToMatomo(gitMatomoEventTypes.DISCONNECTFROMGITHUB)
setAuthorized(false)
setGitHubResponse(null)
await pluginActions.saveToken(null)
@@ -71,10 +78,11 @@ export const GetDeviceCode = () => {
return (
<>
- {(context.gitHubUser && context.gitHubUser.login) ? null :
- {
- getDeviceCodeFromGitHub();
- }}> Login in with github
+ {(context.gitHubUser && context.gitHubUser.login) ? null : <>
+ Connect to GitHub
+ {
+ await getDeviceCodeFromGitHub()
+ }}> Login in with github >
}
{gitHubResponse && !authorized &&
@@ -83,7 +91,7 @@ export const GetDeviceCode = () => {
@@ -107,21 +115,29 @@ export const GetDeviceCode = () => {
{
(context.gitHubUser && context.gitHubUser.login) ?
-
-
- Connected as {context.gitHubUser.login}
-
+
+ Connected as {context.gitHubUser.login}
+
+ {context.gitHubUser.avatar_url ?
+
: null}
+
+
+
+ {context.gitHubUser.html_url ? <>
+
user on github:
+
{context.gitHubUser.html_url} > : null}
+ {context.userEmails && context.userEmails.length > 0 ? <>
+
email:
{context.userEmails && context.userEmails.filter((email: any) => email.primary).map((email: any) => {
return
{email.email}
- })}
-
-
-
+ })}> : null}
+
+
: null
}
>)
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/github/repositoryselect.tsx b/libs/remix-ui/git/src/components/github/repositoryselect.tsx
index 6d8aabb91b..72b055ba9a 100644
--- a/libs/remix-ui/git/src/components/github/repositoryselect.tsx
+++ b/libs/remix-ui/git/src/components/github/repositoryselect.tsx
@@ -1,14 +1,15 @@
import React, { useState, useEffect } from 'react';
-import { Button } from 'react-bootstrap';
import Select from 'react-select';
import { gitActionsContext } from '../../state/context';
import { repository } from '@remix-api';
+import { gitMatomoEventTypes } from '../../types';
import { selectStyles, selectTheme } from '../../types/styles';
import { gitPluginContext } from '../gitui';
-import { TokenWarning } from '../panels/tokenWarning';
+import { sendToMatomo } from '../../lib/pluginActions';
interface RepositorySelectProps {
select: (repo: repository) => void;
+ title: string;
}
const RepositorySelect = (props: RepositorySelectProps) => {
@@ -17,6 +18,7 @@ const RepositorySelect = (props: RepositorySelectProps) => {
const actions = React.useContext(gitActionsContext)
const [loading, setLoading] = useState(false)
const [show, setShow] = useState(false)
+ const [selected, setSelected] = useState
(null)
useEffect(() => {
if (context.repositories && context.repositories.length > 0) {
@@ -38,6 +40,7 @@ const RepositorySelect = (props: RepositorySelectProps) => {
const selectRepo = async (e: any) => {
if (!e || !e.value) {
props.select(null)
+ setSelected(null)
return
}
const value = e && e.value
@@ -48,11 +51,13 @@ const RepositorySelect = (props: RepositorySelectProps) => {
if (repo) {
props.select(repo)
+ setSelected(repo)
await actions.remoteBranches(repo.owner.login, repo.name)
}
}
const fetchRepositories = async () => {
+ await sendToMatomo(gitMatomoEventTypes.LOADREPOSITORIESFROMGITHUB)
try {
setShow(true)
setLoading(true)
@@ -64,22 +69,25 @@ const RepositorySelect = (props: RepositorySelectProps) => {
};
return (
- <>
- Fetch Repositories from GitHub
-
+ <>
+ {props.title}
+
{
show ?
- selectRepo(e)}
- theme={selectTheme}
- styles={selectStyles}
- isClearable={true}
- placeholder="Type to search for a repository..."
- isLoading={loading}
- /> : null
+ <>
+ selectRepo(e)}
+ theme={selectTheme}
+ styles={selectStyles}
+ isClearable={true}
+ placeholder="Type to search for a repository..."
+ isLoading={loading}
+ />
+ { selected ? null : Please select a repository }
+ >: null
}>
);
};
diff --git a/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx b/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx
index 497f5b6e1f..9c3e879c71 100644
--- a/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx
+++ b/libs/remix-ui/git/src/components/github/selectandclonerepositories.tsx
@@ -18,7 +18,7 @@ export const SelectAndCloneRepositories = (props: RepositoriesProps) => {
const [branch, setBranch] = useState({ name: "" });
const [repo, setRepo] = useState(null);
- const selectRemoteBranch = async (branch:{ name: string }) => {
+ const selectRemoteBranch = async (branch: { name: string }) => {
setBranch(branch)
}
@@ -43,16 +43,19 @@ export const SelectAndCloneRepositories = (props: RepositoriesProps) => {
return (
<>
+
-
- {repo && }
+ {repo && }
{repo && branch && branch.name && branch.name !== '0' ?
{
await clone()
}}>clone {repo.full_name}:{branch.name} : null}
+ {repo && (!branch || branch.name === '0') ?
+ Please select a branch to clone : null}
+
>
)
}
diff --git a/libs/remix-ui/git/src/components/gitui.tsx b/libs/remix-ui/git/src/components/gitui.tsx
index 9a4289b1d5..814ad4cdd8 100644
--- a/libs/remix-ui/git/src/components/gitui.tsx
+++ b/libs/remix-ui/git/src/components/gitui.tsx
@@ -1,10 +1,10 @@
import React, { useEffect, useReducer, useState, useContext } from 'react'
import { add, addall, checkout, checkoutfile, clone, commit, createBranch, remoteBranches, repositories, rm, getCommitChanges, diff, resolveRef, getBranchCommits, setUpstreamRemote, loadGitHubUserFromToken, getBranches, getRemotes, remoteCommits, saveGitHubCredentials, getGitHubCredentialsFromLocalStorage, fetch, pull, push, setDefaultRemote, addRemote, removeRemote, sendToGitLog, clearGitLog, getBranchDifferences, getFileStatusMatrix, init, showAlert, gitlog } from '../lib/gitactions'
import { loadFiles, setCallBacks } from '../lib/listeners'
-import { openDiff, openFile, openFolderInSameWindow, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions'
+import { openDiff, openFile, openFolderInSameWindow, sendToMatomo, saveToken, setModifiedDecorator, setPlugin, setUntrackedDecorator, statusChanged } from '../lib/pluginActions'
import { gitActionsContext, pluginActionsContext } from '../state/context'
import { gitReducer } from '../state/gitreducer'
-import { defaultGitState, defaultLoaderState, gitState, loaderState } from '../types'
+import { defaultGitState, defaultLoaderState, gitMatomoEventTypes, gitState, gitUIPanels, loaderState } from '../types'
import { Accordion } from "react-bootstrap";
import { CommitMessage } from './buttons/commitmessage'
import { Commits } from './panels/commits'
@@ -31,8 +31,8 @@ import { SourceControl } from './panels/sourcontrol'
import { GitHubCredentials } from './panels/githubcredentials'
import { Setup } from './panels/setup'
import { Init } from './panels/init'
-import { CustomRemixApi } from "@remix-api";
-import { Plugin } from "@remixproject/engine";
+import { CustomRemixApi } from "@remix-api"
+import { Plugin } from "@remixproject/engine"
import { Disabled } from './disabled'
import { platformContext } from '@remix-ui/app'
import { Version } from './panels/version'
@@ -122,6 +122,13 @@ export const GitUI = (props: IGitUi) => {
}, [gitState.gitHubUser, gitState.currentBranch, gitState.remotes, gitState.gitHubAccessToken, gitState.currentHead])
+ useEffect(() => {
+ const panelName = Object.keys(gitUIPanels)
+ .filter(k => gitUIPanels[k] === activePanel);
+ if (!(panelName && panelName[0])) return
+ sendToMatomo(gitMatomoEventTypes.OPENPANEL, [panelName && panelName[0]])
+ }, [activePanel])
+
const gitActionsProviderValue = {
commit,
addall,
@@ -168,9 +175,8 @@ export const GitUI = (props: IGitUi) => {
}
return (
- <>{(!gitState.canUseApp) ?
- :
-
+ <>{(!gitState.canUseApp) ?
:
+
@@ -180,68 +186,67 @@ export const GitUI = (props: IGitUi) => {
{setup && !needsInit ? : null}
{needsInit ? : null}
{!setup && !needsInit ?
- <>
-
-
-
-
- <>
-
-
- >
-
-
-
-
- <>
-
- >
-
-
-
-
- <>
-
- >
-
-
-
-
- <>
- >
-
-
-
-
- <>
-
- >
-
-
-
-
- <>
- >
-
-
-
-
- <>
-
-
-
- >
-
-
-
-
- <>
-
- >
-
-
-
- >
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
: null}
@@ -250,4 +255,4 @@ export const GitUI = (props: IGitUi) => {
}
>
)
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/navigation/branchedetails.tsx b/libs/remix-ui/git/src/components/navigation/branchedetails.tsx
index 40a40c5b70..502a1244d4 100644
--- a/libs/remix-ui/git/src/components/navigation/branchedetails.tsx
+++ b/libs/remix-ui/git/src/components/navigation/branchedetails.tsx
@@ -5,6 +5,7 @@ import { gitActionsContext } from "../../state/context";
import { branch } from "@remix-api";
import GitUIButton from "../buttons/gituibutton";
import { gitPluginContext } from "../gitui";
+import { removeGitFromUrl } from "../../utils";
interface BrancheDetailsNavigationProps {
eventKey: string;
@@ -12,10 +13,11 @@ interface BrancheDetailsNavigationProps {
callback: (eventKey: string) => void;
branch: branch;
checkout: (branch: branch) => void;
+ allowCheckout: boolean;
}
export const BrancheDetailsNavigation = (props: BrancheDetailsNavigationProps) => {
- const { eventKey, activePanel, callback, branch, checkout } = props;
+ const { eventKey, activePanel, callback, branch, checkout, allowCheckout } = props;
const context = React.useContext(gitPluginContext)
const actions = React.useContext(gitActionsContext)
const handleClick = () => {
@@ -33,7 +35,7 @@ export const BrancheDetailsNavigation = (props: BrancheDetailsNavigationProps) =
const openRemote = () => {
const remote = branch.remote || getRemote()
- window.open(`${remote.url}/tree/${branch.name}`, '_blank');
+ window.open(`${removeGitFromUrl(remote.url)}/tree/${branch.name}`, '_blank');
}
const reloadBranch = () => {
@@ -55,6 +57,10 @@ export const BrancheDetailsNavigation = (props: BrancheDetailsNavigationProps) =
}
+ if (branch.name === 'HEAD'){
+ return null;
+ }
+
return (
<>
@@ -63,30 +69,31 @@ export const BrancheDetailsNavigation = (props: BrancheDetailsNavigationProps) =
activePanel === eventKey ?
:
}
-
{branch.name} {branch.remote ? `on ${branch.remote.name}` : ''}
+
{branch.name} {branch.remote ? `on ${branch.remote.name}` : ''}
- {context.currentBranch && context.currentBranch.name === branch.name ?
-
{ }}>
-
-
- :
-
checkout(branch)}>
-
-
- }
+ {allowCheckout ?
+ context.currentBranch && context.currentBranch.name === branch.name ?
+
{ }}>
+
+
+ :
+
checkout(branch)}>
+
+
+ : null}
{!branch.remote && canFetch() && <>
-
fetchBranch()}>
-
openRemote()}>
+
fetchBranch()}>
+
openRemote()}>
>}
{branch.remote?.url && <>
-
reloadBranch()}>
+ reloadBranch()}>
>}
{branch.remote?.url && <>
- openRemote()}>
+ openRemote()}>
>}
diff --git a/libs/remix-ui/git/src/components/navigation/branches.tsx b/libs/remix-ui/git/src/components/navigation/branches.tsx
index b9dd9b06f2..21decc6e7a 100644
--- a/libs/remix-ui/git/src/components/navigation/branches.tsx
+++ b/libs/remix-ui/git/src/components/navigation/branches.tsx
@@ -23,10 +23,10 @@ export const BranchesNavigation = ({ eventKey, activePanel, callback }) => {
{
activePanel === eventKey ? :
}
- BRANCHES
+ BRANCHES
>
);
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/navigation/clone.tsx b/libs/remix-ui/git/src/components/navigation/clone.tsx
index ee9e1579bf..d81c8fc9ca 100644
--- a/libs/remix-ui/git/src/components/navigation/clone.tsx
+++ b/libs/remix-ui/git/src/components/navigation/clone.tsx
@@ -20,10 +20,10 @@ export const CloneNavigation = ({ eventKey, activePanel, callback }) => {
{
activePanel === eventKey ? :
}
- CLONE
+ CLONE
>
);
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/navigation/commands.tsx b/libs/remix-ui/git/src/components/navigation/commands.tsx
index 9a3b3f03df..0a035beabe 100644
--- a/libs/remix-ui/git/src/components/navigation/commands.tsx
+++ b/libs/remix-ui/git/src/components/navigation/commands.tsx
@@ -21,15 +21,14 @@ export const CommandsNavigation = ({ eventKey, activePanel, callback }) => {
return (
<>
- handleClick()} role={'button'} className='nav d-flex justify-content-start align-items-center w-75'>
+ handleClick()} role={'button'} className="nav d-flex justify-content-start align-items-center w-75">
{
activePanel === eventKey ? :
}
- COMMANDS
-
-
+ COMMANDS
+
>
);
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/navigation/commitdetails.tsx b/libs/remix-ui/git/src/components/navigation/commitdetails.tsx
index 1cae572a00..2e49875f52 100644
--- a/libs/remix-ui/git/src/components/navigation/commitdetails.tsx
+++ b/libs/remix-ui/git/src/components/navigation/commitdetails.tsx
@@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import React, { useContext, useEffect } from "react";
import { CommitSummary } from "../panels/commits/commitsummary";
import { ReadCommitResult } from "isomorphic-git"
+import { branch } from "../../types";
interface CommitDetailsNavigationProps {
commit: ReadCommitResult,
@@ -11,10 +12,11 @@ interface CommitDetailsNavigationProps {
activePanel: string
callback: (eventKey: string) => void
isAheadOfRepo: boolean
+ branch: branch
}
export const CommitDetailsNavigation = (props: CommitDetailsNavigationProps) => {
- const { commit, checkout, eventKey, activePanel, callback, isAheadOfRepo } = props;
+ const { commit, checkout, eventKey, activePanel, callback, isAheadOfRepo, branch } = props;
const handleClick = () => {
if (!callback) return
if (activePanel === eventKey) {
@@ -30,7 +32,7 @@ export const CommitDetailsNavigation = (props: CommitDetailsNavigationProps) =>
activePanel === eventKey ? :
}
-
+
>
);
diff --git a/libs/remix-ui/git/src/components/navigation/commits.tsx b/libs/remix-ui/git/src/components/navigation/commits.tsx
index a3c59950e3..44c9299eb8 100644
--- a/libs/remix-ui/git/src/components/navigation/commits.tsx
+++ b/libs/remix-ui/git/src/components/navigation/commits.tsx
@@ -48,9 +48,8 @@ export const CommitsNavigation = ({ eventKey, activePanel, callback, title, bran
}
{ahead? : null}
{behind? : null}
- {title}
+ {title}
-
{showButtons ?
@@ -60,4 +59,4 @@ export const CommitsNavigation = ({ eventKey, activePanel, callback, title, bran
>
);
-}
\ No newline at end of file
+}
diff --git a/libs/remix-ui/git/src/components/navigation/github.tsx b/libs/remix-ui/git/src/components/navigation/github.tsx
index 2e45e3317a..5324cfbdbb 100644
--- a/libs/remix-ui/git/src/components/navigation/github.tsx
+++ b/libs/remix-ui/git/src/components/navigation/github.tsx
@@ -1,7 +1,7 @@
-import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import React, { } from "react";
-import { pluginActionsContext } from "../../state/context";
+import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons"
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import React, { } from "react"
+import { pluginActionsContext } from "../../state/context"
export const GitHubNavigation = ({ eventKey, activePanel, callback }) => {
const pluginactions = React.useContext(pluginActionsContext)
@@ -21,9 +21,9 @@ export const GitHubNavigation = ({ eventKey, activePanel, callback }) => {
{
activePanel === eventKey ?