Introduce pluginKey

Summary: Exposed the `pluginKey` to sandy plugins (which we will use later for storing table preferences per plugin). And a little moving code around because circular deps problem roared its ugly head again.

Reviewed By: nikoant

Differential Revision: D27009721

fbshipit-source-id: 7ad29e72ff8028c9daae270c4749b657bd8ff049
This commit is contained in:
Michel Weststrate
2021-03-16 14:54:53 -07:00
committed by Facebook GitHub Bot
parent be25df6490
commit 2ca52f81d2
16 changed files with 63 additions and 36 deletions

View File

@@ -7,12 +7,7 @@
* @format * @format
*/ */
import { import {PluginDefinition, FlipperPlugin, FlipperDevicePlugin} from './plugin';
PluginDefinition,
isSandyPlugin,
FlipperPlugin,
FlipperDevicePlugin,
} from './plugin';
import BaseDevice, {OS} from './devices/BaseDevice'; import BaseDevice, {OS} from './devices/BaseDevice';
import {Logger} from './fb-interfaces/Logger'; import {Logger} from './fb-interfaces/Logger';
import {Store} from './reducers/index'; import {Store} from './reducers/index';
@@ -30,6 +25,7 @@ import invariant from 'invariant';
import { import {
getPluginKey, getPluginKey,
defaultEnabledBackgroundPlugins, defaultEnabledBackgroundPlugins,
isSandyPlugin,
} from './utils/pluginUtils'; } from './utils/pluginUtils';
import {processMessagesLater} from './utils/messageQueue'; import {processMessagesLater} from './utils/messageQueue';
import {emitBytesReceived} from './dispatcher/tracking'; import {emitBytesReceived} from './dispatcher/tracking';
@@ -260,6 +256,7 @@ export default class Client extends EventEmitter {
_getFlipperLibImplementation(), _getFlipperLibImplementation(),
plugin, plugin,
this, this,
getPluginKey(this.id, {serial: this.query.device_id}, plugin.id),
initialStates[pluginId], initialStates[pluginId],
), ),
); );
@@ -306,7 +303,12 @@ export default class Client extends EventEmitter {
// TODO: needs to be wrapped in error tracking T68955280 // TODO: needs to be wrapped in error tracking T68955280
this.sandyPluginStates.set( this.sandyPluginStates.set(
plugin.id, plugin.id,
new _SandyPluginInstance(_getFlipperLibImplementation(), plugin, this), new _SandyPluginInstance(
_getFlipperLibImplementation(),
plugin,
this,
getPluginKey(this.id, {serial: this.query.device_id}, plugin.id),
),
); );
} }
} }

View File

@@ -12,7 +12,6 @@ import {
FlipperDevicePlugin, FlipperDevicePlugin,
Props as PluginProps, Props as PluginProps,
PluginDefinition, PluginDefinition,
isSandyPlugin,
} from './plugin'; } from './plugin';
import {Logger} from './fb-interfaces/Logger'; import {Logger} from './fb-interfaces/Logger';
import BaseDevice from './devices/BaseDevice'; import BaseDevice from './devices/BaseDevice';
@@ -47,7 +46,7 @@ import {IdlerImpl} from './utils/Idler';
import {processMessageQueue} from './utils/messageQueue'; import {processMessageQueue} from './utils/messageQueue';
import {ToggleButton, SmallText, Layout} from './ui'; import {ToggleButton, SmallText, Layout} from './ui';
import {theme, TrackingScope, _SandyPluginRenderer} from 'flipper-plugin'; import {theme, TrackingScope, _SandyPluginRenderer} from 'flipper-plugin';
import {isDevicePluginDefinition} from './utils/pluginUtils'; import {isDevicePluginDefinition, isSandyPlugin} from './utils/pluginUtils';
import {ContentContainer} from './sandy-chrome/ContentContainer'; import {ContentContainer} from './sandy-chrome/ContentContainer';
import {Alert, Typography} from 'antd'; import {Alert, Typography} from 'antd';
import {InstalledPluginDetails} from 'plugin-lib'; import {InstalledPluginDetails} from 'plugin-lib';

View File

@@ -242,6 +242,12 @@ export default class BaseDevice {
_getFlipperLibImplementation(), _getFlipperLibImplementation(),
plugin, plugin,
this, this,
// break circular dep, one of those days again...
require('../utils/pluginUtils').getPluginKey(
undefined,
{serial: this.serial},
plugin.id,
),
initialState, initialState,
), ),
); );

View File

@@ -10,7 +10,7 @@
import {Store} from '../reducers/index'; import {Store} from '../reducers/index';
import {Logger} from '../fb-interfaces/Logger'; import {Logger} from '../fb-interfaces/Logger';
import {PluginNotification} from '../reducers/notifications'; import {PluginNotification} from '../reducers/notifications';
import {PluginDefinition, isSandyPlugin} from '../plugin'; import {PluginDefinition} from '../plugin';
import {setStaticView} from '../reducers/connections'; import {setStaticView} from '../reducers/connections';
import {ipcRenderer, IpcRendererEvent} from 'electron'; import {ipcRenderer, IpcRendererEvent} from 'electron';
import { import {
@@ -22,7 +22,7 @@ import {textContent} from '../utils/index';
import GK from '../fb-stubs/GK'; import GK from '../fb-stubs/GK';
import {deconstructPluginKey} from '../utils/clientUtils'; import {deconstructPluginKey} from '../utils/clientUtils';
import NotificationScreen from '../chrome/NotificationScreen'; import NotificationScreen from '../chrome/NotificationScreen';
import {getPluginTitle} from '../utils/pluginUtils'; import {getPluginTitle, isSandyPlugin} from '../utils/pluginUtils';
import {sideEffect} from '../utils/sideEffect'; import {sideEffect} from '../utils/sideEffect';
type NotificationEvents = 'show' | 'click' | 'close' | 'reply' | 'action'; type NotificationEvents = 'show' | 'click' | 'close' | 'reply' | 'action';

View File

@@ -36,12 +36,6 @@ export type ClientPluginDefinition =
export type ClientPluginMap = Map<string, ClientPluginDefinition>; export type ClientPluginMap = Map<string, ClientPluginDefinition>;
export type DevicePluginMap = Map<string, DevicePluginDefinition>; export type DevicePluginMap = Map<string, DevicePluginDefinition>;
export function isSandyPlugin(
plugin?: PluginDefinition | null,
): plugin is _SandyPluginDefinition {
return plugin instanceof _SandyPluginDefinition;
}
// This function is intended to be called from outside of the plugin. // This function is intended to be called from outside of the plugin.
// If you want to `call` from the plugin use, this.client.call // If you want to `call` from the plugin use, this.client.call
export function callClient( export function callClient(

View File

@@ -25,7 +25,6 @@ import {
PluginDefinition, PluginDefinition,
DevicePluginMap, DevicePluginMap,
ClientPluginMap, ClientPluginMap,
isSandyPlugin,
} from '../plugin'; } from '../plugin';
import {default as BaseDevice} from '../devices/BaseDevice'; import {default as BaseDevice} from '../devices/BaseDevice';
import {default as ArchivedDevice} from '../devices/ArchivedDevice'; import {default as ArchivedDevice} from '../devices/ArchivedDevice';
@@ -46,7 +45,7 @@ import {setSelectPluginsToExportActiveSheet} from '../reducers/application';
import {deconstructClientId, deconstructPluginKey} from '../utils/clientUtils'; import {deconstructClientId, deconstructPluginKey} from '../utils/clientUtils';
import {performance} from 'perf_hooks'; import {performance} from 'perf_hooks';
import {processMessageQueue} from './messageQueue'; import {processMessageQueue} from './messageQueue';
import {getPluginTitle} from './pluginUtils'; import {getPluginTitle, isSandyPlugin} from './pluginUtils';
import {capture} from './screenshot'; import {capture} from './screenshot';
import {uploadFlipperMedia} from '../fb-stubs/user'; import {uploadFlipperMedia} from '../fb-stubs/user';
import {Idler} from 'flipper-plugin'; import {Idler} from 'flipper-plugin';

View File

@@ -8,7 +8,7 @@
*/ */
import {PersistedStateReducer, FlipperDevicePlugin} from '../plugin'; import {PersistedStateReducer, FlipperDevicePlugin} from '../plugin';
import {State, MiddlewareAPI} from '../reducers/index'; import type {State, MiddlewareAPI} from '../reducers/index';
import {setPluginState} from '../reducers/pluginStates'; import {setPluginState} from '../reducers/pluginStates';
import { import {
clearMessageQueue, clearMessageQueue,

View File

@@ -7,16 +7,15 @@
* @format * @format
*/ */
import {Store} from '../reducers/index'; import type {Store} from '../reducers/index';
import { import type {
ClientPluginMap, ClientPluginMap,
DevicePluginMap, DevicePluginMap,
PluginDefinition, PluginDefinition,
isSandyPlugin,
} from '../plugin'; } from '../plugin';
import {setPluginState} from '../reducers/pluginStates'; import {setPluginState} from '../reducers/pluginStates';
import BaseDevice from '../devices/BaseDevice'; import type BaseDevice from '../devices/BaseDevice';
import {getPersistedState} from '../utils/pluginUtils'; import {getPersistedState, isSandyPlugin} from '../utils/pluginUtils';
export function registerDeviceCallbackOnPlugins( export function registerDeviceCallbackOnPlugins(
store: Store, store: Store,

View File

@@ -12,7 +12,6 @@ import {
FlipperBasePlugin, FlipperBasePlugin,
PluginDefinition, PluginDefinition,
DevicePluginDefinition, DevicePluginDefinition,
isSandyPlugin,
ClientPluginDefinition, ClientPluginDefinition,
} from '../plugin'; } from '../plugin';
import type {State} from '../reducers'; import type {State} from '../reducers';
@@ -54,6 +53,12 @@ export function getPluginKey(
return `unknown#${pluginID}`; return `unknown#${pluginID}`;
} }
export function isSandyPlugin(
plugin?: PluginDefinition | null,
): plugin is _SandyPluginDefinition {
return plugin instanceof _SandyPluginDefinition;
}
export function getPersistedState<PersistedState>( export function getPersistedState<PersistedState>(
pluginKey: string, pluginKey: string,
persistingPlugin: typeof FlipperBasePlugin | null, persistingPlugin: typeof FlipperBasePlugin | null,

View File

@@ -88,9 +88,10 @@ export class SandyDevicePluginInstance extends BasePluginInstance {
flipperLib: FlipperLib, flipperLib: FlipperLib,
definition: SandyPluginDefinition, definition: SandyPluginDefinition,
realDevice: RealFlipperDevice, realDevice: RealFlipperDevice,
pluginKey: string,
initialStates?: Record<string, any>, initialStates?: Record<string, any>,
) { ) {
super(flipperLib, definition, realDevice, initialStates); super(flipperLib, definition, realDevice, pluginKey, initialStates);
this.client = { this.client = {
...this.createBasePluginClient(), ...this.createBasePluginClient(),
isPluginAvailable(pluginId: string) { isPluginAvailable(pluginId: string) {

View File

@@ -148,9 +148,16 @@ export class SandyPluginInstance extends BasePluginInstance {
flipperLib: FlipperLib, flipperLib: FlipperLib,
definition: SandyPluginDefinition, definition: SandyPluginDefinition,
realClient: RealFlipperClient, realClient: RealFlipperClient,
pluginKey: string,
initialStates?: Record<string, any>, initialStates?: Record<string, any>,
) { ) {
super(flipperLib, definition, realClient.deviceSync, initialStates); super(
flipperLib,
definition,
realClient.deviceSync,
pluginKey,
initialStates,
);
this.realClient = realClient; this.realClient = realClient;
this.definition = definition; this.definition = definition;
const self = this; const self = this;

View File

@@ -23,6 +23,7 @@ type StateExportHandler<T = any> = (
type StateImportHandler<T = any> = (data: T) => void; type StateImportHandler<T = any> = (data: T) => void;
export interface BasePluginClient { export interface BasePluginClient {
readonly pluginKey: string;
readonly device: Device; readonly device: Device;
/** /**
@@ -117,6 +118,9 @@ export abstract class BasePluginInstance {
/** the device owning this plugin */ /** the device owning this plugin */
readonly device: Device; readonly device: Device;
/** the unique plugin key for this plugin instance, which is unique for this device/app?/pluginId combo */
readonly pluginKey: string;
activated = false; activated = false;
destroyed = false; destroyed = false;
readonly events = new EventEmitter(); readonly events = new EventEmitter();
@@ -140,11 +144,13 @@ export abstract class BasePluginInstance {
flipperLib: FlipperLib, flipperLib: FlipperLib,
definition: SandyPluginDefinition, definition: SandyPluginDefinition,
realDevice: RealFlipperDevice, realDevice: RealFlipperDevice,
pluginKey: string,
initialStates?: Record<string, any>, initialStates?: Record<string, any>,
) { ) {
this.flipperLib = flipperLib; this.flipperLib = flipperLib;
this.definition = definition; this.definition = definition;
this.initialStates = initialStates; this.initialStates = initialStates;
this.pluginKey = pluginKey;
if (!realDevice) { if (!realDevice) {
throw new Error('Illegal State: Device has not yet been loaded'); throw new Error('Illegal State: Device has not yet been loaded');
} }
@@ -213,6 +219,7 @@ export abstract class BasePluginInstance {
protected createBasePluginClient(): BasePluginClient { protected createBasePluginClient(): BasePluginClient {
return { return {
pluginKey: this.pluginKey,
device: this.device, device: this.device,
onActivate: (cb) => { onActivate: (cb) => {
this.events.on('activate', batched(cb)); this.events.on('activate', batched(cb));

View File

@@ -15,13 +15,20 @@ export const SandyPluginContext = createContext<
SandyPluginInstance | SandyDevicePluginInstance | undefined SandyPluginInstance | SandyDevicePluginInstance | undefined
>(undefined); >(undefined);
export function usePluginInstance():
| SandyPluginInstance
| SandyDevicePluginInstance {
const pluginInstance = useContext(SandyPluginContext);
if (!pluginInstance) {
throw new Error('Sandy Plugin context not available');
}
return pluginInstance;
}
export function usePlugin< export function usePlugin<
Factory extends PluginFactory<any, any> | DevicePluginFactory Factory extends PluginFactory<any, any> | DevicePluginFactory
>(plugin: Factory): ReturnType<Factory> { >(plugin: Factory): ReturnType<Factory> {
const pluginInstance = useContext(SandyPluginContext); const pluginInstance = usePluginInstance();
if (!pluginInstance) {
throw new Error('Plugin context not available');
}
// In principle we don't *need* the plugin, but having it passed it makes sure the // In principle we don't *need* the plugin, but having it passed it makes sure the
// return of this function is strongly typed, without the user needing to create it's own // return of this function is strongly typed, without the user needing to create it's own
// context. // context.

View File

@@ -234,6 +234,7 @@ export function startPlugin<Module extends FlipperPluginModule<any>>(
flipperUtils, flipperUtils,
definition, definition,
fakeFlipperClient, fakeFlipperClient,
`${fakeFlipperClient.id}#${definition.id}`,
options?.initialState, options?.initialState,
); );
@@ -313,6 +314,7 @@ export function startDevicePlugin<Module extends FlipperDevicePluginModule>(
flipperLib, flipperLib,
definition, definition,
testDevice, testDevice,
`${testDevice.serial}#${definition.id}`,
options?.initialState, options?.initialState,
); );

View File

@@ -44,8 +44,8 @@ import {tableContextMenuFactory} from './TableContextMenu';
import {Typography} from 'antd'; import {Typography} from 'antd';
import {CoffeeOutlined, SearchOutlined} from '@ant-design/icons'; import {CoffeeOutlined, SearchOutlined} from '@ant-design/icons';
import {useAssertStableRef} from '../../utils/useAssertStableRef'; import {useAssertStableRef} from '../../utils/useAssertStableRef';
import {TrackingScopeContext} from 'flipper-plugin/src/ui/Tracked';
import {Formatter} from '../DataFormatter'; import {Formatter} from '../DataFormatter';
import {usePluginInstance} from '../../plugin/PluginContext';
interface DataTableProps<T = any> { interface DataTableProps<T = any> {
columns: DataTableColumn<T>[]; columns: DataTableColumn<T>[];
@@ -103,7 +103,7 @@ export function DataTable<T extends object>(
// lint disabled for conditional inclusion of a hook (_testHeight is asserted to be stable) // lint disabled for conditional inclusion of a hook (_testHeight is asserted to be stable)
// eslint-disable-next-line // eslint-disable-next-line
const scope = props._testHeight ? "" : useContext(TrackingScopeContext); // TODO + plugin id const scope = props._testHeight ? "" : usePluginInstance().pluginKey;
const virtualizerRef = useRef<DataSourceVirtualizer | undefined>(); const virtualizerRef = useRef<DataSourceVirtualizer | undefined>();
const [state, dispatch] = useReducer( const [state, dispatch] = useReducer(
dataTableManagerReducer as DataTableReducer<T>, dataTableManagerReducer as DataTableReducer<T>,

View File

@@ -104,7 +104,6 @@ export type DataTableReducer<T> = Reducer<
>; >;
export type DataTableDispatch<T = any> = React.Dispatch<DataManagerActions<T>>; export type DataTableDispatch<T = any> = React.Dispatch<DataManagerActions<T>>;
// TODO: make argu inference correct
export const dataTableManagerReducer = produce(function <T>( export const dataTableManagerReducer = produce(function <T>(
draft: DataManagerState<T>, draft: DataManagerState<T>,
action: DataManagerActions<T>, action: DataManagerActions<T>,
@@ -208,7 +207,7 @@ export const dataTableManagerReducer = produce(function <T>(
throw new Error('Unknown action ' + (action as any).type); throw new Error('Unknown action ' + (action as any).type);
} }
} }
}) as any; // TODO: remove }) as any;
/** /**
* Public only imperative convienience API for DataTable * Public only imperative convienience API for DataTable