create separate plugincards for active and inactive state. create custom hook for localstorage and method to handle pluginManager state
parent
e3c887f88c
commit
3c951a9cbf
@ -1,29 +0,0 @@ |
||||
import React, { useState } from 'react' |
||||
import { PluginManagerComponent } from '../../types' |
||||
|
||||
interface ActivateButtonProps { |
||||
buttonText: string |
||||
pluginName: string |
||||
pluginComponent: PluginManagerComponent |
||||
} |
||||
|
||||
function ActivateButton ({ |
||||
buttonText, |
||||
pluginName, |
||||
pluginComponent |
||||
}: ActivateButtonProps) { |
||||
const [dataId] = useState(`pluginManagerComponent${buttonText}Button${pluginName}`) |
||||
|
||||
return ( |
||||
<button |
||||
onClick={() => { |
||||
pluginComponent.activateP(pluginName) |
||||
}} |
||||
className={buttonText === 'Activate' ? 'btn btn-success btn-sm' : 'btn btn-secondary btn-sm'} |
||||
data-id={dataId} |
||||
> |
||||
{buttonText} |
||||
</button> |
||||
) |
||||
} |
||||
export default ActivateButton |
@ -0,0 +1,76 @@ |
||||
import { Profile } from '@remixproject/plugin-utils' |
||||
import React, { useState } from 'react' |
||||
import { RemoveActivatedPlugin } from '../../pluginManagerStateMachine' |
||||
// import { RemoveActivatedPlugin } from '../../pluginManagerStateMachine'
|
||||
import { PluginManagerComponent } from '../../types' |
||||
import '../remix-ui-plugin-manager.css' |
||||
interface PluginCardProps { |
||||
profile: Profile & { |
||||
icon?: string |
||||
} |
||||
pluginComponent: PluginManagerComponent |
||||
buttonText: string |
||||
reRender: () => void |
||||
} |
||||
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
function ActivePluginCard ({ |
||||
profile, |
||||
pluginComponent, |
||||
buttonText, |
||||
reRender |
||||
}: PluginCardProps) { |
||||
const [displayName] = useState<string>((profile.displayName) ? profile.displayName : profile.name) |
||||
const [docLink] = useState<JSX.Element>((profile.documentation) ? ( |
||||
<a href={profile.documentation} className="px-1" title="link to documentation" target="_blank" rel="noreferrer"> |
||||
<i aria-hidden="true" className="fas fa-book"/> |
||||
</a> |
||||
) : null) |
||||
|
||||
const [versionWarning] = useState<JSX.Element>((profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) ? ( |
||||
<small title="Version Alpha" className="remixui_versionWarning plugin-version">alpha</small> |
||||
) : (profile.version && profile.version.match(/\b(\w*beta\w*)\b/g)) ? ( |
||||
<small title="Version Beta" className="remixui_versionWarning plugin-version">beta</small> |
||||
) : null) |
||||
// const [stateManager] = useState<PluginManagerStateMachine>(new PluginManagerStateMachine(pluginComponent))
|
||||
|
||||
return ( |
||||
<div className="list-group list-group-flush plugins-list-group" data-id="pluginManagerComponentActiveTile"> |
||||
<article className="list-group-item py-1 mb-1 plugins-list-group-item" title={displayName}> |
||||
<div className="remixui_row justify-content-between align-items-center mb-2"> |
||||
<h6 className="remixui_displayName plugin-name"> |
||||
<div> |
||||
{displayName} |
||||
{docLink} |
||||
{versionWarning} |
||||
</div> |
||||
{ |
||||
<button |
||||
onClick={() => { |
||||
// pluginComponent.deactivateP(profile.name)
|
||||
console.log('calling pluginComponent.call directly...') |
||||
pluginComponent.call('manager', 'deactivatePlugin', profile.name) |
||||
console.log('called pluginComponent.call successfully') |
||||
pluginComponent._paq.push(['trackEvent', 'manager', 'deactivate', profile.name]) |
||||
console.log('matomo tracking captured for deactivation successfully') |
||||
RemoveActivatedPlugin(profile.name) |
||||
reRender() |
||||
}} |
||||
className="btn btn-secondary btn-sm" |
||||
data-id={`pluginManagerComponentDeactivateButton${profile.name}`} |
||||
> |
||||
{buttonText} |
||||
</button> |
||||
} |
||||
</h6> |
||||
</div> |
||||
<div className="remixui_description d-flex text-body plugin-text mb-2"> |
||||
{ profile.icon ? <img src={profile.icon} className="mr-1 mt-1 remixui_pluginIcon" alt="profile icon"/> : null } |
||||
<span className="remixui_descriptiontext">{profile.description}</span> |
||||
</div> |
||||
</article> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default ActivePluginCard |
@ -0,0 +1,67 @@ |
||||
import { Profile } from '@remixproject/plugin-utils' |
||||
import React, { useState } from 'react' |
||||
import { PersistActivatedPlugin } from '../../pluginManagerStateMachine' |
||||
import { PluginManagerComponent } from '../../types' |
||||
import '../remix-ui-plugin-manager.css' |
||||
interface PluginCardProps { |
||||
profile: Profile & { |
||||
icon?: string |
||||
} |
||||
pluginComponent: PluginManagerComponent |
||||
buttonText: string |
||||
} |
||||
|
||||
// eslint-disable-next-line no-empty-pattern
|
||||
function InactivePluginCard ({ |
||||
profile, |
||||
pluginComponent, |
||||
buttonText |
||||
}: PluginCardProps) { |
||||
const [displayName] = useState<string>((profile.displayName) ? profile.displayName : profile.name) |
||||
const [docLink] = useState<JSX.Element>((profile.documentation) ? ( |
||||
<a href={profile.documentation} className="px-1" title="link to documentation" target="_blank" rel="noreferrer"> |
||||
<i aria-hidden="true" className="fas fa-book"/> |
||||
</a> |
||||
) : null) |
||||
|
||||
const [versionWarning] = useState<JSX.Element>((profile.version && profile.version.match(/\b(\w*alpha\w*)\b/g)) ? ( |
||||
<small title="Version Alpha" className="remixui_versionWarning plugin-version">alpha</small> |
||||
) : (profile.version && profile.version.match(/\b(\w*beta\w*)\b/g)) ? ( |
||||
<small title="Version Beta" className="remixui_versionWarning plugin-version">beta</small> |
||||
) : null) |
||||
// const [stateManager] = useState<PluginManagerStateMachine>(new PluginManagerStateMachine(pluginComponent))
|
||||
|
||||
return ( |
||||
<div className="list-group list-group-flush plugins-list-group" data-id="pluginManagerComponentActiveTile"> |
||||
<article className="list-group-item py-1 mb-1 plugins-list-group-item" title={displayName}> |
||||
<div className="remixui_row justify-content-between align-items-center mb-2"> |
||||
<h6 className="remixui_displayName plugin-name"> |
||||
<div> |
||||
{displayName} |
||||
{docLink} |
||||
{versionWarning} |
||||
</div> |
||||
{ |
||||
<button |
||||
onClick={() => { |
||||
pluginComponent.activateP(profile.name) |
||||
PersistActivatedPlugin(pluginComponent, profile) |
||||
}} |
||||
className="btn btn-success btn-sm" |
||||
data-id={`pluginManagerComponentActivateButton${profile.name}`} |
||||
> |
||||
{buttonText} |
||||
</button> |
||||
} |
||||
</h6> |
||||
</div> |
||||
<div className="remixui_description d-flex text-body plugin-text mb-2"> |
||||
{ profile.icon ? <img src={profile.icon} className="mr-1 mt-1 remixui_pluginIcon" alt="profile icon"/> : null } |
||||
<span className="remixui_descriptiontext">{profile.description}</span> |
||||
</div> |
||||
</article> |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
export default InactivePluginCard |
@ -1,28 +0,0 @@ |
||||
import React, { useState } from 'react' |
||||
import { PluginManagerComponent } from '../../types' |
||||
|
||||
interface DeactivateButtonProps { |
||||
buttonText: string |
||||
pluginName: string |
||||
pluginComponent: PluginManagerComponent |
||||
} |
||||
|
||||
function DeactivateButton ({ |
||||
buttonText, |
||||
pluginName, |
||||
pluginComponent |
||||
}: DeactivateButtonProps) { |
||||
const [dataId] = useState(`pluginManagerComponent${buttonText}Button${pluginName}`) |
||||
return ( |
||||
<button |
||||
onClick={() => { |
||||
pluginComponent.deactivateP(pluginName) |
||||
}} |
||||
className={buttonText === 'Deactivate' ? 'btn btn-secondary btn-sm' : ''} |
||||
data-id={dataId} |
||||
> |
||||
{buttonText} |
||||
</button> |
||||
) |
||||
} |
||||
export default DeactivateButton |
@ -1,14 +0,0 @@ |
||||
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 |
@ -0,0 +1,61 @@ |
||||
import { useRef, useEffect, useState } from 'react' |
||||
|
||||
interface EventHandler<T extends Event = Event> { |
||||
(e: T): void; |
||||
} |
||||
|
||||
interface WindowEventHook { |
||||
<K extends keyof WindowEventMap>( |
||||
eventName: K, |
||||
handler: EventHandler<WindowEventMap[K]> |
||||
): void; |
||||
} |
||||
|
||||
export const useWindowEvent: WindowEventHook = (eventName, handler) => { |
||||
// optimization: using useRef here helps us guarantee that this function is
|
||||
// is only mutated during effect lifecycles, adding some assurance that the
|
||||
// function invoked by the event listener is the same function passed to the
|
||||
// hook.
|
||||
const handlerRef = useRef<typeof handler>() |
||||
|
||||
useEffect(() => { |
||||
handlerRef.current = handler |
||||
}, [handler]) |
||||
|
||||
useEffect(() => { |
||||
const eventListener: typeof handler = event => handlerRef.current(event) |
||||
window.addEventListener(eventName, eventListener) |
||||
|
||||
return () => { |
||||
window.removeEventListener(eventName, eventListener) |
||||
} |
||||
}, [eventName, handler]) |
||||
} |
||||
|
||||
export const useLocalStorage = (key: string) => { |
||||
// initialize the value from localStorage
|
||||
const [currentValue, setCurrentValue] = useState<string | null>(() => |
||||
localStorage.getItem(key) |
||||
) |
||||
|
||||
const handler = (e: StorageEvent) => { |
||||
if ( |
||||
e.storageArea === localStorage && |
||||
e.key === key && |
||||
e.newValue !== currentValue |
||||
) { |
||||
setCurrentValue(e.newValue) |
||||
} |
||||
} |
||||
|
||||
// set up the event listener
|
||||
useWindowEvent('storage', handler) |
||||
|
||||
// update localStorage when the currentValue changes via setCurrentValue
|
||||
useEffect(() => { |
||||
localStorage.setItem(key, currentValue) |
||||
}, [key, currentValue]) |
||||
|
||||
// use as const to tell TypeScript this is a tuple
|
||||
return [currentValue, setCurrentValue] as const |
||||
} |
@ -0,0 +1,75 @@ |
||||
import { Profile } from '@remixproject/plugin-utils' |
||||
import { PluginManagerComponent } from './types' |
||||
|
||||
const defaultActivatedPlugins = [ |
||||
'manager', |
||||
'contentImport', |
||||
'theme', |
||||
'editor', |
||||
'fileManager', |
||||
'compilerMetadata', |
||||
'compilerArtefacts', |
||||
'network', |
||||
'web3Provider', |
||||
'offsetToLineColumnConverter', |
||||
'mainPanel', |
||||
'menuicons', |
||||
'tabs', |
||||
'sidePanel', |
||||
'home', |
||||
'hiddenPanel', |
||||
'contextualListener', |
||||
'terminal', |
||||
'fetchAndCompile', |
||||
'pluginManager', |
||||
'filePanel', |
||||
'settings', |
||||
'udapp' |
||||
] |
||||
|
||||
/** |
||||
* Compares default enabled plugins of remix ide |
||||
* and tracks newly activated plugins and manages |
||||
* their state by persisting in local storage |
||||
* @param newPlugin Profile of a Plugin |
||||
* @param pluginComponent PluginManagerComponent Instance |
||||
*/ |
||||
export async function PersistActivatedPlugin (pluginComponent: PluginManagerComponent, newPlugin: Profile) { |
||||
const persisted = localStorage.getItem('newActivePlugins') |
||||
const activatedPlugins: Profile[] = JSON.parse(persisted) |
||||
|
||||
const newlyActivatedPlugins: Array<Profile> = [] |
||||
if (newPlugin) { |
||||
if (defaultActivatedPlugins.includes(newPlugin.name) === false) { |
||||
// if this is true then we are sure that the profile name is in localStorage/workspace
|
||||
if (activatedPlugins.length > 0 && !activatedPlugins.includes(newPlugin)) { |
||||
await FetchAndPersistPlugin(pluginComponent, newPlugin, activatedPlugins) |
||||
localStorage.setItem('newActivePlugins', JSON.stringify(activatedPlugins)) |
||||
} else { |
||||
await FetchAndPersistPlugin(pluginComponent, newPlugin, newlyActivatedPlugins) |
||||
localStorage.setItem('newActivePlugins', JSON.stringify(newlyActivatedPlugins)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
async function FetchAndPersistPlugin (pluginComponent: PluginManagerComponent, newPlugin: Profile<any>, newlyActivatedPlugins: Profile<any>[]) { |
||||
try { |
||||
const targetProfile = await pluginComponent.appManager.getProfile(newPlugin.name) |
||||
if (targetProfile !== null || targetProfile !== undefined) newlyActivatedPlugins.push(targetProfile) |
||||
} catch { |
||||
throw new Error('Could not fetch and persist target profile!') |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove a deactivated plugin from persistence (localStorage) |
||||
* @param pluginName Name of plugin profile to be removed |
||||
*/ |
||||
export function RemoveActivatedPlugin (pluginName: string) { |
||||
// eslint-disable-next-line no-debugger
|
||||
debugger |
||||
const getWorkspacePlugins = JSON.parse(localStorage.getItem('newActivePlugins')) |
||||
const removeExisting = getWorkspacePlugins.filter(target => target.name === pluginName) |
||||
localStorage.setItem('newActivePlugins', JSON.stringify(removeExisting)) |
||||
} |
Loading…
Reference in new issue