Merge branch 'master' into yann300-patch-38

pull/1956/head
David Disu 3 years ago committed by GitHub
commit cab9485f3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/remix-ide/src/app/tabs/runTab/model/recorder.js
  2. 7
      apps/remix-ide/src/app/tabs/theme-module.js
  3. 5
      libs/remix-ui/editor/src/lib/remix-ui-editor.css
  4. 4
      libs/remix-ui/helper/src/lib/remix-ui-helper.ts
  5. 2
      libs/remix-ui/permission-handler/src/lib/permission-dialog.tsx
  6. 43
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  7. 4
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  8. 4
      libs/remix-ui/run-tab/src/lib/types/index.ts
  9. 46
      libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
  10. 51
      libs/remix-ui/theme-module/src/lib/remix-ui-theme-module.tsx

@ -259,7 +259,7 @@ class Recorder {
cb(err)
}
)
}, () => { self.setListen(true); self.clearAll() })
}, () => { self.setListen(true) })
}
runScenario (json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) {

@ -35,15 +35,17 @@ export class ThemeModule extends Plugin {
}
this.themes = themes.reduce((acc, theme) => {
theme.url = window.location.origin + window.location.pathname + theme.url
return { ...acc, [theme.name]: theme }
return { ...acc, [theme.name.toLocaleLowerCase()]: theme }
}, {})
this._paq = _paq
let queryTheme = (new QueryParams()).get().theme
queryTheme = queryTheme && queryTheme.toLocaleLowerCase()
queryTheme = this.themes[queryTheme] ? queryTheme : null
let currentTheme = this._deps.config.get('settings/theme')
currentTheme = currentTheme && currentTheme.toLocaleLowerCase()
currentTheme = this.themes[currentTheme] ? currentTheme : null
this.currentThemeState = { queryTheme, currentTheme }
this.active = queryTheme || currentTheme || 'Dark'
this.active = queryTheme || currentTheme || 'dark'
this.forced = !!queryTheme
}
@ -82,6 +84,7 @@ export class ThemeModule extends Plugin {
* @param {string} [themeName] - The name of the theme
*/
switchTheme (themeName) {
themeName = themeName && themeName.toLocaleLowerCase()
if (themeName && !Object.keys(this.themes).includes(themeName)) {
throw new Error(`Theme ${themeName} doesn't exist`)
}

@ -10,6 +10,11 @@
width: auto;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
max-width: none !important;
word-wrap: break-word;
}
.contextview {
opacity: 1;
position: absolute;

@ -37,9 +37,9 @@ export const createNonClashingNameAsync = async (name: string, fileManager, pref
let exist = true
do {
const isDuplicate = await fileManager.exists(name + _counter + prefix + '.' + ext)
const isDuplicate = await fileManager.exists(name + (_counter || '') + prefix + '.' + ext)
if (isDuplicate) _counter = (_counter | 0) + 1
if (isDuplicate) _counter = (_counter || 0) + 1
else exist = false
} while (exist)
const counter = _counter || ''

@ -56,7 +56,7 @@ const PermissionHandlerDialog = (props: PermissionHandlerProps) => {
<article className='remember'>
<div className='form-check'>
{rememberSwitch()}
<label className="form-check-label" data-id="permissionHandlerRememberChoice">Remember this choice</label>
<label htmlFor='remember' className="form-check-label" data-id="permissionHandlerRememberChoice">Remember this choice</label>
</div>
<button className="btn btn-sm" onClick={reset}>Reset all Permissions</button>
</article>

@ -2,7 +2,7 @@
import React from 'react'
import * as ethJSUtil from 'ethereumjs-util'
import Web3 from 'web3'
import { addressToString, createNonClashingNameAsync, shortenAddress } from '@remix-ui/helper'
import { addressToString, createNonClashingNameAsync, extractNameFromKey, shortenAddress } from '@remix-ui/helper'
import { addNewInstance, addProvider, clearAllInstances, clearRecorderCount, displayNotification, displayPopUp, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, fetchContractListSuccess, hidePopUp, removeExistingInstance, removeProvider, resetUdapp, setBaseFeePerGas, setConfirmSettings, setCurrentFile, setDecodedResponse, setEnvToasterContent, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setLoadType, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setPassphrase, setPathToScenario, setRecorderCount, setSelectedAccount, setSendUnit, setSendValue, setTxFeeContent, setWeb3Dialog } from './payload'
import { RunTab } from '../types/run-tab'
import { CompilerAbstract } from '@remix-project/remix-solidity'
@ -622,38 +622,39 @@ export const runTransactions = (
)
}
const saveScenario = (promptCb, cb) => {
const saveScenario = (newPath: string, provider, promptCb, cb) => {
const txJSON = JSON.stringify(plugin.recorder.getAll(), null, 2)
const path = plugin.fileManager.currentPath()
promptCb(path, async () => {
const fileProvider = plugin.fileManager.fileProviderOf(path)
if (!fileProvider) return
const newFile = path + '/' + plugin.REACT_API.recorder.pathToScenario
promptCb(() => {
try {
const newPath = await createNonClashingNameAsync(newFile, plugin.fileManager)
if (!fileProvider.set(newPath, txJSON)) return cb('Failed to create file ' + newFile)
plugin.fileManager.open(newFile)
if (!provider.set(newPath, txJSON)) return cb('Failed to create file ' + newPath)
plugin.fileManager.open(newPath)
} catch (error) {
if (error) return cb('Failed to create file. ' + newFile + ' ' + error)
if (error) return cb('Failed to create file. ' + newPath + ' ' + error)
}
})
}
export const storeScenario = (prompt: (msg: string) => JSX.Element) => {
saveScenario(
(path, cb) => {
dispatch(displayNotification('Save transactions as scenario', prompt('Transactions will be saved in a file under ' + path), 'Ok', 'Cancel', cb, null))
export const storeScenario = async (prompt: (msg: string, defaultValue: string) => JSX.Element) => {
const path = plugin.fileManager.currentPath()
const fileProvider = plugin.fileManager.fileProviderOf(path)
if (!fileProvider) return displayNotification('Alert', 'Invalid File Provider', 'OK', null)
const newPath = await createNonClashingNameAsync(path + '/' + plugin.REACT_API.recorder.pathToScenario, plugin.fileManager)
const newName = extractNameFromKey(newPath)
saveScenario(newPath, fileProvider,
(cb) => {
dispatch(displayNotification('Save transactions as scenario', prompt('Transactions will be saved in a file under ' + path, newName), 'OK', 'Cancel', cb, null))
},
(error) => {
if (error) return dispatch(displayNotification('Alert', error, 'Ok', null))
if (error) return dispatch(displayNotification('Alert', error, 'OK', null))
}
)
}
const runScenario = (file: string, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt, logBuilder: (msg: string) => JSX.Element) => {
if (!file) return dispatch(displayNotification('Alert', 'Unable to run scenerio, no specified scenario file', 'Ok', null))
if (!file) return dispatch(displayNotification('Alert', 'Unable to run scenerio, no specified scenario file', 'OK', null))
plugin.fileManager.readFile(file).then((json) => {
// TODO: there is still a UI dependency to remove here, it's still too coupled at this point to remove easily
@ -664,7 +665,7 @@ const runScenario = (file: string, gasEstimationPrompt: (msg: string) => JSX.Ele
}, (okCb, cancelCb) => {
promptHandler(passphrasePrompt, okCb, cancelCb)
}, (msg) => {
dispatch(displayNotification('Alert', msg, 'Ok', null))
dispatch(displayNotification('Alert', msg, 'OK', null))
}, (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
confirmationHandler(confirmDialogContent, network, tx, gasEstimation, continueTxExecution, cancelCb)
}, (msg: string) => {
@ -673,11 +674,11 @@ const runScenario = (file: string, gasEstimationPrompt: (msg: string) => JSX.Ele
return terminalLogger(log)
}, (error, abi, address, contractName) => {
if (error) {
return dispatch(displayNotification('Alert', error, 'Ok', null))
return dispatch(displayNotification('Alert', error, 'OK', null))
}
addInstance({ name: contractName, address, abi })
})
}).catch((error) => dispatch(displayNotification('Alert', error, 'Ok', null)))
}).catch((error) => dispatch(displayNotification('Alert', error, 'OK', null)))
}
export const runCurrentScenario = (gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt, logBuilder: (msg: string) => JSX.Element) => {

@ -172,8 +172,8 @@ export function RunTabUI (props: RunTabProps) {
return <PassphrasePrompt message={message} setPassphrase={setPassphrasePrompt} defaultValue={runTab.passphrase} />
}
const scenarioPrompt = (message: string) => {
return <ScenarioPrompt message={message} setScenarioPath={updateScenarioPath} defaultValue={runTab.recorder.pathToScenario} />
const scenarioPrompt = (message: string, defaultValue) => {
return <ScenarioPrompt message={message} setScenarioPath={updateScenarioPath} defaultValue={defaultValue} />
}
const mainnetPrompt = (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => {

@ -189,13 +189,13 @@ export interface ContractDropdownProps {
}
export interface RecorderProps {
storeScenario: (prompt: (msg: string) => JSX.Element) => void,
storeScenario: (prompt: (msg: string, defaultValue: string) => JSX.Element) => void,
runCurrentScenario: (gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt, logBuilder: (msg: string) => JSX.Element) => void,
logBuilder: (msg: string) => JSX.Element,
mainnetPrompt: MainnetPrompt,
gasEstimationPrompt: (msg: string) => JSX.Element,
passphrasePrompt: (msg: string) => JSX.Element,
scenarioPrompt: (msg: string) => JSX.Element,
scenarioPrompt: (msg: string, defaultValue: string) => JSX.Element,
count: number
}

@ -67,6 +67,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
let [readyTestsNumber, setReadyTestsNumber] = useState<number>(0) // eslint-disable-line
let [runningTestsNumber, setRunningTestsNumber] = useState<number>(0) // eslint-disable-line
const areTestsRunning = useRef<boolean>(false)
const hasBeenStopped = useRef<boolean>(false)
const isDebugging = useRef<boolean>(false)
const allTests = useRef<string[]>([])
@ -74,7 +75,6 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
const currentErrors:any = useRef([]) // eslint-disable-line @typescript-eslint/no-explicit-any
const defaultPath = 'tests'
let areTestsRunning = false
let runningTestFileName: string
const filesContent: Record<string, Record<string, string>> = {}
@ -113,7 +113,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
allTests.current = tests
selectedTests.current = [...allTests.current]
updateTestFileList()
if (!areTestsRunning) await updateRunAction(file)
if (!areTestsRunning.current) await updateRunAction(file)
} catch (e: any) { // eslint-disable-line @typescript-eslint/no-explicit-any
console.log(e)
setToasterMsg(e)
@ -153,7 +153,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
await setCurrentPath(defaultPath)
})
testTab.fileManager.events.on('noFileSelected', () => { }) // eslint-disable-line
testTab.fileManager.events.on('noFileSelected', async () => { await updateForNewCurrent() })
testTab.fileManager.events.on('currentFileChanged', async (file: string) => await updateForNewCurrent(file))
}, []) // eslint-disable-line
@ -167,15 +167,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
const handleTestDirInput = async (e: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
let testDirInput = trimTestDirInput(e.target.value)
testDirInput = helper.removeMultipleSlashes(testDirInput)
if (testDirInput !== '/') testDirInput = helper.removeTrailingSlashes(testDirInput)
setInputPathValue(testDirInput)
if (e.key === 'Enter') {
if (await testTabLogic.pathExists(testDirInput)) {
testTabLogic.setCurrentPath(testDirInput)
await updateForNewCurrent()
return
}
}
if (testDirInput) {
if (testDirInput.endsWith('/') && testDirInput !== '/') {
testDirInput = helper.removeTrailingSlashes(testDirInput)
@ -205,17 +197,6 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
}
}
const handleEnter = async (e: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
let inputPath = e.target.value
inputPath = helper.removeMultipleSlashes(trimTestDirInput(inputPath))
setInputPathValue(inputPath)
if (disableCreateButton) {
if (await testTabLogic.pathExists(inputPath)) {
await setCurrentPath(inputPath)
}
}
}
const handleCreateFolder = async () => {
let inputPath = trimTestDirInput(inputPathValue)
let path = helper.removeMultipleSlashes(inputPath)
@ -519,7 +500,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
if (selectedTests.current?.length !== 0) {
setDisableRunButton(false)
}
areTestsRunning = false
areTestsRunning.current = false
}
}
@ -566,7 +547,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
}
const runTests = () => {
areTestsRunning = true
areTestsRunning.current = true
hasBeenStopped.current = false
readyTestsNumber = 0
setReadyTestsNumber(readyTestsNumber)
@ -587,14 +568,14 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
const updateRunAction = async (currentFile: any = null) => { // eslint-disable-line @typescript-eslint/no-explicit-any
const isSolidityActive = await testTab.appManager.isActive('solidity')
if (!isSolidityActive || !selectedTests.current?.length) {
// setDisableRunButton(true)
if (!isSolidityActive || !selectedTests.current.length) {
setDisableRunButton(true)
if (!currentFile || (currentFile && currentFile.split('.').pop().toLowerCase() !== 'sol')) {
setRunButtonTitle('No solidity file selected')
} else {
setRunButtonTitle('The "Solidity Plugin" should be activated')
}
}
} else setDisableRunButton(false)
}
const stopTests = () => {
@ -611,7 +592,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
const toggleCheckbox = (eChecked: boolean, index: number) => {
testFiles[index].checked = eChecked
setTestFiles(testFiles)
setTestFiles([...testFiles])
selectedTests.current = getCurrentSelectedTests()
if (eChecked) {
setCheckSelectAll(true)
@ -628,7 +609,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
const checkAll = (event: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any
testFiles.forEach((testFileObj) => testFileObj.checked = event.target.checked)
setTestFiles(testFiles)
setTestFiles([...testFiles])
setCheckSelectAll(event.target.checked)
if (event.target.checked) {
selectedTests.current = getCurrentSelectedTests()
@ -646,7 +627,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
}
else
testFiles = []
setTestFiles(testFiles)
setTestFiles([...testFiles])
}
return (
@ -674,8 +655,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
title="Press 'Enter' to change the path for test files."
style={{ backgroundImage: "var(--primary)" }}
onKeyDown={() => { if (inputPathValue === '/') setInputPathValue('')} }
onKeyUp={handleTestDirInput}
onChange={handleEnter}
onChange={handleTestDirInput}
onClick = {() => { if (inputPathValue === '/') setInputPathValue('')} }
/>
<button
@ -728,7 +708,7 @@ export const SolidityUnitTesting = (props: Record<string, any>) => { // eslint-d
/>
<label className="text-nowrap pl-2 mb-0" htmlFor="checkAllTests"> Select all </label>
</div>
<div className="testList py-2 mt-0 border-bottom">{testFiles?.length ? testFiles.map((testFileObj: TestObject, index) => {
<div className="testList py-2 mt-0 border-bottom">{testFiles.length ? testFiles.map((testFileObj: TestObject, index) => {
const elemId = `singleTest${testFileObj.fileName}`
return (
<div className="d-flex align-items-center py-1" key={index}>

@ -8,55 +8,6 @@ export interface RemixUiThemeModuleProps {
themeModule: ThemeModule;
}
const defaultThemes = [
{
name: 'Dark',
quality: 'dark',
url: 'assets/css/themes/remix-dark_tvx1s2.css'
},
{
name: 'Light',
quality: 'light',
url: 'assets/css/themes/remix-light_powaqg.css'
},
{
name: 'Midcentury',
quality: 'light',
url: 'assets/css/themes/remix-midcentury_hrzph3.css'
},
{
name: 'Black',
quality: 'dark',
url: 'assets/css/themes/remix-black_undtds.css'
},
{
name: 'Candy',
quality: 'light',
url: 'assets/css/themes/remix-candy_ikhg4m.css'
},
{
name: 'Cerulean',
quality: 'light',
url: 'assets/css/themes/bootstrap-cerulean.min.css'
},
{
name: 'Flatly',
quality: 'light',
url: 'assets/css/themes/bootstrap-flatly.min.css'
},
{
name: 'Spacelab',
quality: 'light',
url: 'assets/css/themes/bootstrap-spacelab.min.css'
},
{
name: 'Cyborg',
quality: 'dark',
url: 'assets/css/themes/bootstrap-cyborg.min.css'
}
];
export function RemixUiThemeModule({ themeModule }: RemixUiThemeModuleProps) {
const [themeName, setThemeName] = useState('')
@ -85,7 +36,7 @@ export function RemixUiThemeModule({ themeModule }: RemixUiThemeModuleProps) {
name="theme"
id={theme.name}
data-id={`settingsTabTheme${theme.name}`}
checked={themeModule.active === theme.name}
checked={themeModule.active === theme.name.toLocaleLowerCase()}
/>
<label
className="form-check-label custom-control-label"

Loading…
Cancel
Save