diff --git a/frontend/src/components/App/PluginSettings/PluginSettings.tsx b/frontend/src/components/App/PluginSettings/PluginSettings.tsx index ca2a9ec815..c432944a90 100644 --- a/frontend/src/components/App/PluginSettings/PluginSettings.tsx +++ b/frontend/src/components/App/PluginSettings/PluginSettings.tsx @@ -6,6 +6,7 @@ import { MRT_Row } from 'material-react-table'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; +import semver from 'semver'; import helpers from '../../../helpers'; import { useFilterFunc } from '../../../lib/util'; import { PluginInfo, reloadPage, setPluginSettings } from '../../../plugin/pluginsSlice'; @@ -285,9 +286,74 @@ export default function PluginSettings() { const pluginSettings = useTypedSelector(state => state.plugins.pluginSettings); + const [plugins, setPlugins] = useState([]); + + useEffect(() => { + // to do: this is reused code that needs to be refactored for this specific use, maybe in a different PR as a hook + async function get() { + const pluginPaths = (await fetch(`${helpers.getAppUrl()}plugins`).then(resp => + resp.json() + )) as string[]; + const packageInfosPromise = await Promise.all( + pluginPaths.map(path => + fetch(`${helpers.getAppUrl()}${path}/package.json`).then(resp => { + if (!resp.ok) { + if (resp.status !== 404) { + return Promise.reject(resp); + } + { + console.warn( + 'Missing package.json. ' + + `Please upgrade the plugin ${path}` + + ' by running "headlamp-plugin extract" again.' + + ' Please use headlamp-plugin >= 0.8.0' + ); + return { + name: path.split('/').slice(-1)[0], + version: '0.0.0', + author: 'unknown', + description: '', + }; + } + } + return resp.json(); + }) + ) + ); + const packageInfos = await packageInfosPromise; + + const pluginsWithIsEnabled = packageInfos.map(plugin => { + const matchedSetting = pluginSettings.find(p => plugin.name === p.name); + if (matchedSetting) { + // to do: compatible version is also reused code that needs to be refactored for this use + const compatibleVersion = '>=0.8.0-alpha.3'; + + const isCompatible = semver.satisfies( + semver.coerce(plugin.devDependencies?.['@kinvolk/headlamp-plugin']) || '', + compatibleVersion + ); + + return { + ...plugin, + isEnabled: matchedSetting.isEnabled, + isCompatible: isCompatible, + }; + } + return plugin; + }); + + setPlugins(pluginsWithIsEnabled); + } + get(); + }, []); + + if (!plugins.length) { + return null; + } + return ( { dispatch(setPluginSettings(plugins)); dispatch(reloadPage()); diff --git a/frontend/src/plugin/index.ts b/frontend/src/plugin/index.ts index d42a63f672..0c8ae8da4a 100644 --- a/frontend/src/plugin/index.ts +++ b/frontend/src/plugin/index.ts @@ -199,17 +199,20 @@ export function filterSources( */ export function updateSettingsPackages( backendPlugins: PluginInfo[], - settingsPlugins: PluginInfo[] + settingsPlugins: { name: string; isEnabled: boolean }[] ): PluginInfo[] { if (backendPlugins.length === 0) return []; const pluginsChanged = backendPlugins.length !== settingsPlugins.length || - backendPlugins.map(p => p.name + p.version).join('') !== - settingsPlugins.map(p => p.name + p.version).join(''); + backendPlugins.map(p => p.name) !== settingsPlugins.map(p => p.name); if (!pluginsChanged) { - return settingsPlugins; + const updatedPlugins = backendPlugins.filter(plugin => + settingsPlugins.some(setting => setting.name === plugin.name) + ); + + return updatedPlugins; } return backendPlugins.map(plugin => { @@ -241,7 +244,7 @@ export function updateSettingsPackages( * */ export async function fetchAndExecutePlugins( - settingsPackages: PluginInfo[], + settingsPackages: { name: string; isEnabled: boolean }[], onSettingsChange: (plugins: PluginInfo[]) => void, onIncompatible: (plugins: Record) => void ) { diff --git a/frontend/src/plugin/pluginsSlice.ts b/frontend/src/plugin/pluginsSlice.ts index 37e3277ac0..d7cd59ce07 100644 --- a/frontend/src/plugin/pluginsSlice.ts +++ b/frontend/src/plugin/pluginsSlice.ts @@ -91,7 +91,7 @@ export interface PluginsState { /** Have plugins finished executing? */ loaded: boolean; /** Information stored by settings about plugins. */ - pluginSettings: PluginInfo[]; + pluginSettings: { name: string; isEnabled: boolean }[]; } const initialState: PluginsState = { /** Once the plugins have been fetched and executed. */ @@ -110,9 +110,14 @@ export const pluginsSlice = createSlice({ /** * Save the plugin settings. To both the store, and localStorage. */ - setPluginSettings(state, action: PayloadAction) { - state.pluginSettings = action.payload; - localStorage.setItem('headlampPluginSettings', JSON.stringify(action.payload)); + setPluginSettings(state, action: PayloadAction) { + const pluginInfo = action.payload.map(p => ({ + name: p.name, + isEnabled: p.isEnabled, + })); + state.pluginSettings = pluginInfo; + console.log('LOCAL SAVE', pluginInfo); + localStorage.setItem('headlampPluginSettings', JSON.stringify(pluginInfo)); }, /** Reloads the browser page */ reloadPage() {