Introduce showNotification API

Summary: Introduced `showNotifcation` to the Sandy API.

Reviewed By: jknoxville

Differential Revision: D27012001

fbshipit-source-id: d3f237910a478400b0f925f0362af485c96072bb
This commit is contained in:
Michel Weststrate
2021-03-16 14:54:53 -07:00
committed by Facebook GitHub Bot
parent 2ca52f81d2
commit 4e2383cdb0
14 changed files with 92 additions and 21 deletions

View File

@@ -28,7 +28,6 @@ export {
FlipperPlugin,
FlipperDevicePlugin,
callClient,
Notification,
BaseAction,
} from './plugin';
export {PluginClient, Props} from './plugin';
@@ -42,7 +41,7 @@ export {connect} from 'react-redux';
export {selectPlugin, StaticView} from './reducers/connections';
export {writeBufferToFile, bufferToBlob} from './utils/screenshot';
export {getPluginKey, getPersistedState} from './utils/pluginUtils';
export {Idler} from 'flipper-plugin';
export {Idler, Notification} from 'flipper-plugin';
export {Store, MiddlewareAPI, State as ReduxState} from './reducers/index';
export {default as BaseDevice} from './devices/BaseDevice';
export {DeviceLogEntry, LogLevel, DeviceLogListener} from 'flipper-plugin';

View File

@@ -11,7 +11,7 @@ import {KeyboardActions} from './MenuBar';
import {Logger} from './fb-interfaces/Logger';
import Client from './Client';
import {Store} from './reducers/index';
import {ReactNode, Component} from 'react';
import {Component} from 'react';
import BaseDevice from './devices/BaseDevice';
import {serialize, deserialize} from './utils/serialization';
import {StaticView} from './reducers/connections';
@@ -19,7 +19,7 @@ import {State as ReduxState} from './reducers';
import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue';
import {ActivatablePluginDetails} from 'flipper-plugin-lib';
import {Settings} from './reducers/settings';
import {Idler, _SandyPluginDefinition} from 'flipper-plugin';
import {Notification, Idler, _SandyPluginDefinition} from 'flipper-plugin';
type Parameters = {[key: string]: any};
@@ -68,16 +68,6 @@ export interface PluginClient {
type PluginTarget = BaseDevice | Client;
export type Notification = {
id: string;
title: string;
message: string | ReactNode;
severity: 'warning' | 'error';
timestamp?: number;
category?: string;
action?: string;
};
export type Props<T> = {
logger: Logger;
persistedState: T;

View File

@@ -17,7 +17,7 @@ import {
updateCategoryBlocklist,
} from '../notifications';
import {Notification} from '../../plugin';
import {Notification} from 'flipper-plugin';
const notification: Notification = {
id: 'id',

View File

@@ -7,9 +7,10 @@
* @format
*/
import {Notification} from '../plugin';
import {Notification} from 'flipper-plugin';
import {Actions} from './';
import {getStringFromErrorLike} from '../utils';
export type PluginNotification = {
notification: Notification;
pluginId: string;

View File

@@ -8,7 +8,7 @@
*/
import React, {useCallback, useMemo, useState} from 'react';
import {Layout, theme} from 'flipper-plugin';
import {Layout, theme, Notification as NotificationData} from 'flipper-plugin';
import {styled, Glyph} from '../../ui';
import {Input, Typography, Button, Collapse, Dropdown, Menu} from 'antd';
import {
@@ -20,7 +20,6 @@ import {
EllipsisOutlined,
} from '@ant-design/icons';
import {LeftSidebar, SidebarTitle} from '../LeftSidebar';
import {Notification as NotificationData} from '../../plugin';
import {useStore, useDispatch} from '../../utils/useStore';
import {ClientQuery} from '../../Client';
import {deconstructClientId} from '../../utils/clientUtils';

View File

@@ -18,11 +18,11 @@ import {
importDataToStore,
} from '../exportData';
import {FlipperPlugin, FlipperDevicePlugin} from '../../plugin';
import {Notification} from '../../plugin';
import {default as Client, ClientExport} from '../../Client';
import {selectedPlugins, State as PluginsState} from '../../reducers/plugins';
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
import {
Notification,
TestUtils,
_SandyPluginDefinition,
createState,

View File

@@ -15,6 +15,8 @@ import GK from '../fb-stubs/GK';
import type BaseDevice from '../devices/BaseDevice';
import {clipboard} from 'electron';
import constants from '../fb-stubs/constants';
import {addNotification} from '../reducers/notifications';
import {deconstructPluginKey} from './clientUtils';
export function initializeFlipperLibImplementation(
store: Store,
@@ -71,5 +73,15 @@ export function initializeFlipperLibImplementation(
writeTextToClipboard(text: string) {
clipboard.writeText(text);
},
showNotification(pluginId, notification) {
const parts = deconstructPluginKey(pluginId);
store.dispatch(
addNotification({
pluginId: parts.pluginName,
client: parts.client,
notification,
}),
);
},
});
}

View File

@@ -72,6 +72,7 @@ test('Correct top level API exposed', () => {
"Logger",
"MenuEntry",
"NormalizedMenuEntry",
"Notification",
"PluginClient",
"TrackType",
]

View File

@@ -46,6 +46,7 @@ export {
buildInMenuEntries as _buildInMenuEntries,
DefaultKeyboardAction,
} from './plugin/MenuEntry';
export {Notification} from './plugin/Notification';
export {theme} from './ui/theme';
export {Layout} from './ui/Layout';

View File

@@ -11,6 +11,7 @@ import {Logger} from '../utils/Logger';
import {RealFlipperDevice} from './DevicePlugin';
import {NormalizedMenuEntry} from './MenuEntry';
import {RealFlipperClient} from './Plugin';
import {Notification} from './Notification';
/**
* This interface exposes all global methods for which an implementation will be provided by Flipper itself
@@ -33,6 +34,7 @@ export interface FlipperLib {
deeplink: unknown,
): void;
writeTextToClipboard(text: string): void;
showNotification(pluginKey: string, notification: Notification): void;
}
let flipperLibInstance: FlipperLib | undefined;

View File

@@ -0,0 +1,19 @@
/**
* 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
*/
export type Notification = {
id: string;
title: string;
message: string | React.ReactNode;
severity: 'warning' | 'error';
timestamp?: number;
category?: string;
/** The action will be available as deeplink payload when the notification is clicked. */
action?: string;
};

View File

@@ -7,14 +7,15 @@
* @format
*/
import {SandyPluginDefinition} from './SandyPluginDefinition';
import {message} from 'antd';
import {EventEmitter} from 'events';
import {SandyPluginDefinition} from './SandyPluginDefinition';
import {MenuEntry, NormalizedMenuEntry, normalizeMenuEntry} from './MenuEntry';
import {FlipperLib} from './FlipperLib';
import {Device, RealFlipperDevice} from './DevicePlugin';
import {batched} from '../state/batch';
import {Idler} from '../utils/Idler';
import {message} from 'antd';
import {Notification} from './Notification';
type StateExportHandler<T = any> = (
idler: Idler,
@@ -23,6 +24,9 @@ type StateExportHandler<T = any> = (
type StateImportHandler<T = any> = (data: T) => void;
export interface BasePluginClient {
/**
* A key that uniquely identifies this plugin instance, captures the current device/client/plugin combination.
*/
readonly pluginKey: string;
readonly device: Device;
@@ -74,6 +78,14 @@ export interface BasePluginClient {
* Always returns `false` in open source.
*/
GK(gkName: string): boolean;
/**
* Shows an urgent, system wide notification, that will also be registered in Flipper's notification pane.
* For on-screen notifications, we recommend to use either the `message` or `notification` API from `antd` directly.
*
* Clicking the notification will open this plugin. If the `action` id is set, it will be used as deeplink.
*/
showNotification(notification: Notification): void;
}
let currentPluginInstance: BasePluginInstance | undefined = undefined;
@@ -262,6 +274,9 @@ export abstract class BasePluginInstance {
},
createPaste: this.flipperLib.createPaste,
GK: this.flipperLib.GK,
showNotification: (notification: Notification) => {
this.flipperLib.showNotification(this.pluginKey, notification);
},
};
}

View File

@@ -371,6 +371,7 @@ export function createMockFlipperLib(options?: StartPluginOptions): FlipperLib {
selectPlugin: jest.fn(),
isPluginAvailable: jest.fn().mockImplementation(() => false),
writeTextToClipboard: jest.fn(),
showNotification: jest.fn(),
};
}

View File

@@ -50,6 +50,10 @@ The name of the application, for example 'Facebook', 'Instagram' or 'Slack'.
A string that uniquely identifies the current application, is based on a combination of the application name and device serial on which the application is running.
#### `pluginKey`
A key that uniquely identifies this plugin instance, captures the current device/client/plugin combination.
#### `isConnected`
Returns whether there is currently an active connection. This is true if:
@@ -268,6 +272,29 @@ Usage: `client.supportsMethod(method: string): Promise<Boolean>`
Resolves to true if the client supports the specified method. Useful when adding functionality to existing plugins, when connectivity to older clients is still required. Also useful when client plugins are implemented on multitple platforms and don't all have feature parity.
#### showNotification
Usage: `client.showNotification(notification)`
Shows an urgent, system wide notification, that will also be registered in Flipper's notification pane.
For on-screen notifications, we recommend to use either the `message` or `notification` API from `antd` directly.
Clicking the notification will open the sending plugin. If the `action` id is set, it will be used as deeplink.
The notification interface is defined as:
```typescript
interface Notification {
id: string;
title: string;
message: string | React.ReactNode;
severity: 'warning' | 'error';
timestamp?: number;
category?: string;
action?: string;
};
```
#### `createPaste`
Facebook only API.
@@ -343,6 +370,10 @@ See the similarly named method under [`PluginClient`](#pluginclient).
See the similarly named method under [`PluginClient`](#pluginclient).
#### `showNotification`
See the similarly named method under [`PluginClient`](#pluginclient).
### `isPluginAvailable`
See the similarly named method under [`PluginClient`](#pluginclient).