showing inactive plugins correctly

pull/1344/head
joseph izang 4 years ago
parent a5cdacc741
commit adb542909d
  1. 109
      apps/remix-ide/src/app/components/plugin-manager-component.js
  2. 8
      libs/remix-ui/plugin-manager/src/lib/components/button.tsx
  3. 155
      libs/remix-ui/plugin-manager/src/lib/components/localPluginForm.tsx
  4. 4
      libs/remix-ui/plugin-manager/src/lib/components/pluginCard.tsx
  5. 206
      libs/remix-ui/plugin-manager/src/lib/components/rootView.tsx
  6. 19
      libs/remix-ui/plugin-manager/src/lib/remix-ui-plugin-manager.tsx
  7. 56
      libs/remix-ui/plugin-manager/src/types.d.ts

@ -103,28 +103,15 @@ class PluginManagerComponent extends ViewPlugin {
// items: {}
// }
this.localPlugin = new LocalPlugin()
// this.filter = ''
this.filter = ''
this.activePlugins = []
this.inactivePlugins = []
// this.appManager.event.on('activate', () => { this.reRender() })
// this.appManager.event.on('deactivate', () => { this.reRender() })
// this.engine.event.on('onRegistration', () => { this.reRender() })
// const { actives, inactives } = this.getAllPlugins()
}
reactProps () {
return {
views: this.views,
filter: this.filter,
localPlugin: this.localPlugin,
isActive: this.isActive,
activatePlugin: this.activateP,
deactivePlugin: this.deactivateP,
openLocalPlugin: this.openLocalPlugin,
profile: this.profile
// actives: actives,
// inactives: inactives
}
}
onActivation () {
this.renderComponent()
}
@ -137,15 +124,15 @@ class PluginManagerComponent extends ViewPlugin {
engine={this.engine}
localPlugin={this.localPlugin}
isActive={() => false}
actives={[]}
inactives={[]}
actives={this.activePlugins}
inactives={this.inactivePlugins}
/>,
document.getElementById('pluginManager'))
}
// isActive (name) {
// return this.appManager.actives.includes(name)
// }
isActive (name) {
return this.appManager.actives.includes(name)
}
// activateP (name) {
// this.appManager.activatePlugin(name)
@ -180,38 +167,62 @@ class PluginManagerComponent extends ViewPlugin {
}
}
// filterHelper () {
// const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(this.filter)
// const isNotRequired = (profile) => !this.appManager.isRequired(profile.name)
// const isNotDependent = (profile) => !this.appManager.isDependent(profile.name)
// const isNotHome = (profile) => profile.name !== 'home'
// const sortByName = (profileA, profileB) => {
// const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase()
// const nameB = ((profileB.displayName) ? profileB.displayName : profileB.name).toUpperCase()
// return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0
// }
// return (isFiltered, isNotRequired, isNotDependent, isNotHome, sortByName)
// }
filterHelper () {
const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(this.filter)
const isNotRequired = (profile) => !this.appManager.isRequired(profile.name)
const isNotDependent = (profile) => !this.appManager.isDependent(profile.name)
const isNotHome = (profile) => profile.name !== 'home'
const sortByName = (profileA, profileB) => {
const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase()
const nameB = ((profileB.displayName) ? profileB.displayName : profileB.name).toUpperCase()
return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0
}
return (isFiltered, isNotRequired, isNotDependent, isNotHome, sortByName)
}
// getAllPlugins () {
// // // Filter all active and inactive modules that are not required
// const [isFiltered, isNotRequired, isNotDependent, isNotHome, sortByName] = this.filterHelper()
// const { actives, inactives } = this.appManager.getAll()
// .filter(isFiltered)
// .filter(isNotRequired)
// .filter(isNotDependent)
// .filter(isNotHome)
// .sort(sortByName)
// .reduce(({ actives, inactives }, profile) => {
// return this.isActive(profile.name)
// ? { actives: [...actives, profile], inactives }
// : { inactives: [...inactives, profile], actives }
// }, { actives: [], inactives: [] })
// return (actives, inactives)
// }
getAllPlugins () {
// // Filter all active and inactive modules that are not required
const [isFiltered, isNotRequired, isNotDependent, isNotHome, sortByName] = this.filterHelper()
const { actives, inactives } = this.appManager.getAll()
.filter(isFiltered)
.filter(isNotRequired)
.filter(isNotDependent)
.filter(isNotHome)
.sort(sortByName)
.reduce(({ actives, inactives }, profile) => {
return this.isActive(profile.name)
? { actives: [...actives, profile], inactives }
: { inactives: [...inactives, profile], actives }
}, { actives: [], inactives: [] })
this.activePlugins = actives
this.inactivePlugins = inactives
}
render () {
// Filtering helpers
const isFiltered = (profile) => (profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(this.filter)
const isNotRequired = (profile) => !this.appManager.isRequired(profile.name)
const isNotDependent = (profile) => !this.appManager.isDependent(profile.name)
const isNotHome = (profile) => profile.name !== 'home'
const sortByName = (profileA, profileB) => {
const nameA = ((profileA.displayName) ? profileA.displayName : profileA.name).toUpperCase()
const nameB = ((profileB.displayName) ? profileB.displayName : profileB.name).toUpperCase()
return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0
}
const { actives, inactives } = this.appManager.getAll()
.filter(isFiltered)
.filter(isNotRequired)
.filter(isNotDependent)
.filter(isNotHome)
.sort(sortByName)
.reduce(({ actives, inactives }, profile) => {
return this.isActive(profile.name)
? { actives: [...actives, profile], inactives }
: { inactives: [...inactives, profile], actives }
}, { actives: [], inactives: [] })
this.activePlugins = actives
this.inactivePlugins = inactives
return this.htmlElement
}

@ -1,18 +1,20 @@
import React, { useContext } from 'react'
import React, { useContext, useState } from 'react'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
interface ButtonProps {
buttonText: 'Activate' | 'Deactivate'
}
function Button ({ buttonText }: ButtonProps) {
const { profile, deActivatePlugin, activatePlugin } = useContext(PluginManagerContext)
const dataId = `pluginManagerComponentDeactivateButton${profile.name}`
const [needToDeactivate] = useState('btn btn-secondary btn-sm')
const [needToActivate] = useState('btn btn-success btn-sm')
return (
<button
onClick={buttonText === 'Activate' ? () => activatePlugin(profile.name) : () => deActivatePlugin(profile.name)}
className="btn btn-secondary btn-sm"
className={buttonText === 'Activate' ? needToActivate : needToDeactivate}
data-id={dataId}
>
{buttonText}

@ -1,155 +0,0 @@
import React, { FormEvent, MouseEvent, useState } from 'react'
import { FormStateProps } from '../../types'
interface RadioSelectionformState {
pluginType: string
inputLabel: string
radioLabel: string
radioChecked?: boolean
updateProfile: (key: string, e: MouseEvent) => void
}
interface LocalPluginFormProps {
formSubmitHandler: (event: FormEvent, formData: FormStateProps) => void
}
const initialState: FormStateProps = {
name: '',
displayName: '',
url: '',
type: 'iframe',
hash: '',
methods: '',
location: 'sidePanel'
}
function LocalPluginForm ({ formSubmitHandler }: LocalPluginFormProps) {
const [plugin, setPlugin] = useState(initialState)
// const [name, setName] = useState('')
// const [displayName, setDisplayName] = useState('')
// const [methods, setMethods] = useState('')
// const [url, setUrl] = useState('')
// const [type, setType] = useState()
// const [location, setLocation] = useState()
function pluginChangeHandler<P extends keyof FormStateProps> (formProps: P, value: FormStateProps[P]) {
setPlugin({ ...plugin, [formProps]: value })
}
// function handleSubmit (e) {
// console.log('Logging the form submit event', e)
// console.log('state of the plugin', plugin)
// }
// const onValueChange = (event: any) => {
// const value = event.target.type === 'radio' ? event.target.checked : event.target.value
// const name = event.target.name
// if (name === 'name') {
// setName(value)
// } else if (name === 'displayName') {
// setDisplayName(value)
// } else if (name === 'methods') {
// setMethods(value)
// } else if (name === 'url') {
// setUrl(value)
// } else if (name === 'type') {
// setType(value)
// } else if (name === 'location') {
// setLocation(value)
// }
// }
return (
<form id="local-plugin-form" onSubmit={(e) => formSubmitHandler(e, plugin)}>
<div className="form-group">
<label htmlFor="plugin-name">Plugin Name <small>(required)</small></label>
<input className="form-control" onChange={e => pluginChangeHandler('name', e.target.value)} value={plugin.name} id="plugin-name" data-id="localPluginName" placeholder="Should be camelCase"/>
</div>
<div className="form-group">
<label htmlFor="plugin-displayname">Display Name</label>
<input className="form-control" onChange={e => pluginChangeHandler('displayName', e.target.value)} value={plugin.displayName} id="plugin-displayname" data-id="localPluginDisplayName" placeholder="Name in the header"/>
</div>
<div className="form-group">
<label htmlFor="plugin-methods">Api (comma separated list of methods name)</label>
<input className="form-control" onChange={e => pluginChangeHandler('methods', e.target.value)} value={plugin.methods} id="plugin-methods" data-id="localPluginMethods" placeholder="Name in the header"/>
</div>
<div className="form-group">
<label htmlFor="plugin-url">Url <small>(required)</small></label>
<input className="form-control" onChange={e => pluginChangeHandler('url', e.target.value)} value={plugin.url} id="plugin-url" data-id="localPluginUrl" placeholder="ex: https://localhost:8000" />
</div>
<h6>Type of connection <small>(required)</small></h6>
<div className="form-check form-group">
<div className="radio">
<input
className="form-check-input"
type="radio"
name="type"
value="iframe"
id="iframe"
data-id='localPluginRadioButtoniframe'
checked={plugin.type === 'iframe'}
onChange={(e) => pluginChangeHandler('type', e.target.value)}
/>
<label className="form-check-label" htmlFor="iframe">Iframe</label>
</div>
<div className="radio">
<input
className="form-check-input"
type="radio"
name="type"
value="ws"
id="ws"
data-id='localPluginRadioButtonws'
checked={plugin.type === 'ws'}
onChange={(e) => pluginChangeHandler('type', e.target.value)}
/>
<label className="form-check-label" htmlFor="ws">Websocket</label>
</div>
</div>
<h6>Location in remix <small>(required)</small></h6>
<div className="form-check form-group">
<div className="radio">
<input
className="form-check-input"
type="radio"
name="location"
value="sidePanel"
id="sidePanel"
data-id='localPluginRadioButtonsidePanel'
checked={plugin.location === 'sidePanel'}
onChange={(e) => pluginChangeHandler('location', e.target.value)}
/>
<label className="form-check-label" htmlFor="sidePanel">Side Panel</label>
</div>
<div className="radio">
<input
className="form-check-input"
type="radio"
name="location"
value="mainPanel"
id="mainPanel"
data-id='localPluginRadioButtonmainPanel'
checked={plugin.location === 'mainPanel'}
onChange={(e) => pluginChangeHandler('location', e.target.value)}
/>
<label className="form-check-label" htmlFor="mainPanel">Main Panel</label>
</div>
<div className="radio">
<input
className="form-check-input"
type="radio"
name="location"
value="none"
id="none"
data-id='localPluginRadioButtonnone'
checked={plugin.location === 'none'}
onChange={(e) => pluginChangeHandler('location', e.target.value)}
/>
<label className="form-check-label" htmlFor="none">None</label>
</div>
</div>
</form>
)
}
export default LocalPluginForm

@ -1,10 +1,10 @@
import React, { useContext, useState } from 'react'
import { Profile } from '../../types'
import { PluginManagerProfile } from '../../types'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
import '../remix-ui-plugin-manager.css'
import Button from './button'
interface PluginCardProps {
profile: Partial<Profile>
profile: Partial<PluginManagerProfile>
}
// eslint-disable-next-line no-empty-pattern

@ -1,47 +1,200 @@
import React, { FormEvent, Fragment, useContext, useState } from 'react'
/* eslint-disable no-debugger */
import React, { Fragment, useContext, useEffect, useState } from 'react'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
import ModuleHeading from './moduleHeading'
import PluginCard from './pluginCard'
import { ModalDialog } from '@remix-ui/modal-dialog'
import LocalPluginForm from './localPluginForm'
import { FormStateProps } from '../../types'
import { FormStateProps, PluginManagerProfile, RemixAppManager } from '../../types'
import { IframePlugin, WebsocketPlugin } from '@remixproject/engine-web'
import { Profile } from '@remixproject/plugin-utils'
import * as lo from 'lodash'
interface RootViewProps {
localPluginButtonText: string
const initialState: FormStateProps = {
name: 'test',
displayName: 'test',
url: '',
type: 'iframe',
hash: '',
methods: 'test',
location: 'sidePanel'
}
function RootView ({ localPluginButtonText }: RootViewProps) {
const { actives, inactives } = useContext(PluginManagerContext)
interface ShowInactivesProps {
inactives: Partial<PluginManagerProfile>[]
appManager?: RemixAppManager
headinglabel: string
}
function ShowInactives ({ inactives, appManager, headinglabel }: ShowInactivesProps) {
const [plugins] = useState<Profile<any>[]>(appManager.getAll())
const [litUpProfiles] = useState<Profile<any>[]>(appManager.getActiveProfiles())
const pluginNames = litUpProfiles.map(p => p.name)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let temp: Profile<any>[]
pluginNames.forEach(x => {
temp = plugins.filter(plugin => plugin.name === x)
})
return (
<Fragment>
<ModuleHeading headingLabel={headinglabel} />
{inactives.map((profile) => (
<PluginCard key={profile.name} profile={profile} />
))}
</Fragment>
)
}
function ShowActives ({ inactives, appManager, headinglabel }: ShowInactivesProps) {
const [plugins] = useState<any[]>([])
if (inactives.length === 0) {
plugins.map(plugin => inactives.push(plugin))
}
return (
<Fragment>
<ModuleHeading headingLabel={headinglabel} />
{inactives.map((profile) => (
<PluginCard key={profile.name} profile={profile} />
))}
</Fragment>
)
}
function RootView () {
const { appManager, actives, engine, inactives, localPlugin, filter } = useContext(PluginManagerContext)
const [visible, setVisible] = useState<boolean>(true)
const [plugin, setPlugin] = useState(initialState)
const [allPlugins] = useState(appManager.getAll())
const [activePlugins, setActivePlugins] = useState([])
const [inactivePlugins, setInactivePlugins] = useState([])
console.log(`allPlugins state has ${allPlugins.length} plugins ready to be filtered`)
function pluginChangeHandler<P extends keyof FormStateProps> (formProps: P, value: FormStateProps[P]) {
setPlugin({ ...plugin, [formProps]: value })
}
const openModal = () => {
setVisible(false)
}
const closeModal = () => setVisible(true)
const handleSubmit = (evt: FormEvent, formData: FormStateProps) => {
console.log('Data submitted from the form!!!: ', formData)
evt.preventDefault()
closeModal()
const activatePlugin = async (name: string) => {
await appManager.activatePlugin(name)
}
console.log('active plugins', activePlugins)
return (
<Fragment>
<form id="local-plugin-form">
<ModalDialog
handleHide={closeModal}
hide={visible}
title="Local Plugin"
okLabel="OK"
okFn={async () => {
const plugins = appManager.getActiveProfiles()
console.log('There are the active plugins from appManager :', plugins)
const profile: any = await localPlugin.open(appManager.getAll())
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)
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')
} }
cancelLabel="Cancel"
cancelFn={closeModal}
>
<LocalPluginForm
formSubmitHandler={handleSubmit}
/>
</ModalDialog>
<div id="pluginManager" data-id="pluginManagerComponentPluginManager">
<div className="form-group">
<label htmlFor="plugin-name">Plugin Name <small>(required)</small></label>
<input className="form-control" onChange={e => pluginChangeHandler('name', e.target.value)} value={plugin.name} id="plugin-name" data-id="localPluginName" placeholder="Should be camelCase" />
</div>
<div className="form-group">
<label htmlFor="plugin-displayname">Display Name</label>
<input className="form-control" onChange={e => pluginChangeHandler('displayName', e.target.value)} value={plugin.displayName} id="plugin-displayname" data-id="localPluginDisplayName" placeholder="Name in the header" />
</div>
<div className="form-group">
<label htmlFor="plugin-methods">Api (comma separated list of methods name)</label>
<input className="form-control" onChange={e => pluginChangeHandler('methods', e.target.value)} value={plugin.methods} id="plugin-methods" data-id="localPluginMethods" placeholder="Name in the header" />
</div>
<div className="form-group">
<label htmlFor="plugin-url">Url <small>(required)</small></label>
<input className="form-control" onChange={e => pluginChangeHandler('url', e.target.value)} value={plugin.url} id="plugin-url" data-id="localPluginUrl" placeholder="ex: https://localhost:8000" />
</div>
<h6>Type of connection <small>(required)</small></h6>
<div className="form-check form-group">
<div className="radio">
<input
className="form-check-input"
type="radio"
name="type"
value="iframe"
id="iframe"
data-id='localPluginRadioButtoniframe'
checked={plugin.type === 'iframe'}
onChange={(e) => pluginChangeHandler('type', e.target.value)} />
<label className="form-check-label" htmlFor="iframe">Iframe</label>
</div>
<div className="radio">
<input
className="form-check-input"
type="radio"
name="type"
value="ws"
id="ws"
data-id='localPluginRadioButtonws'
checked={plugin.type === 'ws'}
onChange={(e) => pluginChangeHandler('type', e.target.value)} />
<label className="form-check-label" htmlFor="ws">Websocket</label>
</div>
</div>
<h6>Location in remix <small>(required)</small></h6>
<div className="form-check form-group">
<div className="radio">
<input
className="form-check-input"
type="radio"
name="location"
value="sidePanel"
id="sidePanel"
data-id='localPluginRadioButtonsidePanel'
checked={plugin.location === 'sidePanel'}
onChange={(e) => pluginChangeHandler('location', e.target.value)} />
<label className="form-check-label" htmlFor="sidePanel">Side Panel</label>
</div>
<div className="radio">
<input
className="form-check-input"
type="radio"
name="location"
value="mainPanel"
id="mainPanel"
data-id='localPluginRadioButtonmainPanel'
checked={plugin.location === 'mainPanel'}
onChange={(e) => pluginChangeHandler('location', e.target.value)} />
<label className="form-check-label" htmlFor="mainPanel">Main Panel</label>
</div>
<div className="radio">
<input
className="form-check-input"
type="radio"
name="location"
value="none"
id="none"
data-id='localPluginRadioButtonnone'
checked={plugin.location === 'none'}
onChange={(e) => pluginChangeHandler('location', e.target.value)} />
<label className="form-check-label" htmlFor="none">None</label>
</div>
</div>
</ModalDialog>
</form><div id="pluginManager" data-id="pluginManagerComponentPluginManager">
<header className="form-group remixui_pluginSearch plugins-header py-3 px-4 border-bottom" data-id="pluginManagerComponentPluginManagerHeader">
<input type="text" className="form-control" placeholder="Search" data-id="pluginManagerComponentSearchInput" />
<button onClick={openModal} className="remixui_pluginSearchButton btn bg-transparent text-dark border-0 mt-2 text-underline" data-id="pluginManagerComponentPluginSearchButton">
@ -49,22 +202,11 @@ function RootView ({ localPluginButtonText }: RootViewProps) {
</button>
</header>
<section data-id="pluginManagerComponentPluginManagerSection">
{actives.length === 0 ? (
<Fragment>
<ModuleHeading headingLabel="Active Modules"/>
{actives.map((profile) => (
<PluginCard profile={profile}/>
))}
</Fragment>
) : null }
{inactives.length === 0 ? (
<Fragment>
<ModuleHeading headingLabel="Inactive Modules"/>
{inactives.map((profile) => (
<PluginCard profile={profile}/>
))}
</Fragment>
) : null}
{actives !== undefined
? (<ShowActives appManager={appManager} headinglabel="Active Modules" inactives={inactivePlugins} />)
: (<ShowActives headinglabel="Active Modules" inactives={activePlugins}/>)
}
{inactives !== undefined ? (<ShowInactives appManager={appManager} inactives={inactives} headinglabel="Inactive Modules" />) : <ShowInactives inactives={inactives} headinglabel="Inactive Modules" />}
</section>
</div>
</Fragment>

@ -8,26 +8,9 @@ export const RemixUiPluginManager = (props: RemixUiPluginManagerProps) => {
console.log('current state of appmanager', props.appManager)
console.log('The state of props ', props)
// openLocalPlugin () {
// try {
// const profile = await props.localPlugin.open(props.appManager.getAll())
// if (!profile) return
// if (props.appManager.getIds().includes(profile.name)) {
// throw new Error('This name has already been used')
// }
// const plugin = profile.type === 'iframe' ? new IframePlugin(profile) : new WebsocketPlugin(profile)
// props.engine.register(plugin)
// await props.appManager.activatePlugin(plugin.name)
// } catch (err) {
// // TODO : Use an alert to handle this error instead of a console.log
// console.log(`Cannot create Plugin : ${err.message}`)
// addToolTip(`Cannot create Plugin : ${err.message}`)
// }
// }
return (
<PluginManagerContextProvider props={props}>
<RootView localPluginButtonText="Local Plugin"/>
<RootView />
</PluginManagerContextProvider>
)
}

@ -2,6 +2,7 @@ import { PermissionHandler } from './app/ui/persmission-handler'
import { PluginManager } from '@remixproject/engine/lib/manager'
import { EventEmitter } from 'events'
import { Engine } from '@remixproject/engine/lib/engine'
import { Profile } from '@remixproject/plugin-utils'
/* eslint-disable camelcase */
// eslint-disable-next-line no-use-before-define
@ -103,16 +104,17 @@ export class RemixAppManager extends PluginManager {
export interface PluginManagerContextProviderProps {
appManager: RemixAppManager
engine: RemixEngine
localPlugin: LocalPlugin
_paq: _Paq
filter: string
actives: Profile[]
inactives: Profile[]
actives: Partial<PluginManagerProfile>[]
inactives: Partial<PluginManagerProfile>[]
activatePlugin: (name: string) => void
deActivatePlugin: (name: string) => void
isActive: (name: string) => boolean
openLocalPlugin: () => Promise<void>
filterPlugins: () => void
profile: Profile
profile: Partial<PluginManagerProfile>
defaultProfile: DefaultLocalPlugin
headingLabel: string
}
@ -122,14 +124,13 @@ export interface RemixUiPluginManagerProps {
localPlugin: LocalPlugin
_paq: _Paq
filter: string
actives: Profile[]
inactives: Profile[]
actives: Partial<PluginManagerProfile>[]
inactives: Partial<PluginManagerProfile>[]
activatePlugin: (name: string) => void
deActivatePlugin: (name: string) => void
isActive: (name: string) => any
openLocalPlugin: () => Promise<void>
isActive: (name: string) => boolean
filterPlugins: () => void
profile: Profile
profile: Partial<PluginManagerProfile>
headingLabel: string
}
/** @class Reference loaders.
@ -153,43 +154,40 @@ export type PluginManagerSettings = {
render: () => HTMLElement
}
export type LocalPluginType = {
'iframe',
'ws'
}
export type DefaultLocalPlugin = {
export interface DefaultLocalPlugin extends Profile {
name: string
displayName: string
url: string
type: string
hash: string
methods: any
location: string
}
export interface FormStateProps extends DefaultLocalPlugin {
export interface FormStateProps {
name: string
displayName: string
url: string
type: string
hash: string
methods: any
location: string
}
export type Profile = {
name: 'pluginManager',
displayName: 'Plugin manager',
methods: [],
events: [],
export type PluginManagerProfile = Profile & {
name: string,
displayName: string,
methods: Array<any>,
events?: Array<any>,
icon: 'assets/img/pluginManager.webp',
description: 'Start/stop services, modules and plugins',
kind: 'settings',
location: 'sidePanel',
description: string,
kind?: string,
location: 'sidePanel' | 'mainPanel' | 'none',
documentation: 'https://remix-ide.readthedocs.io/en/latest/plugin_manager.html',
version: any
type: 'iframe' | 'ws'
hash: string
}
export type TileLabel = {
label: 'Active Module' | 'Inactive Modules'
}
export type LocalPlugin = {
create: () => Profile
updateName: (target: string) => void

Loading…
Cancel
Save