[MM-57066][MM-57329] Added metrics for all notification stopping points, consolidated categories between metrics and logging (#26799)

* [MM-57066] Add metric counters for notification events

* Some small changes

* Account for Metrics() sometimes being nil

* Fix test (again)

* Fix more tests

* A few changes from testing - added success counter

* Missed a mock

* Lint

* Add feature flag for notification monitoring
Этот коммит содержится в:
Devin Binnie
2024-04-18 10:30:08 -04:00
коммит произвёл GitHub
родитель 0ce5def8e2
Коммит 02e23a3275
26 изменённых файлов: 572 добавлений и 241 удалений

Просмотреть файл

@@ -13,7 +13,7 @@
"@mattermost/client": "*",
"@mattermost/compass-components": "^0.2.12",
"@mattermost/compass-icons": "0.1.39",
"@mattermost/desktop-api": "5.8.0-4",
"@mattermost/desktop-api": "5.8.0-5",
"@mattermost/types": "*",
"@mui/base": "5.0.0-alpha.127",
"@mui/material": "5.11.16",

Просмотреть файл

@@ -80,11 +80,11 @@ export function completePostReceive(post: Post, websocketMessageProps: NewPostMe
dispatch(setThreadRead(post));
}
const {result, reason, data} = await dispatch(sendDesktopNotification(post, websocketMessageProps));
const {status, reason, data} = await dispatch(sendDesktopNotification(post, websocketMessageProps));
// Only ACK for posts that require it
if (websocketMessageProps.should_ack) {
WebSocketClient.acknowledgePostedNotification(post.id, result, reason, data);
WebSocketClient.acknowledgePostedNotification(post.id, status, reason, data);
}
return {data: true};

Просмотреть файл

@@ -57,11 +57,11 @@ export function sendDesktopNotification(post, msgProps) {
const currentUserId = getCurrentUserId(state);
if ((currentUserId === post.user_id && post.props.from_webhook !== 'true')) {
return {result: 'not_sent', reason: 'own_post'};
return {status: 'not_sent', reason: 'own_post'};
}
if (isSystemMessage(post) && !isUserAddedInChannel(post, currentUserId)) {
return {result: 'not_sent', reason: 'system_message'};
return {status: 'not_sent', reason: 'system_message'};
}
let userFromPost = getUser(state, post.user_id);
@@ -92,15 +92,15 @@ export function sendDesktopNotification(post, msgProps) {
const isCrtReply = isCollapsedThreadsEnabled(state) && post.root_id !== '';
if (!member) {
return {result: 'not_sent', reason: 'no_member'};
return {status: 'error', reason: 'no_member'};
}
if (isChannelMuted(member)) {
return {result: 'not_sent', reason: 'channel_muted'};
return {status: 'not_sent', reason: 'channel_muted'};
}
if (userStatus === UserStatuses.DND || userStatus === UserStatuses.OUT_OF_OFFICE) {
return {result: 'not_sent', reason: 'user_status', data: userStatus};
return {status: 'not_sent', reason: 'user_status', data: userStatus};
}
const channelNotifyProp = member?.notify_props?.desktop || NotificationLevels.DEFAULT;
@@ -115,7 +115,7 @@ export function sendDesktopNotification(post, msgProps) {
}
if (notifyLevel === NotificationLevels.NONE) {
return {result: 'not_sent', reason: 'notify_level', data: notifyLevel};
return {status: 'not_sent', reason: 'notify_level_none'};
} else if (channel?.type === 'G' && notifyLevel === NotificationLevels.MENTION) {
// Compose the whole text in the message, including interactive messages.
let text = post.message;
@@ -189,13 +189,13 @@ export function sendDesktopNotification(post, msgProps) {
}
if (!isExplicitlyMentioned) {
return {result: 'not_sent', reason: 'not_explicitly_mentioned', data: mentionableText};
return {status: 'not_sent', reason: 'not_explicitly_mentioned', data: mentionableText};
}
} else if (notifyLevel === NotificationLevels.MENTION && mentions.indexOf(user.id) === -1 && msgProps.channel_type !== Constants.DM_CHANNEL) {
return {result: 'not_sent', reason: 'not_mentioned'};
return {status: 'not_sent', reason: 'not_mentioned'};
} else if (isCrtReply && notifyLevel === NotificationLevels.ALL && followers.indexOf(currentUserId) === -1) {
// if user is not following the thread don't notify
return {result: 'not_sent', reason: 'not_following_thread'};
return {status: 'not_sent', reason: 'not_following_thread'};
}
const config = getConfig(state);
@@ -273,18 +273,18 @@ export function sendDesktopNotification(post, msgProps) {
const channelId = channel ? channel.id : null;
let notify = false;
let notifyResult = {result: 'not_sent', reason: 'unknown'};
let notifyResult = {status: 'not_sent', reason: 'unknown'};
if (state.views.browser.focused) {
notifyResult = {result: 'not_sent', reason: 'window_is_focused'};
notifyResult = {status: 'not_sent', reason: 'window_is_focused'};
if (isCrtReply) {
notify = !isThreadOpen(state, post.root_id);
if (!notify) {
notifyResult = {result: 'not_sent', reason: 'thread_is_open', data: post.root_id};
notifyResult = {status: 'not_sent', reason: 'thread_is_open', data: post.root_id};
}
} else {
notify = activeChannel && activeChannel.id !== channelId;
if (!notify) {
notifyResult = {result: 'not_sent', reason: 'channel_is_open', data: activeChannel?.id};
notifyResult = {status: 'not_sent', reason: 'channel_is_open', data: activeChannel?.id};
}
}
} else {
@@ -305,7 +305,7 @@ export function sendDesktopNotification(post, msgProps) {
const hookResult = await dispatch(runDesktopNotificationHooks(post, msgProps, channel, teamId, args));
if (hookResult.error) {
dispatch(logError(hookResult.error));
return {result: 'error', reason: 'desktop_notification_hook', data: String(hookResult.error)};
return {status: 'error', reason: 'desktop_notification_hook', data: String(hookResult.error)};
}
let silent = false;
@@ -323,7 +323,7 @@ export function sendDesktopNotification(post, msgProps) {
}
if (args.notify && !notify) {
notifyResult = {result: 'not_sent', reason: 'desktop_notification_hook', data: String(hookResult)};
notifyResult = {status: 'not_sent', reason: 'desktop_notification_hook', data: String(hookResult)};
}
return notifyResult;
@@ -349,6 +349,6 @@ export const notifyMe = (title, body, channel, teamId, silent, soundName, url) =
});
} catch (error) {
dispatch(logError(error));
return {result: 'error', reason: 'notification_api', data: String(error)};
return {status: 'error', reason: 'notification_api', data: String(error)};
}
};

Просмотреть файл

@@ -167,7 +167,7 @@ class DesktopAppAPI {
) => {
if (window.desktopAPI?.sendNotification) {
const result = await window.desktopAPI.sendNotification(title, body, channelId, teamId, url, silent, soundName);
return result ?? {result: 'unsupported', reason: 'desktop_app_unsupported'};
return result ?? {status: 'unsupported', reason: 'desktop_app_unsupported'};
}
// get the desktop app to trigger the notification
@@ -186,7 +186,7 @@ class DesktopAppAPI {
},
window.location.origin,
);
return {result: 'unsupported', reason: 'desktop_app_unsupported'};
return {status: 'unsupported', reason: 'desktop_app_unsupported'};
};
doBrowserHistoryPush = (path: string) => {

Просмотреть файл

@@ -53,7 +53,7 @@ export async function showNotification(
if (Notification.permission !== 'granted' && requestedNotificationPermission) {
// User didn't allow notifications
return {result: 'not_sent', reason: 'notifications_permission_previously_denied', data: Notification.permission, callback: () => {}};
return {status: 'not_sent', reason: 'notifications_permission_previously_denied', data: Notification.permission, callback: () => {}};
}
requestedNotificationPermission = true;
@@ -68,7 +68,7 @@ export async function showNotification(
if (permission !== 'granted') {
// User has denied notification for the site
return {result: 'not_sent', reason: 'notifications_permission_denied', data: permission, callback: () => {}};
return {status: 'not_sent', reason: 'notifications_permission_denied', data: permission, callback: () => {}};
}
const notification = new Notification(title, {
@@ -95,7 +95,7 @@ export async function showNotification(
}
return {
result: 'success',
status: 'success',
callback: () => {
notification.close();
},

8
webapp/package-lock.json сгенерированный
Просмотреть файл

@@ -62,7 +62,7 @@
"@mattermost/client": "*",
"@mattermost/compass-components": "^0.2.12",
"@mattermost/compass-icons": "0.1.39",
"@mattermost/desktop-api": "5.8.0-4",
"@mattermost/desktop-api": "5.8.0-5",
"@mattermost/types": "*",
"@mui/base": "5.0.0-alpha.127",
"@mui/material": "5.11.16",
@@ -4290,9 +4290,9 @@
"link": true
},
"node_modules/@mattermost/desktop-api": {
"version": "5.8.0-4",
"resolved": "https://registry.npmjs.org/@mattermost/desktop-api/-/desktop-api-5.8.0-4.tgz",
"integrity": "sha512-oEbh3ByDgM432LrjO9JsRnIwqBIAkF6bJaQkHjYeQAYwkI4/s4CSQ4kZcfMiO9hE0MjfF1VeXnGTBv9wyWsbAw==",
"version": "5.8.0-5",
"resolved": "https://registry.npmjs.org/@mattermost/desktop-api/-/desktop-api-5.8.0-5.tgz",
"integrity": "sha512-YPtFRnduVFOXyK25GedJA+PkAKmFpLDKqfxvV/IIS+SMypv6BD17LJ8AkdBsguFFa6ZWLlZU40M5grKYBbjOuA==",
"peerDependencies": {
"typescript": "^4.3.0 || ^5.0.0"
},

Просмотреть файл

@@ -412,11 +412,11 @@ export default class WebSocketClient {
this.sendMessage('user_update_active_status', data, callback);
}
acknowledgePostedNotification(postId: string, result: 'error' | 'not_sent' | 'unsupported' | 'success', reason?: string, postedData?: string) {
acknowledgePostedNotification(postId: string, status: string, reason?: string, postedData?: string) {
const data = {
post_id: postId,
user_agent: window.navigator.userAgent,
result,
status,
reason,
data: postedData,
};

Просмотреть файл

@@ -221,3 +221,10 @@ export type PostInfo = {
team_display_name: string;
has_joined_team: boolean;
}
export type NotificationStatus = 'error' | 'not_sent' | 'unsupported' | 'success';
export type NotificationResult = {
status: NotificationStatus;
reason?: string;
data?: string;
}