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:
committed by
Facebook GitHub Bot
parent
2ca52f81d2
commit
4e2383cdb0
@@ -28,7 +28,6 @@ export {
|
|||||||
FlipperPlugin,
|
FlipperPlugin,
|
||||||
FlipperDevicePlugin,
|
FlipperDevicePlugin,
|
||||||
callClient,
|
callClient,
|
||||||
Notification,
|
|
||||||
BaseAction,
|
BaseAction,
|
||||||
} from './plugin';
|
} from './plugin';
|
||||||
export {PluginClient, Props} from './plugin';
|
export {PluginClient, Props} from './plugin';
|
||||||
@@ -42,7 +41,7 @@ export {connect} from 'react-redux';
|
|||||||
export {selectPlugin, StaticView} from './reducers/connections';
|
export {selectPlugin, StaticView} from './reducers/connections';
|
||||||
export {writeBufferToFile, bufferToBlob} from './utils/screenshot';
|
export {writeBufferToFile, bufferToBlob} from './utils/screenshot';
|
||||||
export {getPluginKey, getPersistedState} from './utils/pluginUtils';
|
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 {Store, MiddlewareAPI, State as ReduxState} from './reducers/index';
|
||||||
export {default as BaseDevice} from './devices/BaseDevice';
|
export {default as BaseDevice} from './devices/BaseDevice';
|
||||||
export {DeviceLogEntry, LogLevel, DeviceLogListener} from 'flipper-plugin';
|
export {DeviceLogEntry, LogLevel, DeviceLogListener} from 'flipper-plugin';
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {KeyboardActions} from './MenuBar';
|
|||||||
import {Logger} from './fb-interfaces/Logger';
|
import {Logger} from './fb-interfaces/Logger';
|
||||||
import Client from './Client';
|
import Client from './Client';
|
||||||
import {Store} from './reducers/index';
|
import {Store} from './reducers/index';
|
||||||
import {ReactNode, Component} from 'react';
|
import {Component} from 'react';
|
||||||
import BaseDevice from './devices/BaseDevice';
|
import BaseDevice from './devices/BaseDevice';
|
||||||
import {serialize, deserialize} from './utils/serialization';
|
import {serialize, deserialize} from './utils/serialization';
|
||||||
import {StaticView} from './reducers/connections';
|
import {StaticView} from './reducers/connections';
|
||||||
@@ -19,7 +19,7 @@ import {State as ReduxState} from './reducers';
|
|||||||
import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue';
|
import {DEFAULT_MAX_QUEUE_SIZE} from './reducers/pluginMessageQueue';
|
||||||
import {ActivatablePluginDetails} from 'flipper-plugin-lib';
|
import {ActivatablePluginDetails} from 'flipper-plugin-lib';
|
||||||
import {Settings} from './reducers/settings';
|
import {Settings} from './reducers/settings';
|
||||||
import {Idler, _SandyPluginDefinition} from 'flipper-plugin';
|
import {Notification, Idler, _SandyPluginDefinition} from 'flipper-plugin';
|
||||||
|
|
||||||
type Parameters = {[key: string]: any};
|
type Parameters = {[key: string]: any};
|
||||||
|
|
||||||
@@ -68,16 +68,6 @@ export interface PluginClient {
|
|||||||
|
|
||||||
type PluginTarget = BaseDevice | Client;
|
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> = {
|
export type Props<T> = {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
persistedState: T;
|
persistedState: T;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
updateCategoryBlocklist,
|
updateCategoryBlocklist,
|
||||||
} from '../notifications';
|
} from '../notifications';
|
||||||
|
|
||||||
import {Notification} from '../../plugin';
|
import {Notification} from 'flipper-plugin';
|
||||||
|
|
||||||
const notification: Notification = {
|
const notification: Notification = {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
|
|||||||
@@ -7,9 +7,10 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Notification} from '../plugin';
|
import {Notification} from 'flipper-plugin';
|
||||||
import {Actions} from './';
|
import {Actions} from './';
|
||||||
import {getStringFromErrorLike} from '../utils';
|
import {getStringFromErrorLike} from '../utils';
|
||||||
|
|
||||||
export type PluginNotification = {
|
export type PluginNotification = {
|
||||||
notification: Notification;
|
notification: Notification;
|
||||||
pluginId: string;
|
pluginId: string;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useCallback, useMemo, useState} from 'react';
|
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 {styled, Glyph} from '../../ui';
|
||||||
import {Input, Typography, Button, Collapse, Dropdown, Menu} from 'antd';
|
import {Input, Typography, Button, Collapse, Dropdown, Menu} from 'antd';
|
||||||
import {
|
import {
|
||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
EllipsisOutlined,
|
EllipsisOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {LeftSidebar, SidebarTitle} from '../LeftSidebar';
|
import {LeftSidebar, SidebarTitle} from '../LeftSidebar';
|
||||||
import {Notification as NotificationData} from '../../plugin';
|
|
||||||
import {useStore, useDispatch} from '../../utils/useStore';
|
import {useStore, useDispatch} from '../../utils/useStore';
|
||||||
import {ClientQuery} from '../../Client';
|
import {ClientQuery} from '../../Client';
|
||||||
import {deconstructClientId} from '../../utils/clientUtils';
|
import {deconstructClientId} from '../../utils/clientUtils';
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ import {
|
|||||||
importDataToStore,
|
importDataToStore,
|
||||||
} from '../exportData';
|
} from '../exportData';
|
||||||
import {FlipperPlugin, FlipperDevicePlugin} from '../../plugin';
|
import {FlipperPlugin, FlipperDevicePlugin} from '../../plugin';
|
||||||
import {Notification} from '../../plugin';
|
|
||||||
import {default as Client, ClientExport} from '../../Client';
|
import {default as Client, ClientExport} from '../../Client';
|
||||||
import {selectedPlugins, State as PluginsState} from '../../reducers/plugins';
|
import {selectedPlugins, State as PluginsState} from '../../reducers/plugins';
|
||||||
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
|
import {createMockFlipperWithPlugin} from '../../test-utils/createMockFlipperWithPlugin';
|
||||||
import {
|
import {
|
||||||
|
Notification,
|
||||||
TestUtils,
|
TestUtils,
|
||||||
_SandyPluginDefinition,
|
_SandyPluginDefinition,
|
||||||
createState,
|
createState,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import GK from '../fb-stubs/GK';
|
|||||||
import type BaseDevice from '../devices/BaseDevice';
|
import type BaseDevice from '../devices/BaseDevice';
|
||||||
import {clipboard} from 'electron';
|
import {clipboard} from 'electron';
|
||||||
import constants from '../fb-stubs/constants';
|
import constants from '../fb-stubs/constants';
|
||||||
|
import {addNotification} from '../reducers/notifications';
|
||||||
|
import {deconstructPluginKey} from './clientUtils';
|
||||||
|
|
||||||
export function initializeFlipperLibImplementation(
|
export function initializeFlipperLibImplementation(
|
||||||
store: Store,
|
store: Store,
|
||||||
@@ -71,5 +73,15 @@ export function initializeFlipperLibImplementation(
|
|||||||
writeTextToClipboard(text: string) {
|
writeTextToClipboard(text: string) {
|
||||||
clipboard.writeText(text);
|
clipboard.writeText(text);
|
||||||
},
|
},
|
||||||
|
showNotification(pluginId, notification) {
|
||||||
|
const parts = deconstructPluginKey(pluginId);
|
||||||
|
store.dispatch(
|
||||||
|
addNotification({
|
||||||
|
pluginId: parts.pluginName,
|
||||||
|
client: parts.client,
|
||||||
|
notification,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ test('Correct top level API exposed', () => {
|
|||||||
"Logger",
|
"Logger",
|
||||||
"MenuEntry",
|
"MenuEntry",
|
||||||
"NormalizedMenuEntry",
|
"NormalizedMenuEntry",
|
||||||
|
"Notification",
|
||||||
"PluginClient",
|
"PluginClient",
|
||||||
"TrackType",
|
"TrackType",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export {
|
|||||||
buildInMenuEntries as _buildInMenuEntries,
|
buildInMenuEntries as _buildInMenuEntries,
|
||||||
DefaultKeyboardAction,
|
DefaultKeyboardAction,
|
||||||
} from './plugin/MenuEntry';
|
} from './plugin/MenuEntry';
|
||||||
|
export {Notification} from './plugin/Notification';
|
||||||
|
|
||||||
export {theme} from './ui/theme';
|
export {theme} from './ui/theme';
|
||||||
export {Layout} from './ui/Layout';
|
export {Layout} from './ui/Layout';
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {Logger} from '../utils/Logger';
|
|||||||
import {RealFlipperDevice} from './DevicePlugin';
|
import {RealFlipperDevice} from './DevicePlugin';
|
||||||
import {NormalizedMenuEntry} from './MenuEntry';
|
import {NormalizedMenuEntry} from './MenuEntry';
|
||||||
import {RealFlipperClient} from './Plugin';
|
import {RealFlipperClient} from './Plugin';
|
||||||
|
import {Notification} from './Notification';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface exposes all global methods for which an implementation will be provided by Flipper itself
|
* 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,
|
deeplink: unknown,
|
||||||
): void;
|
): void;
|
||||||
writeTextToClipboard(text: string): void;
|
writeTextToClipboard(text: string): void;
|
||||||
|
showNotification(pluginKey: string, notification: Notification): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let flipperLibInstance: FlipperLib | undefined;
|
let flipperLibInstance: FlipperLib | undefined;
|
||||||
|
|||||||
19
desktop/flipper-plugin/src/plugin/Notification.tsx
Normal file
19
desktop/flipper-plugin/src/plugin/Notification.tsx
Normal 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;
|
||||||
|
};
|
||||||
@@ -7,14 +7,15 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {SandyPluginDefinition} from './SandyPluginDefinition';
|
import {message} from 'antd';
|
||||||
import {EventEmitter} from 'events';
|
import {EventEmitter} from 'events';
|
||||||
|
import {SandyPluginDefinition} from './SandyPluginDefinition';
|
||||||
import {MenuEntry, NormalizedMenuEntry, normalizeMenuEntry} from './MenuEntry';
|
import {MenuEntry, NormalizedMenuEntry, normalizeMenuEntry} from './MenuEntry';
|
||||||
import {FlipperLib} from './FlipperLib';
|
import {FlipperLib} from './FlipperLib';
|
||||||
import {Device, RealFlipperDevice} from './DevicePlugin';
|
import {Device, RealFlipperDevice} from './DevicePlugin';
|
||||||
import {batched} from '../state/batch';
|
import {batched} from '../state/batch';
|
||||||
import {Idler} from '../utils/Idler';
|
import {Idler} from '../utils/Idler';
|
||||||
import {message} from 'antd';
|
import {Notification} from './Notification';
|
||||||
|
|
||||||
type StateExportHandler<T = any> = (
|
type StateExportHandler<T = any> = (
|
||||||
idler: Idler,
|
idler: Idler,
|
||||||
@@ -23,6 +24,9 @@ type StateExportHandler<T = any> = (
|
|||||||
type StateImportHandler<T = any> = (data: T) => void;
|
type StateImportHandler<T = any> = (data: T) => void;
|
||||||
|
|
||||||
export interface BasePluginClient {
|
export interface BasePluginClient {
|
||||||
|
/**
|
||||||
|
* A key that uniquely identifies this plugin instance, captures the current device/client/plugin combination.
|
||||||
|
*/
|
||||||
readonly pluginKey: string;
|
readonly pluginKey: string;
|
||||||
readonly device: Device;
|
readonly device: Device;
|
||||||
|
|
||||||
@@ -74,6 +78,14 @@ export interface BasePluginClient {
|
|||||||
* Always returns `false` in open source.
|
* Always returns `false` in open source.
|
||||||
*/
|
*/
|
||||||
GK(gkName: string): boolean;
|
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;
|
let currentPluginInstance: BasePluginInstance | undefined = undefined;
|
||||||
@@ -262,6 +274,9 @@ export abstract class BasePluginInstance {
|
|||||||
},
|
},
|
||||||
createPaste: this.flipperLib.createPaste,
|
createPaste: this.flipperLib.createPaste,
|
||||||
GK: this.flipperLib.GK,
|
GK: this.flipperLib.GK,
|
||||||
|
showNotification: (notification: Notification) => {
|
||||||
|
this.flipperLib.showNotification(this.pluginKey, notification);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -371,6 +371,7 @@ export function createMockFlipperLib(options?: StartPluginOptions): FlipperLib {
|
|||||||
selectPlugin: jest.fn(),
|
selectPlugin: jest.fn(),
|
||||||
isPluginAvailable: jest.fn().mockImplementation(() => false),
|
isPluginAvailable: jest.fn().mockImplementation(() => false),
|
||||||
writeTextToClipboard: jest.fn(),
|
writeTextToClipboard: jest.fn(),
|
||||||
|
showNotification: jest.fn(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
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`
|
#### `isConnected`
|
||||||
|
|
||||||
Returns whether there is currently an active connection. This is true if:
|
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.
|
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`
|
#### `createPaste`
|
||||||
|
|
||||||
Facebook only API.
|
Facebook only API.
|
||||||
@@ -343,6 +370,10 @@ See the similarly named method under [`PluginClient`](#pluginclient).
|
|||||||
|
|
||||||
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`
|
### `isPluginAvailable`
|
||||||
|
|
||||||
See the similarly named method under [`PluginClient`](#pluginclient).
|
See the similarly named method under [`PluginClient`](#pluginclient).
|
||||||
|
|||||||
Reference in New Issue
Block a user