Merge branch 'master' of https://github.com/ethereum/remix-project into editorcontext_merge

pull/2774/head
bunsenstraat 2 years ago
commit 57ca08ecff
  1. 1
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  2. 12
      apps/remix-ide-e2e/src/tests/gist.test.ts
  3. 17
      apps/remix-ide-e2e/src/tests/vyper_api.ts
  4. 6
      apps/remix-ide/src/app/tabs/debugger-tab.js
  5. 3
      apps/remix-ide/src/app/tabs/styles/debugger-tab-styles.js
  6. 165
      apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css
  7. 4
      apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
  8. 4
      apps/solidity-compiler/src/app/compiler-api.ts
  9. 9
      apps/vyper/src/app/app.tsx
  10. 51
      apps/vyper/src/app/components/CompilerButton.tsx
  11. 3
      apps/vyper/src/app/components/LocalUrl.tsx
  12. 19
      apps/vyper/src/app/components/VyperResult.tsx
  13. 161
      apps/vyper/src/app/examples/ballot.tsx
  14. 4
      apps/vyper/src/app/utils/compiler.tsx
  15. 53
      apps/vyper/src/app/utils/remix-client.tsx
  16. 3
      libs/remix-solidity/src/compiler/compiler-worker.ts
  17. 14
      libs/remix-solidity/src/compiler/compiler.ts
  18. 2
      libs/remix-solidity/src/compiler/types.ts
  19. 4
      libs/remix-tests/src/compiler.ts
  20. 4
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.css
  21. 84
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  22. 2
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger-head.tsx
  23. 5
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  24. 1
      libs/remix-ui/helper/src/index.ts
  25. 17
      libs/remix-ui/helper/src/lib/bleach.ts
  26. 1
      libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.css
  27. 4
      libs/remix-ui/panel/src/lib/plugins/panel-header.tsx
  28. 4
      libs/remix-ui/solidity-compiler/src/lib/actions/compiler.ts
  29. 22
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  30. 2
      libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
  31. 4
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  32. 8
      libs/remix-ui/vertical-icons-panel/src/lib/reducers/iconBadgeReducer.ts

@ -205,6 +205,7 @@ module.exports = {
.clickLaunchIcon('debugger') .clickLaunchIcon('debugger')
.waitForElementVisible('*[data-id="slider"]') .waitForElementVisible('*[data-id="slider"]')
.goToVMTraceStep(154) .goToVMTraceStep(154)
.scrollInto('*[data-id="stepdetail"]')
.waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n154', 60000) .waitForElementContainsText('*[data-id="stepdetail"]', 'vm trace step:\n154', 60000)
}, },

@ -9,10 +9,11 @@ const testData = {
// 99266d6da54cc12f37f11586e8171546c7700d67 // 99266d6da54cc12f37f11586e8171546c7700d67
module.exports = { module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) { before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done) init(browser, done)
}, },
UploadToGists: function (browser: NightwatchBrowser) { 'UploadToGists #group1': function (browser: NightwatchBrowser) {
/* /*
- set the access token - set the access token
- publish to gist - 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') browser.clickLaunchIcon('home')
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('filePanel') .clickLaunchIcon('filePanel')
@ -84,7 +85,7 @@ module.exports = {
.modalFooterCancelClick('gisthandler') .modalFooterCancelClick('gisthandler')
}, },
'Display Error Message For Invalid Gist ID': function (browser: NightwatchBrowser) { 'Display Error Message For Invalid Gist ID #group1': function (browser: NightwatchBrowser) {
browser browser
.pause(1000) .pause(1000)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
@ -101,7 +102,7 @@ module.exports = {
.modalFooterOKClick('gisthandler') .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 browser
.pause(1000) .pause(1000)
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
@ -125,7 +126,7 @@ module.exports = {
.click('[data-id="fileSystemModalDialogModalFooter-react"] .modal-ok') .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 browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('settings') .clickLaunchIcon('settings')
@ -140,6 +141,7 @@ module.exports = {
}) })
.setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId) .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId)
.modalFooterOKClick('gisthandler') .modalFooterOKClick('gisthandler')
.pause(10000)
.openFile(`gist-${testData.validGistId}/README.txt`) .openFile(`gist-${testData.validGistId}/README.txt`)
.waitForElementVisible(`div[title='default_workspace/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') .assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt')

@ -21,25 +21,30 @@ module.exports = {
.frame(0) .frame(0)
}, },
'Should add the Ballot.vy #group1': function (browser: NightwatchBrowser) { 'Should clone the Vyper repo #group1': function (browser: NightwatchBrowser) {
browser.click('button[data-id="add-ballot"]') browser.click('button[data-id="add-repository"]')
.frameParent() .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') browser.clickLaunchIcon('vyper')
// @ts-ignore // @ts-ignore
.frame(0) .frame(0)
.click('[data-id="remote-compiler"]') .click('[data-id="remote-compiler"]')
.click('[data-id="compile"]') .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 let contractAddress
browser browser
.frameParent() .frameParent()
.clickLaunchIcon('filePanel')
.switchWorkspace('default_workspace')
.addFile('test.vy', { content: testContract }) .addFile('test.vy', { content: testContract })
.clickLaunchIcon('vyper') .clickLaunchIcon('vyper')
// @ts-ignore // @ts-ignore

@ -3,7 +3,7 @@ import { DebuggerApiMixin } from '@remixproject/debugger-plugin' // eslint-disab
import { ViewPlugin } from '@remixproject/engine-web' import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line 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' import { compilationFinishedToastMsg, compilingToastMsg, localCompilationToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper'
const css = require('./styles/debugger-tab-styles') const css = require('./styles/debugger-tab-styles')
@ -51,7 +51,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => { this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => {
this.call('notification', 'toast', sourceVerificationNotAvailableToastMsg()) this.call('notification', 'toast', sourceVerificationNotAvailableToastMsg())
}) })
return <div className={css.debuggerTabView} id='debugView'><DebuggerUI debuggerAPI={this} /></div> return <div className="overflow-hidden px-1" id='debugView'><DebuggerUI debuggerAPI={this} /></div>
} }
showMessage (title, message) { showMessage (title, message) {
@ -59,7 +59,7 @@ export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
this.call('notification', 'alert', { this.call('notification', 'alert', {
id: 'debuggerTabShowMessage', id: 'debuggerTabShowMessage',
title, title,
message: remixBleach.sanitize(message) message: bleach.sanitize(message)
}) })
} catch (e) { } catch (e) {
console.log(e) console.log(e)

@ -1,9 +1,6 @@
var csjs = require('csjs-inject') var csjs = require('csjs-inject')
const css = csjs` const css = csjs`
.debuggerTabView {
padding: 2%;
}
.debugger { .debugger {
margin-bottom: 1%; margin-bottom: 1%;
} }

@ -34,6 +34,7 @@
--dark:#343a40; --dark:#343a40;
--body-bg: #fff; --body-bg: #fff;
--text-bg-mark: #fcf8e3; --text-bg-mark: #fcf8e3;
--custom-select: #fff;
--breakpoint-xs:0; --breakpoint-xs:0;
--breakpoint-sm:576px; --breakpoint-sm:576px;
--breakpoint-md:768px; --breakpoint-md:768px;
@ -435,25 +436,25 @@ pre code {
.container,.container-sm { .container,.container-sm {
max-width:540px max-width:540px
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.container,.container-md,.container-sm { .container,.container-md,.container-sm {
max-width:720px max-width:720px
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.container,.container-lg,.container-md,.container-sm { .container,.container-lg,.container-md,.container-sm {
max-width:960px max-width:960px
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.container,.container-lg,.container-md,.container-sm,.container-xl { .container,.container-lg,.container-md,.container-sm,.container-xl {
max-width:1140px max-width:1140px
} }
} }
.row { .row {
display:-ms-flexbox; display:-ms-flexbox;
@ -873,7 +874,7 @@ pre code {
.offset-sm-11 { .offset-sm-11 {
margin-left:91.666667% margin-left:91.666667%
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.col-md { .col-md {
@ -1075,7 +1076,7 @@ pre code {
.offset-md-11 { .offset-md-11 {
margin-left:91.666667% margin-left:91.666667%
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.col-lg { .col-lg {
@ -1277,7 +1278,7 @@ pre code {
.offset-lg-11 { .offset-lg-11 {
margin-left:91.666667% margin-left:91.666667%
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.col-xl { .col-xl {
@ -1479,7 +1480,7 @@ pre code {
.offset-xl-11 { .offset-xl-11 {
margin-left:91.666667% margin-left:91.666667%
} }
} }
.table { .table {
width:100%; width:100%;
@ -1662,7 +1663,7 @@ pre code {
.table-responsive-sm>.table-bordered { .table-responsive-sm>.table-bordered {
border:0 border:0
} }
} }
@media (max-width:767.98px) { @media (max-width:767.98px) {
.table-responsive-md { .table-responsive-md {
@ -1674,7 +1675,7 @@ pre code {
.table-responsive-md>.table-bordered { .table-responsive-md>.table-bordered {
border:0 border:0
} }
} }
@media (max-width:991.98px) { @media (max-width:991.98px) {
.table-responsive-lg { .table-responsive-lg {
@ -1686,7 +1687,7 @@ pre code {
.table-responsive-lg>.table-bordered { .table-responsive-lg>.table-bordered {
border:0 border:0
} }
} }
@media (max-width:1199.98px) { @media (max-width:1199.98px) {
.table-responsive-xl { .table-responsive-xl {
@ -1698,7 +1699,7 @@ pre code {
.table-responsive-xl>.table-bordered { .table-responsive-xl>.table-bordered {
border:0 border:0
} }
} }
.table-responsive { .table-responsive {
display:block; display:block;
@ -1728,7 +1729,7 @@ pre code {
.form-control { .form-control {
transition:none transition:none
} }
} }
.form-control::-ms-expand { .form-control::-ms-expand {
background-color:transparent; background-color:transparent;
@ -2114,7 +2115,7 @@ textarea.form-control {
.form-inline .custom-control-label { .form-inline .custom-control-label {
margin-bottom:0 margin-bottom:0
} }
} }
.btn { .btn {
display:inline-block; display:inline-block;
@ -2138,7 +2139,7 @@ textarea.form-control {
.btn { .btn {
transition:none transition:none
} }
} }
.btn:hover { .btn:hover {
color:#495057; color:#495057;
@ -2626,7 +2627,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.fade { .fade {
transition:none transition:none
} }
} }
.fade:not(.show) { .fade:not(.show) {
opacity:0 opacity:0
@ -2644,7 +2645,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.collapsing { .collapsing {
transition:none transition:none
} }
} }
.dropdown,.dropleft,.dropright,.dropup { .dropdown,.dropleft,.dropright,.dropup {
position:relative position:relative
@ -2701,7 +2702,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0; right:0;
left:auto left:auto
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.dropdown-menu-md-left { .dropdown-menu-md-left {
@ -2712,7 +2713,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0; right:0;
left:auto left:auto
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.dropdown-menu-lg-left { .dropdown-menu-lg-left {
@ -2723,7 +2724,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0; right:0;
left:auto left:auto
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.dropdown-menu-xl-left { .dropdown-menu-xl-left {
@ -2734,7 +2735,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
right:0; right:0;
left:auto left:auto
} }
} }
.dropup .dropdown-menu { .dropup .dropdown-menu {
top:auto; 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 { .custom-switch .custom-control-label::after {
transition:none transition:none
} }
} }
.custom-switch .custom-control-input:checked~.custom-control-label::after { .custom-switch .custom-control-input:checked~.custom-control-label::after {
background-color:#fff; background-color:#fff;
@ -3356,7 +3357,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
-webkit-transition:none; -webkit-transition:none;
transition:none transition:none
} }
} }
.custom-range::-webkit-slider-thumb:active { .custom-range::-webkit-slider-thumb:active {
background-color:#cfeaf9 background-color:#cfeaf9
@ -3386,7 +3387,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
-moz-transition:none; -moz-transition:none;
transition:none transition:none
} }
} }
.custom-range::-moz-range-thumb:active { .custom-range::-moz-range-thumb:active {
background-color:#cfeaf9 background-color:#cfeaf9
@ -3418,7 +3419,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
-ms-transition:none; -ms-transition:none;
transition:none transition:none
} }
} }
.custom-range::-ms-thumb:active { .custom-range::-ms-thumb:active {
background-color:#cfeaf9 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 { .custom-control-label::before,.custom-file-label,.custom-select {
transition:none transition:none
} }
} }
.nav { .nav {
display:-ms-flexbox; 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-right:0;
padding-left:0 padding-left:0
} }
} }
@media (min-width:576px) { @media (min-width:576px) {
.navbar-expand-sm { .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 { .navbar-expand-sm .navbar-toggler {
display:none display:none
} }
} }
@media (max-width:767.98px) { @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 { .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-right:0;
padding-left:0 padding-left:0
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.navbar-expand-md { .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 { .navbar-expand-md .navbar-toggler {
display:none display:none
} }
} }
@media (max-width:991.98px) { @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 { .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-right:0;
padding-left:0 padding-left:0
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.navbar-expand-lg { .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 { .navbar-expand-lg .navbar-toggler {
display:none display:none
} }
} }
@media (max-width:1199.98px) { @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 { .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-right:0;
padding-left:0 padding-left:0
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.navbar-expand-xl { .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 { .navbar-expand-xl .navbar-toggler {
display:none display:none
} }
} }
.navbar-expand { .navbar-expand {
-ms-flex-flow:row nowrap; -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-bottom:0;
margin-left:15px margin-left:15px
} }
} }
.card-group>.card { .card-group>.card {
margin-bottom:15px 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 { .card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom {
border-bottom-left-radius:0 border-bottom-left-radius:0
} }
} }
.card-columns .card { .card-columns .card {
margin-bottom:.75rem margin-bottom:.75rem
@ -4071,7 +4072,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
display:inline-block; display:inline-block;
width:100% width:100%
} }
} }
.accordion { .accordion {
overflow-anchor:none overflow-anchor:none
@ -4218,7 +4219,7 @@ input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-
.badge { .badge {
transition:none transition:none
} }
} }
a.badge:focus,a.badge:hover { a.badge:focus,a.badge:hover {
text-decoration:none text-decoration:none
@ -4341,7 +4342,7 @@ a.badge-dark.focus,a.badge-dark:focus {
.jumbotron { .jumbotron {
padding:4rem 2rem padding:4rem 2rem
} }
} }
.jumbotron-fluid { .jumbotron-fluid {
padding-right:0; padding-right:0;
@ -4467,7 +4468,7 @@ a.badge-dark.focus,a.badge-dark:focus {
to { to {
background-position:0 0 background-position:0 0
} }
} }
@keyframes progress-bar-stripes { @keyframes progress-bar-stripes {
from { from {
@ -4476,7 +4477,7 @@ a.badge-dark.focus,a.badge-dark:focus {
to { to {
background-position:0 0 background-position:0 0
} }
} }
.progress { .progress {
display:-ms-flexbox; display:-ms-flexbox;
@ -4506,7 +4507,7 @@ a.badge-dark.focus,a.badge-dark:focus {
.progress-bar { .progress-bar {
transition:none transition:none
} }
} }
.progress-bar-striped { .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); 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; -webkit-animation:none;
animation:none animation:none
} }
} }
.media { .media {
display:-ms-flexbox; display:-ms-flexbox;
@ -4637,7 +4638,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px; margin-left:-1px;
border-left-width:1px border-left-width:1px
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.list-group-horizontal-md { .list-group-horizontal-md {
@ -4663,7 +4664,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px; margin-left:-1px;
border-left-width:1px border-left-width:1px
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.list-group-horizontal-lg { .list-group-horizontal-lg {
@ -4689,7 +4690,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px; margin-left:-1px;
border-left-width:1px border-left-width:1px
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.list-group-horizontal-xl { .list-group-horizontal-xl {
@ -4715,7 +4716,7 @@ a.badge-dark.focus,a.badge-dark:focus {
margin-left:-1px; margin-left:-1px;
border-left-width:1px border-left-width:1px
} }
} }
.list-group-flush { .list-group-flush {
border-radius:0 border-radius:0
@ -4930,7 +4931,7 @@ a.close.disabled {
.modal.fade .modal-dialog { .modal.fade .modal-dialog {
transition:none transition:none
} }
} }
.modal.show .modal-dialog { .modal.show .modal-dialog {
-webkit-transform:none; -webkit-transform:none;
@ -5086,19 +5087,19 @@ a.close.disabled {
.modal-sm { .modal-sm {
max-width:300px max-width:300px
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.modal-lg,.modal-xl { .modal-lg,.modal-xl {
max-width:800px max-width:800px
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.modal-xl { .modal-xl {
max-width:1140px max-width:1140px
} }
} }
.tooltip { .tooltip {
position:absolute; position:absolute;
@ -5365,7 +5366,7 @@ a.close.disabled {
.carousel-item { .carousel-item {
transition:none transition:none
} }
} }
.carousel-item-next,.carousel-item-prev,.carousel-item.active { .carousel-item-next,.carousel-item-prev,.carousel-item.active {
display:block display:block
@ -5397,7 +5398,7 @@ a.close.disabled {
.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right { .carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right {
transition:none transition:none
} }
} }
.carousel-control-next,.carousel-control-prev { .carousel-control-next,.carousel-control-prev {
position:absolute; position:absolute;
@ -5420,7 +5421,7 @@ a.close.disabled {
.carousel-control-next,.carousel-control-prev { .carousel-control-next,.carousel-control-prev {
transition:none transition:none
} }
} }
.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover { .carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover {
color:#fff; color:#fff;
@ -5482,7 +5483,7 @@ a.close.disabled {
.carousel-indicators li { .carousel-indicators li {
transition:none transition:none
} }
} }
.carousel-indicators .active { .carousel-indicators .active {
opacity:1 opacity:1
@ -5503,14 +5504,14 @@ a.close.disabled {
-webkit-transform:rotate(360deg); -webkit-transform:rotate(360deg);
transform:rotate(360deg) transform:rotate(360deg)
} }
} }
@keyframes spinner-border { @keyframes spinner-border {
to { to {
-webkit-transform:rotate(360deg); -webkit-transform:rotate(360deg);
transform:rotate(360deg) transform:rotate(360deg)
} }
} }
.spinner-border { .spinner-border {
display:inline-block; display:inline-block;
@ -5538,7 +5539,7 @@ a.close.disabled {
-webkit-transform:none; -webkit-transform:none;
transform:none transform:none
} }
} }
@keyframes spinner-grow { @keyframes spinner-grow {
0% { 0% {
@ -5550,7 +5551,7 @@ a.close.disabled {
-webkit-transform:none; -webkit-transform:none;
transform:none transform:none
} }
} }
.spinner-grow { .spinner-grow {
display:inline-block; 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:-ms-inline-flexbox!important;
display:inline-flex!important display:inline-flex!important
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.d-md-none { .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:-ms-inline-flexbox!important;
display:inline-flex!important display:inline-flex!important
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.d-lg-none { .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:-ms-inline-flexbox!important;
display:inline-flex!important display:inline-flex!important
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.d-xl-none { .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:-ms-inline-flexbox!important;
display:inline-flex!important display:inline-flex!important
} }
} }
@media print { @media print {
.d-print-none { .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:-ms-inline-flexbox!important;
display:inline-flex!important display:inline-flex!important
} }
} }
.embed-responsive { .embed-responsive {
position:relative; 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; -ms-flex-item-align:stretch!important;
align-self:stretch!important align-self:stretch!important
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.flex-md-row { .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; -ms-flex-item-align:stretch!important;
align-self:stretch!important align-self:stretch!important
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.flex-lg-row { .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; -ms-flex-item-align:stretch!important;
align-self:stretch!important align-self:stretch!important
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.flex-xl-row { .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; -ms-flex-item-align:stretch!important;
align-self:stretch!important align-self:stretch!important
} }
} }
.float-left { .float-left {
float:left!important 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-sm-none {
float:none!important float:none!important
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.float-md-left { .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-md-none {
float:none!important float:none!important
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.float-lg-left { .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-lg-none {
float:none!important float:none!important
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.float-xl-left { .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-xl-none {
float:none!important float:none!important
} }
} }
.user-select-all { .user-select-all {
-webkit-user-select:all!important; -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; top:0;
z-index:1020 z-index:1020
} }
} }
.sr-only { .sr-only {
position:absolute; 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 { .ml-sm-auto,.mx-sm-auto {
margin-left:auto!important margin-left:auto!important
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.m-md-0 { .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 { .ml-md-auto,.mx-md-auto {
margin-left:auto!important margin-left:auto!important
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.m-lg-0 { .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 { .ml-lg-auto,.mx-lg-auto {
margin-left:auto!important margin-left:auto!important
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.m-xl-0 { .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 { .ml-xl-auto,.mx-xl-auto {
margin-left:auto!important margin-left:auto!important
} }
} }
.stretched-link::after { .stretched-link::after {
position:absolute; 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-sm-center {
text-align:center!important text-align:center!important
} }
} }
@media (min-width:768px) { @media (min-width:768px) {
.text-md-left { .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-md-center {
text-align:center!important text-align:center!important
} }
} }
@media (min-width:992px) { @media (min-width:992px) {
.text-lg-left { .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-lg-center {
text-align:center!important text-align:center!important
} }
} }
@media (min-width:1200px) { @media (min-width:1200px) {
.text-xl-left { .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-xl-center {
text-align:center!important text-align:center!important
} }
} }
.text-lowercase { .text-lowercase {
text-transform:lowercase!important text-transform:lowercase!important
@ -8472,7 +8473,7 @@ a.text-dark:focus,a.text-dark:hover {
color:inherit; color:inherit;
border-color:#dee2e6 border-color:#dee2e6
} }
} }
.bg-primary { .bg-primary {
background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5); background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);

@ -9,8 +9,7 @@
* Copyright 2011-2020 The Bootstrap Authors * Copyright 2011-2020 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc. * Copyright 2011-2020 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400; */@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap);
700&display=swap);
:root { :root {
--blue:#2a9fd6; --blue:#2a9fd6;
--indigo:#6610f2; --indigo:#6610f2;
@ -36,6 +35,7 @@
--dark:#adafae; --dark:#adafae;
--body-bg: #060606; --body-bg: #060606;
--text-bg-mark: #fcf8e3; --text-bg-mark: #fcf8e3;
--custom-select: #fff;
--breakpoint-xs:0; --breakpoint-xs:0;
--breakpoint-sm:576px; --breakpoint-sm:576px;
--breakpoint-md:768px; --breakpoint-md:768px;

@ -223,10 +223,10 @@ export const CompilerApiMixin = (Base) => class extends Base {
} }
this.compiler.event.register('loadingCompiler', this.data.eventHandlers.onLoadingCompiler) 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.data.loading = false
this.statusChanged({ key: 'none' }) this.statusChanged({ key: 'none' })
this.emit('compilerLoaded', version) this.emit('compilerLoaded', version, license)
} }
this.compiler.event.register('compilerLoaded', this.data.eventHandlers.onCompilerLoaded) this.compiler.event.register('compilerLoaded', this.data.eventHandlers.onCompilerLoaded)

@ -38,12 +38,15 @@ const App: React.FC = () => {
async function start() { async function start() {
try { try {
await remixClient.loaded() await remixClient.loaded()
remixClient.onFileChange(name => setContract(name)) remixClient.onFileChange(name => setContract(name))
const name = await remixClient.getContractName() remixClient.onNoFileSelected(() => setContract(''))
setContract(name)
} catch (err) { } catch (err) {
console.log(err) console.log(err)
} }
try {
const name = await remixClient.getContractName() // throw if no file are selected
setContract(name)
} catch (e) {}
} }
start() start()
}, []) }, [])

@ -28,22 +28,60 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) {
/** Compile a Contract */ /** Compile a Contract */
async function compileContract() { async function compileContract() {
try { 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({ remixClient.changeStatus({
key: 'loading', key: 'loading',
type: 'info', type: 'info',
title: 'Compiling' 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) setOutput(_contract.name, output)
// ERROR // ERROR
if (isCompilationError(output)) { if (isCompilationError(output)) {
const line = output.line const line = output.line
const lineColumnPos = { if (line) {
start: { line: line - 1 }, const lineColumnPos = {
end: { line: line - 1 } 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) throw new Error(output.message)
} }
// SUCCESS // SUCCESS
@ -61,7 +99,6 @@ function CompilerButton({ contract, setOutput, compilerUrl }: Props) {
type: 'error', type: 'error',
title: err.message title: err.message
}) })
console.error(err)
} }
} }

@ -26,11 +26,10 @@ function LocalUrlInput({ url, setUrl, environment }: Props) {
type="email" type="email"
placeholder="eg http://localhost:8000/compile" /> placeholder="eg http://localhost:8000/compile" />
<Form.Text className="text-muted"> <Form.Text className="text-muted">
The url to your local compiler
</Form.Text> </Form.Text>
</Form.Group> </Form.Group>
</Form> </Form>
) )
} }
export default LocalUrlInput; export default LocalUrlInput;

@ -7,7 +7,6 @@ import {
} from '../utils'; } from '../utils';
import Tabs from 'react-bootstrap/Tabs' import Tabs from 'react-bootstrap/Tabs'
import Tab from 'react-bootstrap/Tab' import Tab from 'react-bootstrap/Tab'
import { Ballot } from '../examples/ballot';
import Button from 'react-bootstrap/Button'; import Button from 'react-bootstrap/Button';
import JSONTree from 'react-json-view' import JSONTree from 'react-json-view'
import { CopyToClipboard } from '@remix-ui/clipboard' import { CopyToClipboard } from '@remix-ui/clipboard'
@ -17,14 +16,20 @@ interface VyperResultProps {
output?: VyperCompilationOutput; output?: VyperCompilationOutput;
} }
export type ExampleContract = {
name: string,
address: string
}
function VyperResult({ output }: VyperResultProps) { function VyperResult({ output }: VyperResultProps) {
const [ active, setActive ] = useState<keyof VyperCompilationResult>('abi'); const [ active, setActive ] = useState<keyof VyperCompilationResult>('abi')
if (!output) return ( if (!output) return (
<div id="result"> <div id="result">
<p>No contract compiled yet.</p> <p>No contract compiled yet.</p>
<Button data-id="add-ballot" variant="info" onClick={() => remixClient.loadContract(Ballot)}> <Button data-id="add-repository" variant="info" onClick={() => remixClient.cloneVyperRepo()}>
Create Ballot.vy example Clone Vyper repository and play with the contract examples
</Button> </Button>
</div> </div>
) )
@ -33,7 +38,7 @@ function VyperResult({ output }: VyperResultProps) {
return ( return (
<div id="result" className="error"> <div id="result" className="error">
<i className="fas fa-exclamation-circle text-danger"></i> <i className="fas fa-exclamation-circle text-danger"></i>
<p data-id="error-message" className="alert alert-danger">{output.message}</p> <pre data-id="error-message" className="alert alert-danger">{output.message}</pre>
</div>) </div>)
} }
@ -41,7 +46,7 @@ function VyperResult({ output }: VyperResultProps) {
<Tabs id="result" activeKey={active} onSelect={(key: any) => setActive(key)}> <Tabs id="result" activeKey={active} onSelect={(key: any) => setActive(key)}>
<Tab eventKey="abi" title="ABI"> <Tab eventKey="abi" title="ABI">
<CopyToClipboard getContent={() => JSON.stringify(output.abi)}> <CopyToClipboard getContent={() => JSON.stringify(output.abi)}>
<Button variant="info" className="copy">Copy ABI</Button> <Button variant="info" className="copy" data-id="copy-abi">Copy ABI</Button>
</CopyToClipboard> </CopyToClipboard>
<JSONTree src={output.abi} /> <JSONTree src={output.abi} />
</Tab> </Tab>

@ -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
`
}

@ -18,8 +18,8 @@ export interface VyperCompilationResult {
export interface VyperCompilationError { export interface VyperCompilationError {
status: 'failed' status: 'failed'
column: number column?: number
line: number line?: number
message: string message: string
} }

@ -3,6 +3,7 @@ import { Api, Status } from '@remixproject/plugin-utils';
import { createClient } from '@remixproject/plugin-webview' import { createClient } from '@remixproject/plugin-webview'
import { PluginClient } from '@remixproject/plugin'; import { PluginClient } from '@remixproject/plugin';
import { Contract } from './compiler'; import { Contract } from './compiler';
import { ExampleContract } from '../components/VyperResult';
export class RemixClient extends PluginClient { export class RemixClient extends PluginClient {
private client = createClient<Api, Readonly<RemixApi>>(this); private client = createClient<Api, Readonly<RemixApi>>(this);
@ -14,34 +15,70 @@ export class RemixClient extends PluginClient {
/** Emit an event when file changed */ /** Emit an event when file changed */
async onFileChange(cb: (contract: string) => any) { async onFileChange(cb: (contract: string) => any) {
this.client.on('fileManager', 'currentFileChanged', async (name: string) => { this.client.on('fileManager', 'currentFileChanged', async (name: string) => {
if (!name) return
cb(name) 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 */ /** Load Ballot contract example into the file manager */
async loadContract({name, content}: Contract) { async loadContract({name, address}: ExampleContract) {
try { try {
await this.client.call('fileManager', 'setFile', name, content) const content = await this.client.call('contentImport', 'resolve', address)
await this.client.call('fileManager', 'switchFile', name) await this.client.call('fileManager', 'setFile', content.cleanUrl, content.content)
await this.client.call('fileManager', 'switchFile', content.cleanUrl)
} catch (err) { } catch (err) {
console.log(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 */ /** Update the status of the plugin in remix */
changeStatus(status: Status) { changeStatus(status: Status) {
this.client.emit('statusChanged', status); this.client.emit('statusChanged', status);
} }
/** Highlight a part of the editor */ /** Highlight a part of the editor */
highlight(lineColumnPos: HighlightPosition, name: string, color: string) { async highlight(lineColumnPos: HighlightPosition, name: string, message: string) {
return this.client.call('editor', 'highlight', lineColumnPos, name, color) 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: <SPDX-License>" 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 */ /** Remove current Hightlight */
discardHighlight() { async discardHighlight() {
return this.client.call('editor', 'discardHighlight') await this.client.call('editor', 'discardHighlight')
await this.client.call('editor', 'clearAnnotations')
} }
/** Get the name of the current contract */ /** Get the name of the current contract */

@ -33,7 +33,8 @@ export default function (self) { // eslint-disable-line @typescript-eslint/expli
} }
self.postMessage({ self.postMessage({
cmd: 'versionLoaded', cmd: 'versionLoaded',
data: compiler.version() data: compiler.version(),
license: compiler.license()
}) })
break break
} }

@ -25,6 +25,7 @@ export class Compiler {
compileJSON: null, compileJSON: null,
worker: null, worker: null,
currentVersion: null, currentVersion: null,
compilerLicense: null,
optimize: false, optimize: false,
runs: 200, runs: 200,
evmVersion: null, evmVersion: null,
@ -95,9 +96,10 @@ export class Compiler {
* @param version compiler version * @param version compiler version
*/ */
onCompilerLoaded(version: string): void { onCompilerLoaded (version: string, license: string): void {
this.state.currentVersion = version 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.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) { if (err) {
console.error('Error in loading remote solc compiler: ', err) console.error('Error in loading remote solc compiler: ', err)
} else { } else {
let license
this.state.compileJSON = (source: SourceWithTarget) => { this.state.compileJSON = (source: SourceWithTarget) => {
const missingInputs: string[] = [] const missingInputs: string[] = []
const missingInputsCallback = (path: string) => { const missingInputsCallback = (path: string) => {
@ -204,13 +207,14 @@ export class Compiler {
} }
result = JSON.parse(remoteCompiler.compile(input, { import: missingInputsCallback })) result = JSON.parse(remoteCompiler.compile(input, { import: missingInputsCallback }))
license = remoteCompiler.license()
} }
} catch (exception) { } catch (exception) {
result = { error: { formattedMessage: 'Uncaught JavaScript exception:\n' + exception, severity: 'error', mode: 'panic' } } result = { error: { formattedMessage: 'Uncaught JavaScript exception:\n' + exception, severity: 'error', mode: 'panic' } }
} }
this.onCompilationFinished(result, missingInputs, source, input, version) this.onCompilationFinished(result, missingInputs, source, input, version)
} }
this.onCompilerLoaded(version) this.onCompilerLoaded(version, license)
} }
}) })
} }
@ -277,7 +281,7 @@ export class Compiler {
} }
switch (data.cmd) { switch (data.cmd) {
case 'versionLoaded': case 'versionLoaded':
if (data.data) this.onCompilerLoaded(data.data) if (data.data && data.license) this.onCompilerLoaded(data.data, data.license)
break break
case 'compiled': case 'compiled':
{ {

@ -163,6 +163,7 @@ export interface CompilerState {
compileJSON: ((input: SourceWithTarget) => void) | null, compileJSON: ((input: SourceWithTarget) => void) | null,
worker: any, worker: any,
currentVersion: string| null| undefined, currentVersion: string| null| undefined,
compilerLicense: string| null
optimize: boolean, optimize: boolean,
runs: number runs: number
evmVersion: EVMVersion| null, evmVersion: EVMVersion| null,
@ -193,6 +194,7 @@ export interface MessageToWorker {
export interface MessageFromWorker { export interface MessageFromWorker {
cmd: string, cmd: string,
license?: string,
job?: number, job?: number,
missingInputs?: string[], missingInputs?: string[],
input?: any, input?: any,

@ -134,7 +134,7 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts
if (runs) compiler.set('runs', runs) if (runs) compiler.set('runs', runs)
if (currentCompilerUrl) { if (currentCompilerUrl) {
compiler.loadRemoteVersion(currentCompilerUrl) compiler.loadRemoteVersion(currentCompilerUrl)
compiler.event.register('compilerLoaded', this, function (version) { compiler.event.register('compilerLoaded', this, function (version, license) {
next() next()
}) })
} else { } else {
@ -198,7 +198,7 @@ export function compileContractSources (sources: SrcIfc, newCompConfig: any, imp
compiler.set('runs', runs) compiler.set('runs', runs)
compiler.loadVersion(usingWorker, currentCompilerUrl) compiler.loadVersion(usingWorker, currentCompilerUrl)
// @ts-ignore // @ts-ignore
compiler.event.register('compilerLoaded', this, (version) => { compiler.event.register('compilerLoaded', this, (version, license) => {
next() next()
}) })
} else { } else {

@ -16,4 +16,8 @@
} }
.validationError { .validationError {
overflow-wrap: break-word; overflow-wrap: break-word;
}
.debuggerPanels {
overflow-y: scroll;
height: fit-content;
} }

@ -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 TxBrowser from './tx-browser/tx-browser' // eslint-disable-line
import StepManager from './step-manager/step-manager' // eslint-disable-line import StepManager from './step-manager/step-manager' // eslint-disable-line
import VmDebugger from './vm-debugger/vm-debugger' // eslint-disable-line import VmDebugger from './vm-debugger/vm-debugger' // eslint-disable-line
@ -36,6 +36,28 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
sourceLocationStatus: '' sourceLocationStatus: ''
}) })
const panelsRef = useRef<HTMLDivElement>(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(() => { useEffect(() => {
return unLoad() return unLoad()
}, []) }, [])
@ -260,34 +282,35 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
}) })
setTimeout(async() => { setTimeout(async() => {
try { try {
await debuggerInstance.debug(blockNumber, txNumber, tx, () => { await debuggerInstance.debug(blockNumber, txNumber, tx, () => {
listenToEvents(debuggerInstance, currentReceipt) 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 => { setState(prevState => {
return { return {
...prevState, ...prevState,
blockNumber, validationError: error.message || error
txNumber,
debugging: true,
currentReceipt,
currentBlock,
currentTransaction,
debugger: debuggerInstance,
toastMessage: `debugging ${txNumber}`,
validationError: ''
} }
}) })
}) }
} catch (error) { }, 300)
unLoad() handleResize()
setState(prevState => {
return {
...prevState,
validationError: error.message || error
}
})
}
}, 300)
} }
const debug = (txHash, web3?) => { 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, 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 registerEvent: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.event.register.bind(state.debugger.step_manager.event) : null
} }
const vmDebugger = { const vmDebugger = {
registerEvent: state.debugger && state.debugger.vmDebuggerLogic ? state.debugger.vmDebuggerLogic.event.register.bind(state.debugger.vmDebuggerLogic.event) : null, 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 triggerEvent: state.debugger && state.debugger.vmDebuggerLogic ? state.debugger.vmDebuggerLogic.event.trigger.bind(state.debugger.vmDebuggerLogic.event) : null
} }
return ( return (
<div> <div>
<Toaster message={state.toastMessage} /> <Toaster message={state.toastMessage} />
<div className="px-2"> <div className="px-2" ref={debuggerTopRef}>
<div> <div>
<p className="my-2 debuggerLabel">Debugger Configuration</p> <div className="mb-2 debuggerConfig custom-control custom-checkbox" title="Using Generated Sources lets you step into compiler outputs while debugging.">
<div className="mt-2 mb-2 debuggerConfig custom-control custom-checkbox">
<input className="custom-control-input" id="debugGeneratedSourcesInput" onChange={({ target: { checked } }) => { <input className="custom-control-input" id="debugGeneratedSourcesInput" onChange={({ target: { checked } }) => {
setState(prevState => { setState(prevState => {
return { ...prevState, opt: { ...prevState.opt, debugWithGeneratedSources: checked } } return { ...prevState, opt: { ...prevState.opt, debugWithGeneratedSources: checked } }
@ -333,7 +357,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
}} type="checkbox" title="Debug with generated sources" /> }} type="checkbox" title="Debug with generated sources" />
<label data-id="debugGeneratedSourcesLabel" className="form-check-label custom-control-label" htmlFor="debugGeneratedSourcesInput">Use generated sources (Solidity {'>='} v0.7.2)</label> <label data-id="debugGeneratedSourcesLabel" className="form-check-label custom-control-label" htmlFor="debugGeneratedSourcesInput">Use generated sources (Solidity {'>='} v0.7.2)</label>
</div> </div>
{ state.isLocalNodeUsed && <div className="mt-2 mb-2 debuggerConfig custom-control custom-checkbox"> { state.isLocalNodeUsed && <div className="mb-2 debuggerConfig custom-control custom-checkbox">
<input className="custom-control-input" id="debugWithLocalNodeInput" onChange={({ target: { checked } }) => { <input className="custom-control-input" id="debugWithLocalNodeInput" onChange={({ target: { checked } }) => {
setState(prevState => { setState(prevState => {
return { ...prevState, opt: { ...prevState.opt, debugWithLocalNode: checked } } return { ...prevState, opt: { ...prevState.opt, debugWithLocalNode: checked } }
@ -356,9 +380,11 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
</span> </span>
</div> } </div> }
{ state.debugging && <StepManager stepManager={ stepManager } /> } { state.debugging && <StepManager stepManager={ stepManager } /> }
</div>
<div className="debuggerPanels" ref={panelsRef}>
{ state.debugging && <VmDebuggerHead vmDebugger={ vmDebugger } /> } { state.debugging && <VmDebuggerHead vmDebugger={ vmDebugger } /> }
{ state.debugging && <VmDebugger vmDebugger={ vmDebugger } currentBlock={ state.currentBlock } currentReceipt={ state.currentReceipt } currentTransaction={ state.currentTransaction } /> }
</div> </div>
{ state.debugging && <VmDebugger vmDebugger={ vmDebugger } currentBlock={ state.currentBlock } currentReceipt={ state.currentReceipt } currentTransaction={ state.currentTransaction } /> }
</div> </div>
) )
} }

@ -98,7 +98,7 @@ export const VmDebuggerHead = ({ vmDebugger: { registerEvent, triggerEvent } })
}, [registerEvent]) }, [registerEvent])
return ( return (
<div id='vmheadView' className="mt-1 px-0"> <div id='vmheadView' className="mt-1 px-2">
<div className='d-flex flex-column'> <div className='d-flex flex-column'>
<div className='w-100'> <div className='w-100'>
<FunctionPanel data={functionPanel} /> <FunctionPanel data={functionPanel} />

@ -75,6 +75,7 @@ type errorMarker = {
}, },
file: string file: string
} }
loader.config({ paths: { vs: 'assets/js/monaco-editor/dev/vs' } }) loader.config({ paths: { vs: 'assets/js/monaco-editor/dev/vs' } })
export type DecorationsReturn = { export type DecorationsReturn = {
@ -442,7 +443,6 @@ export const EditorUI = (props: EditorUIProps) => {
allMarkersPerfile[filePath].push(markerData) allMarkersPerfile[filePath].push(markerData)
} }
} }
console.log(allMarkersPerfile)
for (const filePath in allMarkersPerfile) { for (const filePath in allMarkersPerfile) {
const model = editorModelsState[filePath]?.model const model = editorModelsState[filePath]?.model
if (model) { if (model) {
@ -587,8 +587,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
function handleEditorWillMount(monaco: Monaco) { function handleEditorWillMount(monaco) {
monacoRef.current = monaco monacoRef.current = monaco
// Register a new language // Register a new language
monacoRef.current.languages.register({ id: 'remix-solidity' }) monacoRef.current.languages.register({ id: 'remix-solidity' })

@ -1,4 +1,5 @@
export * from './lib/remix-ui-helper' export * from './lib/remix-ui-helper'
export * from './lib/bleach'
export * from './lib/helper-components' export * from './lib/helper-components'
export * from './lib/components/PluginViewWrapper' export * from './lib/components/PluginViewWrapper'
export * from './lib/components/custom-dropdown' export * from './lib/components/custom-dropdown'

@ -5,7 +5,7 @@
*/ */
import * as he from 'he' import * as he from 'he'
const remixBleach = { export const bleach = {
matcher: /<\/?([a-zA-Z0-9]+)*(.*?)\/?>/igm, matcher: /<\/?([a-zA-Z0-9]+)*(.*?)\/?>/igm,
@ -24,7 +24,7 @@ const remixBleach = {
let match let match
// extract all tags // extract all tags
while ((match = remixBleach.matcher.exec(html)) != null) { while ((match = bleach.matcher.exec(html)) != null) {
const attrr = match[2].split(' ') const attrr = match[2].split(' ')
const attrs = [] const attrs = []
@ -45,7 +45,7 @@ const remixBleach = {
if (attr.name) attrs.push(attr) if (attr.name) attrs.push(attr)
}) })
var tag = { const tag = {
full: match[0], full: match[0],
name: match[1], name: match[1],
attr: attrs attr: attrs
@ -57,14 +57,13 @@ const remixBleach = {
return matches return matches
}, },
sanitize: function (html, options) { sanitize: function (html, options = { mode: 'white', list: bleach.whitelist, encode_entities: false}) {
html = String(html) || '' html = String(html) || ''
options = options || {}
const mode = options.mode || 'white' 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) || if ((mode === 'white' && list.indexOf('script') === -1) ||
(mode === 'black' && list.indexOf('script') !== -1)) { (mode === 'black' && list.indexOf('script') !== -1)) {
@ -95,5 +94,3 @@ const remixBleach = {
return html return html
} }
} }
module.exports = remixBleach

@ -8,6 +8,7 @@
.remixModalBody { .remixModalBody {
overflow-y: auto; overflow-y: auto;
max-height: 600px; max-height: 600px;
white-space: pre-line;
} }
@-webkit-keyframes animatetop { @-webkit-keyframes animatetop {
from {top: -300px; opacity: 0} from {top: -300px; opacity: 0}

@ -27,8 +27,8 @@ const RemixUIPanelHeader = (props: RemixPanelProps) => {
return ( return (
<header className='d-flex flex-column'> <header className='d-flex flex-column'>
<div className="swapitHeader px-3 pt-2 pb-0 d-flex flex-row"> <div className="swapitHeader px-3 pt-2 pb-0 d-flex flex-row">
<h6 className="mb-2" data-id='sidePanelSwapitTitle'>{plugin?.profile.displayName || plugin?.profile.name}</h6> <h6 className="mb-3" data-id='sidePanelSwapitTitle'>{plugin?.profile.displayName || plugin?.profile.name}</h6>
<div className="mt-2 d-flex flex-row"> <div className="d-flex flex-row">
<div className="d-flex flex-row"> <div className="d-flex flex-row">
{plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && (<i aria-hidden="true" className="text-success mt-1 px-1 fas fa-check" title="Maintained by Remix"></i>)} {plugin?.profile?.maintainedBy?.toLowerCase() === "remix" && (<i aria-hidden="true" className="text-success mt-1 px-1 fas fa-check" title="Maintained by Remix"></i>)}
</div> </div>

@ -46,8 +46,8 @@ export const listenToEvents = (compileTabLogic: CompileTabLogic, api) => (dispat
dispatch(setCompilerMode('loadingCompiler')) dispatch(setCompilerMode('loadingCompiler'))
}) })
compileTabLogic.compiler.event.register('compilerLoaded', () => { compileTabLogic.compiler.event.register('compilerLoaded', (version, license) => {
dispatch(setCompilerMode('compilerLoaded')) dispatch(setCompilerMode('compilerLoaded', version, license))
}) })
compileTabLogic.compiler.event.register('compilationFinished', (success, data, source, input, version) => { compileTabLogic.compiler.event.register('compilationFinished', (success, data, source, input, version) => {

@ -48,6 +48,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
timeout: 300, timeout: 300,
allversions: [], allversions: [],
customVersions: [], customVersions: [],
compilerLicense: null,
selectedVersion: null, selectedVersion: null,
defaultVersion: 'soljson-v0.8.7+commit.e28d00a7.js', // this default version is defined: in makeMockCompiler (for browser test) defaultVersion: 'soljson-v0.8.7+commit.e28d00a7.js', // this default version is defined: in makeMockCompiler (for browser test)
runs: '', runs: '',
@ -185,7 +186,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
loadingCompiler() loadingCompiler()
break break
case 'compilerLoaded': case 'compilerLoaded':
compilerLoaded() compilerLoaded(compilerContainer.compiler.args[1])
break break
case 'compilationFinished': case 'compilationFinished':
compilationFinished() compilationFinished()
@ -432,14 +433,20 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
if (!compileIcon.current) return if (!compileIcon.current) return
compileIcon.current.setAttribute('title', 'compiler is loading, please wait a few moments.') compileIcon.current.setAttribute('title', 'compiler is loading, please wait a few moments.')
compileIcon.current.classList.add('remixui_spinningIcon') compileIcon.current.classList.add('remixui_spinningIcon')
setState(prevState => {
return { ...prevState, compilerLicense: 'Compiler is loading. License will be displayed once compiler is loaded'}
})
_updateLanguageSelector() _updateLanguageSelector()
setDisableCompileButton(true) setDisableCompileButton(true)
} }
const compilerLoaded = () => { const compilerLoaded = (license) => {
if (!compileIcon.current) return if (!compileIcon.current) return
compileIcon.current.setAttribute('title', '') compileIcon.current.setAttribute('title', '')
compileIcon.current.classList.remove('remixui_spinningIcon') 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() if (state.autoCompile) compile()
const isDisabled = !compiledFileName || (compiledFileName && !isSolFileSelected(compiledFileName)) 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', () => {}) 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) => { const promptMessage = (message) => {
return ( return (
<> <>
@ -701,10 +712,9 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<article> <article>
<div className='pt-0 remixui_compilerSection'> <div className='pt-0 remixui_compilerSection'>
<div className="mb-1"> <div className="mb-1">
<label className="remixui_compilerLabel form-check-label" htmlFor="versionSelector"> <label className="remixui_compilerLabel form-check-label" htmlFor="versionSelector">Compiler</label>
Compiler <span className="far fa-plus border-0 p-0 ml-3" onClick={() => promptCompiler()} title="Add a custom compiler with URL"></span>
<button className="far fa-plus btn-light border-0 p-0 mx-2 btn-sm" onClick={promptCompiler} title="Add a custom compiler with URL"></button> <span className="fa fa-file-text-o border-0 p-0 ml-2" onClick={() => showCompilerLicense()} title="See compiler license"></span>
</label>
<select value={ state.selectedVersion || state.defaultVersion } onChange={(e) => handleLoadVersion(e.target.value) } className="custom-select" id="versionSelector" disabled={state.allversions.length <= 0}> <select value={ state.selectedVersion || state.defaultVersion } onChange={(e) => handleLoadVersion(e.target.value) } className="custom-select" id="versionSelector" disabled={state.allversions.length <= 0}>
{ state.allversions.length <= 0 && <option disabled data-id={state.selectedVersion === state.defaultVersion ? 'selected' : ''}>{ state.defaultVersion }</option> } { state.allversions.length <= 0 && <option disabled data-id={state.selectedVersion === state.defaultVersion ? 'selected' : ''}>{ state.defaultVersion }</option> }
{ state.allversions.length <= 0 && <option disabled data-id={state.selectedVersion === 'builtin' ? 'selected' : ''}>builtin</option> } { state.allversions.length <= 0 && <option disabled data-id={state.selectedVersion === 'builtin' ? 'selected' : ''}>builtin</option> }

@ -164,7 +164,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
testTab.fileManager.events.on('currentFileChanged', async (file: string) => { testTab.fileManager.events.on('currentFileChanged', async (file: string) => {
await updateForNewCurrent(file) await updateForNewCurrent(file)
}) })
testTab.on('solidity', 'compilerLoaded', async (version: string) => { testTab.on('solidity', 'compilerLoaded', async (version: string, license: string) => {
const { currentVersion } = testTab.compileTab.getCurrentCompilerConfig() const { currentVersion } = testTab.compileTab.getCurrentCompilerConfig()
if (!semver.gt(truncateVersion(currentVersion), '0.4.12')) { if (!semver.gt(truncateVersion(currentVersion), '0.4.12')) {

@ -140,8 +140,8 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
setSlitherEnabled(false) setSlitherEnabled(false)
} }
}) })
// eslint-disable-next-line @typescript-eslint/no-unused-vars
props.analysisModule.on('solidity', 'compilerLoaded', async (version: string) => { props.analysisModule.on('solidity', 'compilerLoaded', async (version: string, license: string) => {
setDisableForRun(version) setDisableForRun(version)
}) })
return () => { } return () => { }

@ -1,5 +1,7 @@
import { checkSpecialChars } from '@remix-ui/helper' import { checkSpecialChars } from '@remix-ui/helper'
import { BadgeStatus, IconStatus } from '../components/Icon' import { BadgeStatus, IconStatus } from '../components/Icon'
import { bleach } from '@remix-ui/helper'
export type IconBadgeReducerAction = { export type IconBadgeReducerAction = {
readonly type: string readonly type: string
@ -20,13 +22,13 @@ function setIconStatus(name: string, status: IconStatus) {
if (typeof status.key === 'number') { if (typeof status.key === 'number') {
key = status.key key = status.key
text = key text = key
} else key = checkSpecialChars(status.key) ? '' : status.key } else key = checkSpecialChars(status.key) ? bleach.sanitize(status.key) : status.key
let thisType = '' let thisType = ''
if (status.type === 'error') { if (status.type === 'error') {
thisType = 'danger' // to use with bootstrap thisType = 'danger' // to use with bootstrap
} else thisType = checkSpecialChars(status.type) ? '' : status.type! } else thisType = checkSpecialChars(status.type) ? bleach.sanitize(status.type) : status.type
const title = checkSpecialChars(status.title) ? '' : status.title const title = checkSpecialChars(status.title) ? bleach.sanitize(status.title) : status.title
const pluginName = status.pluginName const pluginName = status.pluginName
return { title, type: thisType, key, text, pluginName } return { title, type: thisType, key, text, pluginName }
} }

Loading…
Cancel
Save