adding actions to notifications

Summary: This diff adds action buttons to the notifications. Notifications with actions can only be sent from the main process. This is why we need to send a message to the main process which then shows the notification. The action callbacks are sent back to the renderer process to handle the action and log the event.

Reviewed By: passy

Differential Revision: D12999886

fbshipit-source-id: b415fded3172582fad11d88cabf0cfc5b3b8d4f9
This commit is contained in:
Daniel Büchele
2018-11-12 01:47:52 -08:00
committed by Facebook Github Bot
parent 4954d018d0
commit 8cb715bb3a
3 changed files with 117 additions and 18 deletions

View File

@@ -10,12 +10,18 @@ import type Logger from '../fb-stubs/Logger.js';
import type {PluginNotification} from '../reducers/notifications';
import type {FlipperPlugin} from '../plugin.js';
import {ipcRenderer} from 'electron';
import {selectPlugin} from '../reducers/connections';
import {setActiveNotifications} from '../reducers/notifications';
import {
setActiveNotifications,
updatePluginBlacklist,
} from '../reducers/notifications';
import {textContent} from '../utils/index';
import {clientPlugins} from '../plugins/index.js';
import GK from '../fb-stubs/GK';
type NotificationEvents = 'show' | 'click' | 'close' | 'reply' | 'action';
export default (store: Store, logger: Logger) => {
if (GK.get('flipper_disable_notifications')) {
return;
@@ -24,22 +30,67 @@ export default (store: Store, logger: Logger) => {
const knownNotifications: Set<string> = new Set();
const knownPluginStates: Map<string, Object> = new Map();
ipcRenderer.on(
'notificationEvent',
(
e,
eventName: NotificationEvents,
pluginNotification: PluginNotification,
arg: null | string | number,
) => {
if (eventName === 'click' || (eventName === 'action' && arg === 0)) {
store.dispatch(
selectPlugin({
selectedPlugin: 'notifications',
selectedApp: null,
deepLinkPayload: pluginNotification.notification.id,
}),
);
} else if (eventName === 'action') {
if (arg === 1 && pluginNotification.notification.category) {
// Hide similar (category)
logger.track(
'usage',
'notification-hide-category',
pluginNotification,
);
} else if (arg === 2) {
// Hide plugin
logger.track('usage', 'notification-hide-plugin', pluginNotification);
const {blacklistedPlugins} = store.getState().notifications;
if (blacklistedPlugins.indexOf(pluginNotification.pluginId) === -1) {
store.dispatch(
updatePluginBlacklist([
...blacklistedPlugins,
pluginNotification.pluginId,
]),
);
}
}
}
},
);
store.subscribe(() => {
const {notifications, pluginStates} = store.getState();
const pluginMap: Map<string, Class<FlipperPlugin<>>> = clientPlugins.reduce(
(acc, cv) => acc.set(cv.id, cv),
new Map(),
);
Object.keys(pluginStates).forEach(key => {
if (knownPluginStates.get(key) !== pluginStates[key]) {
knownPluginStates.set(key, pluginStates[key]);
const [client, pluginId] = key.split('#');
const persistingPlugin: ?Class<FlipperPlugin<>> = clientPlugins.find(
(p: Class<FlipperPlugin<>>) =>
p.id === pluginId && p.getActiveNotifications,
const persistingPlugin: ?Class<FlipperPlugin<>> = pluginMap.get(
pluginId,
);
if (persistingPlugin) {
if (persistingPlugin && persistingPlugin.getActiveNotifications) {
store.dispatch(
setActiveNotifications({
// $FlowFixMe: Ensured getActiveNotifications is implemented in filter
notifications: persistingPlugin.getActiveNotifications(
pluginStates[key],
),
@@ -55,21 +106,34 @@ export default (store: Store, logger: Logger) => {
activeNotifications.forEach((n: PluginNotification) => {
if (
store.getState().connections.selectedPlugin !== 'notifications' &&
!knownNotifications.has(n.notification.id) &&
blacklistedPlugins.indexOf(n.pluginId) === -1
) {
const notification = new window.Notification(n.notification.title, {
body: textContent(n.notification.message),
ipcRenderer.send('sendNotification', {
payload: {
title: n.notification.title,
body: textContent(n.notification.message),
actions: [
{
type: 'button',
text: 'Show',
},
{
type: 'button',
text: 'Hide similar',
},
{
type: 'button',
text: `Hide all ${pluginMap.get(n.pluginId)?.title || ''}`,
},
],
closeButtonText: 'Hide',
},
closeAfter: 10000,
pluginNotification: n,
});
logger.track('usage', 'native-notification', n.notification);
notification.onclick = () =>
store.dispatch(
selectPlugin({
selectedPlugin: 'notifications',
selectedApp: null,
deepLinkPayload: n.notification.id,
}),
);
knownNotifications.add(n.notification.id);
}
});