Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor all notifications from extensions and UI toggling such that … #4589

Merged
merged 13 commits into from
Aug 14, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {CheckGroup, Checkbox} from 'superdesk-ui-framework/react';

interface IProps {
toggleEmailNotification: (notificationId: string) => void;
preferences?: {[key: string]: any};
preferences?: {[key: string]: {label: string; email?: boolean; default?: boolean;}};
tomaskikutis marked this conversation as resolved.
Show resolved Hide resolved
}

export class EmailNotificationPreferences extends React.PureComponent<IProps> {
Expand All @@ -17,7 +17,7 @@ export class EmailNotificationPreferences extends React.PureComponent<IProps> {
onChange={() => {
this.props.toggleEmailNotification(key);
}}
checked={value?.enabled ?? value?.default ?? false}
checked={value?.email ?? value?.default ?? false}
/>
))}
</CheckGroup>
Expand Down
38 changes: 23 additions & 15 deletions scripts/apps/users/directives/UserPreferencesDirective.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export function UserPreferencesDirective(
link: function(scope, element, attrs) {
const userLang = getUserInterfaceLanguage().replace('_', '-');
const body = angular.element('body');
const NOTIFICATIONS_KEY = 'notifications';

scope.activeNavigation = null;

Expand All @@ -58,27 +59,31 @@ export function UserPreferencesDirective(

scope.emailNotificationsFromExtensions = {};

scope.buildNotificationsFromExtensions = function() {
scope.buildNotificationsFromExtensions = function(rebuild: boolean) {
tomaskikutis marked this conversation as resolved.
Show resolved Hide resolved
for (const extension of Object.values(extensions)) {
for (const [key, value] of Object.entries(extension.activationResult.contributions?.notifications ?? [])) {
if (value.type === 'email') {
preferencesService.registerUserPreference(key, 1);
scope.emailNotificationsFromExtensions[key] = preferencesService.getSync(key);
}
scope.emailNotificationsFromExtensions[key] =
preferencesService.getSync('notifications')?.[key] ?? {
email: true,
default: true,
label: gettext('Send {{ name }} notifications', {name: value.name}),
};
}
}
};

scope.buildNotificationsFromExtensions();

scope.buildNotificationsFromExtensions(false);
tomaskikutis marked this conversation as resolved.
Show resolved Hide resolved

scope.toggleEmailGroupNotifications = function() {
const isGroupEnabled = scope.preferences['email:notification'].enabled;

Object.keys(scope.emailNotificationsFromExtensions).forEach((notificationId) => {
scope.preferences[notificationId].enabled = isGroupEnabled;
scope.preferences[NOTIFICATIONS_KEY][notificationId].email = isGroupEnabled;
scope.emailNotificationsFromExtensions[notificationId] = {
...scope.emailNotificationsFromExtensions[notificationId],
enabled: isGroupEnabled,
email: isGroupEnabled,
};
});

Expand All @@ -87,19 +92,15 @@ export function UserPreferencesDirective(
};

scope.toggleEmailNotification = function(notificationId: string) {
tomaskikutis marked this conversation as resolved.
Show resolved Hide resolved
const enabledUpdate = !(scope.preferences[notificationId]?.enabled ?? false);
const emailEnabledUpdate = !(scope.preferences[NOTIFICATIONS_KEY][notificationId]?.email ?? false);

scope.preferences[notificationId] = {
...(scope.preferences[notificationId] ?? {}),
enabled: enabledUpdate,
};
scope.emailNotificationsFromExtensions[notificationId] = {
...scope.emailNotificationsFromExtensions[notificationId],
enabled: enabledUpdate,
email: emailEnabledUpdate,
};

const notificationsForGroupAreOff = Object.values(scope.emailNotificationsFromExtensions)
.every((value: any) => value?.enabled == false);
.every((value: any) => value?.email == false);

scope.preferences['email:notification'].enabled = !notificationsForGroupAreOff;

Expand All @@ -119,6 +120,7 @@ export function UserPreferencesDirective(
scope.cancel = function() {
scope.userPrefs.$setPristine();
buildPreferences(orig);
scope.buildNotificationsFromExtensions();

scope.datelinePreview = scope.preferences['dateline:located'].located;
};
Expand Down Expand Up @@ -147,6 +149,8 @@ export function UserPreferencesDirective(
* @method save
*/
scope.save = function() {
scope.preferences[NOTIFICATIONS_KEY] = scope.emailNotificationsFromExtensions;

preSaveCategoriesCheck()
.then(() => {
var update = createPatchObject();
Expand All @@ -159,7 +163,7 @@ export function UserPreferencesDirective(
});
}, () => $q.reject('canceledByModal'))
.then((preferences) => {
// ask for browser permission if desktop notification is enable
// ask for browser permission if desktop notification is enable
if (_.get(preferences, 'desktop:notification.enabled')) {
preferencesService.desktopNotification.requestPermission();
}
Expand Down Expand Up @@ -289,6 +293,10 @@ export function UserPreferencesDirective(

scope.preferences = {};
_.each(data, (val, key) => {
if (key == NOTIFICATIONS_KEY) {
scope.preferences[key] = val;
}

if (val.label && val.category) {
scope.preferences[key] = _.create(val);
}
Expand Down
10 changes: 5 additions & 5 deletions scripts/core/menu/notifications/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import _ from 'lodash';
import {gettext} from 'core/utils';
import {AuthoringWorkspaceService} from 'apps/authoring/authoring/services/AuthoringWorkspaceService';
import {extensions} from 'appConfig';
import {IDesktopNotification} from 'superdesk-api';
import {IExtensionActivationResult} from 'superdesk-api';
import {logger} from 'core/services/logger';
import emptyState from 'superdesk-ui-framework/dist/empty-state--small-2.svg';

Expand Down Expand Up @@ -296,7 +296,9 @@ angular.module('superdesk.core.menu.notifications', ['superdesk.core.services.as
scope.emptyState = emptyState;

// merged from all extensions
const notificationsKeyed: {[key: string]: IDesktopNotification['handler']} = {};
const notificationsKeyed: {
[key: string]: IExtensionActivationResult['contributions']['notifications'][0]['handler']
} = {};

for (const extension of Object.values(extensions)) {
const notificationsFromExtensions = extension.activationResult.contributions?.notifications;
Expand All @@ -306,9 +308,7 @@ angular.module('superdesk.core.menu.notifications', ['superdesk.core.services.as
if (notificationsKeyed[key] == null) {
const notificationValue = notificationsFromExtensions[key];

if (notificationValue.type == 'desktop') {
notificationsKeyed[key] = notificationValue.handler;
}
notificationsKeyed[key] = notificationValue.handler;
} else {
logger.error(new Error(`Notification key ${key} already registered.`));
}
Expand Down
3 changes: 2 additions & 1 deletion scripts/core/services/preferencesService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default angular.module('superdesk.core.preferences', ['superdesk.core.not
userPreferences = {
'feature:preview': 1,
'archive:view': 1,
'notifications': 1,
'email:notification': 1,
'desktop:notification': 1,
'slack:notification': 1,
Expand Down Expand Up @@ -90,7 +91,7 @@ export default angular.module('superdesk.core.preferences', ['superdesk.core.not
},
// ask for permission and send a desktop notification
send: (msg) => {
if (_.get(preferences, 'user_preferences.desktop:notification.enabled')) {
if (preferences.user_preferences['desktop:notification'].enabled) {
if ('Notification' in window && Notification.permission !== 'denied') {
Notification.requestPermission((permission) => {
if (permission === 'granted') {
Expand Down
17 changes: 7 additions & 10 deletions scripts/core/superdesk-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,16 +706,7 @@ declare module 'superdesk-api' {
}

interface IEmailNotification {
tomaskikutis marked this conversation as resolved.
Show resolved Hide resolved
type: 'email';
}

export interface IDesktopNotification {
type: 'desktop';
label: string;
handler: (notification: any) => {
body: string;
actions: Array<{label: string; onClick: () => void;}>;
};
}

export interface IExtensionActivationResult {
Expand Down Expand Up @@ -756,7 +747,13 @@ declare module 'superdesk-api' {
workspaceMenuItems?: Array<IWorkspaceMenuItem>;
customFieldTypes?: Array<ICustomFieldType>;
notifications?: {
[id: string]: IEmailNotification | IDesktopNotification;
[id: string]: {
name: string;
handler?: (notification: any) => {
body: string;
actions: Array<{label: string; onClick: () => void;}>;
};
};
};
entities?: {
article?: {
Expand Down
17 changes: 1 addition & 16 deletions scripts/extensions/markForUser/src/extension.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ const extension: IExtension = {
},
notifications: {
'item:marked': {
type: 'desktop',
label: gettext('open item'),
name: gettext('Mark for User'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this unified notification notify both of marking and unmarking? Check with if API exposes this information and coordinate with Petr if not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, works for marking and unmarking. Only difference between the two previously was the body message, handler was indeed the same one.

handler: (notification: any) => ({
body: notification.message,
actions: [{
Expand All @@ -58,20 +57,6 @@ const extension: IExtension = {
}],
}),
},
'item:unmarked': {
label: gettext('open item'),
type: 'desktop',
handler: (notification: any) => ({
body: notification.message,
actions: [{
label: gettext('open item'),
onClick: () => superdesk.ui.article.view(notification.item),
}],
}),
},
'mark_for_user:notification': {
type: 'email',
},
},
entities: {
article: {
Expand Down
Loading