notification category filters

Summary:
Allows filtering notification by category. Category filters are also persisted in redux.

Adds a test suite for notification reducer

Reviewed By: passy

Differential Revision: D12999884

fbshipit-source-id: 5f8d2357e52f091c17b726e1f89ed68f3b7294fb
This commit is contained in:
Daniel Büchele
2018-11-12 01:47:52 -08:00
committed by Facebook Github Bot
parent 8cb715bb3a
commit bd03f891d0
4 changed files with 156 additions and 18 deletions

View File

@@ -15,6 +15,7 @@ import {selectPlugin} from '../reducers/connections';
import {
setActiveNotifications,
updatePluginBlacklist,
updateCategoryBlacklist,
} from '../reducers/notifications';
import {textContent} from '../utils/index';
import {clientPlugins} from '../plugins/index.js';
@@ -54,6 +55,14 @@ export default (store: Store, logger: Logger) => {
'notification-hide-category',
pluginNotification,
);
const {category} = pluginNotification.notification;
const {blacklistedCategories} = store.getState().notifications;
if (category && blacklistedCategories.indexOf(category) === -1) {
store.dispatch(
updateCategoryBlacklist([...blacklistedCategories, category]),
);
}
} else if (arg === 2) {
// Hide plugin
logger.track('usage', 'notification-hide-plugin', pluginNotification);
@@ -102,13 +111,19 @@ export default (store: Store, logger: Logger) => {
}
});
const {activeNotifications, blacklistedPlugins} = notifications;
const {
activeNotifications,
blacklistedPlugins,
blacklistedCategories,
} = notifications;
activeNotifications.forEach((n: PluginNotification) => {
if (
store.getState().connections.selectedPlugin !== 'notifications' &&
!knownNotifications.has(n.notification.id) &&
blacklistedPlugins.indexOf(n.pluginId) === -1
blacklistedPlugins.indexOf(n.pluginId) === -1 &&
(!n.notification.category ||
blacklistedCategories.indexOf(n.notification.category) === -1)
) {
ipcRenderer.send('sendNotification', {
payload: {

View File

@@ -0,0 +1,104 @@
/**
* Copyright 2018-present Facebook.
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* @format
*/
import type {State} from '../notifications';
import {
default as reducer,
setActiveNotifications,
clearAllNotifications,
updatePluginBlacklist,
updateCategoryBlacklist,
} from '../notifications';
const notification = {
id: 'id',
title: 'title',
message: 'message',
severity: 'warning',
};
function getInitialState(): State {
return {
activeNotifications: [],
invalidatedNotifications: [],
blacklistedPlugins: [],
blacklistedCategories: [],
clearedNotifications: new Set(),
};
}
test('reduce updateCategoryBlacklist', () => {
const blacklistedCategories = ['blacklistedCategory'];
const res = reducer(
getInitialState(),
updateCategoryBlacklist(blacklistedCategories),
);
expect(res).toEqual({
...getInitialState(),
blacklistedCategories,
});
});
test('reduce updatePluginBlacklist', () => {
const blacklistedPlugins = ['blacklistedPlugin'];
const res = reducer(
getInitialState(),
updatePluginBlacklist(blacklistedPlugins),
);
expect(res).toEqual({
...getInitialState(),
blacklistedPlugins,
});
});
test('reduce clearAllNotifications', () => {
const pluginId = 'pluginId';
const client = 'client';
const res = reducer(
{
...getInitialState(),
activeNotifications: [
{
client,
pluginId,
notification,
},
],
},
clearAllNotifications(),
);
expect(res).toEqual({
...getInitialState(),
clearedNotifications: new Set([`${pluginId}#${notification.id}`]),
});
});
test('reduce setActiveNotifications', () => {
const pluginId = 'pluginId';
const client = 'client';
const res = reducer(
getInitialState(),
setActiveNotifications({
notifications: [notification],
client,
pluginId,
}),
);
expect(res).toEqual({
...getInitialState(),
activeNotifications: [
{
client,
pluginId,
notification,
},
],
});
});

View File

@@ -64,7 +64,7 @@ export default combineReducers({
{
key: 'notifications',
storage,
whitelist: ['blacklistedPlugins'],
whitelist: ['blacklistedPlugins', 'blacklistedCategories'],
},
notifications,
),

View File

@@ -16,6 +16,7 @@ export type State = {
activeNotifications: Array<PluginNotification>,
invalidatedNotifications: Array<PluginNotification>,
blacklistedPlugins: Array<string>,
blacklistedCategories: Array<string>,
clearedNotifications: Set<string>,
};
@@ -28,24 +29,32 @@ type ActiveNotificationsAction = {
},
};
type ClearAllAction = {
type: 'CLEAR_ALL_NOTIFICATIONS',
};
type UpdateBlacklistAction = {
type: 'UPDATE_PLUGIN_BLACKLIST',
payload: Array<string>,
};
export type Action =
| ActiveNotificationsAction
| ClearAllAction
| UpdateBlacklistAction;
| {
type: 'CLEAR_ALL_NOTIFICATIONS',
}
| {
type: 'SET_ACTIVE_NOTIFICATIONS',
payload: {
notifications: Array<Notification>,
client: ?string,
pluginId: string,
},
}
| {
type: 'UPDATE_PLUGIN_BLACKLIST',
payload: Array<string>,
}
| {
type: 'UPDATE_CATEGORY_BLACKLIST',
payload: Array<string>,
};
const INITIAL_STATE: State = {
activeNotifications: [],
invalidatedNotifications: [],
blacklistedPlugins: [],
blacklistedCategories: [],
clearedNotifications: new Set(),
};
@@ -77,6 +86,11 @@ export default function reducer(
...state,
blacklistedPlugins: action.payload,
};
case 'UPDATE_CATEGORY_BLACKLIST':
return {
...state,
blacklistedCategories: action.payload,
};
default:
return state;
}
@@ -140,11 +154,16 @@ export function clearAllNotifications(): Action {
};
}
export function updatePluginBlacklist(
payload: Array<string>,
): UpdateBlacklistAction {
export function updatePluginBlacklist(payload: Array<string>) {
return {
type: 'UPDATE_PLUGIN_BLACKLIST',
payload,
};
}
export function updateCategoryBlacklist(payload: Array<string>) {
return {
type: 'UPDATE_CATEGORY_BLACKLIST',
payload,
};
}