Commit fbc18a2f authored by filip mertens's avatar filip mertens

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

parents 20913eca 4ddba6b2
...@@ -111,8 +111,7 @@ export const DebuggerApiMixin = (Base) => class extends Base { ...@@ -111,8 +111,7 @@ export const DebuggerApiMixin = (Base) => class extends Base {
} }
return null return null
}, },
debugWithGeneratedSources: false, debugWithGeneratedSources: false
fork: 'berlin'
}) })
return await debug.debugger.traceManager.getTrace(hash) return await debug.debugger.traceManager.getTrace(hash)
} }
......
...@@ -18,6 +18,7 @@ module.exports = { ...@@ -18,6 +18,7 @@ module.exports = {
'Should activate `generate contract metadata`': function (browser) { 'Should activate `generate contract metadata`': function (browser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000) browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.waitForElementVisible('*[data-id="settingsTabGenerateContractMetadataLabel"]', 5000) .waitForElementVisible('*[data-id="settingsTabGenerateContractMetadataLabel"]', 5000)
.verify.elementPresent('[data-id="settingsTabGenerateContractMetadata"]:checked')
.click('*[data-id="verticalIconsFileExplorerIcons"]') .click('*[data-id="verticalIconsFileExplorerIcons"]')
.click('[data-id="treeViewLitreeViewItemcontracts"]') .click('[data-id="treeViewLitreeViewItemcontracts"]')
.openFile('contracts/3_Ballot.sol') .openFile('contracts/3_Ballot.sol')
...@@ -39,22 +40,26 @@ module.exports = { ...@@ -39,22 +40,26 @@ module.exports = {
.click('*[data-id="verticalIconsKindsettings"]') .click('*[data-id="verticalIconsKindsettings"]')
.setValue('*[data-id="settingsTabGistAccessToken"]', '**********') .setValue('*[data-id="settingsTabGistAccessToken"]', '**********')
.click('*[data-id="settingsTabSaveGistToken"]') .click('*[data-id="settingsTabSaveGistToken"]')
.waitForElementVisible('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 5000) .waitForElementVisible('*[data-shared="tooltipPopup"]', 5000)
.assert.containsText('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 'Access token has been saved') .assert.containsText('*[data-shared="tooltipPopup"]', 'Access token has been saved')
.pause(3000)
}, },
'Should copy github access token to clipboard': function (browser: NightwatchBrowser) { 'Should copy github access token to clipboard': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]', 5000) browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]', 5000)
.click('*[data-id="copyToClipboardCopyIcon"]') .click('*[data-id="copyToClipboardCopyIcon"]')
.waitForElementVisible('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 5000) .waitForElementVisible('*[data-shared="tooltipPopup"]', 5000)
.assert.containsText('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 'Copied value to clipboard.') // .waitForElementVisible('*[data-shared="tooltipPopup"]:nth-last-of-type(1) , 5000)
// .assert.containsText('*[data-shared="tooltipPopup"]', 'Copied value to clipboard.')
// .assert.containsText('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 'Copied value to clipboard.')
}, },
'Should remove github access token': function (browser: NightwatchBrowser) { 'Should remove github access token': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]', 5000) browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]', 5000)
.pause(1000)
.click('*[data-id="settingsTabRemoveGistToken"]') .click('*[data-id="settingsTabRemoveGistToken"]')
.waitForElementVisible('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 5000) .waitForElementVisible('*[data-shared="tooltipPopup"]', 5000)
.assert.containsText('*[data-shared="tooltipPopup"]:nth-last-of-type(1)', 'Access token removed') .assert.containsText('*[data-shared="tooltipPopup"]', 'Access token removed')
.assert.containsText('*[data-id="settingsTabGistAccessToken"]', '') .assert.containsText('*[data-id="settingsTabGistAccessToken"]', '')
}, },
......
...@@ -32,6 +32,8 @@ module.exports = { ...@@ -32,6 +32,8 @@ module.exports = {
'Should sign message using account key': function (browser: NightwatchBrowser) { 'Should sign message using account key': function (browser: NightwatchBrowser) {
browser.waitForElementPresent('*[data-id="settingsRemixRunSignMsg"]') browser.waitForElementPresent('*[data-id="settingsRemixRunSignMsg"]')
.click('select[id="selectExEnvOptions"] option[value="vm-berlin"]')
.pause(2000)
.click('*[data-id="settingsRemixRunSignMsg"]') .click('*[data-id="settingsRemixRunSignMsg"]')
.pause(2000) .pause(2000)
.waitForElementPresent('*[data-id="modalDialogCustomPromptText"]') .waitForElementPresent('*[data-id="modalDialogCustomPromptText"]')
......
This diff is collapsed.
/* global ethereum */ /* global ethereum */
'use strict' 'use strict'
import Web3 from 'web3' import Web3 from 'web3'
import { execution } from '@remix-project/remix-lib'
import EventManager from '../lib/events' import EventManager from '../lib/events'
let web3 let web3
...@@ -21,8 +22,7 @@ export class ExecutionContext { ...@@ -21,8 +22,7 @@ export class ExecutionContext {
this.executionContext = null this.executionContext = null
this.blockGasLimitDefault = 4300000 this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault this.blockGasLimit = this.blockGasLimitDefault
this.defaultFork = 'berlin' this.currentFork = 'berlin'
this.currentFork = this.defaultFork
this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3' this.mainNetGenesisHash = '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3'
this.customNetWorks = {} this.customNetWorks = {}
this.blocks = {} this.blocks = {}
...@@ -125,19 +125,16 @@ export class ExecutionContext { ...@@ -125,19 +125,16 @@ export class ExecutionContext {
executionContextChange (value, endPointUrl, confirmCb, infoCb, cb) { executionContextChange (value, endPointUrl, confirmCb, infoCb, cb) {
const context = value.context const context = value.context
const fork = value.fork || this.defaultFork
if (!cb) cb = () => {} if (!cb) cb = () => {}
if (!confirmCb) confirmCb = () => {} if (!confirmCb) confirmCb = () => {}
if (!infoCb) infoCb = () => {} if (!infoCb) infoCb = () => {}
if (context === 'vm') { if (context === 'vm') {
this.executionContext = context this.executionContext = context
this.currentFork = fork this.currentFork = value.fork
this.event.trigger('contextChanged', ['vm']) this.event.trigger('contextChanged', ['vm'])
return cb() return cb()
} }
this.currentFork = this.defaultFork // in the case of injected and web3, we default to the last fork.
if (context === 'injected') { if (context === 'injected') {
if (injectedProvider === undefined) { if (injectedProvider === undefined) {
infoCb('No injected Web3 provider found. Make sure your provider (e.g. MetaMask) is active and running (when recently activated you may have to reload the page).') infoCb('No injected Web3 provider found. Make sure your provider (e.g. MetaMask) is active and running (when recently activated you may have to reload the page).')
...@@ -146,7 +143,7 @@ export class ExecutionContext { ...@@ -146,7 +143,7 @@ export class ExecutionContext {
this.askPermission() this.askPermission()
this.executionContext = context this.executionContext = context
web3.setProvider(injectedProvider) web3.setProvider(injectedProvider)
this._updateBlockGasLimit() this._updateChainContext()
this.event.trigger('contextChanged', ['injected']) this.event.trigger('contextChanged', ['injected'])
return cb() return cb()
} }
...@@ -173,12 +170,19 @@ export class ExecutionContext { ...@@ -173,12 +170,19 @@ export class ExecutionContext {
this.listenOnLastBlockId = null this.listenOnLastBlockId = null
} }
_updateBlockGasLimit () { _updateChainContext () {
if (this.getProvider() !== 'vm') { if (this.getProvider() !== 'vm') {
web3.eth.getBlock('latest', (err, block) => { web3.eth.getBlock('latest', async (err, block) => {
if (!err) { if (!err) {
// we can't use the blockGasLimit cause the next blocks could have a lower limit : https://github.com/ethereum/remix/issues/506 // we can't use the blockGasLimit cause the next blocks could have a lower limit : https://github.com/ethereum/remix/issues/506
this.blockGasLimit = (block && block.gasLimit) ? Math.floor(block.gasLimit - (5 * block.gasLimit) / 1024) : this.blockGasLimitDefault this.blockGasLimit = (block && block.gasLimit) ? Math.floor(block.gasLimit - (5 * block.gasLimit) / 1024) : this.blockGasLimitDefault
try {
this.currentFork = execution.forkAt(await web3.eth.net.getId(), block.number)
} catch (e) {
this.currentFork = 'berlin'
console.log(`unable to detect fork, defaulting to ${this.currentFork}..`)
console.error(e)
}
} else { } else {
this.blockGasLimit = this.blockGasLimitDefault this.blockGasLimit = this.blockGasLimitDefault
} }
...@@ -188,7 +192,7 @@ export class ExecutionContext { ...@@ -188,7 +192,7 @@ export class ExecutionContext {
listenOnLastBlock () { listenOnLastBlock () {
this.listenOnLastBlockId = setInterval(() => { this.listenOnLastBlockId = setInterval(() => {
this._updateBlockGasLimit() this._updateChainContext()
}, 15000) }, 15000)
} }
...@@ -202,7 +206,7 @@ export class ExecutionContext { ...@@ -202,7 +206,7 @@ export class ExecutionContext {
web3.eth.net.isListening((err, isConnected) => { web3.eth.net.isListening((err, isConnected) => {
if (!err && isConnected === true) { if (!err && isConnected === true) {
this.executionContext = context this.executionContext = context
this._updateBlockGasLimit() this._updateChainContext()
this.event.trigger('contextChanged', [context]) this.event.trigger('contextChanged', [context])
this.event.trigger('web3EndpointChanged') this.event.trigger('web3EndpointChanged')
cb() cb()
......
...@@ -41,7 +41,7 @@ export class Ethdebugger { ...@@ -41,7 +41,7 @@ export class Ethdebugger {
this.opts = opts this.opts = opts
this.event = new EventManager() this.event = new EventManager()
this.traceManager = new TraceManager({ web3: this.web3, fork: this.opts.fork }) this.traceManager = new TraceManager({ web3: this.web3 })
this.codeManager = new CodeManager(this.traceManager) this.codeManager = new CodeManager(this.traceManager)
this.solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: this.traceManager.getCurrentCalledAddressAt.bind(this.traceManager), getCode: this.codeManager.getCode.bind(this.codeManager) }) this.solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: this.traceManager.getCurrentCalledAddressAt.bind(this.traceManager), getCode: this.codeManager.getCode.bind(this.codeManager) })
this.storageResolver = null this.storageResolver = null
...@@ -55,7 +55,7 @@ export class Ethdebugger { ...@@ -55,7 +55,7 @@ export class Ethdebugger {
} }
setManagers () { setManagers () {
this.traceManager = new TraceManager({ web3: this.web3, fork: this.opts.fork }) this.traceManager = new TraceManager({ web3: this.web3 })
this.codeManager = new CodeManager(this.traceManager) this.codeManager = new CodeManager(this.traceManager)
this.solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: this.traceManager.getCurrentCalledAddressAt.bind(this.traceManager), getCode: this.codeManager.getCode.bind(this.codeManager) }) this.solidityProxy = new SolidityProxy({ getCurrentCalledAddressAt: this.traceManager.getCurrentCalledAddressAt.bind(this.traceManager), getCode: this.codeManager.getCode.bind(this.codeManager) })
this.storageResolver = null this.storageResolver = null
......
...@@ -26,8 +26,7 @@ export class Debugger { ...@@ -26,8 +26,7 @@ export class Debugger {
this.debugger = new Ethdebugger({ this.debugger = new Ethdebugger({
web3: options.web3, web3: options.web3,
debugWithGeneratedSources: options.debugWithGeneratedSources, debugWithGeneratedSources: options.debugWithGeneratedSources,
compilationResult: this.compilationResult, compilationResult: this.compilationResult
fork: options.fork
}) })
const { traceManager, callTree, solidityProxy } = this.debugger const { traceManager, callTree, solidityProxy } = this.debugger
......
'use strict' 'use strict'
import { util, execution } from '@remix-project/remix-lib'
import { TraceAnalyser } from './traceAnalyser' import { TraceAnalyser } from './traceAnalyser'
import { TraceCache } from './traceCache' import { TraceCache } from './traceCache'
import { TraceStepManager } from './traceStepManager' import { TraceStepManager } from './traceStepManager'
import { isCreateInstruction } from './traceHelper' import { isCreateInstruction } from './traceHelper'
import { util } from '@remix-project/remix-lib'
export class TraceManager { export class TraceManager {
web3 web3
...@@ -17,7 +17,6 @@ export class TraceManager { ...@@ -17,7 +17,6 @@ export class TraceManager {
constructor (options) { constructor (options) {
this.web3 = options.web3 this.web3 = options.web3
this.fork = options.fork
this.isLoading = false this.isLoading = false
this.trace = null this.trace = null
this.traceCache = new TraceCache() this.traceCache = new TraceCache()
...@@ -37,6 +36,15 @@ export class TraceManager { ...@@ -37,6 +36,15 @@ export class TraceManager {
if (result['structLogs'].length > 0) { if (result['structLogs'].length > 0) {
this.trace = result['structLogs'] this.trace = result['structLogs']
try {
const networkId = await this.web3.eth.net.getId()
this.fork = execution.forkAt(networkId, tx.blockNumber)
} catch (e) {
this.fork = 'berlin'
console.log(`unable to detect fork, defaulting to ${this.fork}..`)
console.error(e)
}
this.traceAnalyser.analyse(result['structLogs'], tx) this.traceAnalyser.analyse(result['structLogs'], tx)
this.isLoading = false this.isLoading = false
return true return true
......
'use strict'
/**
* returns the fork name for the @argument networkId and @argument blockNumber
*
* @param {Object} networkId - network Id (1 for VM, 3 for Ropsten, 4 for Rinkeby, 5 for Goerli)
* @param {Object} blockNumber - block number
* @return {String} - fork name (Berlin, Istanbul, ...)
*/
export function forkAt (networkId, blockNumber) {
if (forks[networkId]) {
let currentForkName = forks[networkId][0].name
for (const fork of forks[networkId]) {
if (blockNumber >= fork.number) {
currentForkName = fork.name
}
}
return currentForkName
}
return 'berlin'
}
// see https://github.com/ethereum/go-ethereum/blob/master/params/config.go
const forks = {
1: [
{
number: 4370000,
name: 'byzantium'
},
{
number: 7280000,
name: 'constantinople'
},
{
number: 7280000,
name: 'petersburg'
},
{
number: 9069000,
name: 'istanbul'
},
{
number: 9200000,
name: 'muirglacier'
},
{
number: 12244000,
name: 'berlin'
}
],
3: [
{
number: 1700000,
name: 'byzantium'
},
{
number: 4230000,
name: 'constantinople'
},
{
number: 4939394,
name: 'petersburg'
},
{
number: 6485846,
name: 'istanbul'
},
{
number: 7117117,
name: 'muirglacier'
},
{
number: 9812189,
name: 'berlin'
},
{
number: 10499401,
name: 'london'
}
],
4: [
{
number: 1035301,
name: 'byzantium'
},
{
number: 3660663,
name: 'constantinople'
},
{
number: 4321234,
name: 'petersburg'
},
{
number: 5435345,
name: 'istanbul'
},
{
number: 8290928,
name: 'berlin'
},
{
number: 8897988,
name: 'london'
}
],
5: [
{
number: 1561651,
name: 'istanbul'
},
{
number: 4460644,
name: 'berlin'
},
{
number: 5062605,
name: 'london'
}
]
}
...@@ -13,6 +13,7 @@ import * as txFormat from './execution/txFormat' ...@@ -13,6 +13,7 @@ import * as txFormat from './execution/txFormat'
import { TxListener } from './execution/txListener' import { TxListener } from './execution/txListener'
import { TxRunner } from './execution/txRunner' import { TxRunner } from './execution/txRunner'
import { LogsManager } from './execution/logsManager' import { LogsManager } from './execution/logsManager'
import { forkAt } from './execution/forkAt'
import * as typeConversion from './execution/typeConversion' import * as typeConversion from './execution/typeConversion'
import { TxRunnerVM } from './execution/txRunnerVM' import { TxRunnerVM } from './execution/txRunnerVM'
import { TxRunnerWeb3 } from './execution/txRunnerWeb3' import { TxRunnerWeb3 } from './execution/txRunnerWeb3'
...@@ -45,7 +46,8 @@ function modules () { ...@@ -45,7 +46,8 @@ function modules () {
TxRunnerWeb3: TxRunnerWeb3, TxRunnerWeb3: TxRunnerWeb3,
TxRunnerVM: TxRunnerVM, TxRunnerVM: TxRunnerVM,
typeConversion: typeConversion, typeConversion: typeConversion,
LogsManager LogsManager,
forkAt
} }
} }
} }
...@@ -91,7 +91,6 @@ export class VMContext { ...@@ -91,7 +91,6 @@ export class VMContext {
blocks blocks
latestBlockNumber latestBlockNumber
txs txs
defaultFork
currentVm currentVm
web3vm web3vm
logsManager logsManager
...@@ -100,8 +99,7 @@ export class VMContext { ...@@ -100,8 +99,7 @@ export class VMContext {
constructor (fork?) { constructor (fork?) {
this.blockGasLimitDefault = 4300000 this.blockGasLimitDefault = 4300000
this.blockGasLimit = this.blockGasLimitDefault this.blockGasLimit = this.blockGasLimitDefault
this.defaultFork = fork || 'berlin' this.currentFork = fork || 'berlin'
this.currentFork = this.defaultFork
this.currentVm = this.createVm(this.currentFork) this.currentVm = this.createVm(this.currentFork)
this.blocks = {} this.blocks = {}
this.latestBlockNumber = 0 this.latestBlockNumber = 0
......
...@@ -150,7 +150,7 @@ export interface CompilerInputOptions { ...@@ -150,7 +150,7 @@ export interface CompilerInputOptions {
language?: Language language?: Language
} }
export type EVMVersion = 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople' | 'petersburg' | 'istanbul' | 'muirGlacier' | 'berlin' | null export type EVMVersion = 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople' | 'petersburg' | 'istanbul' | 'muirGlacier' | 'berlin' | 'london' | null
export type Language = 'Solidity' | 'Yul' export type Language = 'Solidity' | 'Yul'
......
...@@ -6,6 +6,7 @@ import './copy-to-clipboard.css' ...@@ -6,6 +6,7 @@ import './copy-to-clipboard.css'
export const CopyToClipboard = ({ content, tip='Copy', icon='fa-copy', ...otherProps }) => { export const CopyToClipboard = ({ content, tip='Copy', icon='fa-copy', ...otherProps }) => {
const [message, setMessage] = useState(tip) const [message, setMessage] = useState(tip)
const handleClick = (event) => { const handleClick = (event) => {
if (content && content !== '') { // module `copy` keeps last copied thing in the memory, so don't show tooltip if nothing is copied, because nothing was added to memory if (content && content !== '') { // module `copy` keeps last copied thing in the memory, so don't show tooltip if nothing is copied, because nothing was added to memory
try { try {
......
...@@ -208,8 +208,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => { ...@@ -208,8 +208,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
} }
return null return null
}, },
debugWithGeneratedSources: state.opt.debugWithGeneratedSources, debugWithGeneratedSources: state.opt.debugWithGeneratedSources
fork: 'berlin'
}) })
debuggerInstance.debug(blockNumber, txNumber, tx, () => { debuggerInstance.debug(blockNumber, txNumber, tx, () => {
......
{
"presets": ["@nrwl/react/babel"],
"plugins": []
}
{
"env": {
"browser": true,
"es6": true
},
"extends": "../../../.eslintrc",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 11,
"sourceType": "module"
},
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error"
}
}
# remix-ui-settings
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test remix-ui-settings` to execute the unit tests via [Jest](https://jestjs.io).
export * from './lib/remix-ui-settings'
export const generateContractMetadataText = 'Generate contract metadata. Generate a JSON file in the contract folder. Allows to specify library addresses the contract depends on. If nothing is specified, Remix deploys libraries automatically.'
export const textSecondary = 'text-secondary'
export const textDark = 'text-dark'
export const warnText = 'Be sure the endpoint is opened before enabling it. \nThis mode allows a user to provide a passphrase in the Remix interface without having to unlock the account. Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...). Remix never persists any passphrase'.split('\n').map(s => s.trim()).join(' ')
export const gitAccessTokenTitle = 'Github Access Token'
export const gitAccessTokenText = 'Manage the access token used to publish to Gist and retrieve Github contents.'
export const gitAccessTokenText2 = 'Go to github token page (link below) to create a new token and save it in Remix. Make sure this token has only \'create gist\' permission.'
export const gitAccessTokenLink = 'https://github.com/settings/tokens'
export const ethereunVMText = 'Always use Ethereum VM at load'
export const wordWrapText = 'Word wrap in editor'
export const enablePersonalModeText = ' Enable Personal Mode for web3 provider. Transaction sent over Web3 will use the web3.personal API.\n'
export const matomoAnalytics = 'Enable Matomo Analytics. We do not collect personally identifiable information (PII). The info is used to improve the site’s UX & UI. See more about '
import React, { useState, useReducer, useEffect, useCallback } from 'react' // eslint-disable-line
import { CopyToClipboard } from '@remix-ui/clipboard' // eslint-disable-line
import { enablePersonalModeText, ethereunVMText, generateContractMetadataText, gitAccessTokenLink, gitAccessTokenText, gitAccessTokenText2, gitAccessTokenTitle, matomoAnalytics, textDark, textSecondary, warnText, wordWrapText } from './constants'
import './remix-ui-settings.css'
import { etherumVM, generateContractMetadat, personal, textWrapEventAction, useMatomoAnalytics, saveTokenToast, removeTokenToast } from './settingsAction'
import { initialState, toastInitialState, toastReducer, settingReducer } from './settingsReducer'
import { Toaster } from '@remix-ui/toaster'// eslint-disable-line
/* eslint-disable-next-line */
export interface RemixUiSettingsProps {
config: any,
editor: any,
_deps: any
}
export const RemixUiSettings = (props: RemixUiSettingsProps) => {
const [, dispatch] = useReducer(settingReducer, initialState)
const [state, dispatchToast] = useReducer(toastReducer, toastInitialState)
const [tokenValue, setTokenValue] = useState('')
const [themeName, setThemeName] = useState('')
useEffect(() => {
const token = props.config.get('settings/gist-access-token')
if (token === undefined) {
props.config.set('settings/generate-contract-metadata', true)
dispatch({ type: 'contractMetadata', payload: { name: 'contractMetadata', isChecked: true, textClass: textDark } })
}
if (token) {
setTokenValue(token)
}
}, [themeName, state.message])
const onchangeGenerateContractMetadata = (event) => {
generateContractMetadat(props, event, dispatch)
}
const onchangeOption = (event) => {
etherumVM(props, event, dispatch)
}
const textWrapEvent = (event) => {
textWrapEventAction(props, event, dispatch)
}
const onchangePersonal = event => {
personal(props, event, dispatch)
}
const onchangeMatomoAnalytics = event => {
useMatomoAnalytics(props, event, dispatch)
}
const onswitchTheme = (event, name) => {
props._deps.themeModule.switchTheme(name)
setThemeName(name)
}
const getTextClass = (key) => {
if (props.config.get(key)) {
return textDark
} else {
return textSecondary
}
}
const generalConfig = () => (
<div className="$border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">General settings</h6>
<div className="mt-2 custom-control custom-checkbox mb-1">
<input onChange={onchangeGenerateContractMetadata} id="generatecontractmetadata" data-id="settingsTabGenerateContractMetadata" type="checkbox" className="custom-control-input" name="contractMetadata" checked = { props.config.get('settings/generate-contract-metadata') }/>
<label className={`form-check-label custom-control-label align-middle ${getTextClass('settings/generate-contract-metadata')}`} data-id="settingsTabGenerateContractMetadataLabel" htmlFor="generatecontractmetadata">{generateContractMetadataText}</label>
</div>
<div className="fmt-2 custom-control custom-checkbox mb-1">
<input onChange={onchangeOption} className="custom-control-input" id="alwaysUseVM" data-id="settingsTabAlwaysUseVM" type="checkbox" name="ethereumVM" checked={ props.config.get('settings/always-use-vm') }/>
<label className={`form-check-label custom-control-label align-middle ${getTextClass('settings/always-use-vm')}`} htmlFor="alwaysUseVM">{ethereunVMText}</label>
</div>
<div className="mt-2 custom-control custom-checkbox mb-1">
<input id="editorWrap" className="custom-control-input" type="checkbox" onChange={textWrapEvent} checked = { props.config.get('settings/text-wrap')}/>
<label className={`form-check-label custom-control-label align-middle ${getTextClass('settings/text-wrap')}`} htmlFor="editorWrap">{wordWrapText}</label>
</div>
<div className="custom-control custom-checkbox mb-1">
<input onChange={onchangePersonal} id="personal" type="checkbox" className="custom-control-input" checked = { props.config.get('settings/personal-mode')}/>
<label className={`form-check-label custom-control-label align-middle ${getTextClass('settings/personal-mode')}`} htmlFor="personal">
<i className="fas fa-exclamation-triangle text-warning" aria-hidden="true"></i> <span> </span>
<span> </span>{enablePersonalModeText} {warnText}
</label>
</div>
<div className="custom-control custom-checkbox mb-1">
<input onChange={onchangeMatomoAnalytics} id="settingsMatomoAnalytics" type="checkbox" className="custom-control-input" checked={ props.config.get('settings/matomo-analytics')}/>
<label className={`form-check-label custom-control-label align-middle ${getTextClass('settings/matomo-analytics')}`} htmlFor="settingsMatomoAnalytics">
<span>{matomoAnalytics}</span>
<a href="https://medium.com/p/66ef69e14931/" target="_blank"> Analytics in Remix IDE</a> <span>&</span> <a target="_blank" href="https://matomo.org/free-software">Matomo</a>
</label>
</div>
</div>
</div>
)
const saveToken = () => {
saveTokenToast(props, dispatchToast, tokenValue)
}
const removeToken = () => {
setTokenValue('')
removeTokenToast(props, dispatchToast)
}
const handleSaveTokenState = useCallback(
(event) => {
setTokenValue(event.target.value)
},
[tokenValue]
)
const gistToken = () => (
<div className="border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">{ gitAccessTokenTitle }</h6>
<p className="mb-1">{ gitAccessTokenText }</p>
<p className="">{ gitAccessTokenText2 }</p>
<p className="mb-1"><a className="text-primary" target="_blank" href="https://github.com/settings/tokens">{ gitAccessTokenLink }</a></p>
<div className=""><label>TOKEN:</label>
<div className="text-secondary mb-0 h6">
<input id="gistaccesstoken" data-id="settingsTabGistAccessToken" type="password" className="form-control" onChange={handleSaveTokenState} value={ tokenValue } />
<div className="d-flex justify-content-end pt-2">
<CopyToClipboard content={tokenValue} data-id='copyToClipboardCopyIcon' />
<input className="btn btn-sm btn-primary ml-2" id="savegisttoken" data-id="settingsTabSaveGistToken" onClick={() => saveToken()} value="Save" type="button" disabled={tokenValue === ''}></input>
<button className="btn btn-sm btn-secondary ml-2" id="removegisttoken" data-id="settingsTabRemoveGistToken" title="Delete Github access token" onClick={() => removeToken()}>Remove</button>
</div>
</div></div>
</div>
</div>
)
const themes = () => {
const themes = props._deps.themeModule.getThemes()
if (themes) {
return themes.map((aTheme, index) => (
<div className="radio custom-control custom-radio mb-1 form-check" key={index}>
<input type="radio" onChange={event => { onswitchTheme(event, aTheme.name) }} className="align-middle custom-control-input" name='theme' id={aTheme.name} data-id={`settingsTabTheme${aTheme.name}`} checked = {props._deps.themeModule.active === aTheme.name ? true : null}/>
<label className="form-check-label custom-control-label" data-id={`settingsTabThemeLabel${aTheme.name}`} htmlFor={aTheme.name}>{aTheme.name} ({aTheme.quality})</label>
</div>
)
)
}
}
return (
<div>
{state.message ? <Toaster message= {state.message}/> : null}
{generalConfig()}
{gistToken()}
<div className="border-top">
<div className="card-body pt-3 pb-2">
<h6 className="card-title">Themes</h6>
<div className="card-text themes-container">
{themes()}
</div>
</div>
</div>
</div>
)
}
import { textDark, textSecondary } from './constants'
declare global {
interface Window {
_paq: any
}
}
const _paq = window._paq = window._paq || [] //eslint-disable-line
export const generateContractMetadat = (element, event, dispatch) => {
element.config.set('settings/generate-contract-metadata', event.target.checked)
dispatch({ type: 'contractMetadata', payload: { name: event.target.name, isChecked: event.target.checked, textClass: event.target.checked ? textDark : textSecondary } })
}
export const etherumVM = (element, event, dispatch) => {
element.config.set('settings/always-use-vm', event.target.checked)
dispatch({ type: 'ethereumVM', payload: { name: event.target.name, isChecked: event.target.checked, textClass: event.target.checked ? textDark : textSecondary } })
}
export const textWrapEventAction = (element, event, dispatch) => {
element.config.set('settings/text-wrap', event.target.checked)
element.editor.resize(event.target.checked)
dispatch({ type: 'textWrap', payload: { name: event.target.name, isChecked: event.target.checked, textClass: event.target.checked ? textDark : textSecondary } })
}
export const personal = (element, event, dispatch) => {
element.config.set('settings/personal-mode', event.target.checked)
dispatch({ type: 'personal', payload: { name: event.target.name, isChecked: event.target.checked, textClass: event.target.checked ? textDark : textSecondary } })
}
export const useMatomoAnalytics = (element, event, dispatch) => {
element.config.set('settings/matomo-analytics', event.target.checked)
dispatch({ type: 'useMatomoAnalytics', payload: { name: event.target.name, isChecked: event.target.checked, textClass: event.target.checked ? textDark : textSecondary } })
if (event.target.checked) {
_paq.push(['forgetUserOptOut'])
// @TODO remove next line when https://github.com/matomo-org/matomo/commit/9e10a150585522ca30ecdd275007a882a70c6df5 is used
document.cookie = 'mtm_consent_removed=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
} else {
_paq.push(['optUserOut'])
}
}
export const saveTokenToast = (props, dispatch, tokenValue) => {
props.config.set('settings/gist-access-token', tokenValue)
dispatch({ type: 'save', payload: { message: 'Access token has been saved' } })
}
export const removeTokenToast = (props, dispatch) => {
props.config.set('settings/gist-access-token', '')
dispatch({ type: 'removed', payload: { message: 'Access token removed' } })
}
import { textSecondary } from './constants'
export const initialState = {
elementState: [
{
name: 'contractMetadata',
isChecked: false,
textClass: textSecondary
},
{
name: 'ethereumVM',
isChecked: false,
textClass: textSecondary
},
{
name: 'textWrap',
isChecked: false,
textClass: textSecondary
},
{
name: 'personal',
isChecked: false,
textClass: textSecondary
},
{
name: 'useMatomoAnalytics',
isChecked: false,
textClass: textSecondary
}
]
}
export const settingReducer = (state, action) => {
switch (action.type) {
case 'contractMetadata':
state.elementState.map(element => {
if (element.name === 'contractMetadata') {
element.isChecked = action.payload.isChecked
element.textClass = action.payload.textClass
}
})
return {
...state
}
case 'ethereumVM':
state.elementState.map(element => {
if (element.name === 'ethereumVM') {
element.isChecked = action.payload.isChecked
element.textClass = action.payload.textClass
}
})
return {
...state
}
case 'textWrap':
state.elementState.map(element => {
if (element.name === 'textWrap') {
element.isChecked = action.payload.isChecked
element.textClass = action.payload.textClass
}
})
return {
...state
}
case 'personal':
state.elementState.map(element => {
if (element.name === 'personal') {
element.isChecked = action.payload.isChecked
element.textClass = action.payload.textClass
}
})
return {
...state
}
case 'useMatomoAnalytics':
state.elementState.map(element => {
if (element.name === 'useMatomoAnalytics') {
element.isChecked = action.payload.isChecked
element.textClass = action.payload.textClass
}
})
return {
...state
}
default:
return initialState
}
}
export const toastInitialState = {
message: ''
}
export const toastReducer = (state, action) => {
switch (action.type) {
case 'save' :
return { ...state, message: action.payload.message }
case 'removed' :
return { ...state, message: action.payload.message }
default :
return { ...state, message: '' }
}
}
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}
...@@ -96,6 +96,9 @@ ...@@ -96,6 +96,9 @@
"remix-ui-workspace": { "remix-ui-workspace": {
"tags": [] "tags": []
}, },
"remix-ui-settings": {
"tags": []
},
"remix-ui-static-analyser": { "remix-ui-static-analyser": {
"tags": [] "tags": []
}, },
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
"workspace-schematic": "nx workspace-schematic", "workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph", "dep-graph": "nx dep-graph",
"help": "nx help", "help": "nx help",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-core-plugin", "lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer,remix-ui-debugger-ui,remix-ui-workspace,remix-ui-static-analyser,remix-ui-checkbox,remix-ui-settings,remix-core-plugin",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-core-plugin", "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd,remix-core-plugin",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs", "publish:libs": "npm run build:libs && lerna publish --skip-git && npm run bumpVersion:libs",
......
...@@ -39,13 +39,12 @@ ...@@ -39,13 +39,12 @@
"@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"], "@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"],
"@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"], "@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"],
"@remix-ui/workspace": ["libs/remix-ui/workspace/src/index.ts"], "@remix-ui/workspace": ["libs/remix-ui/workspace/src/index.ts"],
"@remix-ui/static-analyser": [
"libs/remix-ui/static-analyser/src/index.ts"
],
"@remix-ui/checkbox": ["libs/remix-ui/checkbox/src/index.ts"],
"@remix-project/core-plugin": [ "@remix-project/core-plugin": [
"libs/remix-core-plugin/src/index.ts" "libs/remix-core-plugin/src/index.ts"
] ],
"@remix-ui/static-analyser": ["libs/remix-ui/static-analyser/src/index.ts"],
"@remix-ui/checkbox": ["libs/remix-ui/checkbox/src/index.ts"],
"@remix-ui/settings": ["libs/remix-ui/settings/src/index.ts"]
} }
}, },
"exclude": ["node_modules", "tmp"] "exclude": ["node_modules", "tmp"]
......
...@@ -726,6 +726,22 @@ ...@@ -726,6 +726,22 @@
} }
} }
}, },
"remix-ui-settings": {
"root": "libs/remix-ui/settings",
"sourceRoot": "libs/remix-ui/settings/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/settings/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/settings/**/*"]
}
}
}
},
"remix-ui-static-analyser": { "remix-ui-static-analyser": {
"root": "libs/remix-ui/static-analyser", "root": "libs/remix-ui/static-analyser",
"sourceRoot": "libs/remix-ui/static-analyser/src", "sourceRoot": "libs/remix-ui/static-analyser/src",
...@@ -858,4 +874,4 @@ ...@@ -858,4 +874,4 @@
} }
}, },
"defaultProject": "remix-ide" "defaultProject": "remix-ide"
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment