diff --git a/desktop/app/src/chrome/LocationsButton.tsx b/desktop/app/src/chrome/LocationsButton.tsx index b25f738d7..07880d53d 100644 --- a/desktop/app/src/chrome/LocationsButton.tsx +++ b/desktop/app/src/chrome/LocationsButton.tsx @@ -15,7 +15,6 @@ import {useStore} from '../utils/useStore'; import {useMemoize} from '../utils/useMemoize'; import {State} from '../reducers'; -// TODO T71355623 // eslint-disable-next-line flipper/no-relative-imports-across-packages import type {NavigationPlugin} from '../../../plugins/navigation/index'; // eslint-disable-next-line flipper/no-relative-imports-across-packages diff --git a/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx b/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx index 00e0a3fae..998056a18 100644 --- a/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx +++ b/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx @@ -11,12 +11,18 @@ import React from 'react'; import {Alert} from 'antd'; import {LeftSidebar, SidebarTitle, InfoIcon} from '../LeftSidebar'; import {Layout, Link, styled} from '../../ui'; -import {NUX, theme} from 'flipper-plugin'; +import {theme} from 'flipper-plugin'; import {AppSelector} from './AppSelector'; import {useStore} from '../../utils/useStore'; import {PluginList} from './PluginList'; import ScreenCaptureButtons from '../../chrome/ScreenCaptureButtons'; import MetroButton from '../../chrome/MetroButton'; +import {BookmarkSection} from './BookmarkSection'; +import {useMemoize} from '../../utils/useMemoize'; +import Client from '../../Client'; +import {State} from '../../reducers'; +import BaseDevice from '../../devices/BaseDevice'; +import MetroDevice from '../../devices/MetroDevice'; const appTooltip = ( <> @@ -30,8 +36,23 @@ const appTooltip = ( ); export function AppInspect() { - const selectedDevice = useStore((state) => state.connections.selectedDevice); - const isArchived = !!selectedDevice?.isArchived; + const connections = useStore((state) => state.connections); + + const metroDevice = useMemoize(findMetroDevice, [connections.devices]); + const client = useMemoize(findBestClient, [ + connections.clients, + connections.selectedApp, + connections.userPreferredApp, + ]); + // // if the selected device is Metro, we want to keep the owner of the selected App as active device if possible + const activeDevice = useMemoize(findBestDevice, [ + client, + connections.devices, + connections.selectedDevice, + metroDevice, + connections.userPreferredDevice, + ]); + const isArchived = !!activeDevice?.isArchived; return ( @@ -42,14 +63,14 @@ export function AppInspect() { - { - isArchived ? ( - - ) : null /* TODO: add bookmarks back T77016599 */ - } + {isArchived ? ( + + ) : ( + + )} {!isArchived && ( @@ -59,8 +80,12 @@ export function AppInspect() { - {selectedDevice ? ( - + {activeDevice ? ( + ) : ( )} @@ -75,3 +100,44 @@ const Toolbar = styled(Layout.Horizontal)({ border: 'none', }, }); + +export function findBestClient( + clients: Client[], + selectedApp: string | null, + userPreferredApp: string | null, +): Client | undefined { + return clients.find((c) => c.id === (selectedApp || userPreferredApp)); +} + +export function findMetroDevice( + devices: State['connections']['devices'], +): MetroDevice | undefined { + return devices?.find( + (device) => device.os === 'Metro' && !device.isArchived, + ) as MetroDevice; +} + +export function findBestDevice( + client: Client | undefined, + devices: State['connections']['devices'], + selectedDevice: BaseDevice | null, + metroDevice: BaseDevice | undefined, + userPreferredDevice: string | null, +): BaseDevice | undefined { + // if not Metro device, use the selected device as metro device + const selected = selectedDevice ?? undefined; + if (selected !== metroDevice) { + return selected; + } + // if there is an active app, use device owning the app + if (client) { + return client.deviceSync; + } + // if no active app, use the preferred device + if (userPreferredDevice) { + return ( + devices.find((device) => device.title === userPreferredDevice) ?? selected + ); + } + return selected; +} diff --git a/desktop/app/src/sandy-chrome/appinspect/BookmarkSection.tsx b/desktop/app/src/sandy-chrome/appinspect/BookmarkSection.tsx new file mode 100644 index 000000000..e52db37e1 --- /dev/null +++ b/desktop/app/src/sandy-chrome/appinspect/BookmarkSection.tsx @@ -0,0 +1,80 @@ +/** + * 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 React, {useCallback, useMemo} from 'react'; +import {AutoComplete, Input} from 'antd'; +import {StarFilled, StarOutlined} from '@ant-design/icons'; +import {useStore} from '../../utils/useStore'; +import {NUX, useValue} from 'flipper-plugin'; +import {navPluginStateSelector} from '../../chrome/LocationsButton'; + +// eslint-disable-next-line flipper/no-relative-imports-across-packages +import type {NavigationPlugin} from '../../../../plugins/navigation/index'; + +export function BookmarkSection() { + const navPlugin = useStore(navPluginStateSelector); + + return navPlugin ? ( + + + + ) : null; +} + +function BookmarkSectionInput({navPlugin}: {navPlugin: NavigationPlugin}) { + const currentURI = useValue(navPlugin.currentURI); + const bookmarks = useValue(navPlugin.bookmarks); + + const isBookmarked = useMemo(() => bookmarks.has(currentURI), [ + bookmarks, + currentURI, + ]); + const handleBookmarkClick = useCallback(() => { + if (isBookmarked) { + navPlugin.removeBookmark(currentURI); + } else { + navPlugin.addBookmark({ + uri: currentURI, + commonName: null, + }); + } + }, [navPlugin, currentURI, isBookmarked]); + + const bookmarkButton = isBookmarked ? ( + + ) : ( + + ); + + return ( + ({ + value: bookmark.uri, + label: bookmark.commonName + ? `${bookmark.commonName} - ${bookmark.uri}` + : bookmark.uri, + }))}> + { + navPlugin.currentURI.set(e.target.value); + }} + onPressEnter={(e) => { + navPlugin.navigateTo(currentURI); + }} + /> + + ); +} diff --git a/desktop/app/src/sandy-chrome/appinspect/PluginList.tsx b/desktop/app/src/sandy-chrome/appinspect/PluginList.tsx index 8ea40a357..9088a0c7a 100644 --- a/desktop/app/src/sandy-chrome/appinspect/PluginList.tsx +++ b/desktop/app/src/sandy-chrome/appinspect/PluginList.tsx @@ -23,29 +23,24 @@ import BaseDevice from '../../devices/BaseDevice'; import {getFavoritePlugins} from '../../chrome/mainsidebar/sidebarUtils'; import {PluginDetails} from 'flipper-plugin-lib'; import {useMemoize} from '../../utils/useMemoize'; +import MetroDevice from '../../devices/MetroDevice'; const {SubMenu} = Menu; const {Text} = Typography; -export const PluginList = memo(function PluginList() { +export const PluginList = memo(function PluginList({ + client, + activeDevice, + metroDevice, +}: { + client: Client | undefined; + activeDevice: BaseDevice | undefined; + metroDevice: MetroDevice | undefined; +}) { const dispatch = useDispatch(); const connections = useStore((state) => state.connections); const plugins = useStore((state) => state.plugins); - const metroDevice = useMemoize(findMetroDevice, [connections.devices]); - const client = useMemoize(findBestClient, [ - connections.clients, - connections.selectedApp, - connections.userPreferredApp, - ]); - // // if the selected device is Metro, we want to keep the owner of the selected App as active device if possible - const activeDevice = useMemoize(findBestDevice, [ - client, - connections.devices, - connections.selectedDevice, - metroDevice, - connections.userPreferredDevice, - ]); const { devicePlugins, metroPlugins, @@ -351,45 +346,6 @@ function getPluginTooltip(details: PluginDetails): string { }`; } -export function findBestClient( - clients: Client[], - selectedApp: string | null, - userPreferredApp: string | null, -): Client | undefined { - return clients.find((c) => c.id === (selectedApp || userPreferredApp)); -} - -export function findMetroDevice( - devices: State['connections']['devices'], -): BaseDevice | undefined { - return devices?.find((device) => device.os === 'Metro' && !device.isArchived); -} - -export function findBestDevice( - client: Client | undefined, - devices: State['connections']['devices'], - selectedDevice: BaseDevice | null, - metroDevice: BaseDevice | undefined, - userPreferredDevice: string | null, -): BaseDevice | undefined { - // if not Metro device, use the selected device as metro device - const selected = selectedDevice ?? undefined; - if (selected !== metroDevice) { - return selected; - } - // if there is an active app, use device owning the app - if (client) { - return client.deviceSync; - } - // if no active app, use the preferred device - if (userPreferredDevice) { - return ( - devices.find((device) => device.title === userPreferredDevice) ?? selected - ); - } - return selected; -} - export function computePluginLists( device: BaseDevice | undefined, metroDevice: BaseDevice | undefined, diff --git a/desktop/app/src/sandy-chrome/appinspect/__tests__/PluginList.spec.tsx b/desktop/app/src/sandy-chrome/appinspect/__tests__/PluginList.spec.tsx index 4c61e45b6..3163fb080 100644 --- a/desktop/app/src/sandy-chrome/appinspect/__tests__/PluginList.spec.tsx +++ b/desktop/app/src/sandy-chrome/appinspect/__tests__/PluginList.spec.tsx @@ -11,12 +11,8 @@ import { createMockFlipperWithPlugin, MockFlipperResult, } from '../../../test-utils/createMockFlipperWithPlugin'; -import { - findBestClient, - findBestDevice, - findMetroDevice, - computePluginLists, -} from '../PluginList'; +import {computePluginLists} from '../PluginList'; +import {findBestClient, findBestDevice, findMetroDevice} from '../AppInspect'; import {FlipperPlugin} from '../../../plugin'; import MetroDevice from '../../../devices/MetroDevice'; import BaseDevice from '../../../devices/BaseDevice';