Yarn workspaces
Summary: 1) moved "sonar/desktop/src" to "sonar/desktop/app/src", so "app" is now a separate package containing the core Flipper app code 2) Configured yarn workspaces with the root in "sonar/desktop": app, static, pkg, doctor, headless-tests. Plugins are not included for now, I plan to do this later. Reviewed By: jknoxville Differential Revision: D20535782 fbshipit-source-id: 600b2301960f37c7d72166e0d04eba462bec9fc1
This commit is contained in:
committed by
Facebook GitHub Bot
parent
676d7bbd24
commit
863f89351e
240
desktop/app/src/utils/pluginUtils.tsx
Normal file
240
desktop/app/src/utils/pluginUtils.tsx
Normal file
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user