Merge pull request #1917 from ethereum/unused_code

Remove yo-yo remnants.
pull/1861/head^2
bunsenstraat 3 years ago committed by GitHub
commit 70f2c0fdaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      apps/remix-ide/src/app.js
  2. 3
      apps/remix-ide/src/app/components/plugin-manager-component.js
  3. 147
      apps/remix-ide/src/app/components/plugin-manager-settings.js
  4. 24
      apps/remix-ide/src/app/files/fileManager.ts
  5. 8
      apps/remix-ide/src/app/files/fileProvider.js
  6. 6
      apps/remix-ide/src/app/plugins/modal.tsx
  7. 4
      apps/remix-ide/src/app/plugins/permission-handler-plugin.tsx
  8. 6
      apps/remix-ide/src/app/plugins/remixd-handle.tsx
  9. 19
      apps/remix-ide/src/app/tabs/compile-tab.js
  10. 33
      apps/remix-ide/src/app/tabs/debugger-tab.js
  11. 4
      apps/remix-ide/src/app/tabs/hardhat-provider.tsx
  12. 114
      apps/remix-ide/src/app/ui/modal-dialog-custom.js
  13. 150
      apps/remix-ide/src/app/ui/modaldialog.js
  14. 110
      apps/remix-ide/src/app/ui/tooltip.js
  15. 4
      apps/remix-ide/src/remixAppManager.js
  16. 12
      libs/remix-core-plugin/src/lib/gist-handler.ts
  17. 2
      libs/remix-ui/app/src/lib/remix-app/actions/modals.ts
  18. 2
      libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
  19. 4
      libs/remix-ui/app/src/lib/remix-app/interface/index.ts
  20. 1
      libs/remix-ui/helper/src/index.ts
  21. 55
      libs/remix-ui/helper/src/lib/helper-components.tsx
  22. 6
      libs/remix-ui/helper/tsconfig.json
  23. 6
      libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx
  24. 5
      libs/remix-ui/plugin-manager/src/lib/components/rootView.tsx
  25. 4
      libs/remix-ui/plugin-manager/src/lib/remix-ui-plugin-manager.tsx
  26. 25
      libs/remix-ui/toaster/src/lib/toaster.tsx

@ -36,7 +36,6 @@ const FileManager = require('./app/files/fileManager')
const FileProvider = require('./app/files/fileProvider') const FileProvider = require('./app/files/fileProvider')
const DGitProvider = require('./app/files/dgitProvider') const DGitProvider = require('./app/files/dgitProvider')
const WorkspaceFileProvider = require('./app/files/workspaceFileProvider') const WorkspaceFileProvider = require('./app/files/workspaceFileProvider')
const toolTip = require('./app/ui/tooltip')
const PluginManagerComponent = require('./app/components/plugin-manager-component') const PluginManagerComponent = require('./app/components/plugin-manager-component')
@ -319,7 +318,7 @@ class AppComponent {
console.log("couldn't register iframe plugins", e.message) console.log("couldn't register iframe plugins", e.message)
} }
await self.appManager.activatePlugin(['layout']) await self.appManager.activatePlugin(['layout'])
await self.appManager.activatePlugin(['modal']) await self.appManager.activatePlugin(['notification'])
await self.appManager.activatePlugin(['editor']) await self.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['permissionhandler', 'theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) await self.appManager.activatePlugin(['permissionhandler', 'theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
@ -368,7 +367,7 @@ class AppComponent {
if (params.call) { if (params.call) {
const callDetails = params.call.split('//') const callDetails = params.call.split('//')
if (callDetails.length > 1) { if (callDetails.length > 1) {
toolTip(`initiating ${callDetails[0]} ...`) self.appManager.call('notification', 'toast', `initiating ${callDetails[0]} ...`)
// @todo(remove the timeout when activatePlugin is on 0.3.0) // @todo(remove the timeout when activatePlugin is on 0.3.0)
self.appManager.call(...callDetails).catch(console.error) self.appManager.call(...callDetails).catch(console.error)
} }

@ -1,5 +1,4 @@
import { ViewPlugin } from '@remixproject/engine-web' import { ViewPlugin } from '@remixproject/engine-web'
import { PluginManagerSettings } from './plugin-manager-settings'
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import {RemixUiPluginManager} from '@remix-ui/plugin-manager' // eslint-disable-line import {RemixUiPluginManager} from '@remix-ui/plugin-manager' // eslint-disable-line
@ -24,7 +23,6 @@ class PluginManagerComponent extends ViewPlugin {
super(profile) super(profile)
this.appManager = appManager this.appManager = appManager
this.engine = engine this.engine = engine
this.pluginManagerSettings = new PluginManagerSettings()
this.htmlElement = document.createElement('div') this.htmlElement = document.createElement('div')
this.htmlElement.setAttribute('id', 'pluginManager') this.htmlElement.setAttribute('id', 'pluginManager')
this.filter = '' this.filter = ''
@ -90,7 +88,6 @@ class PluginManagerComponent extends ViewPlugin {
ReactDOM.render( ReactDOM.render(
<RemixUiPluginManager <RemixUiPluginManager
pluginComponent={this} pluginComponent={this}
pluginManagerSettings={this.pluginManagerSettings}
/>, />,
this.htmlElement) this.htmlElement)
} }

@ -1,147 +0,0 @@
const yo = require('yo-yo')
const csjs = require('csjs-inject')
const modalDialog = require('../ui/modaldialog')
const css = csjs`
.remixui_permissions {
position: sticky;
bottom: 0;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 5px 20px;
}
.permissions button {
padding: 2px 5px;
cursor: pointer;
}
.permissionForm h4 {
font-size: 1.3rem;
text-align: center;
}
.permissionForm h6 {
font-size: 1.1rem;
}
.permissionForm hr {
width: 80%;
}
.permissionKey {
display: flex;
justify-content: space-between;
align-items: center;
}
.permissionKey i {
cursor: pointer;
}
.checkbox {
display: flex;
align-items: center;
}
.checkbox label {
margin: 0;
font-size: 1rem;
}
`
export class PluginManagerSettings {
constructor () {
const fromLocal = window.localStorage.getItem('plugins/permissions')
this.permissions = JSON.parse(fromLocal || '{}')
}
openDialog () {
this.currentSetting = this.settings()
modalDialog('Plugin Manager Permissions', this.currentSetting,
{ fn: () => this.onValidation() }
)
}
onValidation () {
const permissions = JSON.stringify(this.permissions)
window.localStorage.setItem('plugins/permissions', permissions)
}
/** Clear one permission from a plugin */
clearPersmission (from, to, method) {
// eslint-disable-next-line no-debugger
debugger
if (this.permissions[to] && this.permissions[to][method]) {
delete this.permissions[to][method][from]
if (Object.keys(this.permissions[to][method]).length === 0) {
delete this.permissions[to][method]
}
if (Object.keys(this.permissions[to]).length === 0) {
delete this.permissions[to]
}
yo.update(this.currentSetting, this.settings())
}
}
/** Clear all persmissions from a plugin */
clearAllPersmission (to) {
// eslint-disable-next-line no-debugger
debugger
if (!this.permissions[to]) return
delete this.permissions[to]
yo.update(this.currentSetting, this.settings())
}
settings () {
const permissionByToPlugin = (toPlugin, funcObj) => {
const permissionByMethod = (methodName, fromPlugins) => {
const togglePermission = (fromPlugin) => {
this.permissions[toPlugin][methodName][fromPlugin].allow = !this.permissions[toPlugin][methodName][fromPlugin].allow
}
return Object.keys(fromPlugins).map(fromName => {
const fromPluginPermission = fromPlugins[fromName]
const checkbox = fromPluginPermission.allow
? yo`<input onchange=${() => togglePermission(fromName)} class="mr-2" type="checkbox" checked id="permission-checkbox-${toPlugin}-${methodName}-${toPlugin}" aria-describedby="module ${fromPluginPermission} asks permission for ${methodName}" />`
: yo`<input onchange=${() => togglePermission(fromName)} class="mr-2" type="checkbox" id="permission-checkbox-${toPlugin}-${methodName}-${toPlugin}" aria-describedby="module ${fromPluginPermission} asks permission for ${methodName}" />`
return yo`
<div class="form-group ${css.permissionKey}">
<div class="${css.checkbox}">
${checkbox}
<label for="permission-checkbox-${toPlugin}-${methodName}-${toPlugin}" data-id="permission-label-${toPlugin}-${methodName}-${toPlugin}">Allow <u>${fromName}</u> to call <u>${methodName}</u></label>
</div>
<i onclick="${() => this.clearPersmission(fromName, toPlugin, methodName)}" class="fa fa-trash-alt" data-id="pluginManagerSettingsRemovePermission-${toPlugin}-${methodName}-${toPlugin}"></i>
</div>
`
})
}
const permissionsByFunctions = Object
.keys(funcObj)
.map(methodName => permissionByMethod(methodName, funcObj[methodName]))
return yo`
<div border p-2>
<div class="pb-2 ${css.permissionKey}">
<h3>${toPlugin} permissions:</h3>
<i onclick="${() => this.clearAllPersmission(toPlugin)}" class="far fa-trash-alt" data-id="pluginManagerSettingsClearAllPermission-${toPlugin}"></i>
</div>
${permissionsByFunctions}
</div>`
}
const byToPlugin = Object
.keys(this.permissions)
.map(toPlugin => permissionByToPlugin(toPlugin, this.permissions[toPlugin]))
const title = byToPlugin.length === 0
? yo`<h4>No Permission requested yet.</h4>`
: yo`<h4>Current Permission settings</h4>`
return yo`<form class="${css.permissionForm}" data-id="pluginManagerSettingsPermissionForm">
${title}
<hr/>
${byToPlugin}
</form>`
}
render () {
return yo`
<footer class="bg-light ${css.permissions} remix-bg-opacity">
<button onclick="${() => this.openDialog()}" class="btn btn-primary settings-button" data-id="pluginManagerPermissionsButton">Permissions</button>
</footer>`
}
}

@ -1,13 +1,11 @@
'use strict' 'use strict'
import yo from 'yo-yo'
import async from 'async' import async from 'async'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry' import Registry from '../state/registry'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types' import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types'
const toaster = require('../ui/tooltip') import { fileChangedToastMsg } from '@remix-ui/helper'
const helper = require('../../lib/helper.js') const helper = require('../../lib/helper.js')
/* /*
@ -317,7 +315,7 @@ class FileManager extends Plugin {
if (isFile) { if (isFile) {
if (newPathExists) { if (newPathExists) {
this.call('modal', 'alert', { this.call('notification', 'alert', {
id: 'fileManagerAlert', id: 'fileManagerAlert',
message: 'File already exists' message: 'File already exists'
}) })
@ -326,7 +324,7 @@ class FileManager extends Plugin {
return provider.rename(oldPath, newPath, false) return provider.rename(oldPath, newPath, false)
} else { } else {
if (newPathExists) { if (newPathExists) {
this.call('modal', 'alert', { this.call('notification', 'alert', {
id: 'fileManagerAlert', id: 'fileManagerAlert',
message: 'Directory already exists' message: 'Directory already exists'
}) })
@ -528,17 +526,7 @@ class FileManager extends Plugin {
const required = this.appManager.isRequired(this.currentRequest.from) const required = this.appManager.isRequired(this.currentRequest.from)
if (canCall && !required) { if (canCall && !required) {
// inform the user about modification after permission is granted and even if permission was saved before // inform the user about modification after permission is granted and even if permission was saved before
toaster(yo` this.call('notification','toast', fileChangedToastMsg(this.currentRequest.from, path))
<div>
<i class="fas fa-exclamation-triangle text-danger mr-1"></i>
<span>
${this.currentRequest.from}
<span class="font-weight-bold text-warning">
is modifying
</span>${path}
</span>
</div>
`, '', { time: 3000 })
} }
} }
return await this._setFileInternal(path, content) return await this._setFileInternal(path, content)
@ -778,12 +766,12 @@ class FileManager extends Plugin {
helper.createNonClashingName(file, self._deps.filesProviders[fileProvider], helper.createNonClashingName(file, self._deps.filesProviders[fileProvider],
(error, name) => { (error, name) => {
if (error) { if (error) {
this.call('modal', 'alert', { this.call('notification', 'alert', {
id: 'fileManagerAlert', id: 'fileManagerAlert',
message: 'Unexpected error loading file ' + file + ': ' + error message: 'Unexpected error loading file ' + file + ': ' + error
}) })
} else if (helper.checkSpecialChars(name)) { } else if (helper.checkSpecialChars(name)) {
this.call('modal', 'alert', { this.call('notification', 'alert', {
id: 'fileManagerAlert', id: 'fileManagerAlert',
message: 'Special characters are not allowed in file names.' message: 'Special characters are not allowed in file names.'
}) })

@ -2,8 +2,6 @@
import { CompilerImports } from '@remix-project/core-plugin' import { CompilerImports } from '@remix-project/core-plugin'
const EventManager = require('events') const EventManager = require('events')
const modalDialogCustom = require('../ui/modal-dialog-custom')
const tooltip = require('../ui/tooltip')
const remixLib = require('@remix-project/remix-lib') const remixLib = require('@remix-project/remix-lib')
const Storage = remixLib.Storage const Storage = remixLib.Storage
@ -49,7 +47,7 @@ class FileProvider {
return this.externalFolders.includes(path) return this.externalFolders.includes(path)
} }
discardChanges (path) { discardChanges (path, toastCb, modalCb) {
this.remove(path) this.remove(path)
const compilerImport = new CompilerImports() const compilerImport = new CompilerImports()
this.providerExternalsStorage.keys().map(value => { this.providerExternalsStorage.keys().map(value => {
@ -57,10 +55,10 @@ class FileProvider {
compilerImport.import( compilerImport.import(
this.getNormalizedName(value), this.getNormalizedName(value),
true, true,
(loadingMsg) => { tooltip(loadingMsg) }, (loadingMsg) => { toastCb(loadingMsg) },
(error, content, cleanUrl, type, url) => { (error, content, cleanUrl, type, url) => {
if (error) { if (error) {
modalDialogCustom.alert(error) modalCb(error)
} else { } else {
this.addExternal(type + '/' + cleanUrl, content, url) this.addExternal(type + '/' + cleanUrl, content, url)
} }

@ -14,9 +14,9 @@ interface IModalApi {
} }
const profile:LibraryProfile<IModalApi> = { const profile:LibraryProfile<IModalApi> = {
name: 'modal', name: 'notification',
displayName: 'Modal', displayName: 'Notification',
description: 'Modal', description: 'Displays notifications',
methods: ['modal', 'alert', 'toast'] methods: ['modal', 'alert', 'toast']
} }

@ -72,7 +72,7 @@ export class PermissionHandlerPlugin extends Plugin {
const { allow, hash } = this.permissions[to.name][method][from.name] const { allow, hash } = this.permissions[to.name][method][from.name]
if (!allow) { if (!allow) {
const warning = this.notAllowWarning(from, to, method) const warning = this.notAllowWarning(from, to, method)
this.call('modal', 'toast', warning) this.call('notification', 'toast', warning)
return false return false
} }
return hash === from.hash return hash === from.hash
@ -100,7 +100,7 @@ export class PermissionHandlerPlugin extends Plugin {
cancelLabel: 'Decline' cancelLabel: 'Decline'
} }
const result = await this.call('modal', 'modal', modal) const result = await this.call('notification', 'modal', modal)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (result) { if (result) {
if (this.permissions[to.name][method][from.name]) { if (this.permissions[to.name][method][from.name]) {

@ -69,7 +69,7 @@ export class RemixdHandle extends WebsocketPlugin {
id: 'connectionAlert', id: 'connectionAlert',
message: 'Cannot connect to the remixd daemon. Please make sure you have the remixd running in the background.' message: 'Cannot connect to the remixd daemon. Please make sure you have the remixd running in the background.'
} }
this.call('modal', 'alert', alert) this.call('notification', 'alert', alert)
this.canceled() this.canceled()
} else { } else {
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
@ -80,7 +80,7 @@ export class RemixdHandle extends WebsocketPlugin {
id: 'connectionAlert', id: 'connectionAlert',
message: 'Connection to remixd terminated.Please make sure remixd is still running in the background.' message: 'Connection to remixd terminated.Please make sure remixd is still running in the background.'
} }
this.call('modal', 'alert', alert) this.call('notification', 'alert', alert)
this.canceled() this.canceled()
} }
}, 3000) }, 3000)
@ -102,7 +102,7 @@ export class RemixdHandle extends WebsocketPlugin {
okLabel: 'Connect', okLabel: 'Connect',
cancelLabel: 'Cancel', cancelLabel: 'Cancel',
} }
const result = await this.call('modal', 'modal', mod) const result = await this.call('notification', 'modal', mod)
if(result) { if(result) {
try { try {
this.localhostProvider.preInit() this.localhostProvider.preInit()

@ -8,11 +8,7 @@ import { ViewPlugin } from '@remixproject/engine-web'
import QueryParams from '../../lib/query-params' import QueryParams from '../../lib/query-params'
// import { ICompilerApi } from '@remix-project/remix-lib-ts' // import { ICompilerApi } from '@remix-project/remix-lib-ts'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import { compilerConfigChangedToastMsg, compileToastMsg } from '@remix-ui/helper'
const yo = require('yo-yo')
const addTooltip = require('../ui/tooltip')
const css = require('./styles/compile-tab-styles')
const profile = { const profile = {
name: 'solidity', name: 'solidity',
@ -41,6 +37,8 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
this.compiler = this.compileTabLogic.compiler this.compiler = this.compileTabLogic.compiler
this.compileTabLogic.init() this.compileTabLogic.init()
this.initCompilerApi() this.initCompilerApi()
this.el = document.createElement('div')
this.el.setAttribute('id', 'compileTabView')
} }
renderComponent () { renderComponent () {
@ -70,11 +68,6 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
} }
render () { render () {
if (this.el) return this.el
this.el = yo`
<div class="${css.debuggerTabView}" id="compileTabView">
<div id="compiler" class="${css.compiler}"></div>
</div>`
this.renderComponent() this.renderComponent()
return this.el return this.el
@ -101,11 +94,13 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
super.setCompilerConfig(settings) super.setCompilerConfig(settings)
this.renderComponent() this.renderComponent()
// @todo(#2875) should use loading compiler return value to check whether the compiler is loaded instead of "setInterval" // @todo(#2875) should use loading compiler return value to check whether the compiler is loaded instead of "setInterval"
addTooltip(yo`<div><b>${this.currentRequest.from}</b> is updating the <b>Solidity compiler configuration</b>.<pre class="text-left">${JSON.stringify(settings, null, '\t')}</pre></div>`) const value = JSON.stringify(settings, null, '\t')
this.call('notification', 'toast', compilerConfigChangedToastMsg(this.currentRequest.from, value))
} }
compile (fileName) { compile (fileName) {
addTooltip(yo`<div><b>${this.currentRequest.from}</b> is requiring to compile <b>${fileName}</b></div>`) this.call('notification', 'toast', compileToastMsg(this.currentRequest.from, fileName))
super.compile(fileName) super.compile(fileName)
} }

@ -1,14 +1,12 @@
import toaster from '../ui/tooltip'
import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line
import { DebuggerApiMixin } from '@remixproject/debugger-plugin' import { DebuggerApiMixin } from '@remixproject/debugger-plugin'
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 ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import modalDialogCustom from '../ui/modal-dialog-custom'
import * as remixBleach from '../../lib/remixBleach' import * as remixBleach from '../../lib/remixBleach'
import { compilationFinishedToastMsg, compilingToastMsg, localCompilationToastMsg, notFoundToastMsg, sourceVerificationNotAvailableToastMsg } from '@remix-ui/helper'
const css = require('./styles/debugger-tab-styles') const css = require('./styles/debugger-tab-styles')
const yo = require('yo-yo')
const profile = { const profile = {
name: 'debugger', name: 'debugger',
@ -26,46 +24,45 @@ const profile = {
export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) {
constructor () { constructor () {
super(profile) super(profile)
this.el = null this.el = document.createElement('div')
this.el.setAttribute('id', 'debugView')
this.el.classList.add(css.debuggerTabView)
this.initDebuggerApi() this.initDebuggerApi()
} }
render () { render () {
if (this.el) return this.el
this.el = yo`
<div class="${css.debuggerTabView}" id="debugView">
<div id="debugger" class="${css.debugger}"></div>
</div>`
this.on('fetchAndCompile', 'compiling', (settings) => { this.on('fetchAndCompile', 'compiling', (settings) => {
toaster(yo`<div><b>Recompiling and debugging with params</b><pre class="text-left">${JSON.stringify(settings, null, '\t')}</pre></div>`) settings = JSON.stringify(settings, null, '\t')
this.call('notification', 'toast', compilingToastMsg(settings))
}) })
this.on('fetchAndCompile', 'compilationFailed', (data) => { this.on('fetchAndCompile', 'compilationFailed', (data) => {
toaster(yo`<div><b>Compilation failed...</b> continuing <i>without</i> source code debugging.</div>`) this.call('notification', 'toast', compilationFinishedToastMsg())
}) })
this.on('fetchAndCompile', 'notFound', (contractAddress) => { this.on('fetchAndCompile', 'notFound', (contractAddress) => {
toaster(yo`<div><b>Contract ${contractAddress} not found in source code repository</b> continuing <i>without</i> source code debugging.</div>`) this.call('notification', 'toast', notFoundToastMsg(contractAddress))
}) })
this.on('fetchAndCompile', 'usingLocalCompilation', (contractAddress) => { this.on('fetchAndCompile', 'usingLocalCompilation', (contractAddress) => {
toaster(yo`<div><b>Using compilation result from Solidity module</b></div>`) this.call('notification', 'toast', localCompilationToastMsg())
}) })
this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => { this.on('fetchAndCompile', 'sourceVerificationNotAvailable', () => {
toaster(yo`<div><b>Source verification plugin not activated or not available.</b> continuing <i>without</i> source code debugging.</div>`) this.call('notification', 'toast', sourceVerificationNotAvailableToastMsg())
}) })
this.renderComponent() this.renderComponent()
return this.el return this.el
} }
showMessage (title, message) { showMessage (title, message) {
try { try {
modalDialogCustom.alert(title, remixBleach.sanitize(message)) this.call('notification', 'alert', {
id: 'debuggerTabShowMessage',
title,
message: remixBleach.sanitize(message)
})
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }

@ -83,7 +83,7 @@ export class HardhatProvider extends Plugin {
}, },
defaultValue: 'http://127.0.0.1:8545' defaultValue: 'http://127.0.0.1:8545'
} }
this.call('modal', 'modal', modalContent) this.call('notification', 'modal', modalContent)
}) })
})() })()
} catch (e) { } catch (e) {
@ -114,7 +114,7 @@ export class HardhatProvider extends Plugin {
title: 'Hardhat Provider', title: 'Hardhat Provider',
message: `Error while connecting to the hardhat provider: ${error.message}`, message: `Error while connecting to the hardhat provider: ${error.message}`,
} }
this.call('modal', 'alert', modalContent) this.call('notification', 'alert', modalContent)
await this.call('udapp', 'setEnvironmentMode', { context: 'vm', fork: 'london' }) await this.call('udapp', 'setEnvironmentMode', { context: 'vm', fork: 'london' })
this.provider = null this.provider = null
setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm

@ -1,114 +0,0 @@
var modal = require('./modaldialog.js')
var yo = require('yo-yo')
var css = require('./styles/modal-dialog-custom-styles')
module.exports = {
alert: function (title, text) {
if (text) return modal(title, yo`<div>${text}</div>`, null, { label: null })
return modal('Alert', yo`<div>${title}</div>`, null, { label: null })
},
prompt: function (title, text, inputValue, ok, cancel, focus) {
return prompt(title, text, false, inputValue, ok, cancel, focus)
},
promptPassphrase: function (title, text, inputValue, ok, cancel) {
return prompt(title, text, true, inputValue, ok, cancel)
},
promptPassphraseCreation: function (ok, cancel) {
var text = 'Please provide a Passphrase for the account creation'
var input = yo`
<div>
<input id="prompt1" type="password" name='prompt_text' class="${css.prompt_text}" oninput="${(e) => validateInput(e)}">
<br>
<br>
<input id="prompt2" type="password" name='prompt_text' class="${css.prompt_text}" oninput="${(e) => validateInput(e)}">
</div>
`
return modal(null, yo`<div>${text}<div>${input}</div></div>`,
{
fn: () => {
if (typeof ok === 'function') {
if (input.querySelector('#prompt1').value === input.querySelector('#prompt2').value) {
ok(null, input.querySelector('#prompt1').value)
} else {
ok('Passphase does not match')
}
}
}
},
{
fn: () => {
if (typeof cancel === 'function') cancel()
}
}
)
},
promptMulti: function ({ title, text, inputValue }, ok, cancel) {
if (!inputValue) inputValue = ''
const input = yo`
<textarea
id="prompt_text"
data-id="modalDialogCustomPromptText"
class=${css.prompt_text}
rows="4"
cols="50"
oninput="${(e) => validateInput(e)}"
></textarea>
`
return modal(title, yo`<div>${text}<div>${input}</div></div>`,
{
fn: () => { if (typeof ok === 'function') ok(document.getElementById('prompt_text').value) }
},
{
fn: () => { if (typeof cancel === 'function') cancel() }
}
)
},
confirm: function (title, text, ok, cancel) {
return modal(title, yo`<div>${text}</div>`,
{
fn: () => { if (typeof ok === 'function') ok() }
},
{
fn: () => { if (typeof cancel === 'function') cancel() }
}
)
}
}
const validateInput = (e) => {
if (!document.getElementById('modal-footer-ok')) return
if (e.target.value === '') {
document.getElementById('modal-footer-ok').classList.add('disabled')
document.getElementById('modal-footer-ok').style.pointerEvents = 'none'
} else {
document.getElementById('modal-footer-ok').classList.remove('disabled')
document.getElementById('modal-footer-ok').style.pointerEvents = 'auto'
}
}
function prompt (title, text, hidden, inputValue, ok, cancel, focus) {
if (!inputValue) inputValue = ''
var type = hidden ? 'password' : 'text'
var input = yo`
<input
type=${type}
name='prompt_text'
id='prompt_text'
class="${css.prompt_text} form-control"
value='${inputValue}'
data-id="modalDialogCustomPromptText"
oninput="${(e) => validateInput(e)}"
>
`
modal(title, yo`<div>${text}<div>${input}</div></div>`,
{
fn: () => { if (typeof ok === 'function') ok(document.getElementById('prompt_text').value) }
},
{
fn: () => { if (typeof cancel === 'function') cancel() }
},
focus ? '#prompt_text' : undefined
)
}

@ -1,150 +0,0 @@
var yo = require('yo-yo')
var css = require('./styles/modaldialog-styles')
let incomingModal = false // in case modals are queued, ensure we are not hiding the last one.
module.exports = (title, content, ok, cancel, focusSelector, opts) => {
let agreed = true
let footerIsActive = false
opts = opts || {}
var container = document.getElementById('modal-dialog')
if (!container) {
document.querySelector('body').appendChild(html(opts))
container = document.getElementById('modal-dialog')
incomingModal = false
} else incomingModal = true
var closeDiv = document.getElementById('modal-close')
if (opts.hideClose) closeDiv.style.display = 'none'
var okDiv = document.getElementById('modal-footer-ok')
okDiv.innerHTML = (ok && ok.label !== undefined) ? ok.label : 'OK'
okDiv.style.display = okDiv.innerHTML === '' ? 'none' : 'inline-block'
var cancelDiv = document.getElementById('modal-footer-cancel')
cancelDiv.innerHTML = (cancel && cancel.label !== undefined) ? cancel.label : 'Cancel'
cancelDiv.style.display = cancelDiv.innerHTML === '' ? 'none' : 'inline-block'
var modal = document.getElementById('modal-body-id')
var modalTitle = document.getElementById('modal-title-h6')
modalTitle.innerHTML = ''
if (title) modalTitle.innerText = title
modal.innerHTML = ''
if (content) modal.appendChild(content)
setFocusOn('ok')
show()
function setFocusOn (btn) {
var okDiv = document.getElementById('modal-footer-ok')
var cancelDiv = document.getElementById('modal-footer-cancel')
if (btn === 'ok') {
okDiv.className = okDiv.className.replace(/\bbtn-light\b/g, 'btn-dark')
cancelDiv.className = cancelDiv.className.replace(/\bbtn-dark\b/g, 'btn-light')
} else {
cancelDiv.className = cancelDiv.className.replace(/\bbtn-light\b/g, 'btn-dark')
okDiv.className = okDiv.className.replace(/\bbtn-dark\b/g, 'btn-light')
}
}
function okListener () {
removeEventListener()
if (ok && ok.fn && agreed) ok.fn()
if (!incomingModal) hide()
incomingModal = false
}
function cancelListener () {
removeEventListener()
if (cancel && cancel.fn) cancel.fn()
if (!incomingModal) hide()
incomingModal = false
}
function modalKeyEvent (e) {
if (e.keyCode === 27) { // Esc
cancelListener()
} else if (e.keyCode === 13) { // Enter
e.preventDefault()
okListener()
} else if (e.keyCode === 37 && footerIsActive) { // Arrow Left
e.preventDefault()
agreed = true
setFocusOn('ok')
} else if (e.keyCode === 39 && footerIsActive) { // Arrow Right
e.preventDefault()
agreed = false
setFocusOn('cancel')
}
}
function hide () {
if (!container) return
container.style.display = 'none'
if (container.parentElement) container.parentElement.removeChild(container)
container = null
incomingModal = false
}
function show () {
if (!container) return
container.style.display = 'block'
if (focusSelector) {
const focusTarget = document.querySelector(`.modal ${focusSelector}`)
if (focusTarget) {
focusTarget.focus()
if (typeof focusTarget.setSelectionRange === 'function') {
focusTarget.setSelectionRange(0, focusTarget.value.length)
}
}
}
}
function removeEventListener () {
okDiv.removeEventListener('click', okListener)
cancelDiv.removeEventListener('click', cancelListener)
closeDiv.removeEventListener('click', cancelListener)
document.removeEventListener('keydown', modalKeyEvent)
if (document.getElementById('modal-background')) {
document.getElementById('modal-background').removeEventListener('click', cancelListener)
}
}
okDiv.addEventListener('click', okListener)
cancelDiv.addEventListener('click', cancelListener)
closeDiv.addEventListener('click', cancelListener)
document.addEventListener('keydown', modalKeyEvent)
const modalDialog = document.getElementById('modal-dialog')
if (modalDialog) {
modalDialog.addEventListener('click', (e) => {
footerIsActive = document.activeElement === modalDialog
if (e.toElement === modalDialog) {
cancelListener() // click is outside of modal-content
}
})
}
return { container, okListener, cancelListener, hide }
}
function html (opts) {
return yo`
<div id="modal-dialog" data-id="modalDialogContainer" data-backdrop="static" data-keyboard="false" class="modal" tabindex="-1" role="dialog">
<div id="modal-background" class="modal-dialog" role="document">
<div class="modal-content ${css.modalContent} ${opts.class}">
<div class="modal-header">
<h6 id="modal-title-h6" class="modal-title" data-id="modalDialogModalTitle"></h6>
<span class="modal-close">
<i id="modal-close" title="Close" class="fas fa-times" aria-hidden="true"></i>
</span>
</div>
<div id="modal-body-id" class="modal-body ${css.modalBody}" data-id="modalDialogModalBody"> - </div>
<div class="modal-footer" data-id="modalDialogModalFooter" autofocus>
<span id="modal-footer-ok" class="${css.modalFooterOk} modal-ok btn btn-sm btn-light" tabindex='5'>OK</span>
<span id="modal-footer-cancel" class="${css.modalFooterCancel} modal-cancel btn btn-sm btn-light" tabindex='10' data-dismiss="modal">Cancel</span>
</div>
</div>
</div>
</div>`
}

@ -1,110 +0,0 @@
/* global Element */
var yo = require('yo-yo')
var css = require('./styles/tooltip-styles')
var modal = require('./modal-dialog-custom')
/**
* Open a tooltip
* @param {string} tooltipText The text shown by the tooltip
* @param {function} [action] Returns An HTMLElement to display for action
*/
module.exports = function addTooltip (tooltipText, action, opts) {
action = action || function () { return yo`<div></div>` }
const t = new Toaster()
return t.render(tooltipText, action(t), opts)
}
class Toaster {
hide () {
if (this.id) clearTimeout(this.id)
setTimeout(() => {
// remove from body after the animation is finished
if (this.tooltip.parentElement) this.tooltip.parentElement.removeChild(this.tooltip)
}, 2000)
animation(this.tooltip, css.animateTop.className)
}
render (tooltipText, actionElement, opts) {
opts = defaultOptions(opts)
let canShorten = true
if (tooltipText instanceof Element) {
canShorten = false
} else {
if (typeof tooltipText === 'object') {
if (tooltipText.message) {
tooltipText = tooltipText.message
} else {
try {
tooltipText = JSON.stringify(tooltipText)
} catch (e) {
}
}
}
}
return new Promise((resolve, reject) => {
const shortTooltipText = (canShorten && tooltipText.length > 201) ? tooltipText.substring(0, 200) + '...' : tooltipText
this.resolveFn = resolve
function showFullMessage () {
modal.alert(tooltipText)
}
function closeTheToaster (self) {
self.hide()
over()
resolve()
}
const button = tooltipText.length > 201 ? yo`
<button class="btn btn-secondary btn-sm mx-3" style="white-space: nowrap;" onclick=${() => showFullMessage()}>Show full message</button>
` : ''
this.tooltip = yo`
<div data-shared="tooltipPopup" class="${css.tooltip} alert alert-info p-2" onmouseenter=${() => { over() }} onmouseleave=${() => { out() }}>
<span class="px-2">
${shortTooltipText}
${button}
${actionElement}
</span>
<span style="align-self: baseline;">
<button data-id="tooltipCloseButton" class="fas fa-times btn-info mx-1 p-0" onclick=${() => closeTheToaster(this)}></button>
</span>
</div>`
const timeOut = () => {
return setTimeout(() => {
if (this.id) {
this.hide()
resolve()
}
}, opts.time)
}
const over = () => {
if (this.id) {
clearTimeout(this.id)
this.id = null
}
}
const out = () => {
if (!this.id) this.id = timeOut()
}
this.id = timeOut()
document.body.appendChild(this.tooltip)
animation(this.tooltip, css.animateBottom.className)
})
}
}
const defaultOptions = (opts) => {
opts = opts || {}
return {
time: opts.time || 7000
}
}
const animation = (tooltip, anim) => {
tooltip.classList.remove(css.animateTop.className)
tooltip.classList.remove(css.animateBottom.className)
// eslint-disable-next-line
void tooltip.offsetWidth // trick for restarting the animation
tooltip.classList.add(anim)
}

@ -8,12 +8,12 @@ const _paq = window._paq = window._paq || []
const requiredModules = [ // services + layout views + system views const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', 'modal', 'permissionhandler'] 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', 'notification', 'permissionhandler']
const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd) const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)
export function isNative (name) { export function isNative (name) {
const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'modal'] const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons', 'solidity', 'hardhat-provider', 'solidityStaticAnalysis', 'solidityUnitTesting', 'layout', 'notification']
return nativePlugins.includes(name) || requiredModules.includes(name) return nativePlugins.includes(name) || requiredModules.includes(name)
} }

@ -45,7 +45,7 @@ export class GistHandler extends Plugin {
setTimeout(() => reject(new Error('Hide')), 0) setTimeout(() => reject(new Error('Hide')), 0)
} }
} }
this.call('modal', 'modal', modalContent) this.call('notification', 'modal', modalContent)
}) })
})() })()
} catch (e) { } catch (e) {
@ -63,7 +63,7 @@ export class GistHandler extends Plugin {
title: 'Gist load error', title: 'Gist load error',
message: 'Error while loading gist. Please provide a valid Gist ID or URL.' message: 'Error while loading gist. Please provide a valid Gist ID or URL.'
} }
this.call('modal', 'alert', modalContent) this.call('notification', 'alert', modalContent)
} }
} else { } else {
const modalContent = { const modalContent = {
@ -71,7 +71,7 @@ export class GistHandler extends Plugin {
title: 'Gist load error', title: 'Gist load error',
message: 'Error while loading gist. Id cannot be empty.' message: 'Error while loading gist. Id cannot be empty.'
} }
this.call('modal', 'alert', modalContent) this.call('notification', 'alert', modalContent)
} }
return loadingFromGist return loadingFromGist
} else { } else {
@ -97,7 +97,7 @@ export class GistHandler extends Plugin {
modalType: 'alert', modalType: 'alert',
okLabel: 'OK' okLabel: 'OK'
} }
await this.call('modal', 'modal', modalContent) await this.call('notification', 'modal', modalContent)
return return
} }
} catch (e: any) { } catch (e: any) {
@ -107,7 +107,7 @@ export class GistHandler extends Plugin {
message: e.message message: e.message
} }
await this.call('modal', 'alert', modalContent) await this.call('notification', 'alert', modalContent)
return return
} }
@ -124,7 +124,7 @@ export class GistHandler extends Plugin {
message: errorSavingFiles.message || errorSavingFiles message: errorSavingFiles.message || errorSavingFiles
} }
this.call('modal', 'alert', modalContent) this.call('notification', 'alert', modalContent)
} }
}) })
}) })

@ -21,7 +21,7 @@ export const enum modalActionTypes {
type ModalPayload = { type ModalPayload = {
[modalActionTypes.setModal]: AppModal [modalActionTypes.setModal]: AppModal
[modalActionTypes.handleHideModal]: any [modalActionTypes.handleHideModal]: any
[modalActionTypes.setToast]: string [modalActionTypes.setToast]: string | JSX.Element
[modalActionTypes.handleToaster]: any [modalActionTypes.handleToaster]: any
} }

@ -30,7 +30,7 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt
}) })
} }
const toast = (message: string) => { const toast = (message: string | JSX.Element) => {
dispatch({ dispatch({
type: modalActionTypes.setToast, type: modalActionTypes.setToast,
payload: message payload: message

@ -24,7 +24,7 @@ export interface AlertModal {
export interface ModalState { export interface ModalState {
modals: AppModal[], modals: AppModal[],
toasters: string[], toasters: (string | JSX.Element)[],
focusModal: AppModal, focusModal: AppModal,
focusToaster: string focusToaster: string | JSX.Element
} }

@ -1 +1,2 @@
export * from './lib/remix-ui-helper' export * from './lib/remix-ui-helper'
export * from './lib/helper-components'

@ -0,0 +1,55 @@
import React from 'react'
export const fileChangedToastMsg = (from: string, path: string) => (
<div><i className="fas fa-exclamation-triangle text-danger mr-1"></i>
<span>
{from}
<span className="font-weight-bold text-warning">
is modifying
</span>{path}
</span>
</div>
)
export const compilerConfigChangedToastMsg = (from: string, value: string) => (
<div>
<b>{ from }</b> is updating the <b>Solidity compiler configuration</b>.
<pre className="text-left">{value}</pre>
</div>
)
export const compileToastMsg = (from: string, fileName: string) => (
<div>
<b>{from}</b> is requiring to compile <b>{fileName}</b>
</div>
)
export const compilingToastMsg = (settings: string) => (
<div>
<b>Recompiling and debugging with params</b>
<pre className="text-left">{settings}</pre></div>
)
export const compilationFinishedToastMsg = () => (
<div>
<b>Compilation failed...</b> continuing <i>without</i> source code debugging.
</div>
)
export const notFoundToastMsg = (address: string) => (
<div>
<b>Contract {address} not found in source code repository</b> continuing <i>without</i> source code debugging.
</div>
)
export const localCompilationToastMsg = () => (
<div>
<b>Using compilation result from Solidity module</b>
</div>
)
export const sourceVerificationNotAvailableToastMsg = () => (
<div>
<b>Source verification plugin not activated or not available.</b> continuing <i>without</i> source code debugging.
</div>
)

@ -1,5 +1,11 @@
{ {
"extends": "../../../tsconfig.base.json", "extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"files": [], "files": [],
"include": [], "include": [],
"references": [ "references": [

@ -5,11 +5,7 @@ import { ModalDialog } from '@remix-ui/modal-dialog'
import useLocalStorage from '../custom-hooks/useLocalStorage' import useLocalStorage from '../custom-hooks/useLocalStorage'
import { PluginPermissions } from '../../types' import { PluginPermissions } from '../../types'
interface PermissionSettingsProps { function PermisssionsSettings () {
pluginSettings: any
}
function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
const [modalVisibility, setModalVisibility] = useState<boolean>(true) const [modalVisibility, setModalVisibility] = useState<boolean>(true)
const [permissions, setPermissions] = useLocalStorage<PluginPermissions>('plugins/permissions', {} as PluginPermissions) const [permissions, setPermissions] = useLocalStorage<PluginPermissions>('plugins/permissions', {} as PluginPermissions)
const [permissionCache, setpermissionCache] = useState<PluginPermissions>() const [permissionCache, setpermissionCache] = useState<PluginPermissions>()

@ -7,7 +7,6 @@ import LocalPluginForm from './LocalPluginForm'
interface RootViewProps { interface RootViewProps {
pluginComponent: PluginManagerComponent pluginComponent: PluginManagerComponent
pluginManagerSettings: PluginManagerSettings
children: ReactNode children: ReactNode
} }
@ -21,7 +20,7 @@ export interface pluginActivated {
profile: Profile profile: Profile
} }
function RootView ({ pluginComponent, pluginManagerSettings, children }: RootViewProps) { function RootView ({ pluginComponent, children }: RootViewProps) {
const [visible, setVisible] = useState<boolean>(true) const [visible, setVisible] = useState<boolean>(true)
const [filterPlugins, setFilterPlugin] = useState<string>('') const [filterPlugins, setFilterPlugin] = useState<string>('')
@ -52,7 +51,7 @@ function RootView ({ pluginComponent, pluginManagerSettings, children }: RootVie
</button> </button>
</header> </header>
{children} {children}
<PermisssionsSettings pluginSettings={pluginManagerSettings}/> <PermisssionsSettings />
</div> </div>
<LocalPluginForm <LocalPluginForm
closeModal={closeModal} closeModal={closeModal}

@ -7,11 +7,11 @@ import InactivePluginCardContainer from './components/InactivePluginCardContaine
import RootView from './components/rootView' import RootView from './components/rootView'
import './remix-ui-plugin-manager.css' import './remix-ui-plugin-manager.css'
export const RemixUiPluginManager = ({ pluginComponent, pluginManagerSettings }: RemixUiPluginManagerProps) => { export const RemixUiPluginManager = ({ pluginComponent }: RemixUiPluginManagerProps) => {
const [activeProfiles, setActiveProfiles] = useState<Profile[]>(pluginComponent.activePlugins) const [activeProfiles, setActiveProfiles] = useState<Profile[]>(pluginComponent.activePlugins)
const [inactiveProfiles, setinactiveProfiles] = useState<Profile[]>(pluginComponent.inactivePlugins) const [inactiveProfiles, setinactiveProfiles] = useState<Profile[]>(pluginComponent.inactivePlugins)
return ( return (
<RootView pluginComponent={pluginComponent} pluginManagerSettings={pluginManagerSettings}> <RootView pluginComponent={pluginComponent}>
<section data-id="pluginManagerComponentPluginManagerSection"> <section data-id="pluginManagerComponentPluginManagerSection">
<ActivePluginCardContainer <ActivePluginCardContainer
pluginComponent={pluginComponent} pluginComponent={pluginComponent}

@ -5,19 +5,28 @@ import './toaster.css'
/* eslint-disable-next-line */ /* eslint-disable-next-line */
export interface ToasterProps { export interface ToasterProps {
message: string message: string | JSX.Element
timeOut?: number, timeOut?: number,
handleHide?: () => void handleHide?: () => void
} }
export const Toaster = (props: ToasterProps) => { export const Toaster = (props: ToasterProps) => {
const [state, setState] = useState({ const [state, setState] = useState<{
message: string | JSX.Element,
hide: boolean,
hiding: boolean,
timeOutId: any,
timeOut: number,
showModal: boolean,
showFullBtn: boolean
}>({
message: '', message: '',
hide: true, hide: true,
hiding: false, hiding: false,
timeOutId: null, timeOutId: null,
timeOut: props.timeOut || 7000, timeOut: props.timeOut || 7000,
showModal: false showModal: false,
showFullBtn: false
}) })
useEffect(() => { useEffect(() => {
@ -29,9 +38,15 @@ export const Toaster = (props: ToasterProps) => {
}, state.timeOut) }, state.timeOut)
setState(prevState => { setState(prevState => {
const shortTooltipText = props.message.length > 201 ? props.message.substring(0, 200) + '...' : props.message if (typeof props.message === 'string' && (props.message.length > 201)) {
const shortTooltipText = props.message.substring(0, 200) + '...'
return { ...prevState, hide: false, hiding: false, timeOutId, message: shortTooltipText } return { ...prevState, hide: false, hiding: false, timeOutId, message: shortTooltipText }
} else {
const shortTooltipText = props.message
return { ...prevState, hide: false, hiding: false, timeOutId, message: shortTooltipText }
}
}) })
} }
}, [props.message]) }, [props.message])
@ -103,7 +118,7 @@ export const Toaster = (props: ToasterProps) => {
<div data-shared="tooltipPopup" className={`remixui_tooltip alert alert-info p-2 ${state.hiding ? 'remixui_animateTop' : 'remixui_animateBottom'}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}> <div data-shared="tooltipPopup" className={`remixui_tooltip alert alert-info p-2 ${state.hiding ? 'remixui_animateTop' : 'remixui_animateBottom'}`} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<span className="px-2"> <span className="px-2">
{ state.message } { state.message }
{ (props.message.length > 201) && <button className="btn btn-secondary btn-sm mx-3" style={{ whiteSpace: 'nowrap' }} onClick={showFullMessage}>Show full message</button> } { state.showFullBtn && <button className="btn btn-secondary btn-sm mx-3" style={{ whiteSpace: 'nowrap' }} onClick={showFullMessage}>Show full message</button> }
</span> </span>
<span style={{ alignSelf: 'baseline' }}> <span style={{ alignSelf: 'baseline' }}>
<button data-id="tooltipCloseButton" className="fas fa-times btn-info mx-1 p-0" onClick={closeTheToaster}></button> <button data-id="tooltipCloseButton" className="fas fa-times btn-info mx-1 p-0" onClick={closeTheToaster}></button>

Loading…
Cancel
Save