feat: improve customization of notification snackbar
see changeset Signed-off-by: Hellgren Heikki <heikki.hellgren@op.fi>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
'@backstage/plugin-notifications': patch
|
||||
---
|
||||
|
||||
Improve customization of the notification snackbar.
|
||||
|
||||
Users can now customize the notification snackbar by providing custom components and icons
|
||||
for different severity levels. Additionally, the location of the snackbar notifications
|
||||
can be modified, the density of the snackbar can be changed, and the number of snacks can
|
||||
be limited.
|
||||
@@ -13,6 +13,7 @@ import { Notification as Notification_2 } from '@backstage/plugin-notifications-
|
||||
import { NotificationSettings } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationSeverity } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationStatus } from '@backstage/plugin-notifications-common';
|
||||
import * as React_2 from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { TableProps } from '@backstage/core-components';
|
||||
|
||||
@@ -100,6 +101,23 @@ export class NotificationsClient implements NotificationsApi {
|
||||
): Promise<NotificationSettings>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type NotificationSnackbarProperties = {
|
||||
enabled?: boolean;
|
||||
autoHideDuration?: number | null;
|
||||
anchorOrigin?: {
|
||||
vertical: 'top' | 'bottom';
|
||||
horizontal: 'left' | 'center' | 'right';
|
||||
};
|
||||
dense?: boolean;
|
||||
maxSnack?: number;
|
||||
snackStyle?: React_2.CSSProperties;
|
||||
iconVariant?: Partial<Record<NotificationSeverity, React_2.ReactNode>>;
|
||||
Components?: {
|
||||
[key in NotificationSeverity]: React_2.JSXElementConstructor<any>;
|
||||
};
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const NotificationsPage: (
|
||||
props?: NotificationsPageProps,
|
||||
@@ -125,17 +143,23 @@ export const notificationsPlugin: BackstagePlugin<
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const NotificationsSidebarItem: (props?: {
|
||||
export const NotificationsSidebarItem: (
|
||||
props?: NotificationsSideBarItemProps,
|
||||
) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export type NotificationsSideBarItemProps = {
|
||||
webNotificationsEnabled?: boolean;
|
||||
titleCounterEnabled?: boolean;
|
||||
snackbarEnabled?: boolean;
|
||||
snackbarAutoHideDuration?: number | null;
|
||||
snackbarProps?: NotificationSnackbarProperties;
|
||||
className?: string;
|
||||
icon?: IconComponent;
|
||||
text?: string;
|
||||
disableHighlight?: boolean;
|
||||
noTrack?: boolean;
|
||||
}) => JSX_2.Element;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const NotificationsTable: ({
|
||||
|
||||
+83
-20
@@ -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,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user