Summary: Changed the plugin display logic in SupportForm to show plugins which are enabled(includes device plugins) and plugins which has `exportPersistedState` defined. Reviewed By: mweststrate Differential Revision: D19643857 fbshipit-source-id: 7a4a5882507c06c6b6f9c481ee2c5c36ecc32ac6
241 lines
7.6 KiB
TypeScript
241 lines
7.6 KiB
TypeScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
*/
|
|
|
|
import {FlipperDevicePlugin, FlipperPlugin, FlipperBasePlugin} from '../plugin';
|
|
import BaseDevice from '../devices/BaseDevice';
|
|
import {State as PluginStatesState} from '../reducers/pluginStates';
|
|
import {State as PluginsState} from '../reducers/plugins';
|
|
import {State as PluginMessageQueueState} from '../reducers/pluginMessageQueue';
|
|
import {PluginDefinition} from '../dispatcher/plugins';
|
|
import {deconstructPluginKey, deconstructClientId} from './clientUtils';
|
|
|
|
type Client = import('../Client').default;
|
|
|
|
export function pluginsClassMap(
|
|
plugins: PluginsState,
|
|
): Map<string, typeof FlipperDevicePlugin | typeof FlipperPlugin> {
|
|
const pluginsMap: Map<
|
|
string,
|
|
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
|
> = new Map([]);
|
|
plugins.clientPlugins.forEach((val, key) => {
|
|
pluginsMap.set(key, val);
|
|
});
|
|
plugins.devicePlugins.forEach((val, key) => {
|
|
pluginsMap.set(key, val);
|
|
});
|
|
return pluginsMap;
|
|
}
|
|
|
|
export function getPluginKey(
|
|
selectedAppId: string | null,
|
|
baseDevice: BaseDevice | null,
|
|
pluginID: string,
|
|
): string {
|
|
if (selectedAppId) {
|
|
return `${selectedAppId}#${pluginID}`;
|
|
}
|
|
if (baseDevice) {
|
|
// If selected App is not defined, then the plugin is a device plugin
|
|
return `${baseDevice.serial}#${pluginID}`;
|
|
}
|
|
return `unknown#${pluginID}`;
|
|
}
|
|
|
|
export function getPersistedState<PersistedState>(
|
|
pluginKey: string,
|
|
persistingPlugin: typeof FlipperBasePlugin | null,
|
|
pluginStates: PluginStatesState,
|
|
): PersistedState | null {
|
|
if (!persistingPlugin) {
|
|
return null;
|
|
}
|
|
|
|
const persistedState: PersistedState = {
|
|
...persistingPlugin.defaultPersistedState,
|
|
...pluginStates[pluginKey],
|
|
};
|
|
return persistedState;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param starredPlugin starredPlugin is the dictionary of client and its enabled plugin
|
|
* @param client Optional paramater indicating the selected client.
|
|
* @param plugins Plugins from the state which has the mapping to Plugin's Class.
|
|
|
|
* Returns plugins which are enabled or which has exportPersistedState function defined for the passed client.
|
|
* Note all device plugins are enabled.
|
|
*/
|
|
|
|
export function getEnabledOrExportPersistedStatePlugins(
|
|
starredPlugin: {
|
|
[client: string]: string[];
|
|
},
|
|
client: Client,
|
|
plugins: PluginsState,
|
|
): Array<{id: string; label: string}> {
|
|
const appName = deconstructClientId(client.id).app;
|
|
const pluginsMap: Map<
|
|
string,
|
|
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
|
> = pluginsClassMap(plugins);
|
|
// Enabled Plugins with no exportPersistedState function defined
|
|
const enabledPlugins = starredPlugin[appName]
|
|
? starredPlugin[appName]
|
|
.map(pluginName => pluginsMap.get(pluginName)!)
|
|
.filter(plugin => {
|
|
return !plugin.exportPersistedState;
|
|
})
|
|
.sort(sortPluginsByName)
|
|
.map(plugin => {
|
|
return {id: plugin.id, label: getPluginTitle(plugin)};
|
|
})
|
|
: [];
|
|
// Device Plugins
|
|
const devicePlugins = Array.from(plugins.devicePlugins.keys())
|
|
.filter(plugin => {
|
|
return client.plugins.includes(plugin);
|
|
})
|
|
.map(plugin => {
|
|
return {
|
|
id: plugin,
|
|
label: getPluginTitle(plugins.devicePlugins.get(plugin)!),
|
|
};
|
|
});
|
|
// Plugins which have defined exportPersistedState.
|
|
const exportPersistedStatePlugins = client.plugins
|
|
.filter(name => {
|
|
return pluginsMap.get(name)?.exportPersistedState != null;
|
|
})
|
|
.map(name => {
|
|
const plugin = pluginsMap.get(name)!;
|
|
return {id: plugin.id, label: getPluginTitle(plugin)};
|
|
});
|
|
return [
|
|
...devicePlugins,
|
|
...enabledPlugins,
|
|
...exportPersistedStatePlugins,
|
|
{id: 'DeviceLogs', label: 'Logs'},
|
|
];
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param pluginsState PluginsState of the Redux Store.
|
|
* @param plugins Plugins from the state which has the mapping to Plugin's Class.
|
|
* @param selectedClient Optional paramater indicating the selected client.
|
|
* Returns active persistent plugin, which means plugins which has the data in redux store or has the `exportPersistedState` function defined which can return the plugin's data when called.
|
|
* If the selectedClient is defined then the active persistent plugins only for the selectedClient will be returned, otherwise it will return all active persistent plugins.
|
|
*/
|
|
export function getActivePersistentPlugins(
|
|
pluginsState: PluginStatesState,
|
|
pluginsMessageQueue: PluginMessageQueueState,
|
|
plugins: PluginsState,
|
|
selectedClient?: Client,
|
|
): {id: string; label: string}[] {
|
|
const pluginsMap: Map<
|
|
string,
|
|
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
|
> = pluginsClassMap(plugins);
|
|
return getPersistentPlugins(plugins)
|
|
.map(pluginName => pluginsMap.get(pluginName)!)
|
|
.sort(sortPluginsByName)
|
|
.map(plugin => {
|
|
const keys = [
|
|
...new Set([
|
|
...Object.keys(pluginsState),
|
|
...Object.keys(pluginsMessageQueue),
|
|
]),
|
|
]
|
|
.filter(k => !selectedClient || k.includes(selectedClient.id))
|
|
.map(key => deconstructPluginKey(key).pluginName);
|
|
let result = plugin.id == 'DeviceLogs';
|
|
const pluginsWithExportPersistedState =
|
|
plugin && plugin.exportPersistedState != undefined;
|
|
const pluginsWithReduxData = keys.includes(plugin.id);
|
|
if (!result && selectedClient) {
|
|
// If there is a selected client, active persistent plugin is the plugin which is active for selectedClient and also persistent.
|
|
result =
|
|
selectedClient.plugins.includes(plugin.id) &&
|
|
(pluginsWithExportPersistedState || pluginsWithReduxData);
|
|
} else if (!result && !selectedClient) {
|
|
// If there is no selected client, active persistent plugin is the plugin which is just persistent.
|
|
result =
|
|
(plugin && plugin.exportPersistedState != undefined) ||
|
|
keys.includes(plugin.id);
|
|
}
|
|
return (result
|
|
? {
|
|
id: plugin.id,
|
|
label: getPluginTitle(plugin),
|
|
}
|
|
: undefined)!;
|
|
})
|
|
.filter(Boolean);
|
|
}
|
|
|
|
export function getPersistentPlugins(plugins: PluginsState): Array<string> {
|
|
const pluginsMap: Map<
|
|
string,
|
|
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
|
> = pluginsClassMap(plugins);
|
|
|
|
const arr: Array<PluginDefinition> = plugins.disabledPlugins.concat(
|
|
plugins.gatekeepedPlugins,
|
|
);
|
|
arr.forEach((plugin: PluginDefinition) => {
|
|
if (pluginsMap.has(plugin.name)) {
|
|
pluginsMap.delete(plugin.name);
|
|
}
|
|
});
|
|
|
|
plugins.failedPlugins.forEach((plugin: [PluginDefinition, string]) => {
|
|
if (plugin[0] && plugin[0].name && pluginsMap.has(plugin[0].name)) {
|
|
pluginsMap.delete(plugin[0].name);
|
|
}
|
|
});
|
|
|
|
const activePlugins = [...pluginsMap.keys()];
|
|
|
|
return activePlugins.filter(plugin => {
|
|
const pluginClass = pluginsMap.get(plugin);
|
|
return (
|
|
plugin == 'DeviceLogs' ||
|
|
(pluginClass &&
|
|
(pluginClass.defaultPersistedState != undefined ||
|
|
pluginClass.exportPersistedState != undefined))
|
|
);
|
|
});
|
|
}
|
|
|
|
export function getPluginTitle(pluginClass: typeof FlipperBasePlugin) {
|
|
return pluginClass.title || pluginClass.id;
|
|
}
|
|
|
|
export function sortPluginsByName(
|
|
a: typeof FlipperBasePlugin,
|
|
b: typeof FlipperBasePlugin,
|
|
): number {
|
|
// make sure Device plugins are sorted before normal plugins
|
|
if (
|
|
a.prototype instanceof FlipperDevicePlugin &&
|
|
!(b.prototype instanceof FlipperDevicePlugin)
|
|
) {
|
|
return -1;
|
|
}
|
|
if (
|
|
b.prototype instanceof FlipperDevicePlugin &&
|
|
!(a.prototype instanceof FlipperDevicePlugin)
|
|
) {
|
|
return 1;
|
|
}
|
|
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
|
|
}
|