Fix components and plug props at provider level

pull/1344/head
joseph izang 4 years ago
parent 9f516a8467
commit 4c05461e58
  1. 157
      apps/remix-ide/src/app/components/plugin-manager-component.js
  2. 19
      libs/remix-ui/plugin-manager/src/lib/components/activeTile.tsx
  3. 12
      libs/remix-ui/plugin-manager/src/lib/components/listGroupItem.tsx
  4. 28
      libs/remix-ui/plugin-manager/src/lib/components/pluginCard.tsx
  5. 77
      libs/remix-ui/plugin-manager/src/lib/components/renderItem.tsx
  6. 37
      libs/remix-ui/plugin-manager/src/lib/components/rootView.tsx
  7. 14
      libs/remix-ui/plugin-manager/src/lib/contexts/pluginmanagercontext.tsx
  8. 95
      libs/remix-ui/plugin-manager/src/lib/remix-ui-plugin-manager.tsx
  9. 36
      libs/remix-ui/plugin-manager/src/types.d.ts

@ -92,11 +92,12 @@ const profile = {
class PluginManagerComponent extends ViewPlugin {
constructor (appManager, engine) {
super(profile)
// this.event = new EventEmitter() //already exists in engine so not needed here
// this.appManager = appManager
// this.engine = engine
// this.event = new EventEmitter() // already exists in engine so not needed here
this.appManager = appManager
this.engine = engine
this.htmlElement = document.createElement('div')
this.htmlElement.setAttribute('id', 'pluginManager')
this.props = {}
// this.views = {
// root: null,
// items: {}
@ -106,6 +107,22 @@ class PluginManagerComponent extends ViewPlugin {
// 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 () {
@ -113,22 +130,46 @@ class PluginManagerComponent extends ViewPlugin {
}
renderComponent () {
ReactDOM.render(<RemixUiPluginManager />, document.getElementById('pluginManager'))
// const props = this.reactProps()
ReactDOM.render(
// <RemixUiPluginManager
// activatePlugin={this.activateP}
// deActivatePlugin={this.deactivate}
// filter={this.filter}
// appManager={this.appManager}
// engine={this.engine}
// profile={this.profile}
// isActive={this.isActive}
// openLocalPlugin={this.openLocalPlugin}
// tileLabel
// _paq={_paq}
// {...props}
// />,
<RemixUiPluginManager
profile={profile}
appManager={this.appManager}
engine={this.engine}
activesCount={3}
inactivesCount={4}
actives={[]}
inactives={[]}
/>,
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)
_paq.push(['trackEvent', 'manager', 'activate', name])
}
// activateP (name) {
// this.appManager.activatePlugin(name)
// _paq.push(['trackEvent', 'manager', 'activate', name])
// }
deactivateP (name) {
this.call('manager', 'deactivatePlugin', name)
_paq.push(['trackEvent', 'manager', 'deactivate', name])
}
// deactivateP (name) {
// this.call('manager', 'deactivatePlugin', name)
// _paq.push(['trackEvent', 'manager', 'deactivate', name])
// }
// renderItem (profile) {
// const displayName = (profile.displayName) ? profile.displayName : profile.name
@ -189,47 +230,55 @@ class PluginManagerComponent extends ViewPlugin {
/**
* Add a local plugin to the list of plugins
*/
async openLocalPlugin () {
try {
const profile = await this.localPlugin.open(this.appManager.getAll())
if (!profile) return
if (this.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)
this.engine.register(plugin)
await this.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}`)
}
}
// async openLocalPlugin () {
// try {
// const profile = await this.localPlugin.open(this.appManager.getAll())
// if (!profile) return
// if (this.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)
// this.engine.register(plugin)
// await this.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}`)
// }
// }
// 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)
// }
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
}
// // Filter all active and inactive modules that are not required
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: [] })
// const activeTile = actives.length !== 0
// ? yo`
@ -275,7 +324,7 @@ class PluginManagerComponent extends ViewPlugin {
return this.htmlElement
}
// reRender () { --> no needed possibly
// reRender () {
// if (this.views.root) {
// yo.update(this.views.root, this.render())
// }

@ -1,21 +1,20 @@
import React from 'react'
import { TileLabel } from '../../customTypes'
import React, { useContext } from 'react'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
interface ActiveTileProps {
inactivesCount?: number
activesCount?: number
tileLabel?: TileLabel
interface ModuleHeadingProps {
headingLabel: string
}
function ActiveTile ({ inactivesCount, activesCount, tileLabel }: ActiveTileProps) {
function ModuleHeading ({ headingLabel }: ModuleHeadingProps) {
const { inactivesCount, activesCount } = useContext(PluginManagerContext)
return (
<nav className="plugins-list-header justify-content-between navbar navbar-expand-lg bg-light navbar-light align-items-center">
<span className="navbar-brand plugins-list-title h6 mb-0 mr-2">{tileLabel.label}</span>
<span className="navbar-brand plugins-list-title h6 mb-0 mr-2">{headingLabel}</span>
<span className="badge badge-primary" style={{ cursor: 'default' }} data-id="pluginManagerComponentInactiveTilesCount">
{tileLabel.label === 'Active Module' ? activesCount : tileLabel.label === 'Inactive Modules' ? inactivesCount : '-' }
{headingLabel === 'Active Modules' ? activesCount : inactivesCount}
</span>
</nav>
)
}
export default ActiveTile
export default ModuleHeading

@ -3,21 +3,23 @@ import { Profile } from '../../customTypes'
import RenderItem from './renderItem'
interface ListGroupItemProps {
activeProfiles: Profile[]
inactiveProfiles: Profile[]
activeProfiles?: Profile[]
inactiveProfiles?: Profile[]
}
function ListGroupItem ({ activeProfiles, inactiveProfiles }: ListGroupItemProps) {
function ListGroupItem () {
return (
<div className="list-group list-group-flush plugins-list-group" data-id="pluginManagerComponentActiveTile">
{ activeProfiles.length > 0
{/* { activeProfiles.length > 0
? activeProfiles.map(profile => (
<RenderItem profile={profile} />
))
: inactiveProfiles.map(profile => (
<RenderItem profile={profile}/>
))
}
} */}
<RenderItem />
<h6 className="h6">List Group Item Component</h6>
</div>
)
}

@ -1,4 +1,5 @@
import React from 'react'
import React, { useContext } from 'react'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
import '../remix-ui-plugin-manager.css'
import Button from './button'
interface PluginCardProps {
@ -10,32 +11,27 @@ interface PluginCardProps {
profileDescription: string
}
function PluginCard ({
profileName,
displayName,
docLink,
versionWarning,
profileIcon,
profileDescription
}: PluginCardProps) {
// eslint-disable-next-line no-empty-pattern
function PluginCard () {
const { profile } = useContext(PluginManagerContext)
return (
<article className="list-group-item py-1 mb-1 plugins-list-group-item" title={displayName}>
<article className="list-group-item py-1 mb-1 plugins-list-group-item" title="PLuginCardTitle">
<div className="row justify-content-between align-items-center mb-2">
<h6 className="displayName plugin-name">
<div>
{displayName}
{docLink}
{versionWarning}
{profile.displayName}
{profile.docLink}
{profile.versionWarning}
</div>
<Button
profileName={profileName}
profileName="Sample Profile"
isActive
/>
</h6>
</div>
<div className="description d-flex text-body plugin-text mb-2">
<img src={profileIcon} className="mr-1 mt-1 pluginIcon" alt="profile icon"/>
<span className="descriptiontext">{profileDescription}</span>
<img src="" className="mr-1 mt-1 pluginIcon" alt="profile icon"/>
<span className="descriptiontext">{profile.description}</span>
</div>
</article>
)

@ -1,52 +1,55 @@
import React, { useEffect, useState } from 'react'
import React, { useContext } from 'react'
import { Profile } from '../../customTypes'
import { PluginManagerContext } from '../contexts/pluginmanagercontext'
import PluginCard from './pluginCard'
interface RenderItemProps {
profile: Profile
}
function RenderItem ({ profile }: RenderItemProps) {
const [displayName, setDisplayName] = useState('')
const [docLink, setDocLink] = useState<any>()
const [versionWarning, setVersionWarning] = useState<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>>()
function RenderItem () {
const { profile } = useContext(PluginManagerContext)
// const [displayName, setDisplayName] = useState('')
// const [docLink, setDocLink] = useState<any>()
// const [versionWarning, setVersionWarning] = useState<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>>()
useEffect(() => {
const checkPluginVersion = (version: string) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let versionWarning: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
if (version && version.match(/\b(\w*alpha\w*)\b/g)) {
versionWarning = <small title="Version Alpha" className="remixui_versionWarning plugin-version">alpha</small>
}
// Beta
if (version && version.match(/\b(\w*beta\w*)\b/g)) {
versionWarning = <small title="Version Beta" className="remixui_versionWarning plugin-version">beta</small>
}
return versionWarning
}
// useEffect(() => {
// const checkPluginVersion = (version: string) => {
// // eslint-disable-next-line @typescript-eslint/no-unused-vars
// let versionWarning: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
// if (version && version.match(/\b(\w*alpha\w*)\b/g)) {
// versionWarning = <small title="Version Alpha" className="remixui_versionWarning plugin-version">alpha</small>
// }
// // Beta
// if (version && version.match(/\b(\w*beta\w*)\b/g)) {
// versionWarning = <small title="Version Beta" className="remixui_versionWarning plugin-version">beta</small>
// }
// return versionWarning
// }
setDisplayName((profile.displayName) ? profile.displayName : profile.name)
setDocLink(
profile.documentation ? (
<a href={profile.documentation}
className="px-1"
title="link to documentation"
// eslint-disable-next-line react/jsx-no-target-blank
target="_blank">
<i aria-hidden="true" className="fas fa-book"></i>
</a>
) : '')
setVersionWarning(checkPluginVersion(profile.version))
}, [profile.displayName, profile.documentation, profile.name, profile.version, versionWarning])
// setDisplayName((profile.displayName) ? profile.displayName : profile.name)
// setDocLink(
// profile.documentation ? (
// <a href={profile.documentation}
// className="px-1"
// title="link to documentation"
// // eslint-disable-next-line react/jsx-no-target-blank
// target="_blank">
// <i aria-hidden="true" className="fas fa-book"></i>
// </a>
// ) : '')
// setVersionWarning(checkPluginVersion(profile.version))
// }, [profile.displayName, profile.documentation, profile.name, profile.version, versionWarning])
console.log('Profile object from render item component', profile)
return (
<PluginCard
displayName={displayName}
docLink={docLink}
versionWarning={versionWarning}
profileDescription={profile.description}
profileIcon={profile.icon}
profileName={profile.name}
// displayName={displayName}
// docLink={docLink}
// versionWarning={versionWarning}
// profileDescription={profile.description}
// profileIcon={profile.icon}
// profileName={profile.name}
/>
)
}

@ -1,5 +1,4 @@
import React, { useContext } from 'react'
import { PluginManagerContext } from '../remix-ui-plugin-manager'
import React from 'react'
import ActiveTile from './activeTile'
import ListGroupItem from './listGroupItem'
@ -8,23 +7,35 @@ interface RootViewProps {
}
function RootView ({ localPluginButtonText }: RootViewProps) {
const { actives, inactives, tileLabel } = useContext(PluginManagerContext)
// const { actives, inactives, tileLabel } = useContext(PluginManagerContext)
return (
// <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 className="btn btn-secondary text-dark border-0" data-id="pluginManagerComponentPluginSearchButton">{localPluginButtonText}</button>
// </header>
// <section data-id="pluginManagerComponentPluginManagerSection">
// <ActiveTile
// activesCount={actives.length}
// inactivesCount={inactives.length}
// tileLabel={tileLabel}
// />
// <ListGroupItem
// activeProfiles={actives}
// inactiveProfiles={inactives}
// />
// </section>
// </div>
<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 className="btn btn-secondary text-dark border-0" data-id="pluginManagerComponentPluginSearchButton">{localPluginButtonText}</button>
<button className="btn btn-secondary text-dark border-0" data-id="pluginManagerComponentPluginSearchButton">Connect to a local Plugin</button>
</header>
<section data-id="pluginManagerComponentPluginManagerSection">
<ActiveTile
activesCount={actives.length}
inactivesCount={inactives.length}
tileLabel={tileLabel}
/>
<ListGroupItem
activeProfiles={actives}
inactiveProfiles={inactives}
/>
<ActiveTile headingLabel="Active Modules"/>
<ActiveTile headingLabel="Inactive Modules"/>
<ListGroupItem />
</section>
</div>
)

@ -0,0 +1,14 @@
import React, { createContext } from 'react'
import { PluginManagerContextProviderProps } from '../../types'
export const PluginManagerContext = createContext<Partial<PluginManagerContextProviderProps>>({})
function PluginManagerContextProvider ({ children, props }) {
return (
<PluginManagerContext.Provider value={props}>
{children}
</PluginManagerContext.Provider>
)
}
export default PluginManagerContextProvider

@ -1,91 +1,20 @@
import React, { createContext, useEffect, useState } from 'react'
import { Profile, TileLabel } from '../customTypes'
import { RemixAppManager, RemixEngine, _Paq } from '../types'
import React from 'react'
import { RemixUiPluginManagerProps } from '../types'
import RootView from './components/rootView'
import PluginManagerContextProvider from './contexts/pluginmanagercontext'
import './remix-ui-plugin-manager.css'
/* eslint-disable-next-line */
export interface PluginManagerContextProviderProps {
appManager: RemixAppManager
engine: RemixEngine
_paq: _Paq
filter: string
actives: Profile[]
inactives: Profile[]
activatePlugin: (name: string) => void
deActivatePlugin: (name: string) => void
isActive: (name: string) => any
openLocalPlugin: () => Promise<void>
filterPlugins: () => void
profile: Profile
tileLabel: TileLabel
}
export interface RemixUiPluginManagerProps {
appManager: RemixAppManager
engine: RemixEngine
_paq: _Paq
filter: string
actives: Profile[]
inactives: Profile[]
activatePlugin: (name: string) => void
deActivatePlugin: (name: string) => void
isActive: (name: string) => any
openLocalPlugin: () => Promise<void>
filterPlugins: () => void
profile: Profile
tileLabel: TileLabel
}
export const PluginManagerContext = createContext<Partial<PluginManagerContextProviderProps>>({})
function PluginManagerContextProvider ({ children, props }) {
const [isFiltered] = useState((profile) =>
(profile.displayName ? profile.displayName : profile.name).toLowerCase().includes(props.filter))
const [isNotRequired, setIsNotRequired] = useState<any>()
const [isNotDependent, setIsNotDependent] = useState<any>()
const [isNotHome, setIsNotHome] = useState<any>()
const [sortByName, setSortByName] = useState<any>()
const { actives, inactives } = props.appManager.getAll()
.filter(isFiltered)
.filter(isNotRequired)
.filter(isNotDependent)
.filter(isNotHome)
.sort(sortByName)
.reduce(({ actives, inactives }, profile) => {
return props.isActive(profile.name)
? { actives: [...actives, profile], inactives }
: { inactives: [...inactives, profile], actives }
}, { actives: [], inactives: [] })
props.actives = actives
props.inactives = inactives
useEffect(() => {
const notRequired = (profile: Profile) => !props.appManager.isRequired(profile.name)
const notDependent = (profile) => !props.appManager.isDependent(profile.name)
const notHome = (profile) => profile.name !== 'home'
const sortedByName = (profileA: Profile, profileB: Profile) => {
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
}
setIsNotRequired(notRequired(props.profile))
setIsNotDependent(notDependent(notDependent))
setIsNotHome(notHome)
setSortByName(sortedByName)
}, [props.appManager, props.profile])
return (
<PluginManagerContext.Provider value={...props}>
{children}
</PluginManagerContext.Provider>
)
}
export const RemixUiPluginManager = (props: RemixUiPluginManagerProps) => {
console.log('current state of appmanager', props.appManager)
return (
<PluginManagerContextProvider props>
<RootView
localPluginButtonText="Connect to a Local Plugin"
/>
// <PluginManagerContextProvider props={props}>
// <RootView
// localPluginButtonText="Connect to a Local Plugin"
// />
// </PluginManagerContextProvider>
<PluginManagerContextProvider props={props}>
<h3 className="h3">Remix UI Plugin Manager React</h3>
<RootView localPluginButtonText="Local Plugin"/>
</PluginManagerContextProvider>
)
}

@ -60,6 +60,42 @@ export class RemixAppManager extends PluginManager {
isRequired(name: any): any;
registeredPlugins(): Promise<any>;
}
export interface PluginManagerContextProviderProps {
appManager: RemixAppManager
engine: RemixEngine
_paq: _Paq
filter: string
actives: Profile[]
inactives: Profile[]
activatePlugin: (name: string) => void
deActivatePlugin: (name: string) => void
isActive: (name: string) => any
openLocalPlugin: () => Promise<void>
filterPlugins: () => void
profile: Profile
inactivesCount: number
activesCount: number
headingLabel: string
}
export interface RemixUiPluginManagerProps {
appManager: RemixAppManager
engine: RemixEngine
_paq: _Paq
filter: string
actives: Profile[]
inactives: Profile[]
activatePlugin: (name: string) => void
deActivatePlugin: (name: string) => void
isActive: (name: string) => any
openLocalPlugin: () => Promise<void>
filterPlugins: () => void
profile: Profile
inactivesCount: number
activesCount: number
headingLabel: string
}
/** @class Reference loaders.
* A loader is a get,set based object which load a workspace from a defined sources.
* (localStorage, queryParams)

Loading…
Cancel
Save