Introduce types for Sandy plugins through code base
Summary:
So far there were 2 types of plugins: `FlipperPlugin` and `FlipperDevicePlugin`. This introduces a third kind: `SandyPluginDefinition`.
Unlike with the old plugins, the export of the module is not directly exposed as the plugin definition. Rather, we use class `SandyPluginDefinition` (instance) that holds a loaded definition and its meta data separately (`PluginDetails`). This means that we don't have to mix in and mutate loaded definitions, and that for unit tests we can avoid needing to provide a bunch of meta data. This also prevents a bunch of meta data existing on two places: on the loaded classes as static fields, and in the meta data field of the loaded class as well. Finally, we can now freely extends the `PluginDetails` interface in flipper, without needing to store it on the loaded classes and we are sure that no naming conflicts are caused by this in the future.
For compatibility with the existing code base, common fields are delegated from the `SandyPluginDefinition` class to the meta data.
Also cleaned up types around plugins a little bit and removed some unnecessary casts.
For all features that reason about plugins in general (such as exports), sandy plugins are ignored for now.
`SandyPluginInstance` is worked out in further diffs
The `instanceof` calls are replaced by a utility function in later diffs.
{F241363645}
Reviewed By: jknoxville
Differential Revision: D22091432
fbshipit-source-id: 3aa6b12fda5925268913779f3c3c9e84494438f8
This commit is contained in:
committed by
Facebook GitHub Bot
parent
845c9b67f5
commit
1029a6c97c
@@ -15,6 +15,7 @@ const pattern = /^\*\r?\n[\S\s]*Facebook[\S\s]* \* @format\r?\n/;
|
||||
const builtInModules = [
|
||||
'flipper',
|
||||
'flipper-plugin',
|
||||
'flipper-plugin-lib',
|
||||
'react',
|
||||
'react-dom',
|
||||
'electron',
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from './plugin';
|
||||
import {PluginDefinition, ClientPluginDefinition} from './plugin';
|
||||
import BaseDevice, {OS} from './devices/BaseDevice';
|
||||
import {App} from './App';
|
||||
import {Logger} from './fb-interfaces/Logger';
|
||||
@@ -32,6 +32,7 @@ import {sideEffect} from './utils/sideEffect';
|
||||
import {emitBytesReceived} from './dispatcher/tracking';
|
||||
import {debounce} from 'lodash';
|
||||
import {batch} from 'react-redux';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
type Plugins = Array<string>;
|
||||
|
||||
@@ -130,7 +131,7 @@ export default class Client extends EventEmitter {
|
||||
messageBuffer: Record<
|
||||
string /*pluginKey*/,
|
||||
{
|
||||
plugin: typeof FlipperPlugin | typeof FlipperDevicePlugin;
|
||||
plugin: PluginDefinition;
|
||||
messages: Params[];
|
||||
}
|
||||
> = {};
|
||||
@@ -244,7 +245,7 @@ export default class Client extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
supportsPlugin(Plugin: typeof FlipperPlugin): boolean {
|
||||
supportsPlugin(Plugin: ClientPluginDefinition): boolean {
|
||||
return this.plugins.includes(Plugin.id);
|
||||
}
|
||||
|
||||
@@ -393,14 +394,18 @@ export default class Client extends EventEmitter {
|
||||
const bytes = msg.length * 2; // string lengths are measured in UTF-16 units (not characters), so 2 bytes per char
|
||||
emitBytesReceived(params.api, bytes);
|
||||
|
||||
const persistingPlugin:
|
||||
| typeof FlipperPlugin
|
||||
| typeof FlipperDevicePlugin
|
||||
| undefined =
|
||||
const persistingPlugin: PluginDefinition | undefined =
|
||||
this.store.getState().plugins.clientPlugins.get(params.api) ||
|
||||
this.store.getState().plugins.devicePlugins.get(params.api);
|
||||
|
||||
if (persistingPlugin && persistingPlugin.persistedStateReducer) {
|
||||
let handled = false; // This is just for analysis
|
||||
// TODO: support Sandy plugins T68683442
|
||||
if (
|
||||
persistingPlugin &&
|
||||
!(persistingPlugin instanceof SandyPluginDefinition) &&
|
||||
persistingPlugin.persistedStateReducer
|
||||
) {
|
||||
handled = true;
|
||||
const pluginKey = getPluginKey(
|
||||
this.id,
|
||||
{serial: this.query.device_id},
|
||||
@@ -417,17 +422,19 @@ export default class Client extends EventEmitter {
|
||||
this.flushMessageBufferDebounced();
|
||||
}
|
||||
const apiCallbacks = this.broadcastCallbacks.get(params.api);
|
||||
if (!apiCallbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (apiCallbacks) {
|
||||
const methodCallbacks = apiCallbacks.get(params.method);
|
||||
if (methodCallbacks) {
|
||||
for (const callback of methodCallbacks) {
|
||||
handled = true;
|
||||
callback(params.params);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!handled) {
|
||||
console.warn(`Unhandled message ${params.api}.${params.method}`);
|
||||
}
|
||||
}
|
||||
return; // method === 'execute'
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from './plugin';
|
||||
import {FlipperPlugin, FlipperDevicePlugin, PluginDefinition} from './plugin';
|
||||
import {
|
||||
showOpenDialog,
|
||||
startFileExport,
|
||||
@@ -71,7 +71,7 @@ function actionHandler(action: string) {
|
||||
}
|
||||
|
||||
export function setupMenuBar(
|
||||
plugins: Array<typeof FlipperPlugin | typeof FlipperDevicePlugin>,
|
||||
plugins: PluginDefinition[],
|
||||
store: Store,
|
||||
logger: Logger,
|
||||
) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {SearchableProps, FlipperBasePlugin, FlipperPlugin} from 'flipper';
|
||||
import {SearchableProps} from 'flipper';
|
||||
import {Logger} from './fb-interfaces/Logger';
|
||||
import {
|
||||
Searchable,
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
styled,
|
||||
colors,
|
||||
} from 'flipper';
|
||||
import {FlipperDevicePlugin} from './plugin';
|
||||
import {PluginDefinition, DevicePluginMap, ClientPluginMap} from './plugin';
|
||||
import {connect} from 'react-redux';
|
||||
import React, {Component, Fragment} from 'react';
|
||||
import {clipboard} from 'electron';
|
||||
@@ -47,8 +47,8 @@ type StateFromProps = {
|
||||
invalidatedNotifications: Array<PluginNotification>;
|
||||
blacklistedPlugins: Array<string>;
|
||||
blacklistedCategories: Array<string>;
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>;
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||
devicePlugins: DevicePluginMap;
|
||||
clientPlugins: ClientPluginMap;
|
||||
};
|
||||
|
||||
type DispatchFromProps = {
|
||||
@@ -417,7 +417,7 @@ type ItemProps = {
|
||||
deepLinkPayload: string | null;
|
||||
}) => any;
|
||||
logger?: Logger;
|
||||
plugin: typeof FlipperBasePlugin | null | undefined;
|
||||
plugin: PluginDefinition | null | undefined;
|
||||
};
|
||||
|
||||
type ItemState = {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
FlipperPlugin,
|
||||
FlipperDevicePlugin,
|
||||
Props as PluginProps,
|
||||
PluginDefinition,
|
||||
} from './plugin';
|
||||
import {Logger} from './fb-interfaces/Logger';
|
||||
import BaseDevice from './devices/BaseDevice';
|
||||
@@ -45,6 +46,7 @@ import {Message} from './reducers/pluginMessageQueue';
|
||||
import {Idler} from './utils/Idler';
|
||||
import {processMessageQueue} from './utils/messageQueue';
|
||||
import {ToggleButton, SmallText} from './ui';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
const Container = styled(FlexColumn)({
|
||||
width: 0,
|
||||
@@ -95,7 +97,7 @@ type OwnProps = {
|
||||
|
||||
type StateFromProps = {
|
||||
pluginState: Object;
|
||||
activePlugin: typeof FlipperPlugin | typeof FlipperDevicePlugin | null;
|
||||
activePlugin: PluginDefinition | undefined;
|
||||
target: Client | BaseDevice | null;
|
||||
pluginKey: string | null;
|
||||
deepLinkPayload: string | null;
|
||||
@@ -190,6 +192,8 @@ class PluginContainer extends PureComponent<Props, State> {
|
||||
if (
|
||||
pluginIsEnabled &&
|
||||
activePlugin &&
|
||||
// TODO: support sandy: T68683442
|
||||
!(activePlugin instanceof SandyPluginDefinition) &&
|
||||
activePlugin.persistedStateReducer &&
|
||||
pluginKey &&
|
||||
pendingMessages?.length
|
||||
@@ -328,6 +332,10 @@ class PluginContainer extends PureComponent<Props, State> {
|
||||
console.warn(`No selected plugin. Rendering empty!`);
|
||||
return null;
|
||||
}
|
||||
if (activePlugin instanceof SandyPluginDefinition) {
|
||||
// TODO:
|
||||
return null;
|
||||
}
|
||||
const props: PluginProps<Object> & {
|
||||
key: string;
|
||||
ref: (
|
||||
@@ -404,14 +412,11 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
}) => {
|
||||
let pluginKey = null;
|
||||
let target = null;
|
||||
let activePlugin:
|
||||
| typeof FlipperDevicePlugin
|
||||
| typeof FlipperPlugin
|
||||
| null = null;
|
||||
let activePlugin: PluginDefinition | undefined;
|
||||
let pluginIsEnabled = false;
|
||||
|
||||
if (selectedPlugin) {
|
||||
activePlugin = devicePlugins.get(selectedPlugin) || null;
|
||||
activePlugin = devicePlugins.get(selectedPlugin);
|
||||
target = selectedDevice;
|
||||
if (selectedDevice && activePlugin) {
|
||||
pluginKey = getPluginKey(selectedDevice.serial, activePlugin.id);
|
||||
@@ -419,7 +424,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
} else {
|
||||
target =
|
||||
clients.find((client: Client) => client.id === selectedApp) || null;
|
||||
activePlugin = clientPlugins.get(selectedPlugin) || null;
|
||||
activePlugin = clientPlugins.get(selectedPlugin);
|
||||
if (activePlugin && target) {
|
||||
pluginKey = getPluginKey(target.id, activePlugin.id);
|
||||
pluginIsEnabled = pluginIsStarred(
|
||||
|
||||
@@ -20,8 +20,6 @@ import {
|
||||
Glyph,
|
||||
styled,
|
||||
GK,
|
||||
FlipperPlugin,
|
||||
FlipperDevicePlugin,
|
||||
ArchivedDevice,
|
||||
SmallText,
|
||||
Info,
|
||||
@@ -62,8 +60,9 @@ import {
|
||||
getFavoritePlugins,
|
||||
} from './sidebarUtils';
|
||||
import {useLocalStorage} from '../../utils/useLocalStorage';
|
||||
import {PluginDefinition, ClientPluginMap, DevicePluginMap} from '../../plugin';
|
||||
|
||||
type FlipperPlugins = typeof FlipperPlugin[];
|
||||
type FlipperPlugins = PluginDefinition[];
|
||||
type PluginsByCategory = [string, FlipperPlugins][];
|
||||
|
||||
type SectionLevel = 1 | 2 | 3;
|
||||
@@ -184,8 +183,8 @@ type StateFromProps = {
|
||||
deviceId?: string;
|
||||
errorMessage?: string;
|
||||
}>;
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>;
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||
devicePlugins: DevicePluginMap;
|
||||
clientPlugins: ClientPluginMap;
|
||||
};
|
||||
|
||||
type SelectPlugin = (payload: {
|
||||
@@ -469,7 +468,7 @@ const PluginList = memo(function PluginList({
|
||||
}: {
|
||||
client: Client;
|
||||
device: BaseDevice;
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||
clientPlugins: ClientPluginMap;
|
||||
starPlugin: typeof starPluginAction;
|
||||
userStarredPlugins: Store['connections']['userStarredPlugins'];
|
||||
selectedPlugin?: null | string;
|
||||
@@ -497,7 +496,7 @@ const PluginList = memo(function PluginList({
|
||||
);
|
||||
|
||||
const allPlugins = Array.from(clientPlugins.values()).filter(
|
||||
(p: typeof FlipperPlugin) => client.plugins.indexOf(p.id) > -1,
|
||||
(p) => client.plugins.indexOf(p.id) > -1,
|
||||
);
|
||||
const favoritePlugins: FlipperPlugins = getFavoritePlugins(
|
||||
device,
|
||||
|
||||
@@ -14,9 +14,7 @@ import {
|
||||
Text,
|
||||
Glyph,
|
||||
styled,
|
||||
FlipperPlugin,
|
||||
FlexColumn,
|
||||
FlipperBasePlugin,
|
||||
ToggleButton,
|
||||
brandColors,
|
||||
Spacer,
|
||||
@@ -27,8 +25,9 @@ import {
|
||||
} from 'flipper';
|
||||
import {BackgroundColorProperty} from 'csstype';
|
||||
import {getPluginTitle} from '../../utils/pluginUtils';
|
||||
import {PluginDefinition} from '../../plugin';
|
||||
|
||||
export type FlipperPlugins = typeof FlipperPlugin[];
|
||||
export type FlipperPlugins = PluginDefinition[];
|
||||
export type PluginsByCategory = [string, FlipperPlugins][];
|
||||
|
||||
export const ListItem = styled.div<{active?: boolean; disabled?: boolean}>(
|
||||
@@ -133,7 +132,7 @@ export const Plugins = styled(FlexColumn)({
|
||||
export const PluginSidebarListItem: React.FC<{
|
||||
onClick: () => void;
|
||||
isActive: boolean;
|
||||
plugin: typeof FlipperBasePlugin;
|
||||
plugin: PluginDefinition;
|
||||
app?: string | null | undefined;
|
||||
helpRef?: any;
|
||||
provided?: any;
|
||||
|
||||
@@ -12,18 +12,10 @@ import Client from '../../Client';
|
||||
import {TableBodyRow} from '../../ui/components/table/types';
|
||||
import React, {Component, Fragment} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
Text,
|
||||
ManagedTable,
|
||||
styled,
|
||||
colors,
|
||||
Link,
|
||||
FlipperPlugin,
|
||||
FlipperDevicePlugin,
|
||||
Bordered,
|
||||
} from 'flipper';
|
||||
import {Text, ManagedTable, styled, colors, Link, Bordered} from 'flipper';
|
||||
import StatusIndicator from '../../ui/components/StatusIndicator';
|
||||
import {State as Store} from '../../reducers';
|
||||
import {DevicePluginDefinition, ClientPluginDefinition} from '../../plugin';
|
||||
|
||||
const InfoText = styled(Text)({
|
||||
lineHeight: '130%',
|
||||
@@ -51,8 +43,8 @@ type StateFromProps = {
|
||||
failedPlugins: Array<[PluginDetails, string]>;
|
||||
clients: Array<Client>;
|
||||
selectedDevice: string | null | undefined;
|
||||
devicePlugins: Array<typeof FlipperDevicePlugin>;
|
||||
clientPlugins: Array<typeof FlipperPlugin>;
|
||||
devicePlugins: DevicePluginDefinition[];
|
||||
clientPlugins: ClientPluginDefinition[];
|
||||
};
|
||||
|
||||
type DispatchFromProps = {};
|
||||
@@ -299,10 +291,8 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
},
|
||||
connections: {clients, selectedDevice},
|
||||
}) => ({
|
||||
devicePlugins: Array.from<typeof FlipperDevicePlugin>(
|
||||
devicePlugins.values(),
|
||||
),
|
||||
clientPlugins: Array.from<typeof FlipperPlugin>(clientPlugins.values()),
|
||||
devicePlugins: Array.from(devicePlugins.values()),
|
||||
clientPlugins: Array.from(clientPlugins.values()),
|
||||
gatekeepedPlugins,
|
||||
clients,
|
||||
disabledPlugins,
|
||||
|
||||
@@ -162,6 +162,7 @@ test('requirePlugin loads plugin', () => {
|
||||
version: '1.0.0',
|
||||
});
|
||||
expect(plugin).not.toBeNull();
|
||||
// @ts-ignore
|
||||
expect(plugin!.prototype).toBeInstanceOf(FlipperPlugin);
|
||||
expect(plugin!.id).toBe(TestPlugin.id);
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import {Store} from '../reducers/index';
|
||||
import {Logger} from '../fb-interfaces/Logger';
|
||||
import {PluginNotification} from '../reducers/notifications';
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin';
|
||||
import {PluginDefinition} from '../plugin';
|
||||
import isHeadless from '../utils/isHeadless';
|
||||
import {setStaticView, setDeeplinkPayload} from '../reducers/connections';
|
||||
import {ipcRenderer, IpcRendererEvent} from 'electron';
|
||||
@@ -25,6 +25,7 @@ import {deconstructPluginKey} from '../utils/clientUtils';
|
||||
import NotificationScreen from '../chrome/NotificationScreen';
|
||||
import {getPluginTitle} from '../utils/pluginUtils';
|
||||
import {sideEffect} from '../utils/sideEffect';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
type NotificationEvents = 'show' | 'click' | 'close' | 'reply' | 'action';
|
||||
const NOTIFICATION_THROTTLE = 5 * 1000; // in milliseconds
|
||||
@@ -110,11 +111,15 @@ export default (store: Store, logger: Logger) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const persistingPlugin:
|
||||
| undefined
|
||||
| typeof FlipperPlugin
|
||||
| typeof FlipperDevicePlugin = getPlugin(pluginName);
|
||||
if (persistingPlugin && persistingPlugin.getActiveNotifications) {
|
||||
const persistingPlugin: undefined | PluginDefinition = getPlugin(
|
||||
pluginName,
|
||||
);
|
||||
// TODO: add support for Sandy plugins T68683442
|
||||
if (
|
||||
persistingPlugin &&
|
||||
!(persistingPlugin instanceof SandyPluginDefinition) &&
|
||||
persistingPlugin.getActiveNotifications
|
||||
) {
|
||||
try {
|
||||
const notifications = persistingPlugin.getActiveNotifications(
|
||||
pluginStates[key],
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
import {Store} from '../reducers/index';
|
||||
import {Logger} from '../fb-interfaces/Logger';
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin';
|
||||
import {PluginDefinition} from '../plugin';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import adbkit from 'adbkit';
|
||||
@@ -58,9 +58,10 @@ export default (store: Store, logger: Logger) => {
|
||||
|
||||
const defaultPluginsIndex = getPluginIndex();
|
||||
|
||||
const initialPlugins: Array<
|
||||
typeof FlipperPlugin | typeof FlipperDevicePlugin
|
||||
> = filterNewestVersionOfEachPlugin(getBundledPlugins(), getDynamicPlugins())
|
||||
const initialPlugins: PluginDefinition[] = filterNewestVersionOfEachPlugin(
|
||||
getBundledPlugins(),
|
||||
getDynamicPlugins(),
|
||||
)
|
||||
.map(reportVersion)
|
||||
.filter(checkDisabled(disabledPlugins))
|
||||
.filter(checkGK(gatekeepedPlugins))
|
||||
@@ -247,9 +248,7 @@ export const requirePlugin = (
|
||||
defaultPluginsIndex: any,
|
||||
reqFn: Function = global.electronRequire,
|
||||
) => {
|
||||
return (
|
||||
pluginDetails: PluginDetails,
|
||||
): typeof FlipperPlugin | typeof FlipperDevicePlugin | null => {
|
||||
return (pluginDetails: PluginDetails): PluginDefinition | null => {
|
||||
try {
|
||||
return tryCatchReportPluginFailures(
|
||||
() => requirePluginInternal(pluginDetails, defaultPluginsIndex, reqFn),
|
||||
@@ -281,6 +280,7 @@ const requirePluginInternal = (
|
||||
|
||||
plugin.id = plugin.id || pluginDetails.id;
|
||||
plugin.packageName = pluginDetails.name;
|
||||
plugin.flipperSDKVersion = pluginDetails.flipperSDKVersion;
|
||||
plugin.details = pluginDetails;
|
||||
|
||||
// set values from package.json as static variables on class
|
||||
|
||||
@@ -22,8 +22,21 @@ import {State as ReduxState} from './reducers';
|
||||
import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue';
|
||||
import {PluginDetails} from 'flipper-plugin-lib';
|
||||
import {Settings} from './reducers/settings';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
type Parameters = {[key: string]: any};
|
||||
|
||||
export type PluginDefinition = ClientPluginDefinition | DevicePluginDefinition;
|
||||
|
||||
// TODO: T68738317 add SandyPluginDefinition
|
||||
export type DevicePluginDefinition = typeof FlipperDevicePlugin;
|
||||
|
||||
export type ClientPluginDefinition =
|
||||
| typeof FlipperPlugin
|
||||
| SandyPluginDefinition;
|
||||
|
||||
export type ClientPluginMap = Map<string, ClientPluginDefinition>;
|
||||
export type DevicePluginMap = Map<string, DevicePluginDefinition>;
|
||||
|
||||
// This function is intended to be called from outside of the plugin.
|
||||
// If you want to `call` from the plugin use, this.client.call
|
||||
export function callClient(
|
||||
@@ -100,6 +113,7 @@ export abstract class FlipperBasePlugin<
|
||||
static category: string | null = null;
|
||||
static id: string = '';
|
||||
static packageName: string = '';
|
||||
static flipperSDKVersion: string | undefined = undefined;
|
||||
static version: string = '';
|
||||
static icon: string | null = null;
|
||||
static gatekeeper: string | null = null;
|
||||
@@ -113,7 +127,7 @@ export abstract class FlipperBasePlugin<
|
||||
static maxQueueSize: number = DEFAULT_MAX_QUEUE_SIZE;
|
||||
static metricsReducer:
|
||||
| ((persistedState: StaticPersistedState) => Promise<MetricType>)
|
||||
| null;
|
||||
| undefined;
|
||||
static exportPersistedState:
|
||||
| ((
|
||||
callClient: (method: string, params?: any) => Promise<any>,
|
||||
@@ -123,10 +137,10 @@ export abstract class FlipperBasePlugin<
|
||||
statusUpdate?: (msg: string) => void,
|
||||
supportsMethod?: (method: string) => Promise<boolean>,
|
||||
) => Promise<StaticPersistedState | undefined>)
|
||||
| null;
|
||||
| undefined;
|
||||
static getActiveNotifications:
|
||||
| ((persistedState: StaticPersistedState) => Array<Notification>)
|
||||
| null;
|
||||
| undefined;
|
||||
static onRegisterDevice:
|
||||
| ((
|
||||
store: Store,
|
||||
|
||||
@@ -14,7 +14,6 @@ import MacDevice from '../devices/MacDevice';
|
||||
import Client from '../Client';
|
||||
import {UninitializedClient} from '../UninitializedClient';
|
||||
import {isEqual} from 'lodash';
|
||||
import iosUtil from '../utils/iOSContainerUtility';
|
||||
import {performance} from 'perf_hooks';
|
||||
import isHeadless from '../utils/isHeadless';
|
||||
import {Actions} from '.';
|
||||
@@ -31,6 +30,7 @@ import {
|
||||
import {deconstructClientId} from '../utils/clientUtils';
|
||||
import {FlipperDevicePlugin} from '../plugin';
|
||||
import {RegisterPluginAction} from './plugins';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
export type StaticView =
|
||||
| null
|
||||
@@ -423,7 +423,11 @@ export default (state: State = INITAL_STATE, action: Actions): State => {
|
||||
// plugins are registered after creating the base devices, so update them
|
||||
const plugins = action.payload;
|
||||
plugins.forEach((plugin) => {
|
||||
if (plugin.prototype instanceof FlipperDevicePlugin) {
|
||||
// TODO: T68738317 support sandy device plugin
|
||||
if (
|
||||
!(plugin instanceof SandyPluginDefinition) &&
|
||||
plugin.prototype instanceof FlipperDevicePlugin
|
||||
) {
|
||||
// smell: devices are mutable
|
||||
state.devices.forEach((device) => {
|
||||
// @ts-ignore
|
||||
|
||||
@@ -7,25 +7,24 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin';
|
||||
import {DevicePluginMap, ClientPluginMap, PluginDefinition} from '../plugin';
|
||||
import {PluginDetails} from 'flipper-plugin-lib';
|
||||
import {Actions} from '.';
|
||||
import produce from 'immer';
|
||||
import {isDevicePluginDefinition} from '../utils/pluginUtils';
|
||||
|
||||
export type State = {
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>;
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||
devicePlugins: DevicePluginMap;
|
||||
clientPlugins: ClientPluginMap;
|
||||
gatekeepedPlugins: Array<PluginDetails>;
|
||||
disabledPlugins: Array<PluginDetails>;
|
||||
failedPlugins: Array<[PluginDetails, string]>;
|
||||
selectedPlugins: Array<string>;
|
||||
};
|
||||
|
||||
type PluginClass = typeof FlipperPlugin | typeof FlipperDevicePlugin;
|
||||
|
||||
export type RegisterPluginAction = {
|
||||
type: 'REGISTER_PLUGINS';
|
||||
payload: Array<PluginClass>;
|
||||
payload: PluginDefinition[];
|
||||
};
|
||||
|
||||
export type Action =
|
||||
@@ -63,16 +62,14 @@ export default function reducer(
|
||||
if (action.type === 'REGISTER_PLUGINS') {
|
||||
return produce(state, (draft) => {
|
||||
const {devicePlugins, clientPlugins} = draft;
|
||||
action.payload.forEach((p: PluginClass) => {
|
||||
action.payload.forEach((p) => {
|
||||
if (devicePlugins.has(p.id) || clientPlugins.has(p.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p.prototype instanceof FlipperDevicePlugin) {
|
||||
// @ts-ignore doesn't know p must be typeof FlipperDevicePlugin here
|
||||
if (isDevicePluginDefinition(p)) {
|
||||
devicePlugins.set(p.id, p);
|
||||
} else if (p.prototype instanceof FlipperPlugin) {
|
||||
// @ts-ignore doesn't know p must be typeof FlipperPlugin here
|
||||
} else {
|
||||
clientPlugins.set(p.id, p);
|
||||
}
|
||||
});
|
||||
@@ -107,7 +104,7 @@ export const selectedPlugins = (payload: Array<string>): Action => ({
|
||||
payload,
|
||||
});
|
||||
|
||||
export const registerPlugins = (payload: Array<PluginClass>): Action => ({
|
||||
export const registerPlugins = (payload: PluginDefinition[]): Action => ({
|
||||
type: 'REGISTER_PLUGINS',
|
||||
payload,
|
||||
});
|
||||
|
||||
@@ -20,10 +20,12 @@ import Client, {ClientExport, ClientQuery} from '../Client';
|
||||
import {pluginKey} from '../reducers/pluginStates';
|
||||
import {
|
||||
FlipperDevicePlugin,
|
||||
FlipperPlugin,
|
||||
callClient,
|
||||
supportsMethod,
|
||||
FlipperBasePlugin,
|
||||
PluginDefinition,
|
||||
DevicePluginMap,
|
||||
ClientPluginMap,
|
||||
} from '../plugin';
|
||||
import {default as BaseDevice} from '../devices/BaseDevice';
|
||||
import {default as ArchivedDevice} from '../devices/ArchivedDevice';
|
||||
@@ -47,6 +49,7 @@ import {processMessageQueue} from './messageQueue';
|
||||
import {getPluginTitle} from './pluginUtils';
|
||||
import {capture} from './screenshot';
|
||||
import {uploadFlipperMedia} from '../fb-stubs/user';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace';
|
||||
export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace';
|
||||
@@ -93,7 +96,7 @@ type PluginsToProcess = {
|
||||
pluginKey: string;
|
||||
pluginId: string;
|
||||
pluginName: string;
|
||||
pluginClass: typeof FlipperPlugin | typeof FlipperDevicePlugin;
|
||||
pluginClass: PluginDefinition;
|
||||
client: Client;
|
||||
}[];
|
||||
|
||||
@@ -212,14 +215,17 @@ export function processNotificationStates(
|
||||
|
||||
const serializePluginStates = async (
|
||||
pluginStates: PluginStatesState,
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>,
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>,
|
||||
clientPlugins: ClientPluginMap,
|
||||
devicePlugins: DevicePluginMap,
|
||||
statusUpdate?: (msg: string) => void,
|
||||
idler?: Idler,
|
||||
): Promise<PluginStatesExportState> => {
|
||||
const pluginsMap: Map<string, typeof FlipperBasePlugin> = new Map([]);
|
||||
clientPlugins.forEach((val, key) => {
|
||||
// TODO: Support Sandy T68683449 and use ClientPluginsMap
|
||||
if (!(val instanceof SandyPluginDefinition)) {
|
||||
pluginsMap.set(key, val);
|
||||
}
|
||||
});
|
||||
devicePlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
@@ -248,12 +254,13 @@ const serializePluginStates = async (
|
||||
|
||||
const deserializePluginStates = (
|
||||
pluginStatesExportState: PluginStatesExportState,
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>,
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>,
|
||||
clientPlugins: ClientPluginMap,
|
||||
devicePlugins: DevicePluginMap,
|
||||
): PluginStatesState => {
|
||||
const pluginsMap: Map<string, typeof FlipperBasePlugin> = new Map([]);
|
||||
clientPlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
// TODO: Support Sandy T68683449
|
||||
if (!(val instanceof SandyPluginDefinition)) pluginsMap.set(key, val);
|
||||
});
|
||||
devicePlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
@@ -358,8 +365,8 @@ type ProcessStoreOptions = {
|
||||
device: BaseDevice | null;
|
||||
pluginStates: PluginStatesState;
|
||||
clients: Array<ClientExport>;
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>;
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>;
|
||||
devicePlugins: DevicePluginMap;
|
||||
clientPlugins: ClientPluginMap;
|
||||
salt: string;
|
||||
selectedPlugins: Array<string>;
|
||||
statusUpdate?: (msg: string) => void;
|
||||
@@ -514,7 +521,11 @@ async function processQueues(
|
||||
pluginKey,
|
||||
pluginClass,
|
||||
} of pluginsToProcess) {
|
||||
if (pluginClass.persistedStateReducer) {
|
||||
// TODO: Support Sandy T68683449
|
||||
if (
|
||||
!(pluginClass instanceof SandyPluginDefinition) &&
|
||||
pluginClass.persistedStateReducer
|
||||
) {
|
||||
const processQueueMarker = `${EXPORT_FLIPPER_TRACE_EVENT}:process-queue-per-plugin`;
|
||||
performance.mark(processQueueMarker);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from 'flipper';
|
||||
import {serialize} from './serialization';
|
||||
import {State as PluginStatesState} from '../reducers/pluginStates';
|
||||
import {Store} from '../reducers';
|
||||
@@ -20,6 +19,8 @@ import {
|
||||
import {deserializeObject} from './serialization';
|
||||
import {deconstructPluginKey} from './clientUtils';
|
||||
import {pluginsClassMap} from './pluginUtils';
|
||||
import {PluginDefinition} from '../plugin';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
export type MetricType = {[metricName: string]: number};
|
||||
type MetricPluginType = {[pluginID: string]: MetricType};
|
||||
@@ -27,7 +28,7 @@ export type ExportMetricType = {[clientID: string]: MetricPluginType};
|
||||
|
||||
async function exportMetrics(
|
||||
pluginStates: PluginStatesState,
|
||||
pluginsMap: Map<string, typeof FlipperDevicePlugin | typeof FlipperPlugin>,
|
||||
pluginsMap: Map<string, PluginDefinition>,
|
||||
selectedPlugins: Array<string>,
|
||||
): Promise<string> {
|
||||
const metrics: ExportMetricType = {};
|
||||
@@ -46,8 +47,10 @@ async function exportMetrics(
|
||||
const pluginClass = pluginsMap.get(pluginName);
|
||||
const metricsReducer:
|
||||
| (<U>(persistedState: U) => Promise<MetricType>)
|
||||
| null
|
||||
| undefined = pluginClass && pluginClass.metricsReducer;
|
||||
| undefined =
|
||||
pluginClass && !(pluginClass instanceof SandyPluginDefinition)
|
||||
? pluginClass.metricsReducer
|
||||
: undefined;
|
||||
if (pluginsMap.has(pluginName) && metricsReducer) {
|
||||
const metricsObject = await metricsReducer(pluginStateData);
|
||||
const pluginObject: MetricPluginType = {};
|
||||
@@ -67,10 +70,7 @@ export async function exportMetricsWithoutTrace(
|
||||
store: Store,
|
||||
pluginStates: PluginStatesState,
|
||||
): Promise<string | null> {
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
||||
> = pluginsClassMap(store.getState().plugins);
|
||||
const pluginsMap = pluginsClassMap(store.getState().plugins);
|
||||
const {clients, selectedDevice} = store.getState().connections;
|
||||
const pluginsToProcess = determinePluginsToProcess(
|
||||
clients,
|
||||
@@ -107,7 +107,7 @@ function parseJSON(str: string): any {
|
||||
|
||||
export async function exportMetricsFromTrace(
|
||||
trace: string,
|
||||
pluginsMap: Map<string, typeof FlipperDevicePlugin | typeof FlipperPlugin>,
|
||||
pluginsMap: Map<string, PluginDefinition>,
|
||||
selectedPlugins: Array<string>,
|
||||
): Promise<string> {
|
||||
const data = fs.readFileSync(trace, 'utf8');
|
||||
@@ -136,5 +136,6 @@ export async function exportMetricsFromTrace(
|
||||
),
|
||||
);
|
||||
}
|
||||
// TODO: Support Sandy T68683449 and use ClientPluginsMap, or kill feature
|
||||
return await exportMetrics(pluginStates, pluginsMap, selectedPlugins);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import {pluginIsStarred, getSelectedPluginKey} from '../reducers/connections';
|
||||
import {deconstructPluginKey} from './clientUtils';
|
||||
import {onBytesReceived} from '../dispatcher/tracking';
|
||||
import {defaultEnabledBackgroundPlugins} from './pluginUtils';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
const MAX_BACKGROUND_TASK_TIME = 25;
|
||||
|
||||
@@ -189,14 +190,22 @@ export function processMessagesImmediately(
|
||||
export function processMessagesLater(
|
||||
store: MiddlewareAPI,
|
||||
pluginKey: string,
|
||||
plugin: {
|
||||
plugin:
|
||||
| {
|
||||
defaultPersistedState: any;
|
||||
id: string;
|
||||
persistedStateReducer: PersistedStateReducer | null;
|
||||
maxQueueSize?: number;
|
||||
},
|
||||
}
|
||||
| SandyPluginDefinition,
|
||||
messages: Message[],
|
||||
) {
|
||||
if (plugin instanceof SandyPluginDefinition) {
|
||||
// TODO:
|
||||
throw new Error(
|
||||
'Receiving messages is not yet supported for Sandy plugins',
|
||||
);
|
||||
}
|
||||
const isSelected =
|
||||
pluginKey === getSelectedPluginKey(store.getState().connections);
|
||||
switch (true) {
|
||||
|
||||
@@ -8,21 +8,21 @@
|
||||
*/
|
||||
|
||||
import {Store} from '../reducers/index';
|
||||
import {FlipperPlugin, FlipperDevicePlugin} from '../plugin';
|
||||
import {ClientPluginMap, DevicePluginMap, PluginDefinition} from '../plugin';
|
||||
import {setPluginState} from '../reducers/pluginStates';
|
||||
import BaseDevice from '../devices/BaseDevice';
|
||||
import {getPersistedState} from '../utils/pluginUtils';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
export function registerDeviceCallbackOnPlugins(
|
||||
store: Store,
|
||||
devicePlugins: Map<string, typeof FlipperDevicePlugin>,
|
||||
clientPlugins: Map<string, typeof FlipperPlugin>,
|
||||
devicePlugins: DevicePluginMap,
|
||||
clientPlugins: ClientPluginMap,
|
||||
device: BaseDevice,
|
||||
) {
|
||||
const callRegisterDeviceHook = (
|
||||
plugin: typeof FlipperDevicePlugin | typeof FlipperPlugin,
|
||||
) => {
|
||||
if (plugin.onRegisterDevice) {
|
||||
const callRegisterDeviceHook = (plugin: PluginDefinition) => {
|
||||
// This hook is not registered for Sandy plugins, let's see in the future if it is needed
|
||||
if (!(plugin instanceof SandyPluginDefinition) && plugin.onRegisterDevice) {
|
||||
plugin.onRegisterDevice(
|
||||
store,
|
||||
device,
|
||||
|
||||
@@ -12,6 +12,7 @@ import fs from 'fs';
|
||||
import {Store, State} from '../reducers';
|
||||
import {getPluginKey} from './pluginUtils';
|
||||
import {serialize} from './serialization';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
let pluginRecordingState: {
|
||||
recording: string;
|
||||
@@ -67,7 +68,10 @@ async function flipperStartPluginRecording(state: State) {
|
||||
// Note that we don't use the plugin's own serializeState, as that might interact with the
|
||||
// device state, and is used for creating Flipper Exports.
|
||||
pluginRecordingState.startState = await serialize(
|
||||
state.pluginStates[pluginKey] || plugin.defaultPersistedState,
|
||||
state.pluginStates[pluginKey] ||
|
||||
(plugin instanceof SandyPluginDefinition
|
||||
? {}
|
||||
: plugin.defaultPersistedState),
|
||||
);
|
||||
|
||||
console.log(
|
||||
|
||||
@@ -7,12 +7,18 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {FlipperDevicePlugin, FlipperPlugin, FlipperBasePlugin} from '../plugin';
|
||||
import {
|
||||
FlipperDevicePlugin,
|
||||
FlipperBasePlugin,
|
||||
PluginDefinition,
|
||||
DevicePluginDefinition,
|
||||
} from '../plugin';
|
||||
import {State as PluginStatesState} from '../reducers/pluginStates';
|
||||
import {State as PluginsState} from '../reducers/plugins';
|
||||
import {State as PluginMessageQueueState} from '../reducers/pluginMessageQueue';
|
||||
import {PluginDetails} from 'flipper-plugin-lib';
|
||||
import {deconstructPluginKey, deconstructClientId} from './clientUtils';
|
||||
import {SandyPluginDefinition} from 'flipper-plugin';
|
||||
|
||||
type Client = import('../Client').default;
|
||||
|
||||
@@ -20,11 +26,8 @@ export const defaultEnabledBackgroundPlugins = ['Navigation']; // The navigation
|
||||
|
||||
export function pluginsClassMap(
|
||||
plugins: PluginsState,
|
||||
): Map<string, typeof FlipperDevicePlugin | typeof FlipperPlugin> {
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
||||
> = new Map([]);
|
||||
): Map<string, PluginDefinition> {
|
||||
const pluginsMap: Map<string, PluginDefinition> = new Map([]);
|
||||
plugins.clientPlugins.forEach((val, key) => {
|
||||
pluginsMap.set(key, val);
|
||||
});
|
||||
@@ -83,10 +86,7 @@ export function getEnabledOrExportPersistedStatePlugins(
|
||||
plugins: PluginsState,
|
||||
): Array<{id: string; label: string}> {
|
||||
const appName = deconstructClientId(client.id).app;
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
||||
> = pluginsClassMap(plugins);
|
||||
const pluginsMap: Map<string, PluginDefinition> = pluginsClassMap(plugins);
|
||||
// Enabled Plugins with no exportPersistedState function defined
|
||||
const enabledPlugins = starredPlugin[appName]
|
||||
? starredPlugin[appName]
|
||||
@@ -141,10 +141,7 @@ export function getActivePersistentPlugins(
|
||||
plugins: PluginsState,
|
||||
selectedClient?: Client,
|
||||
): {id: string; label: string}[] {
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
||||
> = pluginsClassMap(plugins);
|
||||
const pluginsMap: Map<string, PluginDefinition> = pluginsClassMap(plugins);
|
||||
return getPersistentPlugins(plugins)
|
||||
.map((pluginName) => pluginsMap.get(pluginName)!)
|
||||
.sort(sortPluginsByName)
|
||||
@@ -183,10 +180,7 @@ export function getActivePersistentPlugins(
|
||||
}
|
||||
|
||||
export function getPersistentPlugins(plugins: PluginsState): Array<string> {
|
||||
const pluginsMap: Map<
|
||||
string,
|
||||
typeof FlipperDevicePlugin | typeof FlipperPlugin
|
||||
> = pluginsClassMap(plugins);
|
||||
const pluginsMap: Map<string, PluginDefinition> = pluginsClassMap(plugins);
|
||||
|
||||
const arr: Array<PluginDetails> = plugins.disabledPlugins.concat(
|
||||
plugins.gatekeepedPlugins,
|
||||
@@ -210,32 +204,36 @@ export function getPersistentPlugins(plugins: PluginsState): Array<string> {
|
||||
return (
|
||||
plugin == 'DeviceLogs' ||
|
||||
(pluginClass &&
|
||||
// TODO: support Sandy plugin T68683449
|
||||
!(pluginClass instanceof SandyPluginDefinition) &&
|
||||
(pluginClass.defaultPersistedState != undefined ||
|
||||
pluginClass.exportPersistedState != undefined))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function getPluginTitle(pluginClass: typeof FlipperBasePlugin) {
|
||||
export function getPluginTitle(pluginClass: PluginDefinition) {
|
||||
return pluginClass.title || pluginClass.id;
|
||||
}
|
||||
|
||||
export function sortPluginsByName(
|
||||
a: typeof FlipperBasePlugin,
|
||||
b: typeof FlipperBasePlugin,
|
||||
a: PluginDefinition,
|
||||
b: PluginDefinition,
|
||||
): number {
|
||||
// make sure Device plugins are sorted before normal plugins
|
||||
if (
|
||||
a.prototype instanceof FlipperDevicePlugin &&
|
||||
!(b.prototype instanceof FlipperDevicePlugin)
|
||||
) {
|
||||
if (isDevicePluginDefinition(a) && !isDevicePluginDefinition(b)) {
|
||||
return -1;
|
||||
}
|
||||
if (
|
||||
b.prototype instanceof FlipperDevicePlugin &&
|
||||
!(a.prototype instanceof FlipperDevicePlugin)
|
||||
) {
|
||||
if (isDevicePluginDefinition(b) && !isDevicePluginDefinition(a)) {
|
||||
return 1;
|
||||
}
|
||||
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
|
||||
}
|
||||
|
||||
export function isDevicePluginDefinition(
|
||||
definition: PluginDefinition,
|
||||
): definition is DevicePluginDefinition {
|
||||
// TODO: support Sandy device plugins T68738317
|
||||
// @ts-ignore
|
||||
return definition.prototype instanceof FlipperDevicePlugin;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,4 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
export function hello() {
|
||||
return 'universe ';
|
||||
}
|
||||
export * from './plugin/Plugin';
|
||||
|
||||
133
desktop/flipper-plugin/src/plugin/Plugin.tsx
Normal file
133
desktop/flipper-plugin/src/plugin/Plugin.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* 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 {PluginDetails} from 'flipper-plugin-lib';
|
||||
|
||||
type EventsContract = Record<string, any>;
|
||||
type MethodsContract = Record<string, (params: any) => Promise<any>>;
|
||||
|
||||
/**
|
||||
* API available to a plugin factory
|
||||
*/
|
||||
export interface FlipperClient<
|
||||
Events extends EventsContract,
|
||||
Methods extends MethodsContract
|
||||
> {}
|
||||
|
||||
/**
|
||||
* Internal API exposed by Flipper, and wrapped by FlipperPluginInstance to be passed to the
|
||||
* Plugin Factory
|
||||
*/
|
||||
interface RealFlipperClient {}
|
||||
|
||||
export type FlipperPluginFactory<
|
||||
Events extends EventsContract,
|
||||
Methods extends MethodsContract
|
||||
> = (client: FlipperClient<Events, Methods>) => object;
|
||||
|
||||
export type FlipperPluginComponent = React.FC<{}>;
|
||||
|
||||
export type FlipperPluginModule = {
|
||||
/** the factory function that initializes a plugin instance */
|
||||
plugin: FlipperPluginFactory<any, any>;
|
||||
/** the component type that can render this plugin */
|
||||
Component: FlipperPluginComponent;
|
||||
// TODO: support device plugins T68738317
|
||||
// devicePlugin: FlipperPluginFactory
|
||||
};
|
||||
|
||||
export class FlipperPluginInstance {
|
||||
/** base client provided by Flipper */
|
||||
realClient: RealFlipperClient;
|
||||
/** client that is bound to this instance */
|
||||
client: FlipperClient<any, any>;
|
||||
/** the original plugin definition */
|
||||
definition: FlipperPluginModule;
|
||||
/** the plugin instance api as used inside components and such */
|
||||
instanceApi: object;
|
||||
|
||||
constructor(realClient: RealFlipperClient, definition: FlipperPluginModule) {
|
||||
this.realClient = realClient;
|
||||
this.definition = definition;
|
||||
this.client = {};
|
||||
this.instanceApi = definition.plugin(this.client);
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
|
||||
export class SandyPluginDefinition {
|
||||
id: string;
|
||||
module: FlipperPluginModule;
|
||||
details: PluginDetails;
|
||||
|
||||
// TODO: Implement T68683449
|
||||
exportPersistedState:
|
||||
| ((
|
||||
callClient: (method: string, params?: any) => Promise<any>,
|
||||
persistedState: any, // TODO: type StaticPersistedState | undefined,
|
||||
store: any, // TODO: ReduxState | undefined,
|
||||
idler?: any, // TODO: Idler,
|
||||
statusUpdate?: (msg: string) => void,
|
||||
supportsMethod?: (method: string) => Promise<boolean>,
|
||||
) => Promise<any /* TODO: StaticPersistedState | undefined */>)
|
||||
| undefined = undefined;
|
||||
|
||||
constructor(details: PluginDetails, module: FlipperPluginModule) {
|
||||
this.id = details.id;
|
||||
this.details = details;
|
||||
if (!module.plugin || typeof module.plugin !== 'function') {
|
||||
throw new Error(
|
||||
`Sandy plugin ${this.id} doesn't export a named function called 'plugin'`,
|
||||
);
|
||||
}
|
||||
if (!module.Component || typeof module.Component !== 'function') {
|
||||
throw new Error(
|
||||
`Sandy plugin ${this.id} doesn't export a named function called 'Component'`,
|
||||
);
|
||||
}
|
||||
this.module = module;
|
||||
this.module.Component.displayName = `FlipperPlugin(${this.id})`;
|
||||
}
|
||||
|
||||
get packageName() {
|
||||
return this.details.name;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.details.title;
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this.details.icon;
|
||||
}
|
||||
|
||||
get category() {
|
||||
return this.details.category;
|
||||
}
|
||||
|
||||
get gatekeeper() {
|
||||
return this.details.gatekeeper;
|
||||
}
|
||||
|
||||
get version() {
|
||||
return this.details.version;
|
||||
}
|
||||
|
||||
get isDefault() {
|
||||
return this.details.isDefault;
|
||||
}
|
||||
|
||||
get keyboardActions() {
|
||||
// TODO: T68882551 support keyboard actions
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,7 @@
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/__tests__/*"
|
||||
]
|
||||
"references": [{"path": "../plugin-lib"}],
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user