export function computePluginLists()

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,
  };
}