diff --git a/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap b/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap index 85632831e..5e665a442 100644 --- a/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap +++ b/desktop/app/src/__tests__/__snapshots__/createMockFlipperWithPlugin.node.tsx.snap @@ -56,6 +56,7 @@ Object { "disabledPlugins": Array [], "failedPlugins": Array [], "gatekeepedPlugins": Array [], + "loadedPlugins": Map {}, "marketplacePlugins": Array [], "selectedPlugins": Array [], } diff --git a/desktop/app/src/dispatcher/plugins.tsx b/desktop/app/src/dispatcher/plugins.tsx index abfc08d58..e1254e634 100644 --- a/desktop/app/src/dispatcher/plugins.tsx +++ b/desktop/app/src/dispatcher/plugins.tsx @@ -19,6 +19,7 @@ import { addGatekeepedPlugins, addDisabledPlugins, addFailedPlugins, + registerLoadedPlugins, } from '../reducers/plugins'; import GK from '../fb-stubs/GK'; import {FlipperBasePlugin} from '../plugin'; @@ -63,10 +64,12 @@ export default async (store: Store, logger: Logger) => { const uninstalledPlugins = store.getState().pluginManager.uninstalledPlugins; - const initialPlugins: PluginDefinition[] = filterNewestVersionOfEachPlugin( + const loadedPlugins = filterNewestVersionOfEachPlugin( getBundledPlugins(), await getDynamicPlugins(), - ) + ); + + const initialPlugins: PluginDefinition[] = loadedPlugins .filter((p) => !uninstalledPlugins.has(p.name)) .map(reportVersion) .filter(checkDisabled(disabledPlugins)) @@ -74,6 +77,7 @@ export default async (store: Store, logger: Logger) => { .map(createRequirePluginFunction(failedPlugins)) .filter(notNull); + store.dispatch(registerLoadedPlugins(loadedPlugins)); store.dispatch(addGatekeepedPlugins(gatekeepedPlugins)); store.dispatch(addDisabledPlugins(disabledPlugins)); store.dispatch(addFailedPlugins(failedPlugins)); diff --git a/desktop/app/src/reducers/__tests__/plugins.node.tsx b/desktop/app/src/reducers/__tests__/plugins.node.tsx index 0d48b4652..24db35dc9 100644 --- a/desktop/app/src/reducers/__tests__/plugins.node.tsx +++ b/desktop/app/src/reducers/__tests__/plugins.node.tsx @@ -13,6 +13,7 @@ import { addGatekeepedPlugins, } from '../plugins'; import {FlipperPlugin, FlipperDevicePlugin, BaseAction} from '../../plugin'; +import {InstalledPluginDetails} from 'flipper-plugin-lib'; const testPlugin = class extends FlipperPlugin { static id = 'TestPlugin'; @@ -31,6 +32,7 @@ test('add clientPlugin', () => { { devicePlugins: new Map(), clientPlugins: new Map(), + loadedPlugins: new Map(), gatekeepedPlugins: [], failedPlugins: [], disabledPlugins: [], @@ -47,6 +49,7 @@ test('add devicePlugin', () => { { devicePlugins: new Map(), clientPlugins: new Map(), + loadedPlugins: new Map(), gatekeepedPlugins: [], failedPlugins: [], disabledPlugins: [], @@ -63,6 +66,7 @@ test('do not add plugin twice', () => { { devicePlugins: new Map(), clientPlugins: new Map(), + loadedPlugins: new Map(), gatekeepedPlugins: [], failedPlugins: [], disabledPlugins: [], @@ -75,15 +79,15 @@ test('do not add plugin twice', () => { }); test('add gatekeeped plugin', () => { - const gatekeepedPlugins = [ + const gatekeepedPlugins: InstalledPluginDetails[] = [ { name: 'plugin', - out: 'out.js', version: '1.0.0', dir: '/plugins/test', specVersion: 2, source: 'src/index.ts', isBundled: false, + isActivatable: true, main: 'lib/index.js', title: 'test', id: 'test', @@ -94,6 +98,7 @@ test('add gatekeeped plugin', () => { { devicePlugins: new Map(), clientPlugins: new Map(), + loadedPlugins: new Map(), gatekeepedPlugins: [], failedPlugins: [], disabledPlugins: [], diff --git a/desktop/app/src/reducers/plugins.tsx b/desktop/app/src/reducers/plugins.tsx index 2d84f08ae..64cf20b0a 100644 --- a/desktop/app/src/reducers/plugins.tsx +++ b/desktop/app/src/reducers/plugins.tsx @@ -8,7 +8,10 @@ */ import {DevicePluginMap, ClientPluginMap, PluginDefinition} from '../plugin'; -import {PluginDetails, DownloadablePluginDetails} from 'flipper-plugin-lib'; +import { + DownloadablePluginDetails, + ActivatablePluginDetails, +} from 'flipper-plugin-lib'; import {Actions} from '.'; import produce from 'immer'; import {isDevicePluginDefinition} from '../utils/pluginUtils'; @@ -16,9 +19,10 @@ import {isDevicePluginDefinition} from '../utils/pluginUtils'; export type State = { devicePlugins: DevicePluginMap; clientPlugins: ClientPluginMap; - gatekeepedPlugins: Array; - disabledPlugins: Array; - failedPlugins: Array<[PluginDetails, string]>; + loadedPlugins: Map; + gatekeepedPlugins: Array; + disabledPlugins: Array; + failedPlugins: Array<[ActivatablePluginDetails, string]>; selectedPlugins: Array; marketplacePlugins: Array; }; @@ -32,15 +36,15 @@ export type Action = | RegisterPluginAction | { type: 'GATEKEEPED_PLUGINS'; - payload: Array; + payload: Array; } | { type: 'DISABLED_PLUGINS'; - payload: Array; + payload: Array; } | { type: 'FAILED_PLUGINS'; - payload: Array<[PluginDetails, string]>; + payload: Array<[ActivatablePluginDetails, string]>; } | { type: 'SELECTED_PLUGINS'; @@ -49,11 +53,16 @@ export type Action = | { type: 'MARKETPLACE_PLUGINS'; payload: Array; + } + | { + type: 'REGISTER_LOADED_PLUGINS'; + payload: Array; }; const INITIAL_STATE: State = { devicePlugins: new Map(), clientPlugins: new Map(), + loadedPlugins: new Map(), gatekeepedPlugins: [], disabledPlugins: [], failedPlugins: [], @@ -105,6 +114,11 @@ export default function reducer( ...state, marketplacePlugins: action.payload, }; + } else if (action.type === 'REGISTER_LOADED_PLUGINS') { + return { + ...state, + loadedPlugins: new Map(action.payload.map((p) => [p.id, p])), + }; } else { return state; } @@ -121,19 +135,21 @@ export const registerPlugins = (payload: PluginDefinition[]): Action => ({ }); export const addGatekeepedPlugins = ( - payload: Array, + payload: Array, ): Action => ({ type: 'GATEKEEPED_PLUGINS', payload, }); -export const addDisabledPlugins = (payload: Array): Action => ({ +export const addDisabledPlugins = ( + payload: Array, +): Action => ({ type: 'DISABLED_PLUGINS', payload, }); export const addFailedPlugins = ( - payload: Array<[PluginDetails, string]>, + payload: Array<[ActivatablePluginDetails, string]>, ): Action => ({ type: 'FAILED_PLUGINS', payload, @@ -145,3 +161,10 @@ export const registerMarketplacePlugins = ( type: 'MARKETPLACE_PLUGINS', payload, }); + +export const registerLoadedPlugins = ( + payload: Array, +): Action => ({ + type: 'REGISTER_LOADED_PLUGINS', + payload, +}); diff --git a/desktop/app/src/store.tsx b/desktop/app/src/store.tsx index 106399639..5b2792e79 100644 --- a/desktop/app/src/store.tsx +++ b/desktop/app/src/store.tsx @@ -27,6 +27,7 @@ import {deconstructPluginKey} from './utils/clientUtils'; import {_SandyPluginDefinition} from 'flipper-plugin'; import BaseDevice from './devices/BaseDevice'; import {State as PluginStates} from './reducers/pluginStates'; +import {ActivatablePluginDetails} from 'flipper-plugin-lib'; export const store: Store = createStore( rootReducer, @@ -173,7 +174,7 @@ function updateClientPlugin( clientsWithEnabledPlugin.forEach((client) => { startPlugin(client, plugin, true); }); - draft.pluginManager.uninstalledPlugins.delete(plugin.details.name); + registerLoadedPlugin(draft, plugin.details); }); } @@ -191,6 +192,7 @@ function uninstallPlugin(state: StoreState, plugin: PluginDefinition) { }); cleanupPluginStates(draft.pluginStates, plugin.id); draft.plugins.clientPlugins.delete(plugin.id); + draft.plugins.devicePlugins.delete(plugin.id); draft.pluginManager.uninstalledPlugins.add(plugin.details.name); }); } @@ -209,9 +211,21 @@ function updateDevicePlugin(state: StoreState, plugin: DevicePluginDefinition) { devicesWithEnabledPlugin.forEach((d) => { d.loadDevicePlugin(plugin); }); + registerLoadedPlugin(draft, plugin.details); }); } +function registerLoadedPlugin( + draft: { + pluginManager: StoreState['pluginManager']; + plugins: StoreState['plugins']; + }, + plugin: ActivatablePluginDetails, +) { + draft.pluginManager.uninstalledPlugins.delete(plugin.name); + draft.plugins.loadedPlugins.set(plugin.id, plugin); +} + function supportsDevice(plugin: DevicePluginDefinition, device: BaseDevice) { if (plugin instanceof _SandyPluginDefinition) { return ( diff --git a/desktop/app/src/utils/__tests__/exportData.node.tsx b/desktop/app/src/utils/__tests__/exportData.node.tsx index 253ce4e98..281c30b71 100644 --- a/desktop/app/src/utils/__tests__/exportData.node.tsx +++ b/desktop/app/src/utils/__tests__/exportData.node.tsx @@ -762,6 +762,11 @@ test('test determinePluginsToProcess for mutilple clients having plugins present ['RandomPlugin', TestPlugin], ]), devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]), + loadedPlugins: new Map([ + ['TestPlugin', TestPlugin.details], + ['RandomPlugin', TestPlugin.details], + ['TestDevicePlugin', TestDevicePlugin.details], + ]), gatekeepedPlugins: [], disabledPlugins: [], failedPlugins: [], @@ -828,6 +833,11 @@ test('test determinePluginsToProcess for no selected plugin present in any clien ['RandomPlugin', TestPlugin], ]), devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]), + loadedPlugins: new Map([ + ['TestPlugin', TestPlugin.details], + ['RandomPlugin', TestPlugin.details], + ['TestDevicePlugin', TestDevicePlugin.details], + ]), gatekeepedPlugins: [], disabledPlugins: [], failedPlugins: [], @@ -872,6 +882,10 @@ test('test determinePluginsToProcess for multiple clients on same device', async const plugins: PluginsState = { clientPlugins: new Map([['TestPlugin', TestPlugin]]), devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]), + loadedPlugins: new Map([ + ['TestPlugin', TestPlugin.details], + ['TestDevicePlugin', TestDevicePlugin.details], + ]), gatekeepedPlugins: [], disabledPlugins: [], failedPlugins: [], @@ -954,6 +968,10 @@ test('test determinePluginsToProcess for multiple clients on different device', const plugins: PluginsState = { clientPlugins: new Map([['TestPlugin', TestPlugin]]), devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]), + loadedPlugins: new Map([ + ['TestPlugin', TestPlugin.details], + ['TestDevicePlugin', TestDevicePlugin.details], + ]), gatekeepedPlugins: [], disabledPlugins: [], failedPlugins: [], @@ -1033,6 +1051,10 @@ test('test determinePluginsToProcess to ignore archived clients', async () => { const plugins: PluginsState = { clientPlugins: new Map([['TestPlugin', TestPlugin]]), devicePlugins: new Map([['TestDevicePlugin', TestDevicePlugin]]), + loadedPlugins: new Map([ + ['TestPlugin', TestPlugin.details], + ['TestDevicePlugin', TestDevicePlugin.details], + ]), gatekeepedPlugins: [], disabledPlugins: [], failedPlugins: [],