finish ui for plugins permissions

pull/1344/head
joseph izang 3 years ago
parent 94e8b5b832
commit c830dd4807
  1. 18
      apps/remix-ide/src/app/components/plugin-manager-component.js
  2. 8
      apps/remix-ide/src/remixAppManager.js
  3. 12
      libs/remix-ui/plugin-manager/src/lib/components/button.tsx
  4. 97
      libs/remix-ui/plugin-manager/src/lib/components/permissions/permissionsSettings.tsx
  5. 20
      libs/remix-ui/plugin-manager/src/lib/components/pluginCard.tsx
  6. 91
      libs/remix-ui/plugin-manager/src/lib/components/rootView.tsx
  7. 8
      libs/remix-ui/plugin-manager/src/lib/remix-ui-plugin-manager.tsx
  8. 5
      libs/remix-ui/plugin-manager/src/types.d.ts

@ -92,9 +92,10 @@ const profile = {
class PluginManagerComponent extends ViewPlugin { class PluginManagerComponent extends ViewPlugin {
constructor (appManager, engine) { constructor (appManager, engine) {
super(profile) super(profile)
// this.event = new EventEmitter() // already exists in engine so not needed here this.event = new EventEmitter() // already exists in engine so not needed here
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.views = { this.views = {
@ -103,9 +104,8 @@ class PluginManagerComponent extends ViewPlugin {
} }
this.localPlugin = new LocalPlugin() this.localPlugin = new LocalPlugin()
this.filter = '' this.filter = ''
this.activePlugins = []
this.inactivePlugins = []
this.pluginNames = this.appManager.actives this.pluginNames = this.appManager.actives
// this.pluginManagerSettings.
// this.appManager.event.on('activate', () => { this.renderComponent() }) // this.appManager.event.on('activate', () => { this.renderComponent() })
// this.appManager.event.on('deactivate', () => { this.renderComponent() }) // this.appManager.event.on('deactivate', () => { this.renderComponent() })
// this.engine.event.on('onRegistration', () => { this.renderComponent() }) // this.engine.event.on('onRegistration', () => { this.renderComponent() })
@ -116,10 +116,12 @@ class PluginManagerComponent extends ViewPlugin {
} }
activateP (name) { activateP (name) {
this.appManager.turnPluginOn(name) this.appManager.activatePlugin(name)
console.log('activateP method reached. And activation of method was successful') this.appManager.event.on('activate', () => {
this.renderComponent()
console.log('activateP method reached. And activation of method was successful')
})
_paq.push(['trackEvent', 'manager', 'activate', name]) _paq.push(['trackEvent', 'manager', 'activate', name])
this.renderComponent()
console.log('activation was logged in _paq and renderComponent has been called.') console.log('activation was logged in _paq and renderComponent has been called.')
} }
@ -144,10 +146,6 @@ class PluginManagerComponent extends ViewPlugin {
engine={this.engine} engine={this.engine}
localPlugin={this.localPlugin} localPlugin={this.localPlugin}
activePluginNames={this.pluginNames} activePluginNames={this.pluginNames}
actives={this.activePlugins}
inactives={this.inactivePlugins}
// activatePlugin={this.activateP}
// deActivatePlugin={this.deactivateP}
_paq={_paq} _paq={_paq}
filter={this.filter} filter={this.filter}
/>, />,

@ -75,14 +75,6 @@ export class RemixAppManager extends PluginManager {
return await this.permissionHandler.askPermission(this.profiles[from], this.profiles[to], method, message) return await this.permissionHandler.askPermission(this.profiles[from], this.profiles[to], method, message)
} }
async turnPluginOn (name) {
await this.activatePlugin(name)
}
async turnPluginOff (name) {
await this.deactivatePlugin(name)
}
onPluginActivated (plugin) { onPluginActivated (plugin) {
this.pluginLoader.set(plugin, this.actives) this.pluginLoader.set(plugin, this.actives)
this.event.emit('activate', plugin) this.event.emit('activate', plugin)

@ -1,13 +1,17 @@
import React, { useContext, useState } from 'react' import React, { useState } from 'react'
import { PluginManagerContext } from '../contexts/pluginmanagercontext' import { PluginManagerComponent } from '../../types'
interface ButtonProps { interface ButtonProps {
buttonText: 'Activate' | 'Deactivate' buttonText: 'Activate' | 'Deactivate'
pluginName: string pluginName: string
pluginComponent: PluginManagerComponent
} }
function Button ({ buttonText, pluginName }: ButtonProps) { function Button ({
const { pluginComponent } = useContext(PluginManagerContext) buttonText,
pluginName,
pluginComponent
}: ButtonProps) {
const dataId = `pluginManagerComponentDeactivateButton${pluginName}` const dataId = `pluginManagerComponentDeactivateButton${pluginName}`
const [needToDeactivate] = useState('btn btn-secondary btn-sm') const [needToDeactivate] = useState('btn btn-secondary btn-sm')
const [needToActivate] = useState('btn btn-success btn-sm') const [needToActivate] = useState('btn btn-success btn-sm')

@ -0,0 +1,97 @@
import React, { Fragment, useState } from 'react'
import { RemixUiCheckbox } from '@remix-ui/checkbox'
import { PluginManagerSettings } from '../../../types'
import { ModalDialog } from '@remix-ui/modal-dialog'
interface PermissionSettingsProps {
pluginSettings: PluginManagerSettings
toPlugin?: string
funcObj?: {}
methodName?: string
fromPlugins?: {}
}
// <div className="form-group remixui_permissionKey">
// <div className="remixui_checkbox">
// {fromPluginPermission.allow
// ? <span className="mr-2">
// <RemixUiCheckbox
// checked
// onClick={() => togglePermission(fromName, toPlugin, methodName)}
// inputType="checkbox"
// id={`permission-checkbox-${toPlugin}-${methodName}-${toPlugin}`}
// aria-describedby={`module ${fromPluginPermission} asks permission for ${methodName}`}
// />
// </span>
// : <span className="mr-2">
// <RemixUiCheckbox
// checked={false}
// onClick={() => togglePermission(fromName, toPlugin, methodName)}
// inputType="checkbox"
// id={`permission-checkbox-${toPlugin}-${methodName}-${toPlugin}`}
// aria-describedby={`module ${fromPluginPermission} asks permission for ${methodName}`}
// />
// </span>
// }
// <label
// htmlFor={`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={() => pluginSettings.clearPersmission(fromName, toPlugin, methodName)} className="fa fa-trash-alt" data-id={`pluginManagerSettingsRemovePermission-${toPlugin}-${methodName}-${toPlugin}`}></i>
// </div>
function PermisssionsSettings ({ pluginSettings }: PermissionSettingsProps) {
/**
* Declare component local state
*/
const [modalVisibility, setModalVisibility] = useState<boolean>(true)
const toPluginP = ''
const fromName = ''
const methodName = ''
const openModal = () => setModalVisibility(false)
const closeModal = () => setModalVisibility(true)
const togglePermission = (fromPlugin: string, toPlugin: string, methodName: string) => {
pluginSettings.permissions[toPlugin][methodName][fromPlugin].allow = !pluginSettings.permissions[toPlugin][methodName][fromPlugin].allow
}
return (
<Fragment>
<ModalDialog
handleHide={closeModal}
hide={modalVisibility}
title="Plugin Manager Permissions"
>
<div className="border p-2">
<div className="pb-2 remixui_permissionKey">
<h3>toPlugin permissions:</h3>
<i onClick={() => pluginSettings.clearAllPersmission(toPluginP)} className="far fa-trash-alt" data-id={`pluginManagerSettingsClearAllPermission-${toPluginP}`}></i>
</div>
<form className="remixui_permissionForm" data-id="pluginManagerSettingsPermissionForm">
<h4>No Permission requested yet.</h4>
<div className="form-group remixui_permissionKey">
<div className="remixui_checkbox">
{/* ${checkbox} */}
<label htmlFor="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={() => pluginSettings.clearPersmission(fromName, toPluginP, methodName)} className="fa fa-trash-alt" data-id={`pluginManagerSettingsRemovePermission-${toPluginP}-${methodName}-${toPluginP}`}></i>
</div>
</form>
</div>
</ModalDialog>
<footer className="bg-light remixui_permissions remix-bg-opacity">
<button
onClick={() => setModalVisibility(!modalVisibility)}
className="btn btn-primary settings-button"
data-id="pluginManagerPermissionsButton">
Permissions
</button>
</footer>
</Fragment>
)
}
export default PermisssionsSettings

@ -1,15 +1,17 @@
import React, { useContext, useState } from 'react' import React, { useState } from 'react'
import { PluginManagerProfile } from '../../types' import { PluginManagerComponent, PluginManagerProfile } from '../../types'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
import '../remix-ui-plugin-manager.css' import '../remix-ui-plugin-manager.css'
import Button from './button' import Button from './button'
interface PluginCardProps { interface PluginCardProps {
profile: Partial<PluginManagerProfile> profile: Partial<PluginManagerProfile>
pluginComponent: PluginManagerComponent
} }
// eslint-disable-next-line no-empty-pattern // eslint-disable-next-line no-empty-pattern
function PluginCard ({ profile }: PluginCardProps) { function PluginCard ({
const { pluginComponent } = useContext(PluginManagerContext) profile,
pluginComponent
}: PluginCardProps) {
const [displayName] = useState<string>((profile.displayName) ? profile.displayName : profile.name) const [displayName] = useState<string>((profile.displayName) ? profile.displayName : profile.name)
const [docLink] = useState<JSX.Element>((profile.documentation) ? ( const [docLink] = useState<JSX.Element>((profile.documentation) ? (
<a href={profile.documentation} className="px-1" title="link to documentation" target="_blank" rel="noreferrer"> <a href={profile.documentation} className="px-1" title="link to documentation" target="_blank" rel="noreferrer">
@ -35,7 +37,13 @@ function PluginCard ({ profile }: PluginCardProps) {
<Button <Button
buttonText="Deactivate" buttonText="Deactivate"
pluginName={profile.name} pluginName={profile.name}
/>) : <Button buttonText="Activate" pluginName={profile.name}/> pluginComponent={pluginComponent}
/>)
: <Button
buttonText="Activate"
pluginName={profile.name}
pluginComponent={pluginComponent}
/>
} }
</h6> </h6>
</div> </div>

@ -1,10 +1,12 @@
/* eslint-disable no-debugger */ /* eslint-disable no-debugger */
import React, { Fragment, useContext, useEffect, useState } from 'react' import React, { Fragment, useEffect, useState } from 'react'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
import ModuleHeading from './moduleHeading' import ModuleHeading from './moduleHeading'
import PluginCard from './pluginCard' import PluginCard from './pluginCard'
import { ModalDialog } from '@remix-ui/modal-dialog' import { ModalDialog } from '@remix-ui/modal-dialog'
import { FormStateProps, PluginManagerProfile } from '../../types' import { FormStateProps, PluginManagerComponent, PluginManagerProfile, PluginManagerSettings } from '../../types'
import { IframePlugin, WebsocketPlugin } from '@remixproject/engine-web'
import { Profile } from '@remixproject/plugin-utils'
import PermisssionsSettings from './permissions/permissionsSettings'
const initialState: FormStateProps = { const initialState: FormStateProps = {
name: 'test', name: 'test',
@ -16,28 +18,40 @@ const initialState: FormStateProps = {
location: 'sidePanel' location: 'sidePanel'
} }
function RootView () { interface RootViewProps {
const { appManager, pluginComponent, activePluginNames } = useContext(PluginManagerContext) pluginComponent: PluginManagerComponent
}
function RootView ({ pluginComponent }: RootViewProps) {
/**
* Component Local State declaration
*/
const [visible, setVisible] = useState<boolean>(true) const [visible, setVisible] = useState<boolean>(true)
const [plugin, setPlugin] = useState(initialState) const [plugin, setPlugin] = useState(initialState)
const [filterPlugins, setFilterPlugin] = useState('') const [filterPlugins, setFilterPlugin] = useState('')
// eslint-disable-next-line @typescript-eslint/no-unused-vars const [activeP, setActiveP] = useState<Partial<PluginManagerProfile>[]>()
const [_, setGetAndFilter] = useState<any>() const [inactiveP, setInactiveP] = useState<Partial<PluginManagerProfile>[]>()
const [activeP, setActiveP] = useState<any[]>()
const [inactiveP, setInactiveP] = useState<any[]>()
function pluginChangeHandler<P extends keyof FormStateProps> (formProps: P, value: FormStateProps[P]) { function pluginChangeHandler<P extends keyof FormStateProps> (formProps: P, value: FormStateProps[P]) {
setPlugin({ ...plugin, [formProps]: value }) setPlugin({ ...plugin, [formProps]: value })
appManager.activatePlugin('')
} }
/**
* Modal Visibility States
*/
const openModal = () => { const openModal = () => {
setVisible(false) setVisible(false)
} }
const closeModal = () => setVisible(true) const closeModal = () => setVisible(true)
// <-- End Modal Visibility States -->
/**
* Plugins list filtering and Sorting based on search input field state change
*/
const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(filterPlugins) const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(filterPlugins)
const isNotRequired = (profile) => !appManager.isRequired(profile.name) const isNotRequired = (profile) => !pluginComponent.appManager.isRequired(profile.name)
const isNotDependent = (profile) => !appManager.isDependent(profile.name) const isNotDependent = (profile) => !pluginComponent.appManager.isDependent(profile.name)
const isNotHome = (profile) => profile.name !== 'home' const isNotHome = (profile) => profile.name !== 'home'
const sortByName = (profileA, profileB) => { const sortByName = (profileA, profileB) => {
const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase() const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase()
@ -46,30 +60,32 @@ function RootView () {
} }
const getAndFilterPlugins = () => { const getAndFilterPlugins = () => {
const { actives, inactives } = appManager.getAll() const { actives, inactives } = pluginComponent.appManager.getAll()
.filter(isFiltered) .filter(isFiltered)
.filter(isNotRequired) .filter(isNotRequired)
.filter(isNotDependent) .filter(isNotDependent)
.filter(isNotHome) .filter(isNotHome)
.sort(sortByName) .sort(sortByName)
.reduce(({ actives, inactives }, profile) => { .reduce(({ actives, inactives }, profile) => {
return activePluginNames.includes(profile.name) return pluginComponent.isActive(profile.name)
? { actives: [...actives, profile], inactives } ? { actives: [...actives, profile], inactives }
: { inactives: [...inactives, profile], actives } : { inactives: [...inactives, profile], actives }
}, { actives: [], inactives: [] }) }, { actives: [], inactives: [] })
setActiveP(actives) setActiveP(actives)
console.log('profile property on appmanager', pluginComponent.appManager.profile)
setInactiveP(inactives) setInactiveP(inactives)
} }
// <-- End Filtering and Sorting based on search input field
useEffect(() => { useEffect(() => {
setGetAndFilter(getAndFilterPlugins()) getAndFilterPlugins()
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [filterPlugins]) }, [filterPlugins])
useEffect(() => { useEffect(() => {
}) }, [activeP, inactiveP])
console.log('This is the result of getting and filtering all plugins from app manager :', inactiveP)
return ( return (
<Fragment> <Fragment>
<form id="local-plugin-form"> <form id="local-plugin-form">
@ -78,21 +94,14 @@ function RootView () {
hide={visible} hide={visible}
title="Local Plugin" title="Local Plugin"
okLabel="OK" okLabel="OK"
okFn={async () => { okFn={() => {
// const plugins = appManager.getActiveProfiles() const profile: any = pluginComponent.localPlugin.open(pluginComponent.appManager.getAll())
// console.log('There are the active plugins from appManager :', plugins) if (pluginComponent.appManager.getIds().includes(profile.name)) {
// const profile: any = await localPlugin.open(appManager.getAll()) throw new Error('This name has already been used')
// if (appManager.getIds().includes(profile.name)) { }
// throw new Error('This name has already been used') const lPlugin = profile.type === 'iframe' ? new IframePlugin(profile) : new WebsocketPlugin(profile)
// } pluginComponent.engine.register(lPlugin)
// const lPlugin = profile.type === 'iframe' ? new IframePlugin(profile) : new WebsocketPlugin(profile) pluginComponent.appManager.activatePlugin(lPlugin.name)
// console.log('handle submit local plugin', lPlugin)
// console.log('Local PLugin type from legacy as props', localPlugin)
// engine.register(lPlugin)
// console.log('engine has registered lPlugin')
// await appManager.activatePlugin(lPlugin.name)
// console.log('appManager has activated lPlugin')
await pluginComponent.openLocalPlugin()
} } } }
cancelLabel="Cancel" cancelLabel="Cancel"
cancelFn={closeModal} cancelFn={closeModal}
@ -183,7 +192,8 @@ function RootView () {
</div> </div>
</ModalDialog> </ModalDialog>
</form><div id="pluginManager" data-id="pluginManagerComponentPluginManager"> </form>
<div id="pluginManager" data-id="pluginManagerComponentPluginManager">
<header className="form-group remixui_pluginSearch plugins-header py-3 px-4 border-bottom" data-id="pluginManagerComponentPluginManagerHeader"> <header className="form-group remixui_pluginSearch plugins-header py-3 px-4 border-bottom" data-id="pluginManagerComponentPluginManagerHeader">
<input <input
type="text" type="text"
@ -204,7 +214,11 @@ function RootView () {
<Fragment> <Fragment>
<ModuleHeading headingLabel="Active Modules" actives={activeP} inactives={inactiveP} /> <ModuleHeading headingLabel="Active Modules" actives={activeP} inactives={inactiveP} />
{activeP.map((profile) => ( {activeP.map((profile) => (
<PluginCard key={profile.name} profile={profile} /> <PluginCard
key={profile.name}
profile={profile}
pluginComponent={pluginComponent}
/>
))} ))}
</Fragment> </Fragment>
) )
@ -214,11 +228,16 @@ function RootView () {
<Fragment> <Fragment>
<ModuleHeading headingLabel="Inactive Modules" inactives={inactiveP} actives={activeP} /> <ModuleHeading headingLabel="Inactive Modules" inactives={inactiveP} actives={activeP} />
{inactiveP.map((profile) => ( {inactiveP.map((profile) => (
<PluginCard key={profile.name} profile={profile} /> <PluginCard
key={profile.name}
profile={profile}
pluginComponent={pluginComponent}
/>
))} ))}
</Fragment> </Fragment>
) : null} ) : null}
</section> </section>
<PermisssionsSettings pluginSettings={pluginComponent.pluginSettings}/>
</div> </div>
</Fragment> </Fragment>
) )

@ -1,16 +1,10 @@
import React from 'react' import React from 'react'
import { RemixUiPluginManagerProps } from '../types' import { RemixUiPluginManagerProps } from '../types'
import RootView from './components/rootView' import RootView from './components/rootView'
import PluginManagerContextProvider from './contexts/pluginmanagercontext'
import './remix-ui-plugin-manager.css' import './remix-ui-plugin-manager.css'
export const RemixUiPluginManager = (props: RemixUiPluginManagerProps) => { export const RemixUiPluginManager = (props: RemixUiPluginManagerProps) => {
console.log('current state of appmanager', props.pluginComponent)
console.log('The state of props ', props)
return ( return (
<PluginManagerContextProvider props={props}> <RootView pluginComponent={props.pluginComponent}/>
<RootView />
</PluginManagerContextProvider>
) )
} }

@ -76,6 +76,7 @@ export class PluginManagerSettings {
export class PluginManagerComponent extends ViewPlugin extends Plugin implements PluginBase { export class PluginManagerComponent extends ViewPlugin extends Plugin implements PluginBase {
constructor(appManager: RemixAppManager, engine: Engine) constructor(appManager: RemixAppManager, engine: Engine)
appManager: RemixAppManager appManager: RemixAppManager
pluginSettings: PluginManagerSettings
engine: Engine engine: Engine
htmlElement: HTMLDivElement htmlElement: HTMLDivElement
views: { root: null, items: {} } views: { root: null, items: {} }
@ -138,8 +139,6 @@ export interface PluginManagerContextProviderProps {
pluginComponent: PluginManagerComponent pluginComponent: PluginManagerComponent
pluginSettings: PluginManagerSettings pluginSettings: PluginManagerSettings
activePluginNames: string[] activePluginNames: string[]
actives: Partial<PluginManagerProfile>[]
inactives: Partial<PluginManagerProfile>[]
isActive?: (name: string) => boolean isActive?: (name: string) => boolean
filterPlugins: () => void filterPlugins: () => void
profile: Partial<PluginManagerProfile> profile: Partial<PluginManagerProfile>
@ -152,8 +151,6 @@ export interface RemixUiPluginManagerProps {
pluginComponent: PluginManagerComponent pluginComponent: PluginManagerComponent
pluginSettings: PluginManagerSettings // Window & typeof globalThis | [] pluginSettings: PluginManagerSettings // Window & typeof globalThis | []
activePluginNames: string[] activePluginNames: string[]
actives: Partial<PluginManagerProfile>[]
inactives: Partial<PluginManagerProfile>[]
isActive?: (name: string) => boolean isActive?: (name: string) => boolean
filterPlugins: () => void filterPlugins: () => void
profile: Partial<PluginManagerProfile> profile: Partial<PluginManagerProfile>

Loading…
Cancel
Save