Merge pull request #30897 from drodil/notification_snackbar_customization

feat: improve customization of notification snackbar
This commit is contained in:
Fredrik Adelöw
2025-08-19 09:13:51 +02:00
committed by GitHub
3 changed files with 119 additions and 22 deletions
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState, useCallback, useEffect } from 'react';
import * as React from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNotificationsApi } from '../../hooks';
import { Link, SidebarItem } from '@backstage/core-components';
import NotificationsIcon from '@material-ui/icons/Notifications';
@@ -27,6 +28,7 @@ import { rootRouteRef } from '../../routes';
import { useSignal } from '@backstage/plugin-signals-react';
import {
Notification,
NotificationSeverity,
NotificationSignal,
} from '@backstage/plugin-notifications-common';
import { useWebNotifications } from '../../hooks/useWebNotifications';
@@ -79,18 +81,51 @@ declare module 'notistack' {
}
}
/** @public */
export const NotificationsSidebarItem = (props?: {
/**
* @public
*/
export type NotificationSnackbarProperties = {
enabled?: boolean;
autoHideDuration?: number | null;
anchorOrigin?: {
vertical: 'top' | 'bottom';
horizontal: 'left' | 'center' | 'right';
};
dense?: boolean;
maxSnack?: number;
snackStyle?: React.CSSProperties;
iconVariant?: Partial<Record<NotificationSeverity, React.ReactNode>>;
Components?: {
[key in NotificationSeverity]: React.JSXElementConstructor<any>;
};
};
/**
* @public
*/
export type NotificationsSideBarItemProps = {
webNotificationsEnabled?: boolean;
titleCounterEnabled?: boolean;
/**
* @deprecated Use `snackbarProps` instead.
*/
snackbarEnabled?: boolean;
/**
* @deprecated Use `snackbarProps` instead.
*/
snackbarAutoHideDuration?: number | null;
snackbarProps?: NotificationSnackbarProperties;
className?: string;
icon?: IconComponent;
text?: string;
disableHighlight?: boolean;
noTrack?: boolean;
}) => {
};
/** @public */
export const NotificationsSidebarItem = (
props?: NotificationsSideBarItemProps,
) => {
const {
webNotificationsEnabled = false,
titleCounterEnabled = true,
@@ -102,10 +137,21 @@ export const NotificationsSidebarItem = (props?: {
} = props ?? {
webNotificationsEnabled: false,
titleCounterEnabled: true,
snackbarEnabled: true,
snackbarAutoHideDuration: 10000,
snackbarProps: {
enabled: true,
autoHideDuration: 10000,
},
};
const snackbarProps = useMemo(
() =>
props?.snackbarProps ?? {
enabled: snackbarEnabled,
autoHideDuration: snackbarAutoHideDuration,
},
[props?.snackbarProps, snackbarAutoHideDuration, snackbarEnabled],
);
const { loading, error, value, retry } = useNotificationsApi(api =>
api.getStatus(),
);
@@ -185,7 +231,7 @@ export const NotificationsSidebarItem = (props?: {
useEffect(() => {
const handleNotificationSignal = (signal: NotificationSignal) => {
if (
(!webNotificationsEnabled && !snackbarEnabled) ||
(!webNotificationsEnabled && !snackbarProps.enabled) ||
signal.action !== 'new_notification'
) {
return;
@@ -204,7 +250,7 @@ export const NotificationsSidebarItem = (props?: {
link: notification.payload.link,
});
}
if (snackbarEnabled) {
if (snackbarProps.enabled) {
const { action } = getSnackbarProperties(notification);
const snackBarText =
notification.payload.title.length > 50
@@ -212,10 +258,14 @@ export const NotificationsSidebarItem = (props?: {
: notification.payload.title;
enqueueSnackbar(snackBarText, {
key: notification.id,
style: snackbarProps.snackStyle,
variant: notification.payload.severity,
anchorOrigin: { vertical: 'bottom', horizontal: 'right' },
anchorOrigin: snackbarProps.anchorOrigin ?? {
vertical: 'bottom',
horizontal: 'right',
},
action,
autoHideDuration: snackbarAutoHideDuration,
autoHideDuration: snackbarProps.autoHideDuration,
} as OptionsWithExtraProps<VariantType>);
}
})
@@ -235,11 +285,10 @@ export const NotificationsSidebarItem = (props?: {
lastSignal,
sendWebNotification,
webNotificationsEnabled,
snackbarEnabled,
snackbarAutoHideDuration,
notificationsApi,
alertApi,
getSnackbarProperties,
snackbarProps,
]);
useEffect(() => {
@@ -261,16 +310,30 @@ export const NotificationsSidebarItem = (props?: {
{snackbarEnabled && (
<SnackbarProvider
iconVariant={{
normal: <SeverityIcon severity="normal" />,
critical: <SeverityIcon severity="critical" />,
high: <SeverityIcon severity="high" />,
low: <SeverityIcon severity="low" />,
normal: snackbarProps?.iconVariant?.normal ?? (
<SeverityIcon severity="normal" />
),
critical: snackbarProps?.iconVariant?.critical ?? (
<SeverityIcon severity="critical" />
),
high: snackbarProps?.iconVariant?.high ?? (
<SeverityIcon severity="high" />
),
low: snackbarProps?.iconVariant?.low ?? (
<SeverityIcon severity="low" />
),
}}
dense={snackbarProps?.dense}
maxSnack={snackbarProps?.maxSnack}
Components={{
normal: StyledMaterialDesignContent,
critical: StyledMaterialDesignContent,
high: StyledMaterialDesignContent,
low: StyledMaterialDesignContent,
normal:
snackbarProps?.Components?.normal ?? StyledMaterialDesignContent,
critical:
snackbarProps?.Components?.critical ??
StyledMaterialDesignContent,
high:
snackbarProps?.Components?.high ?? StyledMaterialDesignContent,
low: snackbarProps?.Components?.low ?? StyledMaterialDesignContent,
}}
/>
)}