diff --git a/.changeset/ten-penguins-roll.md b/.changeset/ten-penguins-roll.md new file mode 100644 index 0000000000..152bb1524b --- /dev/null +++ b/.changeset/ten-penguins-roll.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': minor +--- + +By default, set notification as read when opening snackbar or web notification link diff --git a/plugins/notifications/api-report.md b/plugins/notifications/api-report.md index 9240bdb1c2..5e06ae2616 100644 --- a/plugins/notifications/api-report.md +++ b/plugins/notifications/api-report.md @@ -176,20 +176,5 @@ export function useNotificationsApi( value: T; }; -// @public (undocumented) -export function useTitleCounter(): { - setNotificationCount: (newCount: number) => void; -}; - -// @public (undocumented) -export function useWebNotifications(enabled: boolean): { - sendWebNotification: (options: { - id: string; - title: string; - description: string; - link?: string; - }) => Notification | null; -}; - // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx index 7b55c63747..457893b016 100644 --- a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx +++ b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx @@ -114,7 +114,9 @@ export const NotificationsSidebarItem = (props?: { const notificationsRoute = useRouteRef(rootRouteRef); // TODO: Do we want to add long polling in case signals are not available const { lastSignal } = useSignal('notifications'); - const { sendWebNotification } = useWebNotifications(webNotificationsEnabled); + const { sendWebNotification, requestUserPermission } = useWebNotifications( + webNotificationsEnabled, + ); const [refresh, setRefresh] = React.useState(false); const { setNotificationCount } = useTitleCounter(); @@ -126,6 +128,19 @@ export const NotificationsSidebarItem = (props?: { component={Link} to={notification.payload.link ?? notificationsRoute()} onClick={() => { + if (notification.payload.link) { + notificationsApi + .updateNotifications({ + ids: [notification.id], + read: true, + }) + .catch(() => { + alertApi.post({ + message: 'Failed to mark notification as read', + severity: 'error', + }); + }); + } closeSnackbar(snackBarId); }} > @@ -259,6 +274,9 @@ export const NotificationsSidebarItem = (props?: { )} { + requestUserPermission(); + }} hasNotifications={!error && !!unreadCount} text={text} icon={icon} diff --git a/plugins/notifications/src/hooks/useTitleCounter.ts b/plugins/notifications/src/hooks/useTitleCounter.ts index 0793cd58d6..399bfb84f4 100644 --- a/plugins/notifications/src/hooks/useTitleCounter.ts +++ b/plugins/notifications/src/hooks/useTitleCounter.ts @@ -25,7 +25,7 @@ const throttledSetTitle = throttle((shownTitle: string) => { document.title = shownTitle; }, 100); -/** @public */ +/** @internal */ export function useTitleCounter() { const [title, setTitle] = useState(document.title); const [count, setCount] = useState(0); diff --git a/plugins/notifications/src/hooks/useWebNotifications.ts b/plugins/notifications/src/hooks/useWebNotifications.ts index 728d992130..ec120a614d 100644 --- a/plugins/notifications/src/hooks/useWebNotifications.ts +++ b/plugins/notifications/src/hooks/useWebNotifications.ts @@ -13,19 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useState } from 'react'; import { rootRouteRef } from '../routes'; -import { useRouteRef } from '@backstage/core-plugin-api'; +import { useApi, useRouteRef } from '@backstage/core-plugin-api'; import { useNavigate } from 'react-router-dom'; +import { notificationsApiRef } from '../api'; -/** @public */ +/** @internal */ export function useWebNotifications(enabled: boolean) { const [webNotificationPermission, setWebNotificationPermission] = useState('default'); const notificationsRoute = useRouteRef(rootRouteRef); + const notificationsApi = useApi(notificationsApiRef); const navigate = useNavigate(); - useEffect(() => { + const requestUserPermission = useCallback(() => { if ( enabled && 'Notification' in window && @@ -57,6 +59,10 @@ export function useWebNotifications(enabled: boolean) { event.preventDefault(); if (options.link) { window.open(options.link, '_blank'); + notificationsApi.updateNotifications({ + ids: [options.id], + read: true, + }); } else { navigate(notificationsRoute()); } @@ -65,8 +71,8 @@ export function useWebNotifications(enabled: boolean) { return notification; }, - [webNotificationPermission, navigate, notificationsRoute], + [webNotificationPermission, notificationsApi, navigate, notificationsRoute], ); - return { sendWebNotification }; + return { sendWebNotification, requestUserPermission }; } diff --git a/plugins/notifications/src/index.ts b/plugins/notifications/src/index.ts index bb5d76a0cf..25565f1ae1 100644 --- a/plugins/notifications/src/index.ts +++ b/plugins/notifications/src/index.ts @@ -15,5 +15,5 @@ */ export { notificationsPlugin, NotificationsPage } from './plugin'; export * from './api'; -export * from './hooks'; +export { useNotificationsApi } from './hooks'; export * from './components';