@backstage/plugin-notifications 0.5.14-next.1 → 0.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @backstage/plugin-notifications
2
2
 
3
+ ## 0.5.14
4
+
5
+ ### Patch Changes
6
+
7
+ - 8005286: Added `renderItem` prop to `NotificationsSidebarItem` component, allowing custom UI rendering while retaining all built-in notification logic (unread count, snackbar, signals, web notifications).
8
+ - a7e0d50: Updated `react-router-dom` peer dependency to `^6.30.2` and explicitly disabled v7 future flags to suppress deprecation warnings.
9
+ - Updated dependencies
10
+ - @backstage/core-components@0.18.7
11
+ - @backstage/theme@0.7.2
12
+ - @backstage/frontend-plugin-api@0.14.0
13
+ - @backstage/plugin-notifications-common@0.2.1
14
+ - @backstage/core-plugin-api@1.12.3
15
+ - @backstage/plugin-signals-react@0.0.19
16
+
17
+ ## 0.5.14-next.2
18
+
19
+ ### Patch Changes
20
+
21
+ - a7e0d50: Prepare for React Router v7 migration by updating to v6.30.2 across all NFS packages and enabling v7 future flags. Convert routes from splat paths to parent/child structure with Outlet components.
22
+ - Updated dependencies
23
+ - @backstage/frontend-plugin-api@0.14.0-next.2
24
+ - @backstage/core-components@0.18.7-next.2
25
+ - @backstage/core-plugin-api@1.12.3-next.1
26
+ - @backstage/plugin-signals-react@0.0.19-next.1
27
+ - @backstage/theme@0.7.2-next.1
28
+
3
29
  ## 0.5.14-next.1
4
30
 
5
31
  ### Patch Changes
package/dist/alpha.d.ts CHANGED
@@ -5,8 +5,8 @@ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
5
5
  /** @alpha */
6
6
  declare const notificationsTranslationRef: _backstage_frontend_plugin_api.TranslationRef<"plugin.notifications", {
7
7
  readonly "table.errors.markAllReadFailed": "Failed to mark all notifications as read";
8
- readonly "table.pagination.firstTooltip": "First Page";
9
8
  readonly "table.pagination.labelDisplayedRows": "{from}-{to} of {count}";
9
+ readonly "table.pagination.firstTooltip": "First Page";
10
10
  readonly "table.pagination.labelRowsSelect": "rows";
11
11
  readonly "table.pagination.lastTooltip": "Last Page";
12
12
  readonly "table.pagination.nextTooltip": "Next Page";
@@ -82,19 +82,40 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
82
82
  name: undefined;
83
83
  config: {
84
84
  path: string | undefined;
85
+ title: string | undefined;
85
86
  };
86
87
  configInput: {
88
+ title?: string | undefined;
87
89
  path?: string | undefined;
88
90
  };
89
- output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
91
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
92
+ optional: true;
93
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {
94
+ optional: true;
95
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
90
96
  optional: true;
91
97
  }>;
92
- inputs: {};
98
+ inputs: {
99
+ pages: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
100
+ optional: true;
101
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {
102
+ optional: true;
103
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
104
+ optional: true;
105
+ }>, {
106
+ singleton: false;
107
+ optional: false;
108
+ internal: false;
109
+ }>;
110
+ };
93
111
  params: {
94
112
  defaultPath?: [Error: `Use the 'path' param instead`];
95
113
  path: string;
96
- loader: () => Promise<JSX.Element>;
114
+ title?: string;
115
+ icon?: _backstage_frontend_plugin_api.IconElement;
116
+ loader?: () => Promise<react.JSX.Element>;
97
117
  routeRef?: _backstage_frontend_plugin_api.RouteRef;
118
+ noHeader?: boolean;
98
119
  };
99
120
  }>;
100
121
  }>;
@@ -193,6 +193,17 @@ const NotificationsSidebarItem = (props) => {
193
193
  }
194
194
  }, [titleCounterEnabled, unreadCount, setNotificationCount]);
195
195
  const count = !error && !!unreadCount ? unreadCount : void 0;
196
+ const handleClick = useCallback(() => {
197
+ requestUserPermission();
198
+ }, [requestUserPermission]);
199
+ const renderItemProps = useMemo(
200
+ () => ({
201
+ unreadCount,
202
+ to: notificationsRoute,
203
+ onClick: handleClick
204
+ }),
205
+ [unreadCount, notificationsRoute, handleClick]
206
+ );
196
207
  return /* @__PURE__ */ jsxs(Fragment, { children: [
197
208
  snackbarEnabled && /* @__PURE__ */ jsx(
198
209
  SnackbarProvider,
@@ -213,13 +224,11 @@ const NotificationsSidebarItem = (props) => {
213
224
  }
214
225
  }
215
226
  ),
216
- /* @__PURE__ */ jsx(
227
+ props?.renderItem ? props.renderItem(renderItemProps) : /* @__PURE__ */ jsx(
217
228
  SidebarItem,
218
229
  {
219
230
  to: notificationsRoute,
220
- onClick: () => {
221
- requestUserPermission();
222
- },
231
+ onClick: handleClick,
223
232
  text,
224
233
  icon,
225
234
  ...restProps,
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationsSideBarItem.esm.js","sources":["../../../src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useNotificationsApi } from '../../hooks';\nimport { Link, SidebarItem } from '@backstage/core-components';\nimport NotificationsIcon from '@material-ui/icons/Notifications';\nimport {\n alertApiRef,\n IconComponent,\n useApi,\n useRouteRef,\n} from '@backstage/core-plugin-api';\nimport { rootRouteRef } from '../../routes';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport {\n Notification,\n NotificationSeverity,\n NotificationSignal,\n} from '@backstage/plugin-notifications-common';\nimport { useWebNotifications } from '../../hooks/useWebNotifications';\nimport { useTitleCounter } from '../../hooks/useTitleCounter';\nimport { notificationsApiRef } from '../../api';\nimport {\n closeSnackbar,\n enqueueSnackbar,\n MaterialDesignContent,\n OptionsWithExtraProps,\n SnackbarKey,\n SnackbarProvider,\n VariantType,\n} from 'notistack';\nimport { SeverityIcon } from '../NotificationsTable/SeverityIcon';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport MarkAsReadIcon from '@material-ui/icons/CheckCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport Chip from '@material-ui/core/Chip';\nimport { styled } from '@material-ui/core/styles';\n\nconst StyledMaterialDesignContent = styled(MaterialDesignContent)(\n ({ theme }) => ({\n '&.notistack-MuiContent-low': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-normal': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-high': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-critical': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n }),\n);\n\ndeclare module 'notistack' {\n interface VariantOverrides {\n // Custom variants for the snackbar\n low: true;\n normal: true;\n high: true;\n critical: true;\n }\n}\n\n/**\n * @public\n */\nexport type NotificationSnackbarProperties = {\n enabled?: boolean;\n autoHideDuration?: number | null;\n anchorOrigin?: {\n vertical: 'top' | 'bottom';\n horizontal: 'left' | 'center' | 'right';\n };\n dense?: boolean;\n maxSnack?: number;\n snackStyle?: React.CSSProperties;\n iconVariant?: Partial<Record<NotificationSeverity, React.ReactNode>>;\n Components?: {\n [key in NotificationSeverity]: React.JSXElementConstructor<any>;\n };\n};\n\n/**\n * @public\n */\nexport type NotificationsSideBarItemProps = {\n webNotificationsEnabled?: boolean;\n titleCounterEnabled?: boolean;\n /**\n * @deprecated Use `snackbarProps` instead.\n */\n snackbarEnabled?: boolean;\n /**\n * @deprecated Use `snackbarProps` instead.\n */\n snackbarAutoHideDuration?: number | null;\n snackbarProps?: NotificationSnackbarProperties;\n className?: string;\n icon?: IconComponent;\n text?: string;\n disableHighlight?: boolean;\n noTrack?: boolean;\n};\n\n/** @public */\nexport const NotificationsSidebarItem = (\n props?: NotificationsSideBarItemProps,\n) => {\n const {\n webNotificationsEnabled = false,\n titleCounterEnabled = true,\n snackbarEnabled = true,\n snackbarAutoHideDuration = 10000,\n icon = NotificationsIcon,\n text = 'Notifications',\n ...restProps\n } = props ?? {\n webNotificationsEnabled: false,\n titleCounterEnabled: true,\n snackbarProps: {\n enabled: true,\n autoHideDuration: 10000,\n },\n };\n\n const snackbarProps = useMemo(\n () =>\n props?.snackbarProps ?? {\n enabled: snackbarEnabled,\n autoHideDuration: snackbarAutoHideDuration,\n },\n [props?.snackbarProps, snackbarAutoHideDuration, snackbarEnabled],\n );\n\n const { loading, error, value, retry } = useNotificationsApi(api =>\n api.getStatus(),\n );\n const notificationsApi = useApi(notificationsApiRef);\n const alertApi = useApi(alertApiRef);\n const [unreadCount, setUnreadCount] = useState(0);\n const notificationsRoute = useRouteRef(rootRouteRef)();\n // TODO: Do we want to add long polling in case signals are not available\n const { lastSignal } = useSignal<NotificationSignal>('notifications');\n const { sendWebNotification, requestUserPermission } = useWebNotifications(\n webNotificationsEnabled,\n );\n const [refresh, setRefresh] = useState(false);\n const { setNotificationCount } = useTitleCounter();\n\n const getSnackbarProperties = useCallback(\n (notification: Notification) => {\n const action = (snackBarId: SnackbarKey) => (\n <>\n <IconButton\n component={Link}\n to={notification.payload.link ?? notificationsRoute}\n onClick={() => {\n if (notification.payload.link) {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }\n closeSnackbar(snackBarId);\n }}\n >\n <OpenInNew fontSize=\"small\" />\n </IconButton>\n <IconButton\n onClick={() => {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .then(() => {\n closeSnackbar(snackBarId);\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }}\n >\n <MarkAsReadIcon fontSize=\"small\" />\n </IconButton>\n </>\n );\n\n return { action };\n },\n [notificationsRoute, notificationsApi, alertApi],\n );\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, retry]);\n\n useEffect(() => {\n const handleNotificationSignal = (signal: NotificationSignal) => {\n if (\n (!webNotificationsEnabled && !snackbarProps.enabled) ||\n signal.action !== 'new_notification'\n ) {\n return;\n }\n notificationsApi\n .getNotification(signal.notification_id)\n .then(notification => {\n if (!notification) {\n return;\n }\n if (webNotificationsEnabled) {\n sendWebNotification({\n id: notification.id,\n title: notification.payload.title,\n description: notification.payload.description ?? '',\n link: notification.payload.link,\n });\n }\n if (snackbarProps.enabled) {\n const { action } = getSnackbarProperties(notification);\n const snackBarText =\n notification.payload.title.length > 50\n ? `${notification.payload.title.substring(0, 50)}...`\n : notification.payload.title;\n enqueueSnackbar(snackBarText, {\n key: notification.id,\n style: snackbarProps.snackStyle,\n variant: notification.payload.severity,\n anchorOrigin: snackbarProps.anchorOrigin ?? {\n vertical: 'bottom',\n horizontal: 'right',\n },\n action,\n autoHideDuration: snackbarProps.autoHideDuration,\n } as OptionsWithExtraProps<VariantType>);\n }\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to fetch notification',\n severity: 'error',\n });\n });\n };\n\n if (lastSignal && lastSignal.action) {\n handleNotificationSignal(lastSignal);\n setRefresh(true);\n }\n }, [\n lastSignal,\n sendWebNotification,\n webNotificationsEnabled,\n notificationsApi,\n alertApi,\n getSnackbarProperties,\n snackbarProps,\n ]);\n\n useEffect(() => {\n if (!loading && !error && value) {\n setUnreadCount(value.unread);\n }\n }, [loading, error, value]);\n\n useEffect(() => {\n if (titleCounterEnabled) {\n setNotificationCount(unreadCount);\n }\n }, [titleCounterEnabled, unreadCount, setNotificationCount]);\n\n const count = !error && !!unreadCount ? unreadCount : undefined;\n\n return (\n <>\n {snackbarEnabled && (\n <SnackbarProvider\n iconVariant={{\n normal: snackbarProps?.iconVariant?.normal ?? (\n <SeverityIcon severity=\"normal\" />\n ),\n critical: snackbarProps?.iconVariant?.critical ?? (\n <SeverityIcon severity=\"critical\" />\n ),\n high: snackbarProps?.iconVariant?.high ?? (\n <SeverityIcon severity=\"high\" />\n ),\n low: snackbarProps?.iconVariant?.low ?? (\n <SeverityIcon severity=\"low\" />\n ),\n }}\n dense={snackbarProps?.dense}\n maxSnack={snackbarProps?.maxSnack}\n Components={{\n normal:\n snackbarProps?.Components?.normal ?? StyledMaterialDesignContent,\n critical:\n snackbarProps?.Components?.critical ??\n StyledMaterialDesignContent,\n high:\n snackbarProps?.Components?.high ?? StyledMaterialDesignContent,\n low: snackbarProps?.Components?.low ?? StyledMaterialDesignContent,\n }}\n />\n )}\n <SidebarItem\n to={notificationsRoute}\n onClick={() => {\n requestUserPermission();\n }}\n text={text}\n icon={icon}\n {...restProps}\n >\n {count && <Chip size=\"small\" label={count > 99 ? '99+' : count} />}\n </SidebarItem>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NotificationsSideBarItem.esm.js","sources":["../../../src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useNotificationsApi } from '../../hooks';\nimport { Link, SidebarItem } from '@backstage/core-components';\nimport NotificationsIcon from '@material-ui/icons/Notifications';\nimport {\n alertApiRef,\n IconComponent,\n useApi,\n useRouteRef,\n} from '@backstage/core-plugin-api';\nimport { rootRouteRef } from '../../routes';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport {\n Notification,\n NotificationSeverity,\n NotificationSignal,\n} from '@backstage/plugin-notifications-common';\nimport { useWebNotifications } from '../../hooks/useWebNotifications';\nimport { useTitleCounter } from '../../hooks/useTitleCounter';\nimport { notificationsApiRef } from '../../api';\nimport {\n closeSnackbar,\n enqueueSnackbar,\n MaterialDesignContent,\n OptionsWithExtraProps,\n SnackbarKey,\n SnackbarProvider,\n VariantType,\n} from 'notistack';\nimport { SeverityIcon } from '../NotificationsTable/SeverityIcon';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport MarkAsReadIcon from '@material-ui/icons/CheckCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport Chip from '@material-ui/core/Chip';\nimport { styled } from '@material-ui/core/styles';\n\nconst StyledMaterialDesignContent = styled(MaterialDesignContent)(\n ({ theme }) => ({\n '&.notistack-MuiContent-low': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-normal': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-high': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-critical': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n }),\n);\n\ndeclare module 'notistack' {\n interface VariantOverrides {\n // Custom variants for the snackbar\n low: true;\n normal: true;\n high: true;\n critical: true;\n }\n}\n\n/**\n * @public\n */\nexport type NotificationSnackbarProperties = {\n enabled?: boolean;\n autoHideDuration?: number | null;\n anchorOrigin?: {\n vertical: 'top' | 'bottom';\n horizontal: 'left' | 'center' | 'right';\n };\n dense?: boolean;\n maxSnack?: number;\n snackStyle?: React.CSSProperties;\n iconVariant?: Partial<Record<NotificationSeverity, React.ReactNode>>;\n Components?: {\n [key in NotificationSeverity]: React.JSXElementConstructor<any>;\n };\n};\n\n/**\n * Props passed to the custom renderItem function\n * @public\n */\nexport type NotificationsRenderItemProps = {\n /** Current unread notification count */\n unreadCount: number;\n /** Route path to the notifications page */\n to: string;\n /** Click handler that requests web notification permission */\n onClick: () => void;\n};\n\n/**\n * @public\n */\nexport type NotificationsSideBarItemProps = {\n webNotificationsEnabled?: boolean;\n titleCounterEnabled?: boolean;\n /**\n * @deprecated Use `snackbarProps` instead.\n */\n snackbarEnabled?: boolean;\n /**\n * @deprecated Use `snackbarProps` instead.\n */\n snackbarAutoHideDuration?: number | null;\n snackbarProps?: NotificationSnackbarProperties;\n className?: string;\n icon?: IconComponent;\n text?: string;\n disableHighlight?: boolean;\n noTrack?: boolean;\n /**\n * Optional render function to provide custom UI instead of the default SidebarItem.\n */\n renderItem?: (props: NotificationsRenderItemProps) => React.ReactNode;\n};\n\n/** @public */\nexport const NotificationsSidebarItem = (\n props?: NotificationsSideBarItemProps,\n) => {\n const {\n webNotificationsEnabled = false,\n titleCounterEnabled = true,\n snackbarEnabled = true,\n snackbarAutoHideDuration = 10000,\n icon = NotificationsIcon,\n text = 'Notifications',\n ...restProps\n } = props ?? {\n webNotificationsEnabled: false,\n titleCounterEnabled: true,\n snackbarProps: {\n enabled: true,\n autoHideDuration: 10000,\n },\n };\n\n const snackbarProps = useMemo(\n () =>\n props?.snackbarProps ?? {\n enabled: snackbarEnabled,\n autoHideDuration: snackbarAutoHideDuration,\n },\n [props?.snackbarProps, snackbarAutoHideDuration, snackbarEnabled],\n );\n\n const { loading, error, value, retry } = useNotificationsApi(api =>\n api.getStatus(),\n );\n const notificationsApi = useApi(notificationsApiRef);\n const alertApi = useApi(alertApiRef);\n const [unreadCount, setUnreadCount] = useState(0);\n const notificationsRoute = useRouteRef(rootRouteRef)();\n // TODO: Do we want to add long polling in case signals are not available\n const { lastSignal } = useSignal<NotificationSignal>('notifications');\n const { sendWebNotification, requestUserPermission } = useWebNotifications(\n webNotificationsEnabled,\n );\n const [refresh, setRefresh] = useState(false);\n const { setNotificationCount } = useTitleCounter();\n\n const getSnackbarProperties = useCallback(\n (notification: Notification) => {\n const action = (snackBarId: SnackbarKey) => (\n <>\n <IconButton\n component={Link}\n to={notification.payload.link ?? notificationsRoute}\n onClick={() => {\n if (notification.payload.link) {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }\n closeSnackbar(snackBarId);\n }}\n >\n <OpenInNew fontSize=\"small\" />\n </IconButton>\n <IconButton\n onClick={() => {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .then(() => {\n closeSnackbar(snackBarId);\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }}\n >\n <MarkAsReadIcon fontSize=\"small\" />\n </IconButton>\n </>\n );\n\n return { action };\n },\n [notificationsRoute, notificationsApi, alertApi],\n );\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, retry]);\n\n useEffect(() => {\n const handleNotificationSignal = (signal: NotificationSignal) => {\n if (\n (!webNotificationsEnabled && !snackbarProps.enabled) ||\n signal.action !== 'new_notification'\n ) {\n return;\n }\n notificationsApi\n .getNotification(signal.notification_id)\n .then(notification => {\n if (!notification) {\n return;\n }\n if (webNotificationsEnabled) {\n sendWebNotification({\n id: notification.id,\n title: notification.payload.title,\n description: notification.payload.description ?? '',\n link: notification.payload.link,\n });\n }\n if (snackbarProps.enabled) {\n const { action } = getSnackbarProperties(notification);\n const snackBarText =\n notification.payload.title.length > 50\n ? `${notification.payload.title.substring(0, 50)}...`\n : notification.payload.title;\n enqueueSnackbar(snackBarText, {\n key: notification.id,\n style: snackbarProps.snackStyle,\n variant: notification.payload.severity,\n anchorOrigin: snackbarProps.anchorOrigin ?? {\n vertical: 'bottom',\n horizontal: 'right',\n },\n action,\n autoHideDuration: snackbarProps.autoHideDuration,\n } as OptionsWithExtraProps<VariantType>);\n }\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to fetch notification',\n severity: 'error',\n });\n });\n };\n\n if (lastSignal && lastSignal.action) {\n handleNotificationSignal(lastSignal);\n setRefresh(true);\n }\n }, [\n lastSignal,\n sendWebNotification,\n webNotificationsEnabled,\n notificationsApi,\n alertApi,\n getSnackbarProperties,\n snackbarProps,\n ]);\n\n useEffect(() => {\n if (!loading && !error && value) {\n setUnreadCount(value.unread);\n }\n }, [loading, error, value]);\n\n useEffect(() => {\n if (titleCounterEnabled) {\n setNotificationCount(unreadCount);\n }\n }, [titleCounterEnabled, unreadCount, setNotificationCount]);\n\n const count = !error && !!unreadCount ? unreadCount : undefined;\n\n const handleClick = useCallback(() => {\n requestUserPermission();\n }, [requestUserPermission]);\n\n // Props to pass to custom renderItem function\n const renderItemProps: NotificationsRenderItemProps = useMemo(\n () => ({\n unreadCount,\n to: notificationsRoute,\n onClick: handleClick,\n }),\n [unreadCount, notificationsRoute, handleClick],\n );\n\n return (\n <>\n {snackbarEnabled && (\n <SnackbarProvider\n iconVariant={{\n normal: snackbarProps?.iconVariant?.normal ?? (\n <SeverityIcon severity=\"normal\" />\n ),\n critical: snackbarProps?.iconVariant?.critical ?? (\n <SeverityIcon severity=\"critical\" />\n ),\n high: snackbarProps?.iconVariant?.high ?? (\n <SeverityIcon severity=\"high\" />\n ),\n low: snackbarProps?.iconVariant?.low ?? (\n <SeverityIcon severity=\"low\" />\n ),\n }}\n dense={snackbarProps?.dense}\n maxSnack={snackbarProps?.maxSnack}\n Components={{\n normal:\n snackbarProps?.Components?.normal ?? StyledMaterialDesignContent,\n critical:\n snackbarProps?.Components?.critical ??\n StyledMaterialDesignContent,\n high:\n snackbarProps?.Components?.high ?? StyledMaterialDesignContent,\n low: snackbarProps?.Components?.low ?? StyledMaterialDesignContent,\n }}\n />\n )}\n {props?.renderItem ? (\n props.renderItem(renderItemProps)\n ) : (\n <SidebarItem\n to={notificationsRoute}\n onClick={handleClick}\n text={text}\n icon={icon}\n {...restProps}\n >\n {count && <Chip size=\"small\" label={count > 99 ? '99+' : count} />}\n </SidebarItem>\n )}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -31,6 +31,18 @@ type NotificationSnackbarProperties = {
31
31
  [key in NotificationSeverity]: React.JSXElementConstructor<any>;
32
32
  };
33
33
  };
34
+ /**
35
+ * Props passed to the custom renderItem function
36
+ * @public
37
+ */
38
+ type NotificationsRenderItemProps = {
39
+ /** Current unread notification count */
40
+ unreadCount: number;
41
+ /** Route path to the notifications page */
42
+ to: string;
43
+ /** Click handler that requests web notification permission */
44
+ onClick: () => void;
45
+ };
34
46
  /**
35
47
  * @public
36
48
  */
@@ -51,6 +63,10 @@ type NotificationsSideBarItemProps = {
51
63
  text?: string;
52
64
  disableHighlight?: boolean;
53
65
  noTrack?: boolean;
66
+ /**
67
+ * Optional render function to provide custom UI instead of the default SidebarItem.
68
+ */
69
+ renderItem?: (props: NotificationsRenderItemProps) => React.ReactNode;
54
70
  };
55
71
  /** @public */
56
72
  declare const NotificationsSidebarItem: (props?: NotificationsSideBarItemProps) => react_jsx_runtime.JSX.Element;
@@ -182,4 +198,4 @@ declare function useNotificationsApi<T>(f: (api: NotificationsApi) => Promise<T>
182
198
  };
183
199
 
184
200
  export { NotificationsClient, NotificationsPage, NotificationsSidebarItem, NotificationsTable, UserNotificationSettingsCard, notificationsApiRef, notificationsPlugin, useNotificationsApi };
185
- export type { GetNotificationsCommonOptions, GetNotificationsOptions, GetNotificationsResponse, GetTopicsOptions, GetTopicsResponse, NotificationSnackbarProperties, NotificationsApi, NotificationsPageProps, NotificationsSideBarItemProps, NotificationsTableProps, UpdateNotificationsOptions };
201
+ export type { GetNotificationsCommonOptions, GetNotificationsOptions, GetNotificationsResponse, GetTopicsOptions, GetTopicsResponse, NotificationSnackbarProperties, NotificationsApi, NotificationsPageProps, NotificationsRenderItemProps, NotificationsSideBarItemProps, NotificationsTableProps, UpdateNotificationsOptions };
@@ -1,5 +1,5 @@
1
1
  var name = "@backstage/plugin-notifications";
2
- var version = "0.5.14-next.1";
2
+ var version = "0.5.14";
3
3
  var backstage = {
4
4
  role: "frontend-plugin",
5
5
  pluginId: "notifications",
@@ -76,13 +76,13 @@ var devDependencies = {
76
76
  msw: "^1.0.0",
77
77
  react: "^18.0.2",
78
78
  "react-dom": "^18.0.2",
79
- "react-router-dom": "^6.3.0"
79
+ "react-router-dom": "^6.30.2"
80
80
  };
81
81
  var peerDependencies = {
82
82
  "@types/react": "^17.0.0 || ^18.0.0",
83
83
  react: "^17.0.0 || ^18.0.0",
84
84
  "react-dom": "^17.0.0 || ^18.0.0",
85
- "react-router-dom": "^6.3.0"
85
+ "react-router-dom": "^6.30.2"
86
86
  };
87
87
  var peerDependenciesMeta = {
88
88
  "@types/react": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-notifications",
3
- "version": "0.5.14-next.1",
3
+ "version": "0.5.14",
4
4
  "backstage": {
5
5
  "role": "frontend-plugin",
6
6
  "pluginId": "notifications",
@@ -63,13 +63,13 @@
63
63
  "test": "backstage-cli package test"
64
64
  },
65
65
  "dependencies": {
66
- "@backstage/core-components": "0.18.7-next.1",
67
- "@backstage/core-plugin-api": "1.12.3-next.0",
68
- "@backstage/errors": "1.2.7",
69
- "@backstage/frontend-plugin-api": "0.14.0-next.1",
70
- "@backstage/plugin-notifications-common": "0.2.0",
71
- "@backstage/plugin-signals-react": "0.0.19-next.0",
72
- "@backstage/theme": "0.7.2-next.0",
66
+ "@backstage/core-components": "^0.18.7",
67
+ "@backstage/core-plugin-api": "^1.12.3",
68
+ "@backstage/errors": "^1.2.7",
69
+ "@backstage/frontend-plugin-api": "^0.14.0",
70
+ "@backstage/plugin-notifications-common": "^0.2.1",
71
+ "@backstage/plugin-signals-react": "^0.0.19",
72
+ "@backstage/theme": "^0.7.2",
73
73
  "@material-ui/core": "^4.9.13",
74
74
  "@material-ui/icons": "^4.9.1",
75
75
  "lodash": "^4.17.21",
@@ -79,23 +79,23 @@
79
79
  "react-use": "^17.2.4"
80
80
  },
81
81
  "devDependencies": {
82
- "@backstage/cli": "0.35.4-next.1",
83
- "@backstage/dev-utils": "1.1.20-next.1",
84
- "@backstage/plugin-signals": "0.0.28-next.1",
85
- "@backstage/test-utils": "1.7.15-next.1",
82
+ "@backstage/cli": "^0.35.4",
83
+ "@backstage/dev-utils": "^1.1.20",
84
+ "@backstage/plugin-signals": "^0.0.28",
85
+ "@backstage/test-utils": "^1.7.15",
86
86
  "@testing-library/jest-dom": "^6.0.0",
87
87
  "@testing-library/react": "^16.0.0",
88
88
  "@types/react": "^18.0.0",
89
89
  "msw": "^1.0.0",
90
90
  "react": "^18.0.2",
91
91
  "react-dom": "^18.0.2",
92
- "react-router-dom": "^6.3.0"
92
+ "react-router-dom": "^6.30.2"
93
93
  },
94
94
  "peerDependencies": {
95
95
  "@types/react": "^17.0.0 || ^18.0.0",
96
96
  "react": "^17.0.0 || ^18.0.0",
97
97
  "react-dom": "^17.0.0 || ^18.0.0",
98
- "react-router-dom": "^6.3.0"
98
+ "react-router-dom": "^6.30.2"
99
99
  },
100
100
  "peerDependenciesMeta": {
101
101
  "@types/react": {