diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts index 19918de0c4..e55ae8d6fd 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.test.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts @@ -205,6 +205,7 @@ module.exports = { .clickLaunchIcon('debugger') .waitForElementVisible('*[data-id="slider"]') .goToVMTraceStep(154) + .scrollInto('*[data-id="stepdetail"]') .waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n154', 60000) }, diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 5bf3b34d5d..21832de532 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -9,10 +9,11 @@ const testData = { // 99266d6da54cc12f37f11586e8171546c7700d67 module.exports = { + '@disabled': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done) }, - UploadToGists: function (browser: NightwatchBrowser) { + 'UploadToGists #group1': function (browser: NightwatchBrowser) { /* - set the access token - publish to gist @@ -68,7 +69,7 @@ module.exports = { */ }, - 'Load Gist Modal': function (browser: NightwatchBrowser) { + 'Load Gist Modal #group1': function (browser: NightwatchBrowser) { browser.clickLaunchIcon('home') .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .clickLaunchIcon('filePanel') @@ -84,7 +85,7 @@ module.exports = { .modalFooterCancelClick('gisthandler') }, - 'Display Error Message For Invalid Gist ID': function (browser: NightwatchBrowser) { + 'Display Error Message For Invalid Gist ID #group1': function (browser: NightwatchBrowser) { browser .pause(1000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) @@ -101,7 +102,7 @@ module.exports = { .modalFooterOKClick('gisthandler') }, - 'Display Error Message For Missing Gist Token When Publishing': function (browser: NightwatchBrowser) { + 'Display Error Message For Missing Gist Token When Publishing #group1': function (browser: NightwatchBrowser) { browser .pause(1000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) @@ -125,7 +126,7 @@ module.exports = { .click('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') }, - 'Import From Gist For Valid Gist ID': function (browser: NightwatchBrowser) { + 'Import From Gist For Valid Gist ID #group2': function (browser: NightwatchBrowser) { browser .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .clickLaunchIcon('settings') @@ -140,6 +141,7 @@ module.exports = { }) .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId) .modalFooterOKClick('gisthandler') + .pause(10000) .openFile(`gist-${testData.validGistId}/README.txt`) .waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/README.txt']`) .assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt') diff --git a/apps/remix-ide-e2e/src/tests/vyper_api.ts b/apps/remix-ide-e2e/src/tests/vyper_api.ts index f168372963..bb0afc3859 100644 --- a/apps/remix-ide-e2e/src/tests/vyper_api.ts +++ b/apps/remix-ide-e2e/src/tests/vyper_api.ts @@ -21,25 +21,30 @@ module.exports = { .frame(0) }, - 'Should add the Ballot.vy #group1': function (browser: NightwatchBrowser) { - browser.click('button[data-id="add-ballot"]') + 'Should clone the Vyper repo #group1': function (browser: NightwatchBrowser) { + browser.click('button[data-id="add-repository"]') .frameParent() - .openFile('ballot.vy') + .waitForElementContainsText('*[data-shared="tooltipPopup"]', 'Vyper repository cloned', 30000) + .openFile('examples') + .openFile('examples/auctions') + .openFile('examples/auctions/blind_auction.vy') }, - 'Compile ballot.vy should error #group1': function (browser: NightwatchBrowser) { + 'Compile blind_auction should success #group1': function (browser: NightwatchBrowser) { browser.clickLaunchIcon('vyper') // @ts-ignore .frame(0) .click('[data-id="remote-compiler"]') .click('[data-id="compile"]') - .assert.containsText('[data-id="error-message"]', 'unexpected indent') + .waitForElementVisible('[data-id="copy-abi"]') }, - 'Compile test contract should success #group1': function (browser: NightwatchBrowser) { + 'Compile test contract and deploy to remix VM #group1': function (browser: NightwatchBrowser) { let contractAddress browser .frameParent() + .clickLaunchIcon('filePanel') + .switchWorkspace('default_workspace') .addFile('test.vy', { content: testContract }) .clickLaunchIcon('vyper') // @ts-ignore diff --git a/apps/remix-ide/src/app/tabs/debugger-tab.js b/apps/remix-ide/src/app/tabs/debugger-tab.js index a06db0c508..5e62bd93d4 100644 --- a/apps/remix-ide/src/app/tabs/debugger-tab.js +++ b/apps/remix-ide/src/app/tabs/debugger-tab.js @@ -3,7 +3,7 @@ import { DebuggerApiMixin } from '@remixproject/debugger-plugin' // eslint-disab import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line -import * as remixBleach from '../../lib/remixBleach' +import { bleach } from '@remix-ui/helper' import { compilationFinishedToastMsg, compilingToastMsg, localCompilationToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper' const css = require('./styles/debugger-tab-styles') @@ -51,7 +51,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => { this.call('notification', 'toast', sourceVerificationNotAvailableToastMsg()) }) - return
+ return
} showMessage (title, message) { @@ -59,7 +59,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { this.call('notification', 'alert', { id: 'debuggerTabShowMessage', title, - message: remixBleach.sanitize(message) + message: bleach.sanitize(message) }) } catch (e) { console.log(e) diff --git a/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js b/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js index 6a15d2cf56..3fb7add424 100644 --- a/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js +++ b/apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js @@ -1,9 +1,6 @@ var csjs = require('csjs-inject') const css = csjs` - .debuggerTabView { - padding: 2%; - } .debugger { margin-bottom: 1%; } diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css index f95afd68ec..98d4b409c3 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css @@ -34,6 +34,7 @@ --dark:#343a40; --body-bg: #fff; --text-bg-mark: #fcf8e3; + --custom-select: #fff; --breakpoint-xs:0; --breakpoint-sm:576px; --breakpoint-md:768px; @@ -435,25 +436,25 @@ pre code { .container,.container-sm { max-width:540px } - + } @media (min-width:768px) { .container,.container-md,.container-sm { max-width:720px } - + } @media (min-width:992px) { .container,.container-lg,.container-md,.container-sm { max-width:960px } - + } @media (min-width:1200px) { .container,.container-lg,.container-md,.container-sm,.container-xl { max-width:1140px } - + } .row { display:-ms-flexbox; @@ -873,7 +874,7 @@ pre code { .offset-sm-11 { margin-left:91.666667% } - + } @media (min-width:768px) { .col-md { @@ -1075,7 +1076,7 @@ pre code { .offset-md-11 { margin-left:91.666667% } - + } @media (min-width:992px) { .col-lg { @@ -1277,7 +1278,7 @@ pre code { .offset-lg-11 { margin-left:91.666667% } - + } @media (min-width:1200px) { .col-xl { @@ -1479,7 +1480,7 @@ pre code { .offset-xl-11 { margin-left:91.666667% } - + } .table { width:100%; @@ -1662,7 +1663,7 @@ pre code { .table-responsive-sm>.table-bordered { border:0 } - + } @media (max-width:767.98px) { .table-responsive-md { @@ -1674,7 +1675,7 @@ pre code { .table-responsive-md>.table-bordered { border:0 } - + } @media (max-width:991.98px) { .table-responsive-lg { @@ -1686,7 +1687,7 @@ pre code { .table-responsive-lg>.table-bordered { border:0 } - + } @media (max-width:1199.98px) { .table-responsive-xl { @@ -1698,7 +1699,7 @@ pre code { .table-responsive-xl>.table-bordered { border:0 } - + } .table-responsive { display:block; @@ -1728,7 +1729,7 @@ pre code { .form-control { transition:none } - + } .form-control::-ms-expand { background-color:transparent; @@ -2114,7 +2115,7 @@ textarea.form-control { .form-inline .custom-control-label { margin-bottom:0 } - + } .btn { display:inline-block; @@ -2138,7 +2139,7 @@ textarea.form-control { .btn { transition:none } - + } .btn:hover { color:#495057; @@ -2626,7 +2627,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .fade { transition:none } - + } .fade:not(.show) { opacity:0 @@ -2644,7 +2645,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .collapsing { transition:none } - + } .dropdown,.dropleft,.dropright,.dropup { position:relative @@ -2701,7 +2702,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- right:0; left:auto } - + } @media (min-width:768px) { .dropdown-menu-md-left { @@ -2712,7 +2713,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- right:0; left:auto } - + } @media (min-width:992px) { .dropdown-menu-lg-left { @@ -2723,7 +2724,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- right:0; left:auto } - + } @media (min-width:1200px) { .dropdown-menu-xl-left { @@ -2734,7 +2735,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- right:0; left:auto } - + } .dropup .dropdown-menu { top:auto; @@ -3190,7 +3191,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .custom-switch .custom-control-label::after { transition:none } - + } .custom-switch .custom-control-input:checked~.custom-control-label::after { background-color:#fff; @@ -3356,7 +3357,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- -webkit-transition:none; transition:none } - + } .custom-range::-webkit-slider-thumb:active { background-color:#cfeaf9 @@ -3386,7 +3387,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- -moz-transition:none; transition:none } - + } .custom-range::-moz-range-thumb:active { background-color:#cfeaf9 @@ -3418,7 +3419,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- -ms-transition:none; transition:none } - + } .custom-range::-ms-thumb:active { background-color:#cfeaf9 @@ -3463,7 +3464,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .custom-control-label::before,.custom-file-label,.custom-select { transition:none } - + } .nav { display:-ms-flexbox; @@ -3629,7 +3630,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- padding-right:0; padding-left:0 } - + } @media (min-width:576px) { .navbar-expand-sm { @@ -3662,14 +3663,14 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .navbar-expand-sm .navbar-toggler { display:none } - + } @media (max-width:767.98px) { .navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl { padding-right:0; padding-left:0 } - + } @media (min-width:768px) { .navbar-expand-md { @@ -3702,14 +3703,14 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .navbar-expand-md .navbar-toggler { display:none } - + } @media (max-width:991.98px) { .navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl { padding-right:0; padding-left:0 } - + } @media (min-width:992px) { .navbar-expand-lg { @@ -3742,14 +3743,14 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .navbar-expand-lg .navbar-toggler { display:none } - + } @media (max-width:1199.98px) { .navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl { padding-right:0; padding-left:0 } - + } @media (min-width:1200px) { .navbar-expand-xl { @@ -3782,7 +3783,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .navbar-expand-xl .navbar-toggler { display:none } - + } .navbar-expand { -ms-flex-flow:row nowrap; @@ -4010,7 +4011,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- margin-bottom:0; margin-left:15px } - + } .card-group>.card { margin-bottom:15px @@ -4051,7 +4052,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom { border-bottom-left-radius:0 } - + } .card-columns .card { margin-bottom:.75rem @@ -4071,7 +4072,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- display:inline-block; width:100% } - + } .accordion { overflow-anchor:none @@ -4218,7 +4219,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn- .badge { transition:none } - + } a.badge:focus,a.badge:hover { text-decoration:none @@ -4341,7 +4342,7 @@ a.badge-dark.focus,a.badge-dark:focus { .jumbotron { padding:4rem 2rem } - + } .jumbotron-fluid { padding-right:0; @@ -4467,7 +4468,7 @@ a.badge-dark.focus,a.badge-dark:focus { to { background-position:0 0 } - + } @keyframes progress-bar-stripes { from { @@ -4476,7 +4477,7 @@ a.badge-dark.focus,a.badge-dark:focus { to { background-position:0 0 } - + } .progress { display:-ms-flexbox; @@ -4506,7 +4507,7 @@ a.badge-dark.focus,a.badge-dark:focus { .progress-bar { transition:none } - + } .progress-bar-striped { background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent); @@ -4521,7 +4522,7 @@ a.badge-dark.focus,a.badge-dark:focus { -webkit-animation:none; animation:none } - + } .media { display:-ms-flexbox; @@ -4637,7 +4638,7 @@ a.badge-dark.focus,a.badge-dark:focus { margin-left:-1px; border-left-width:1px } - + } @media (min-width:768px) { .list-group-horizontal-md { @@ -4663,7 +4664,7 @@ a.badge-dark.focus,a.badge-dark:focus { margin-left:-1px; border-left-width:1px } - + } @media (min-width:992px) { .list-group-horizontal-lg { @@ -4689,7 +4690,7 @@ a.badge-dark.focus,a.badge-dark:focus { margin-left:-1px; border-left-width:1px } - + } @media (min-width:1200px) { .list-group-horizontal-xl { @@ -4715,7 +4716,7 @@ a.badge-dark.focus,a.badge-dark:focus { margin-left:-1px; border-left-width:1px } - + } .list-group-flush { border-radius:0 @@ -4930,7 +4931,7 @@ a.close.disabled { .modal.fade .modal-dialog { transition:none } - + } .modal.show .modal-dialog { -webkit-transform:none; @@ -5086,19 +5087,19 @@ a.close.disabled { .modal-sm { max-width:300px } - + } @media (min-width:992px) { .modal-lg,.modal-xl { max-width:800px } - + } @media (min-width:1200px) { .modal-xl { max-width:1140px } - + } .tooltip { position:absolute; @@ -5365,7 +5366,7 @@ a.close.disabled { .carousel-item { transition:none } - + } .carousel-item-next,.carousel-item-prev,.carousel-item.active { display:block @@ -5397,7 +5398,7 @@ a.close.disabled { .carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right { transition:none } - + } .carousel-control-next,.carousel-control-prev { position:absolute; @@ -5420,7 +5421,7 @@ a.close.disabled { .carousel-control-next,.carousel-control-prev { transition:none } - + } .carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover { color:#fff; @@ -5482,7 +5483,7 @@ a.close.disabled { .carousel-indicators li { transition:none } - + } .carousel-indicators .active { opacity:1 @@ -5503,14 +5504,14 @@ a.close.disabled { -webkit-transform:rotate(360deg); transform:rotate(360deg) } - + } @keyframes spinner-border { to { -webkit-transform:rotate(360deg); transform:rotate(360deg) } - + } .spinner-border { display:inline-block; @@ -5538,7 +5539,7 @@ a.close.disabled { -webkit-transform:none; transform:none } - + } @keyframes spinner-grow { 0% { @@ -5550,7 +5551,7 @@ a.close.disabled { -webkit-transform:none; transform:none } - + } .spinner-grow { display:inline-block; @@ -5794,7 +5795,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { display:-ms-inline-flexbox!important; display:inline-flex!important } - + } @media (min-width:768px) { .d-md-none { @@ -5826,7 +5827,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { display:-ms-inline-flexbox!important; display:inline-flex!important } - + } @media (min-width:992px) { .d-lg-none { @@ -5858,7 +5859,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { display:-ms-inline-flexbox!important; display:inline-flex!important } - + } @media (min-width:1200px) { .d-xl-none { @@ -5890,7 +5891,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { display:-ms-inline-flexbox!important; display:inline-flex!important } - + } @media print { .d-print-none { @@ -5922,7 +5923,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { display:-ms-inline-flexbox!important; display:inline-flex!important } - + } .embed-responsive { position:relative; @@ -6229,7 +6230,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { -ms-flex-item-align:stretch!important; align-self:stretch!important } - + } @media (min-width:768px) { .flex-md-row { @@ -6368,7 +6369,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { -ms-flex-item-align:stretch!important; align-self:stretch!important } - + } @media (min-width:992px) { .flex-lg-row { @@ -6507,7 +6508,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { -ms-flex-item-align:stretch!important; align-self:stretch!important } - + } @media (min-width:1200px) { .flex-xl-row { @@ -6646,7 +6647,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { -ms-flex-item-align:stretch!important; align-self:stretch!important } - + } .float-left { float:left!important @@ -6667,7 +6668,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .float-sm-none { float:none!important } - + } @media (min-width:768px) { .float-md-left { @@ -6679,7 +6680,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .float-md-none { float:none!important } - + } @media (min-width:992px) { .float-lg-left { @@ -6691,7 +6692,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .float-lg-none { float:none!important } - + } @media (min-width:1200px) { .float-xl-left { @@ -6703,7 +6704,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .float-xl-none { float:none!important } - + } .user-select-all { -webkit-user-select:all!important; @@ -6766,7 +6767,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { top:0; z-index:1020 } - + } .sr-only { position:absolute; @@ -7388,7 +7389,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .ml-sm-auto,.mx-sm-auto { margin-left:auto!important } - + } @media (min-width:768px) { .m-md-0 { @@ -7661,7 +7662,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .ml-md-auto,.mx-md-auto { margin-left:auto!important } - + } @media (min-width:992px) { .m-lg-0 { @@ -7934,7 +7935,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .ml-lg-auto,.mx-lg-auto { margin-left:auto!important } - + } @media (min-width:1200px) { .m-xl-0 { @@ -8207,7 +8208,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .ml-xl-auto,.mx-xl-auto { margin-left:auto!important } - + } .stretched-link::after { position:absolute; @@ -8256,7 +8257,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .text-sm-center { text-align:center!important } - + } @media (min-width:768px) { .text-md-left { @@ -8268,7 +8269,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .text-md-center { text-align:center!important } - + } @media (min-width:992px) { .text-lg-left { @@ -8280,7 +8281,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .text-lg-center { text-align:center!important } - + } @media (min-width:1200px) { .text-xl-left { @@ -8292,7 +8293,7 @@ a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover { .text-xl-center { text-align:center!important } - + } .text-lowercase { text-transform:lowercase!important @@ -8472,7 +8473,7 @@ a.text-dark:focus,a.text-dark:hover { color:inherit; border-color:#dee2e6 } - + } .bg-primary { background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5); diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css index 1ed6d7b4b6..30026bb48b 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css @@ -9,8 +9,7 @@ * Copyright 2011-2020 The Bootstrap Authors * Copyright 2011-2020 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) -*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400; -700&display=swap); +*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap); :root { --blue:#2a9fd6; --indigo:#6610f2; @@ -36,6 +35,7 @@ --dark:#adafae; --body-bg: #060606; --text-bg-mark: #fcf8e3; + --custom-select: #fff; --breakpoint-xs:0; --breakpoint-sm:576px; --breakpoint-md:768px; diff --git a/apps/solidity-compiler/src/app/compiler-api.ts b/apps/solidity-compiler/src/app/compiler-api.ts index 21a2283ef3..12307bffc5 100644 --- a/apps/solidity-compiler/src/app/compiler-api.ts +++ b/apps/solidity-compiler/src/app/compiler-api.ts @@ -223,10 +223,10 @@ export const CompilerApiMixin = (Base) => class extends Base { } this.compiler.event.register('loadingCompiler', this.data.eventHandlers.onLoadingCompiler) - this.data.eventHandlers.onCompilerLoaded = (version) => { + this.data.eventHandlers.onCompilerLoaded = (version, license) => { this.data.loading = false this.statusChanged({ key: 'none' }) - this.emit('compilerLoaded', version) + this.emit('compilerLoaded', version, license) } this.compiler.event.register('compilerLoaded', this.data.eventHandlers.onCompilerLoaded) diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx index a6ce7c9db9..18b0fd0a80 100644 --- a/apps/vyper/src/app/app.tsx +++ b/apps/vyper/src/app/app.tsx @@ -38,12 +38,15 @@ const App: React.FC = () => { async function start() { try { await remixClient.loaded() - remixClient.onFileChange(name => setContract(name)) - const name = await remixClient.getContractName() - setContract(name) + remixClient.onFileChange(name => setContract(name)) + remixClient.onNoFileSelected(() => setContract('')) } catch (err) { console.log(err) } + try { + const name = await remixClient.getContractName() // throw if no file are selected + setContract(name) + } catch (e) {} } start() }, []) diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx index fb0fb6ff05..c7fe318f0d 100644 --- a/apps/vyper/src/app/components/CompilerButton.tsx +++ b/apps/vyper/src/app/components/CompilerButton.tsx @@ -28,22 +28,60 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { /** Compile a Contract */ async function compileContract() { try { - const _contract = await remixClient.getContract() + await remixClient.discardHighlight() + let _contract: any + try { + _contract = await remixClient.getContract() + } catch (e: any) { + setOutput('', { status: 'failed', message: e.message}) + return + } remixClient.changeStatus({ key: 'loading', type: 'info', title: 'Compiling' }) - const output = await compile(compilerUrl, _contract) + let output + try { + output = await compile(compilerUrl, _contract) + } catch (e: any) { + setOutput(_contract.name, { status: 'failed', message: e.message}) + return + } setOutput(_contract.name, output) // ERROR if (isCompilationError(output)) { const line = output.line - const lineColumnPos = { - start: { line: line - 1 }, - end: { line: line - 1 } + if (line) { + const lineColumnPos = { + start: { line: line - 1, column: 10 }, + end: { line: line - 1, column: 10 } + } + remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4') + } else { + const regex = output.message.match(/line ((\d+):(\d+))+/g) + const errors = output.message.split(/line ((\d+):(\d+))+/g) // extract error message + if (regex) { + let errorIndex = 0 + regex.map((errorLocation) => { + const location = errorLocation.replace('line ', '').split(':') + let message = errors[errorIndex] + errorIndex = errorIndex + 4 + if (message && message.split('\n\n').length > 0) { + try { + message = message.split('\n\n')[1] + } catch (e) {} + } + if (location.length > 0) { + const lineColumnPos = { + start: { line: parseInt(location[0]) - 1, column: 10 }, + end: { line: parseInt(location[0]) - 1, column: 10 } + } + remixClient.highlight(lineColumnPos as any, _contract.name, message) + } + }) + } } - remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4') throw new Error(output.message) } // SUCCESS @@ -61,7 +99,6 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) { type: 'error', title: err.message }) - console.error(err) } } diff --git a/apps/vyper/src/app/components/LocalUrl.tsx b/apps/vyper/src/app/components/LocalUrl.tsx index 3659b4094e..5e2dcbacf1 100644 --- a/apps/vyper/src/app/components/LocalUrl.tsx +++ b/apps/vyper/src/app/components/LocalUrl.tsx @@ -26,11 +26,10 @@ function LocalUrlInput({ url, setUrl, environment }: Props) { type="email" placeholder="eg http://localhost:8000/compile" /> - The url to your local compiler ) } -export default LocalUrlInput; \ No newline at end of file +export default LocalUrlInput; diff --git a/apps/vyper/src/app/components/VyperResult.tsx b/apps/vyper/src/app/components/VyperResult.tsx index f550d17370..e58f901fea 100644 --- a/apps/vyper/src/app/components/VyperResult.tsx +++ b/apps/vyper/src/app/components/VyperResult.tsx @@ -7,7 +7,6 @@ import { } from '../utils'; import Tabs from 'react-bootstrap/Tabs' import Tab from 'react-bootstrap/Tab' -import { Ballot } from '../examples/ballot'; import Button from 'react-bootstrap/Button'; import JSONTree from 'react-json-view' import { CopyToClipboard } from '@remix-ui/clipboard' @@ -17,14 +16,20 @@ interface VyperResultProps { output?: VyperCompilationOutput; } +export type ExampleContract = { + name: string, + address: string +} + function VyperResult({ output }: VyperResultProps) { - const [ active, setActive ] = useState('abi'); - + const [ active, setActive ] = useState('abi') + if (!output) return ( +

No contract compiled yet.

-
) @@ -33,7 +38,7 @@ function VyperResult({ output }: VyperResultProps) { return (
-

{output.message}

+
{output.message}
) } @@ -41,7 +46,7 @@ function VyperResult({ output }: VyperResultProps) { setActive(key)}> JSON.stringify(output.abi)}> - + diff --git a/apps/vyper/src/app/examples/ballot.tsx b/apps/vyper/src/app/examples/ballot.tsx deleted file mode 100644 index 4b368c6fda..0000000000 --- a/apps/vyper/src/app/examples/ballot.tsx +++ /dev/null @@ -1,161 +0,0 @@ -export const Ballot = { - name: 'browser/ballot.vy', - content: `# Voting with delegation. - - # Information about voters - struct Voter: - # weight is accumulated by delegation - weight: int128 - # if true, that person already voted (which includes voting by delegating) - voted: bool - # person delegated to - delegate: address - # index of the voted proposal, which is not meaningful unless 'voted' is True. - vote: int128 - - # Users can create proposals - struct Proposal: - # short name (up to 32 bytes) - name: bytes32 - # number of accumulated votes - voteCount: int128 - - voters: public(map(address, Voter)) - proposals: public(map(int128, Proposal)) - voterCount: public(int128) - chairperson: public(address) - int128Proposals: public(int128) - - - @public - @constant - def delegated(addr: address) -> bool: - return self.voters[addr].delegate != ZERO_ADDRESS - - - @public - @constant - def directlyVoted(addr: address) -> bool: - return self.voters[addr].voted and (self.voters[addr].delegate == ZERO_ADDRESS) - - - # Setup global variables - @public - def __init__(_proposalNames: bytes32[2]): - self.chairperson = msg.sender - self.voterCount = 0 - for i in range(2): - self.proposals[i] = Proposal({ - name: _proposalNames[i], - voteCount: 0 - }) - self.int128Proposals += 1 - - # Give a 'voter' the right to vote on this ballot. - # This may only be called by the 'chairperson'. - @public - def giveRightToVote(voter: address): - # Throws if the sender is not the chairperson. - assert msg.sender == self.chairperson - # Throws if the voter has already voted. - assert not self.voters[voter].voted - # Throws if the voter's voting weight isn't 0. - assert self.voters[voter].weight == 0 - self.voters[voter].weight = 1 - self.voterCount += 1 - - # Used by 'delegate' below, and can be called by anyone. - @public - def forwardWeight(delegate_with_weight_to_forward: address): - assert self.delegated(delegate_with_weight_to_forward) - # Throw if there is nothing to do: - assert self.voters[delegate_with_weight_to_forward].weight > 0 - - target: address = self.voters[delegate_with_weight_to_forward].delegate - for i in range(4): - if self.delegated(target): - target = self.voters[target].delegate - # The following effectively detects cycles of length <= 5, - # in which the delegation is given back to the delegator. - # This could be done for any int128ber of loops, - # or even infinitely with a while loop. - # However, cycles aren't actually problematic for correctness; - # they just result in spoiled votes. - # So, in the production version, this should instead be - # the responsibility of the contract's client, and this - # check should be removed. - assert target != delegate_with_weight_to_forward - else: - # Weight will be moved to someone who directly voted or - # hasn't voted. - break - - weight_to_forward: int128 = self.voters[delegate_with_weight_to_forward].weight - self.voters[delegate_with_weight_to_forward].weight = 0 - self.voters[target].weight += weight_to_forward - - if self.directlyVoted(target): - self.proposals[self.voters[target].vote].voteCount += weight_to_forward - self.voters[target].weight = 0 - - # To reiterate: if target is also a delegate, this function will need - # to be called again, similarly to as above. - - # Delegate your vote to the voter 'to'. - @public - def delegate(to: address): - # Throws if the sender has already voted - assert not self.voters[msg.sender].voted - # Throws if the sender tries to delegate their vote to themselves or to - # the default address value of 0x0000000000000000000000000000000000000000 - # (the latter might not be problematic, but I don't want to think about it). - assert to != msg.sender - assert to != ZERO_ADDRESS - - self.voters[msg.sender].voted = True - self.voters[msg.sender].delegate = to - - # This call will throw if and only if this delegation would cause a loop - # of length <= 5 that ends up delegating back to the delegator. - self.forwardWeight(msg.sender) - - # Give your vote (including votes delegated to you) - # to proposal 'proposals[proposal].name'. - @public - def vote(proposal: int128): - # can't vote twice - assert not self.voters[msg.sender].voted - # can only vote on legitimate proposals - assert proposal < self.int128Proposals - - self.voters[msg.sender].vote = proposal - self.voters[msg.sender].voted = True - - # transfer msg.sender's weight to proposal - self.proposals[proposal].voteCount += self.voters[msg.sender].weight - self.voters[msg.sender].weight = 0 - - # Computes the winning proposal taking all - # previous votes into account. - @public - @constant - def winningProposal() -> int128: - winning_vote_count: int128 = 0 - winning_proposal: int128 = 0 - for i in range(2): - if self.proposals[i].voteCount > winning_vote_count: - winning_vote_count = self.proposals[i].voteCount - winning_proposal = i - return winning_proposal - - # Calls winningProposal() function to get the index - # of the winner contained in the proposals array and then - # returns the name of the winner - @public - @constant - def winnerName() -> bytes32: - return self.proposals[self.winningProposal()].name - - ` - } - \ No newline at end of file diff --git a/apps/vyper/src/app/utils/compiler.tsx b/apps/vyper/src/app/utils/compiler.tsx index ebc117dba1..0b65c65a1a 100644 --- a/apps/vyper/src/app/utils/compiler.tsx +++ b/apps/vyper/src/app/utils/compiler.tsx @@ -18,8 +18,8 @@ export interface VyperCompilationResult { export interface VyperCompilationError { status: 'failed' - column: number - line: number + column?: number + line?: number message: string } diff --git a/apps/vyper/src/app/utils/remix-client.tsx b/apps/vyper/src/app/utils/remix-client.tsx index 080ba64a75..913131e594 100644 --- a/apps/vyper/src/app/utils/remix-client.tsx +++ b/apps/vyper/src/app/utils/remix-client.tsx @@ -3,6 +3,7 @@ import { Api, Status } from '@remixproject/plugin-utils'; import { createClient } from '@remixproject/plugin-webview' import { PluginClient } from '@remixproject/plugin'; import { Contract } from './compiler'; +import { ExampleContract } from '../components/VyperResult'; export class RemixClient extends PluginClient { private client = createClient>(this); @@ -14,34 +15,70 @@ export class RemixClient extends PluginClient { /** Emit an event when file changed */ async onFileChange(cb: (contract: string) => any) { this.client.on('fileManager', 'currentFileChanged', async (name: string) => { - if (!name) return cb(name) }) } + /** Emit an event when file changed */ + async onNoFileSelected(cb: () => any) { + this.client.on('fileManager', 'noFileSelected', async () => { + cb() + }) + } + /** Load Ballot contract example into the file manager */ - async loadContract({name, content}: Contract) { + async loadContract({name, address}: ExampleContract) { try { - await this.client.call('fileManager', 'setFile', name, content) - await this.client.call('fileManager', 'switchFile', name) + const content = await this.client.call('contentImport', 'resolve', address) + await this.client.call('fileManager', 'setFile', content.cleanUrl, content.content) + await this.client.call('fileManager', 'switchFile', content.cleanUrl) } catch (err) { console.log(err) } } + async cloneVyperRepo() { + try { + // @ts-ignore + this.call('notification', 'toast', 'cloning Vyper repository...') + await this.call('manager', 'activatePlugin', 'dGitProvider') + // @ts-ignore + await this.call('dGitProvider', 'clone', { url: 'https://github.com/vyperlang/vyper', token: null }, 'vyper-lang') + // @ts-ignore + this.call('notification', 'toast', 'Vyper repository cloned, the workspace Vyper has been created.') + } catch (e) { + // @ts-ignore + this.call('notification', 'toast', e.message) + } + } + /** Update the status of the plugin in remix */ changeStatus(status: Status) { this.client.emit('statusChanged', status); } /** Highlight a part of the editor */ - highlight(lineColumnPos: HighlightPosition, name: string, color: string) { - return this.client.call('editor', 'highlight', lineColumnPos, name, color) + async highlight(lineColumnPos: HighlightPosition, name: string, message: string) { + await this.client.call('editor', 'highlight', lineColumnPos, name) + /* + column: -1 + row: -1 + text: "browser/Untitled1.sol: Warning: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information.↵" + type: "warning" + */ + const annotation = { + column: 0, + row: lineColumnPos.start.line, + type: 'error', + text: message + } + await this.client.call('editor', 'addAnnotation', annotation, name) } /** Remove current Hightlight */ - discardHighlight() { - return this.client.call('editor', 'discardHighlight') + async discardHighlight() { + await this.client.call('editor', 'discardHighlight') + await this.client.call('editor', 'clearAnnotations') } /** Get the name of the current contract */ diff --git a/libs/remix-solidity/src/compiler/compiler-worker.ts b/libs/remix-solidity/src/compiler/compiler-worker.ts index 7fdeef2791..56c20875e1 100644 --- a/libs/remix-solidity/src/compiler/compiler-worker.ts +++ b/libs/remix-solidity/src/compiler/compiler-worker.ts @@ -33,7 +33,8 @@ export default function (self) { // eslint-disable-line @typescript-eslint/expli } self.postMessage({ cmd: 'versionLoaded', - data: compiler.version() + data: compiler.version(), + license: compiler.license() }) break } diff --git a/libs/remix-solidity/src/compiler/compiler.ts b/libs/remix-solidity/src/compiler/compiler.ts index 70dd550eae..f1302f88b9 100644 --- a/libs/remix-solidity/src/compiler/compiler.ts +++ b/libs/remix-solidity/src/compiler/compiler.ts @@ -25,6 +25,7 @@ export class Compiler { compileJSON: null, worker: null, currentVersion: null, + compilerLicense: null, optimize: false, runs: 200, evmVersion: null, @@ -95,9 +96,10 @@ export class Compiler { * @param version compiler version */ - onCompilerLoaded(version: string): void { + onCompilerLoaded (version: string, license: string): void { this.state.currentVersion = version - this.event.trigger('compilerLoaded', [version]) + this.state.compilerLicense = license + this.event.trigger('compilerLoaded', [version, license]) } /** @@ -132,7 +134,7 @@ export class Compiler { } this.onCompilationFinished(result, missingInputs, source, input, this.state.currentVersion) } - this.onCompilerLoaded(compiler.version()) + this.onCompilerLoaded(compiler.version(), compiler.license()) } } @@ -185,6 +187,7 @@ export class Compiler { if (err) { console.error('Error in loading remote solc compiler: ', err) } else { + let license this.state.compileJSON = (source: SourceWithTarget) => { const missingInputs: string[] = [] const missingInputsCallback = (path: string) => { @@ -204,13 +207,14 @@ export class Compiler { } result = JSON.parse(remoteCompiler.compile(input, { import: missingInputsCallback })) + license = remoteCompiler.license() } } catch (exception) { result = { error: { formattedMessage: 'Uncaught JavaScript exception:\n' + exception, severity: 'error', mode: 'panic' } } } this.onCompilationFinished(result, missingInputs, source, input, version) } - this.onCompilerLoaded(version) + this.onCompilerLoaded(version, license) } }) } @@ -277,7 +281,7 @@ export class Compiler { } switch (data.cmd) { case 'versionLoaded': - if (data.data) this.onCompilerLoaded(data.data) + if (data.data && data.license) this.onCompilerLoaded(data.data, data.license) break case 'compiled': { diff --git a/libs/remix-solidity/src/compiler/types.ts b/libs/remix-solidity/src/compiler/types.ts index ea9906c130..6b9af76845 100644 --- a/libs/remix-solidity/src/compiler/types.ts +++ b/libs/remix-solidity/src/compiler/types.ts @@ -163,6 +163,7 @@ export interface CompilerState { compileJSON: ((input: SourceWithTarget) => void) | null, worker: any, currentVersion: string| null| undefined, + compilerLicense: string| null optimize: boolean, runs: number evmVersion: EVMVersion| null, @@ -193,6 +194,7 @@ export interface MessageToWorker { export interface MessageFromWorker { cmd: string, + license?: string, job?: number, missingInputs?: string[], input?: any, diff --git a/libs/remix-tests/src/compiler.ts b/libs/remix-tests/src/compiler.ts index b399f7376e..7fedf9c830 100644 --- a/libs/remix-tests/src/compiler.ts +++ b/libs/remix-tests/src/compiler.ts @@ -134,7 +134,7 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts if (runs) compiler.set('runs', runs) if (currentCompilerUrl) { compiler.loadRemoteVersion(currentCompilerUrl) - compiler.event.register('compilerLoaded', this, function (version) { + compiler.event.register('compilerLoaded', this, function (version, license) { next() }) } else { @@ -198,7 +198,7 @@ export function compileContractSources (sources: SrcIfc, newCompConfig: any, imp compiler.set('runs', runs) compiler.loadVersion(usingWorker, currentCompilerUrl) // @ts-ignore - compiler.event.register('compilerLoaded', this, (version) => { + compiler.event.register('compilerLoaded', this, (version, license) => { next() }) } else { diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css index 7bb10333dc..636cfa4eea 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.css @@ -16,4 +16,8 @@ } .validationError { overflow-wrap: break-word; +} +.debuggerPanels { + overflow-y: scroll; + height: fit-content; } \ No newline at end of file diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index bd8008d0e3..74660fdabe 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react' // eslint-disable-line +import React, { useState, useEffect, useRef } from 'react' // eslint-disable-line import TxBrowser from './tx-browser/tx-browser' // eslint-disable-line import StepManager from './step-manager/step-manager' // eslint-disable-line import VmDebugger from './vm-debugger/vm-debugger' // eslint-disable-line @@ -36,6 +36,28 @@ export const DebuggerUI = (props: DebuggerUIProps) => { sourceLocationStatus: '' }) + const panelsRef = useRef(null) + const debuggerTopRef = useRef(null) + + const handleResize = () => { + if (panelsRef.current && debuggerTopRef.current) { + panelsRef.current.style.height = (window.innerHeight - debuggerTopRef.current.clientHeight) - debuggerTopRef.current.offsetTop - 7 +'px' + } + } + + useEffect(() => { + handleResize() + }, []) + + useEffect(() => { + window.addEventListener('resize', handleResize) + // TODO: not a good way to wait on the ref doms element to be rendered of course + setTimeout(() => + handleResize(), 2000) + return () => window.removeEventListener('resize', handleResize) + }, [state.debugging, state.isActive]) + + useEffect(() => { return unLoad() }, []) @@ -260,34 +282,35 @@ export const DebuggerUI = (props: DebuggerUIProps) => { }) setTimeout(async() => { - try { - await debuggerInstance.debug(blockNumber, txNumber, tx, () => { - listenToEvents(debuggerInstance, currentReceipt) + try { + await debuggerInstance.debug(blockNumber, txNumber, tx, () => { + listenToEvents(debuggerInstance, currentReceipt) + setState(prevState => { + return { + ...prevState, + blockNumber, + txNumber, + debugging: true, + currentReceipt, + currentBlock, + currentTransaction, + debugger: debuggerInstance, + toastMessage: `debugging ${txNumber}`, + validationError: '' + } + }) + }) + } catch (error) { + unLoad() setState(prevState => { return { ...prevState, - blockNumber, - txNumber, - debugging: true, - currentReceipt, - currentBlock, - currentTransaction, - debugger: debuggerInstance, - toastMessage: `debugging ${txNumber}`, - validationError: '' + validationError: error.message || error } }) - }) - } catch (error) { - unLoad() - setState(prevState => { - return { - ...prevState, - validationError: error.message || error - } - }) - } - }, 300) + } + }, 300) + handleResize() } const debug = (txHash, web3?) => { @@ -315,17 +338,18 @@ export const DebuggerUI = (props: DebuggerUIProps) => { traceLength: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.traceLength : null, registerEvent: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.event.register.bind(state.debugger.step_manager.event) : null } + const vmDebugger = { registerEvent: state.debugger && state.debugger.vmDebuggerLogic ? state.debugger.vmDebuggerLogic.event.register.bind(state.debugger.vmDebuggerLogic.event) : null, triggerEvent: state.debugger && state.debugger.vmDebuggerLogic ? state.debugger.vmDebuggerLogic.event.trigger.bind(state.debugger.vmDebuggerLogic.event) : null } + return (
-
+
-

Debugger Configuration

-
+
{ setState(prevState => { return { ...prevState, opt: { ...prevState.opt, debugWithGeneratedSources: checked } } @@ -333,7 +357,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { }} type="checkbox" title="Debug with generated sources" />
- { state.isLocalNodeUsed &&
+ { state.isLocalNodeUsed &&
{ setState(prevState => { return { ...prevState, opt: { ...prevState.opt, debugWithLocalNode: checked } } @@ -356,9 +380,11 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
} { state.debugging && } +
+
{ state.debugging && } + { state.debugging && }
- { state.debugging && }
) } diff --git a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx index 3a58c1d2f4..612757fe36 100644 --- a/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx @@ -98,7 +98,7 @@ export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent } }) }, [registerEvent]) 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 07a1d0238b..47f6b4ff67 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx @@ -75,6 +75,7 @@ type errorMarker = { }, file: string } + loader.config({ paths: { vs: 'assets/js/monaco-editor/dev/vs' } }) export type DecorationsReturn = { @@ -442,7 +443,6 @@ export const EditorUI = (props: EditorUIProps) => { allMarkersPerfile[filePath].push(markerData) } } - console.log(allMarkersPerfile) for (const filePath in allMarkersPerfile) { const model = editorModelsState[filePath]?.model if (model) { @@ -587,8 +587,7 @@ export const EditorUI = (props: EditorUIProps) => { } } - function handleEditorWillMount(monaco: Monaco) { - + function handleEditorWillMount(monaco) { monacoRef.current = monaco // Register a new language monacoRef.current.languages.register({ id: 'remix-solidity' }) diff --git a/libs/remix-ui/helper/src/index.ts b/libs/remix-ui/helper/src/index.ts index 9f050ea8b8..19e7721ac3 100644 --- a/libs/remix-ui/helper/src/index.ts +++ b/libs/remix-ui/helper/src/index.ts @@ -1,4 +1,5 @@ export * from './lib/remix-ui-helper' +export * from './lib/bleach' export * from './lib/helper-components' export * from './lib/components/PluginViewWrapper' export * from './lib/components/custom-dropdown' \ No newline at end of file diff --git a/apps/remix-ide/src/lib/remixBleach.js b/libs/remix-ui/helper/src/lib/bleach.ts similarity index 87% rename from apps/remix-ide/src/lib/remixBleach.js rename to libs/remix-ui/helper/src/lib/bleach.ts index e159c8a6df..44aa129042 100644 --- a/apps/remix-ide/src/lib/remixBleach.js +++ b/libs/remix-ui/helper/src/lib/bleach.ts @@ -5,7 +5,7 @@ */ import * as he from 'he' -const remixBleach = { +export const bleach = { matcher: /<\/?([a-zA-Z0-9]+)*(.*?)\/?>/igm, @@ -24,7 +24,7 @@ const remixBleach = { let match // extract all tags - while ((match = remixBleach.matcher.exec(html)) != null) { + while ((match = bleach.matcher.exec(html)) != null) { const attrr = match[2].split(' ') const attrs = [] @@ -45,7 +45,7 @@ const remixBleach = { if (attr.name) attrs.push(attr) }) - var tag = { + const tag = { full: match[0], name: match[1], attr: attrs @@ -57,14 +57,13 @@ const remixBleach = { return matches }, - sanitize: function (html, options) { + sanitize: function (html, options = { mode: 'white', list: bleach.whitelist, encode_entities: false}) { html = String(html) || '' - options = options || {} - + const mode = options.mode || 'white' - const list = options.list || remixBleach.whitelist + const list = options.list || bleach.whitelist - var matches = remixBleach.analyze(html) + const matches = bleach.analyze(html) if ((mode === 'white' && list.indexOf('script') === -1) || (mode === 'black' && list.indexOf('script') !== -1)) { @@ -95,5 +94,3 @@ const remixBleach = { return html } } - -module.exports = remixBleach diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css index 6f6cd9b221..62a0dd5987 100644 --- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css +++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css @@ -8,6 +8,7 @@ .remixModalBody { overflow-y: auto; max-height: 600px; + white-space: pre-line; } @-webkit-keyframes animatetop { from {top: -300px; opacity: 0} diff --git a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx index 4bffb2565f..b6e8c9948a 100644 --- a/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx +++ b/libs/remix-ui/panel/src/lib/plugins/panel-header.tsx @@ -27,8 +27,8 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => { return (
-
{plugin?.profile.displayName || plugin?.profile.name}
-
+
{plugin?.profile.displayName || plugin?.profile.name}
+
{plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && ()}
diff --git a/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts b/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts index c67aee6ddb..b1c0b686de 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts +++ b/libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts @@ -46,8 +46,8 @@ export const listenToEvents = (compileTabLogic: CompileTabLogic, api) => (dispat dispatch(setCompilerMode('loadingCompiler')) }) - compileTabLogic.compiler.event.register('compilerLoaded', () => { - dispatch(setCompilerMode('compilerLoaded')) + compileTabLogic.compiler.event.register('compilerLoaded', (version, license) => { + dispatch(setCompilerMode('compilerLoaded', version, license)) }) compileTabLogic.compiler.event.register('compilationFinished', (success, data, source, input, version) => { diff --git a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx index 069377d045..857a86e73c 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx @@ -48,6 +48,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => { timeout: 300, allversions: [], customVersions: [], + compilerLicense: null, selectedVersion: null, defaultVersion: 'soljson-v0.8.7+commit.e28d00a7.js', // this default version is defined: in makeMockCompiler (for browser test) runs: '', @@ -185,7 +186,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => { loadingCompiler() break case 'compilerLoaded': - compilerLoaded() + compilerLoaded(compilerContainer.compiler.args[1]) break case 'compilationFinished': compilationFinished() @@ -432,14 +433,20 @@ export const CompilerContainer = (props: CompilerContainerProps) => { if (!compileIcon.current) return compileIcon.current.setAttribute('title', 'compiler is loading, please wait a few moments.') compileIcon.current.classList.add('remixui_spinningIcon') + setState(prevState => { + return { ...prevState, compilerLicense: 'Compiler is loading. License will be displayed once compiler is loaded'} + }) _updateLanguageSelector() setDisableCompileButton(true) } - const compilerLoaded = () => { + const compilerLoaded = (license) => { if (!compileIcon.current) return compileIcon.current.setAttribute('title', '') compileIcon.current.classList.remove('remixui_spinningIcon') + setState(prevState => { + return { ...prevState, compilerLicense: license ? license : 'Could not retreive license for selected compiler version' } + }) if (state.autoCompile) compile() const isDisabled = !compiledFileName || (compiledFileName && !isSolFileSelected(compiledFileName)) @@ -554,6 +561,10 @@ export const CompilerContainer = (props: CompilerContainerProps) => { modal('Add a custom compiler', promptMessage('URL'), 'OK', addCustomCompiler, 'Cancel', () => {}) } + const showCompilerLicense = () => { + modal('Compiler License', state.compilerLicense ? state.compilerLicense : 'License not available', 'OK', () => {}) + } + const promptMessage = (message) => { return ( <> @@ -701,10 +712,9 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
- + + promptCompiler()} title="Add a custom compiler with URL"> + showCompilerLicense()} title="See compiler license">