Skip to content

Commit

Permalink
feat(notifications): Make all error notifications sticky.
Browse files Browse the repository at this point in the history
There are many cases where the error disappears and users easily miss the information.
  • Loading branch information
damencho committed Feb 7, 2025
1 parent 75b4049 commit fbeae84
Show file tree
Hide file tree
Showing 15 changed files with 30 additions and 37 deletions.
4 changes: 2 additions & 2 deletions conference.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,15 +287,15 @@ class ConferenceConnector {
},
descriptionKey: 'dialog.reservationErrorMsg',
titleKey: 'dialog.reservationError'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
break;
}

case JitsiConferenceErrors.GRACEFUL_SHUTDOWN:
APP.store.dispatch(showErrorNotification({
descriptionKey: 'dialog.gracefulShutdown',
titleKey: 'dialog.serviceUnavailable'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
break;

// FIXME FOCUS_DISCONNECTED is a confusing event name.
Expand Down
10 changes: 5 additions & 5 deletions react/features/base/conference/middleware.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
dispatch(showErrorNotification({
description: 'Restart initiated because of a bridge failure',
titleKey: 'dialog.sessionRestarted'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
}

break;
Expand All @@ -190,7 +190,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
descriptionArguments: { msg },
descriptionKey: msg ? 'dialog.connectErrorWithMsg' : 'dialog.connectError',
titleKey: 'connection.CONNFAIL'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

break;
}
Expand All @@ -199,7 +199,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
hideErrorSupportLink: true,
descriptionKey: 'dialog.maxUsersLimitReached',
titleKey: 'dialog.maxUsersLimitReachedTitle'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

// In case of max users(it can be from a visitor node), let's restore
// oldConfig if any as we will be back to the main prosody.
Expand Down Expand Up @@ -236,7 +236,7 @@ function _conferenceFailed({ dispatch, getState }: IStore, next: Function, actio
descriptionKey,
hideErrorSupportLink: true,
titleKey
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}));

sendAnalytics(createNotAllowedErrorEvent(type, msg));

Expand Down Expand Up @@ -416,7 +416,7 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio
descriptionKey: errors ? 'dialog.tokenAuthFailedWithReasons' : 'dialog.tokenAuthFailed',
descriptionArguments: { reason: errors },
titleKey: 'dialog.tokenAuthFailedTitle'
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}));
}
}

Expand Down
2 changes: 1 addition & 1 deletion react/features/base/tracks/actions.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ export function showNoDataFromSourceVideoError(jitsiTrack: any) {
const notificationAction = dispatch(showErrorNotification({
descriptionKey: 'dialog.cameraNotSendingData',
titleKey: 'dialog.cameraNotSendingDataTitle'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

notificationInfo = {
uid: notificationAction?.uid
Expand Down
12 changes: 5 additions & 7 deletions react/features/base/tracks/actions.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ async function _toggleScreenSharing(
try {
tracks = await createLocalTracksF(options) as any[];
} catch (error) {
dispatch(handleScreenSharingError(error, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
dispatch(handleScreenSharingError(error));

throw error;
}
Expand All @@ -171,7 +171,7 @@ async function _toggleScreenSharing(
desktopVideoTrack.dispose();

if (!desktopAudioTrack) {
dispatch(handleScreenSharingError(AUDIO_ONLY_SCREEN_SHARE_NO_TRACK, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
dispatch(handleScreenSharingError(AUDIO_ONLY_SCREEN_SHARE_NO_TRACK));

throw new Error(AUDIO_ONLY_SCREEN_SHARE_NO_TRACK);
}
Expand Down Expand Up @@ -457,7 +457,7 @@ export function displayErrorsForCreateInitialLocalTracks(errors: IInitialTracksE
} = errors;

if (screenSharingError) {
dispatch(handleScreenSharingError(screenSharingError, NOTIFICATION_TIMEOUT_TYPE.LONG));
dispatch(handleScreenSharingError(screenSharingError));
}
if (audioOnlyError || videoOnlyError) {
if (audioOnlyError) {
Expand All @@ -476,12 +476,10 @@ export function displayErrorsForCreateInitialLocalTracks(errors: IInitialTracksE
*
* @private
* @param {Error | AUDIO_ONLY_SCREEN_SHARE_NO_TRACK} error - The error.
* @param {NOTIFICATION_TIMEOUT_TYPE} timeout - The time for showing the notification.
* @returns {Function}
*/
export function handleScreenSharingError(
error: Error | AUDIO_ONLY_SCREEN_SHARE_NO_TRACK,
timeout: NOTIFICATION_TIMEOUT_TYPE) {
error: Error | AUDIO_ONLY_SCREEN_SHARE_NO_TRACK) {
return (dispatch: IStore['dispatch']) => {
logger.error('failed to share local desktop', error);

Expand All @@ -508,6 +506,6 @@ export function handleScreenSharingError(
dispatch(showErrorNotification({
descriptionKey,
titleKey
}, timeout));
}));
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export default class AbstractAddPeopleDialog<P extends IProps, S extends IState>
}));
dispatch(showErrorNotification({
titleKey: 'addPeople.failedToAdd'
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
}));
} else if (!_callFlowsEnabled) {
const invitedCount = invitees.length;
let notificationProps: INotificationProps | undefined;
Expand Down
3 changes: 1 addition & 2 deletions react/features/noise-suppression/actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { IStore } from '../app/types';
import { getLocalJitsiAudioTrack } from '../base/tracks/functions';
import { showErrorNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { NoiseSuppressionEffect } from '../stream-effects/noise-suppression/NoiseSuppressionEffect';

import { SET_NOISE_SUPPRESSION_ENABLED } from './actionTypes';
Expand Down Expand Up @@ -93,7 +92,7 @@ export function setNoiseSuppressionEnabled(enabled: boolean): any {

dispatch(showErrorNotification({
titleKey: 'notify.noiseSuppressionFailedTitle'
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
}));
}
};
}
2 changes: 1 addition & 1 deletion react/features/notifications/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function setNotificationsEnabled(enabled: boolean) {
* @param {string} type - Notification type.
* @returns {Object}
*/
export function showErrorNotification(props: INotificationProps, type?: string) {
export function showErrorNotification(props: INotificationProps, type = NOTIFICATION_TIMEOUT_TYPE.STICKY) {
return showNotification({
...props,
appearance: NOTIFICATION_TYPE.ERROR
Expand Down
3 changes: 1 addition & 2 deletions react/features/old-client-notification/middleware.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { IStore } from '../app/types';
import { APP_WILL_MOUNT } from '../base/app/actionTypes';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { showErrorNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';

import OldElectronAPPNotificationDescription from './components/OldElectronAPPNotificationDescription';
import { isOldJitsiMeetElectronApp } from './functions';
Expand Down Expand Up @@ -35,7 +34,7 @@ function _appWillMount(store: IStore, next: Function, action: AnyAction) {
dispatch(showErrorNotification({
titleKey: 'notify.OldElectronAPPTitle',
description: <OldElectronAPPNotificationDescription />
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
}

return next(action);
Expand Down
9 changes: 4 additions & 5 deletions react/features/prejoin/actions.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
import { openURLInBrowser } from '../base/util/openURLInBrowser';
import { executeDialOutRequest, executeDialOutStatusRequest, getDialInfoPageURL } from '../invite/functions';
import { showErrorNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { INotificationProps } from '../notifications/types';

import {
Expand Down Expand Up @@ -108,23 +107,23 @@ function pollForStatus(
case DIAL_OUT_STATUS.DISCONNECTED: {
dispatch(showErrorNotification({
titleKey: 'prejoin.errorDialOutDisconnected'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

return onFail();
}

case DIAL_OUT_STATUS.FAILED: {
dispatch(showErrorNotification({
titleKey: 'prejoin.errorDialOutFailed'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

return onFail();
}
}
} catch (err) {
dispatch(showErrorNotification({
titleKey: 'prejoin.errorDialOutStatus'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
logger.error('Error getting dial out status', err);
onFail();
}
Expand Down Expand Up @@ -177,7 +176,7 @@ export function dialOut(onSuccess: Function, onFail: Function) {
}
}

dispatch(showErrorNotification(notification, NOTIFICATION_TIMEOUT_TYPE.LONG));
dispatch(showErrorNotification(notification));
logger.error('Error dialing out', err);
onFail();
}
Expand Down
4 changes: 2 additions & 2 deletions react/features/recording/actions.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export function highlightMeetingMoment() {
* @returns {showErrorNotification}
*/
export function showRecordingError(props: Object) {
return showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.LONG);
return showErrorNotification(props);
}

/**
Expand Down Expand Up @@ -301,7 +301,7 @@ export function showStartedRecordingNotification(
} catch (err) {
dispatch(showErrorNotification({
titleKey: 'recording.errorFetchingLink'
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
}));

return logger.error('Could not fetch recording link', err);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
import { updateDropboxToken } from '../../../dropbox/actions';
import { getDropboxData, getNewAccessToken, isEnabled as isDropboxEnabled } from '../../../dropbox/functions.any';
import { showErrorNotification } from '../../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../../notifications/constants';
import { setRequestingSubtitles } from '../../../subtitles/actions.any';
import { setSelectedRecordingService, startLocalVideoRecording } from '../../actions';
import { RECORDING_METADATA_ID, RECORDING_TYPES } from '../../constants';
Expand Down Expand Up @@ -381,7 +380,7 @@ class AbstractStartRecordingDialog extends Component<IProps, IState> {
} else {
dispatch(showErrorNotification({
titleKey: 'dialog.noDropboxToken'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

return;
}
Expand Down
2 changes: 1 addition & 1 deletion react/features/recording/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
false, 'local', err.message, isRecorderTranscriptionsRunning(getState()));
}

dispatch(showErrorNotification(props, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
dispatch(showErrorNotification(props));
});
break;
}
Expand Down
2 changes: 1 addition & 1 deletion react/features/room-lock/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function _setPasswordFailed(store: IStore, next: Function, action: AnyAction) {
APP.store.dispatch(showErrorNotification({
descriptionKey,
titleKey
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
}

return next(action);
Expand Down
3 changes: 1 addition & 2 deletions react/features/transcribing/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { showErrorNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';

import { TRANSCRIBER_LEFT } from './actionTypes';
import './subscriber';
Expand All @@ -17,7 +16,7 @@ MiddlewareRegistry.register(({ dispatch }) => next => action => {
if (action.abruptly) {
dispatch(showErrorNotification({
titleKey: 'transcribing.failed'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));
}
break;
}
Expand Down
6 changes: 3 additions & 3 deletions react/features/videosipgw/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function _inviteRooms(rooms: ISipRoom[], conference: IJitsiConference, dispatch:
dispatch(showErrorNotification({
descriptionKey: 'videoSIPGW.errorInvite',
titleKey: 'videoSIPGW.errorInviteTitle'
}, NOTIFICATION_TIMEOUT_TYPE.LONG));
}));

return;
}
Expand Down Expand Up @@ -159,14 +159,14 @@ function _sessionStateChanged(
displayName: event.displayName
},
descriptionKey: 'videoSIPGW.errorInviteFailed'
}, NOTIFICATION_TIMEOUT_TYPE.LONG);
});
}
case JitsiSIPVideoGWStatus.STATE_OFF: {
if (event.failureReason === JitsiSIPVideoGWStatus.STATUS_BUSY) {
return showErrorNotification({
descriptionKey: 'videoSIPGW.busy',
titleKey: 'videoSIPGW.busyTitle'
}, NOTIFICATION_TIMEOUT_TYPE.LONG);
});
} else if (event.failureReason) {
logger.error(`Unknown sip videogw error ${event.newState} ${
event.failureReason}`);
Expand Down

0 comments on commit fbeae84

Please sign in to comment.