Remove plugin manager settings and replace old toaster in file-manager

pull/1917/head
David Disu 3 years ago
parent 15c0033345
commit 11f5de164b
  1. 2
      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. 6
      apps/remix-ide/src/app/plugins/modal.tsx
  6. 2
      libs/remix-ui/app/src/lib/remix-app/actions/modals.ts
  7. 2
      libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
  8. 4
      libs/remix-ui/app/src/lib/remix-app/interface/index.ts
  9. 1
      libs/remix-ui/helper/src/index.ts
  10. 12
      libs/remix-ui/helper/src/lib/components.tsx
  11. 6
      libs/remix-ui/helper/tsconfig.json
  12. 6
      libs/remix-ui/plugin-manager/src/lib/components/permissionsSettings.tsx
  13. 5
      libs/remix-ui/plugin-manager/src/lib/components/rootView.tsx
  14. 4
      libs/remix-ui/plugin-manager/src/lib/remix-ui-plugin-manager.tsx
  15. 27
      libs/remix-ui/toaster/src/lib/toaster.tsx

@ -319,7 +319,7 @@ class AppComponent {
console.log("couldn't register iframe plugins", e.message)
}
await self.appManager.activatePlugin(['layout'])
await self.appManager.activatePlugin(['modal'])
await self.appManager.activatePlugin(['notification'])
await self.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['permissionhandler', 'theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])

@ -1,5 +1,4 @@
import { ViewPlugin } from '@remixproject/engine-web'
import { PluginManagerSettings } from './plugin-manager-settings'
import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom'
import {RemixUiPluginManager} from '@remix-ui/plugin-manager' // eslint-disable-line
@ -24,7 +23,6 @@ class PluginManagerComponent extends ViewPlugin {
super(profile)
this.appManager = appManager
this.engine = engine
this.pluginManagerSettings = new PluginManagerSettings()
this.htmlElement = document.createElement('div')
this.htmlElement.setAttribute('id', 'pluginManager')
this.filter = ''
@ -90,7 +88,6 @@ class PluginManagerComponent extends ViewPlugin {
ReactDOM.render(
<RemixUiPluginManager
pluginComponent={this}
pluginManagerSettings={this.pluginManagerSettings}
/>,
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'
import yo from 'yo-yo'
import async from 'async'
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry'
import { EventEmitter } from 'events'
import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types'
const toaster = require('../ui/tooltip')
import { fileChangedToasterMsg } from '@remix-ui/helper'
const helper = require('../../lib/helper.js')
/*
@ -317,7 +315,7 @@ class FileManager extends Plugin {
if (isFile) {
if (newPathExists) {
this.call('modal', 'alert', {
this.call('notification', 'alert', {
id: 'fileManagerAlert',
message: 'File already exists'
})
@ -326,7 +324,7 @@ class FileManager extends Plugin {
return provider.rename(oldPath, newPath, false)
} else {
if (newPathExists) {
this.call('modal', 'alert', {
this.call('notification', 'alert', {
id: 'fileManagerAlert',
message: 'Directory already exists'
})
@ -528,17 +526,7 @@ class FileManager extends Plugin {
const required = this.appManager.isRequired(this.currentRequest.from)
if (canCall && !required) {
// inform the user about modification after permission is granted and even if permission was saved before
toaster(yo`
<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 })
this.call('notification','toast', fileChangedToasterMsg(this.currentRequest.from, path))
}
}
return await this._setFileInternal(path, content)
@ -778,12 +766,12 @@ class FileManager extends Plugin {
helper.createNonClashingName(file, self._deps.filesProviders[fileProvider],
(error, name) => {
if (error) {
this.call('modal', 'alert', {
this.call('notification', 'alert', {
id: 'fileManagerAlert',
message: 'Unexpected error loading file ' + file + ': ' + error
})
} else if (helper.checkSpecialChars(name)) {
this.call('modal', 'alert', {
this.call('notification', 'alert', {
id: 'fileManagerAlert',
message: 'Special characters are not allowed in file names.'
})

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

@ -21,7 +21,7 @@ export const enum modalActionTypes {
type ModalPayload = {
[modalActionTypes.setModal]: AppModal
[modalActionTypes.handleHideModal]: any
[modalActionTypes.setToast]: string
[modalActionTypes.setToast]: string | JSX.Element
[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({
type: modalActionTypes.setToast,
payload: message

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

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

@ -0,0 +1,12 @@
import React from 'react'
export const fileChangedToasterMsg = (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>
)

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

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

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

@ -7,11 +7,11 @@ import InactivePluginCardContainer from './components/InactivePluginCardContaine
import RootView from './components/rootView'
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 [inactiveProfiles, setinactiveProfiles] = useState<Profile[]>(pluginComponent.inactivePlugins)
return (
<RootView pluginComponent={pluginComponent} pluginManagerSettings={pluginManagerSettings}>
<RootView pluginComponent={pluginComponent}>
<section data-id="pluginManagerComponentPluginManagerSection">
<ActivePluginCardContainer
pluginComponent={pluginComponent}

@ -5,19 +5,28 @@ import './toaster.css'
/* eslint-disable-next-line */
export interface ToasterProps {
message: string
message: string | JSX.Element
timeOut?: number,
handleHide?: () => void
}
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: '',
hide: true,
hiding: false,
timeOutId: null,
timeOut: props.timeOut || 7000,
showModal: false
showModal: false,
showFullBtn: false
})
useEffect(() => {
@ -29,9 +38,15 @@ export const Toaster = (props: ToasterProps) => {
}, state.timeOut)
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])
@ -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}>
<span className="px-2">
{ 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 style={{ alignSelf: 'baseline' }}>
<button data-id="tooltipCloseButton" className="fas fa-times btn-info mx-1 p-0" onClick={closeTheToaster}></button>

Loading…
Cancel
Save