/** * Copyright (c) Meta Platforms, Inc. and 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 {State} from '../reducers'; import { computePluginLists, computeExportablePlugins, computeActivePluginList, } from '../utils/pluginUtils'; import createSelector from './createSelector'; import {canBeDefaultDevice, getClientsByDevice} from '../reducers/connections'; const getSelectedPluginId = (state: State) => state.connections.selectedPlugin; const getSelectedDevice = (state: State) => state.connections.selectedDevice; const getDevices = (state: State) => state.connections.devices; const getClients = (state: State) => state.connections.clients; const getPluginDownloads = (state: State) => state.pluginDownloads; // N.B. no useSelector, It can't memoise on maps :-/ export const getActiveClient = (state: State) => state.connections.clients.get(state.connections.selectedAppId!) ?? null; export const getMetroDevice = createSelector(getDevices, (devices) => { return ( devices.find((device) => device.os === 'Metro' && !device.isArchived) ?? null ); }); export const getSelectableDevices = createSelector( getDevices, getClients, (devices, clients) => { return devices.filter( (device) => // hide non default devices, unless they have a connected client or plugins canBeDefaultDevice(device) || device.hasDevicePlugins || getClientsByDevice(device, clients).length > 0, ); }, ); export const hasSelectableDevices = createSelector( getSelectableDevices, (selectableDevices) => selectableDevices.length > 0, ); export const getActiveDevice = createSelector( getSelectedDevice, getActiveClient, getMetroDevice, (selectedDevice, client, metroDevice) => { // if not Metro device, use the selected device as metro device if (selectedDevice !== metroDevice) { return selectedDevice; } // if there is an active app, use device owning the app if (client) { // TODO: Will be fixed later in the stack return client.device as any; } return selectedDevice; }, ); export const getPluginLists = createSelector( ({ connections: { enabledDevicePlugins, enabledPlugins, selectedAppPluginListRevision, // used only to invalidate cache }, }: State) => ({ enabledDevicePlugins, enabledPlugins, selectedAppPluginListRevision, }), ({ plugins: { clientPlugins, devicePlugins, marketplacePlugins, loadedPlugins, disabledPlugins, gatekeepedPlugins, failedPlugins, }, }: State) => ({ clientPlugins, devicePlugins, marketplacePlugins, loadedPlugins, disabledPlugins, gatekeepedPlugins, failedPlugins, }), getActiveDevice, getMetroDevice, getActiveClient, computePluginLists, ); export const getExportablePlugins = createSelector( ({plugins, connections, pluginMessageQueue}: State) => ({ plugins, connections, pluginMessageQueue, }), getActiveDevice, getActiveClient, getPluginLists, computeExportablePlugins, ); export const getActivePluginList = createSelector( getPluginLists, computeActivePluginList, ); export const getActivePlugin = createSelector( getSelectedPluginId, getActivePluginList, (pluginId, pluginList) => { if (!pluginId) { return null; } return pluginList[pluginId] ?? null; }, ); export const getPluginDownloadStatusMap = createSelector( getPluginDownloads, (downloads) => { const downloadMap = new Map( Object.values(downloads).map((x) => [x.plugin.id, x]), ); return downloadMap; }, );