in desktop/flipper-ui-core/src/utils/pluginUtils.tsx [155:348]
export function computePluginLists(
connections: Pick<
State['connections'],
'enabledDevicePlugins' | 'enabledPlugins'
>,
plugins: Pick<
State['plugins'],
| 'bundledPlugins'
| 'marketplacePlugins'
| 'loadedPlugins'
| 'devicePlugins'
| 'disabledPlugins'
| 'gatekeepedPlugins'
| 'failedPlugins'
| 'clientPlugins'
>,
device: BaseDevice | null,
metroDevice: BaseDevice | null,
client: Client | null,
): {
devicePlugins: PluginDefinition[];
metroPlugins: PluginDefinition[];
enabledPlugins: PluginDefinition[];
disabledPlugins: PluginDefinition[];
unavailablePlugins: [plugin: PluginDetails, reason: string][];
downloadablePlugins: (DownloadablePluginDetails | BundledPluginDetails)[];
} {
const enabledDevicePluginsState = connections.enabledDevicePlugins;
const enabledPluginsState = connections.enabledPlugins;
const uninstalledMarketplacePlugins = getLatestCompatibleVersionOfEachPlugin([
...plugins.bundledPlugins.values(),
...plugins.marketplacePlugins,
]).filter((p) => !plugins.loadedPlugins.has(p.id));
const devicePlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
.filter((p) => device?.supportsPlugin(p))
.filter((p) => enabledDevicePluginsState.has(p.id));
const metroPlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
.filter((p) => metroDevice?.supportsPlugin(p))
.filter((p) => enabledDevicePluginsState.has(p.id));
const enabledPlugins: PluginDefinition[] = [];
const disabledPlugins: PluginDefinition[] = [
...plugins.devicePlugins.values(),
]
.filter(
(p) =>
device?.supportsPlugin(p.details) ||
metroDevice?.supportsPlugin(p.details),
)
.filter((p) => !enabledDevicePluginsState.has(p.id));
const unavailablePlugins: [plugin: PluginDetails, reason: string][] = [];
const downloadablePlugins: (
| DownloadablePluginDetails
| BundledPluginDetails
)[] = [];
if (device) {
// find all device plugins that aren't part of the current device / metro
for (const p of plugins.devicePlugins.values()) {
if (!device.supportsPlugin(p) && !metroDevice?.supportsPlugin(p)) {
unavailablePlugins.push([
p.details,
`Device plugin '${getPluginTitle(
p.details,
)}' is not supported by the selected device '${device.title}' (${
device.os
})`,
]);
}
}
for (const plugin of uninstalledMarketplacePlugins.filter(
(d) => d.pluginType === 'device',
)) {
if (
device.supportsPlugin(plugin) ||
metroDevice?.supportsPlugin(plugin)
) {
downloadablePlugins.push(plugin);
}
}
} else {
for (const p of plugins.devicePlugins.values()) {
unavailablePlugins.push([
p.details,
`Device plugin '${getPluginTitle(
p.details,
)}' is not available because no device is currently selected`,
]);
}
}
// process problematic plugins
plugins.disabledPlugins.forEach((plugin) => {
unavailablePlugins.push([
plugin,
`Plugin '${plugin.title}' is disabled by configuration`,
]);
});
plugins.gatekeepedPlugins.forEach((plugin) => {
unavailablePlugins.push([
plugin,
`Plugin '${plugin.title}' is only available to members of gatekeeper '${plugin.gatekeeper}'`,
]);
});
plugins.failedPlugins.forEach(([plugin, error]) => {
unavailablePlugins.push([
plugin,
`Plugin '${plugin.title}' failed to load: '${error}'`,
]);
});
const clientPlugins = Array.from(plugins.clientPlugins.values()).sort(
sortPluginsByName,
);
// process all client plugins
if (device && client) {
const favoritePlugins = getFavoritePlugins(
device,
client,
clientPlugins,
client && enabledPluginsState[client.query.app],
true,
);
clientPlugins.forEach((plugin) => {
if (!client.supportsPlugin(plugin.id)) {
unavailablePlugins.push([
plugin.details,
`Plugin '${getPluginTitle(
plugin.details,
)}' is not supported by the selected application '${
client.query.app
}' (${client.query.os})`,
]);
} else if (favoritePlugins.includes(plugin)) {
enabledPlugins.push(plugin);
} else {
disabledPlugins.push(plugin);
}
});
uninstalledMarketplacePlugins.forEach((plugin) => {
if (plugin.pluginType !== 'device' && client.supportsPlugin(plugin.id)) {
downloadablePlugins.push(plugin);
}
});
} else {
clientPlugins.forEach((plugin) => {
unavailablePlugins.push([
plugin.details,
`Plugin '${getPluginTitle(
plugin.details,
)}' is not available because no application is currently selected`,
]);
});
}
const downloadablePluginSet = new Set<string>(
downloadablePlugins.map((p) => p.id),
);
uninstalledMarketplacePlugins
.filter((p) => !downloadablePluginSet.has(p.id))
.forEach((plugin) => {
unavailablePlugins.push([
plugin,
`Plugin '${getPluginTitle(plugin)}' is not supported by the selected ${
plugin.pluginType === 'device' ? 'device' : 'application'
} '${
(plugin.pluginType === 'device'
? device?.title
: client?.query.app) ?? 'unknown'
}' (${
plugin.pluginType === 'device' ? device?.os : client?.query.os
}) and not installed in Flipper`,
]);
});
enabledPlugins.sort(sortPluginsByName);
devicePlugins.sort(sortPluginsByName);
disabledPlugins.sort(sortPluginsByName);
metroPlugins.sort(sortPluginsByName);
unavailablePlugins.sort(([a], [b]) => {
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
});
downloadablePlugins.sort((a, b) => {
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
});
return {
devicePlugins,
metroPlugins,
enabledPlugins,
disabledPlugins,
unavailablePlugins,
downloadablePlugins,
};
}