diff --git a/apps/remix-ide/src/app/editor/examples.js b/apps/remix-ide/src/app/editor/examples.js index 5b63d1a496..4f60ffa646 100644 --- a/apps/remix-ide/src/app/editor/examples.js +++ b/apps/remix-ide/src/app/editor/examples.js @@ -313,7 +313,7 @@ const deployWithEthers = `// Right click on the script name and hit "Run" to exe const readme = `REMIX EXAMPLE PROJECT -Remix example project is present when Remix loads very first time or there are no files existing in the File Explorer. +Remix example project is present when Remix loads for the very first time or there are no files existing in the File Explorer. It contains 3 directories: 1. 'contracts': Holds three contracts with different complexity level, denoted with number prefix in file name. diff --git a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js index f9a5d9aa78..a8b71b815e 100644 --- a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js +++ b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js @@ -259,7 +259,7 @@ class Recorder { cb(err) } ) - }, () => { self.setListen(true); self.clearAll() }) + }, () => { self.setListen(true) }) } runScenario (json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) { diff --git a/apps/remix-ide/src/app/tabs/theme-module.js b/apps/remix-ide/src/app/tabs/theme-module.js index d66ed07854..e973bdd2f9 100644 --- a/apps/remix-ide/src/app/tabs/theme-module.js +++ b/apps/remix-ide/src/app/tabs/theme-module.js @@ -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`) } diff --git a/libs/remix-ui/editor/src/lib/remix-ui-editor.css b/libs/remix-ui/editor/src/lib/remix-ui-editor.css index af7cd06bfd..ad1c9a7d5b 100644 --- a/libs/remix-ui/editor/src/lib/remix-ui-editor.css +++ b/libs/remix-ui/editor/src/lib/remix-ui-editor.css @@ -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; diff --git a/libs/remix-ui/helper/src/lib/remix-ui-helper.ts b/libs/remix-ui/helper/src/lib/remix-ui-helper.ts index 779709c75c..4b9eb28d1c 100644 --- a/libs/remix-ui/helper/src/lib/remix-ui-helper.ts +++ b/libs/remix-ui/helper/src/lib/remix-ui-helper.ts @@ -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 || '' diff --git a/libs/remix-ui/permission-handler/src/lib/permission-dialog.tsx b/libs/remix-ui/permission-handler/src/lib/permission-dialog.tsx index 5d7928b2f4..f1e4c1a6da 100644 --- a/libs/remix-ui/permission-handler/src/lib/permission-dialog.tsx +++ b/libs/remix-ui/permission-handler/src/lib/permission-dialog.tsx @@ -56,7 +56,7 @@ const PermissionHandlerDialog = (props: PermissionHandlerProps) => {
{rememberSwitch()} - +
diff --git a/libs/remix-ui/run-tab/src/lib/actions/index.ts b/libs/remix-ui/run-tab/src/lib/actions/index.ts index 7937e8bc0e..44ce22a873 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/index.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/index.ts @@ -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) => { diff --git a/libs/remix-ui/run-tab/src/lib/run-tab.tsx b/libs/remix-ui/run-tab/src/lib/run-tab.tsx index 19700f43fa..3dc10d1e52 100644 --- a/libs/remix-ui/run-tab/src/lib/run-tab.tsx +++ b/libs/remix-ui/run-tab/src/lib/run-tab.tsx @@ -172,8 +172,8 @@ export function RunTabUI (props: RunTabProps) { return } - const scenarioPrompt = (message: string) => { - return + const scenarioPrompt = (message: string, defaultValue) => { + return } 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) => { diff --git a/libs/remix-ui/run-tab/src/lib/types/index.ts b/libs/remix-ui/run-tab/src/lib/types/index.ts index 0647fca2fd..b2d5c1fe88 100644 --- a/libs/remix-ui/run-tab/src/lib/types/index.ts +++ b/libs/remix-ui/run-tab/src/lib/types/index.ts @@ -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 } diff --git a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx index 2acb1ee4e4..9f9da608f9 100644 --- a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx +++ b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx @@ -67,6 +67,7 @@ export const SolidityUnitTesting = (props: Record) => { // eslint-d let [readyTestsNumber, setReadyTestsNumber] = useState(0) // eslint-disable-line let [runningTestsNumber, setRunningTestsNumber] = useState(0) // eslint-disable-line + const areTestsRunning = useRef(false) const hasBeenStopped = useRef(false) const isDebugging = useRef(false) const allTests = useRef([]) @@ -74,7 +75,6 @@ export const SolidityUnitTesting = (props: Record) => { // 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> = {} @@ -113,7 +113,7 @@ export const SolidityUnitTesting = (props: Record) => { // 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) => { // 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) => { // 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) => { // 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) => { // eslint-d if (selectedTests.current?.length !== 0) { setDisableRunButton(false) } - areTestsRunning = false + areTestsRunning.current = false } } @@ -566,7 +547,7 @@ export const SolidityUnitTesting = (props: Record) => { // 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) => { // 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) => { // 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) => { // 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) => { // eslint-d } else testFiles = [] - setTestFiles(testFiles) + setTestFiles([...testFiles]) } return ( @@ -674,8 +655,7 @@ export const SolidityUnitTesting = (props: Record) => { // 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('')} } />