diff --git a/plugins/notifications/README.md b/plugins/notifications/README.md
index 4efe8767c1..643f5a2f23 100644
--- a/plugins/notifications/README.md
+++ b/plugins/notifications/README.md
@@ -39,7 +39,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
...
{/* New code: */}
-
+
{/* Existing code for reference: */}
@@ -55,13 +55,13 @@ export const Root = ({ children }: PropsWithChildren<{}>) => (
In the `packages/app/src/App.tsx`:
```
-import { NOTIFICATIONS_ROUTE, NotificationsPage } from '@janus-idp/plugin-notifications';
+import { NotificationsPage } from '@janus-idp/plugin-notifications';
...
export const AppBase = () => {
...
{/* New code: */}
- } />
+ } />
```
## How to use the NotificationApi
diff --git a/plugins/notifications/app-config.janus-idp.yaml b/plugins/notifications/app-config.janus-idp.yaml
index f6ccab6a93..1f3d92f96a 100644
--- a/plugins/notifications/app-config.janus-idp.yaml
+++ b/plugins/notifications/app-config.janus-idp.yaml
@@ -4,7 +4,7 @@ dynamicPlugins:
appIcons:
- name: notificationsIcon
module: NotificationsPlugin
- importName: NotificationsIcon
+ importName: NotificationsActiveIcon
dynamicRoutes:
- path: /notifications
importName: NotificationsPage
diff --git a/plugins/notifications/src/components/NotificationsActiveIcon/NotificationsActiveIcon.tsx b/plugins/notifications/src/components/NotificationsActiveIcon/NotificationsActiveIcon.tsx
new file mode 100644
index 0000000000..fc2e03d23a
--- /dev/null
+++ b/plugins/notifications/src/components/NotificationsActiveIcon/NotificationsActiveIcon.tsx
@@ -0,0 +1,99 @@
+import React from 'react';
+
+import { configApiRef, useApi } from '@backstage/core-plugin-api';
+
+import { Badge, Tooltip } from '@material-ui/core';
+import NotificationsIcon from '@material-ui/icons/Notifications';
+import NotificationsOffIcon from '@material-ui/icons/NotificationsOff';
+
+import { notificationsApiRef } from '../../api';
+import { DefaultPollingIntervalMs } from '../../constants';
+import { Notification } from '../../openapi';
+import { usePollingEffect } from '../usePollingEffect';
+import { SystemNotificationAlert } from './SystemNotificationAlert';
+
+const NotificationsErrorIcon = () => (
+
+
+
+);
+
+/**
+ * Dynamic plugins recently do not support passing configuration
+ * to icons or making the left-side menu item texts active (so far strings only).
+ *
+ * This Icon component tries to workaround these limitations but will be subject of
+ * change as the extension points by dynamic plugins will evolve.
+ */
+export const NotificationsActiveIcon = () => {
+ const notificationsApi = useApi(notificationsApiRef);
+ const configApi = useApi(configApiRef);
+
+ let pollingInterval = configApi.getOptionalNumber(
+ 'notifications.pollingIntervalMs',
+ );
+ if (pollingInterval === undefined) {
+ pollingInterval = DefaultPollingIntervalMs;
+ }
+
+ const [error, setError] = React.useState(undefined);
+ const [unreadCount, setUnreadCount] = React.useState(0);
+ const [pageLoadingTime] = React.useState(new Date(Date.now()));
+ const [lastSystemWideNotification, setLastSystemWideNotification] =
+ React.useState();
+ const [closedNotificationId, setClosedNotificationId] =
+ React.useState();
+
+ const pollCallback = React.useCallback(async () => {
+ try {
+ setUnreadCount(
+ await notificationsApi.getNotificationsCount({
+ read: false,
+ messageScope: 'user',
+ }),
+ );
+
+ const data = await notificationsApi.getNotifications({
+ pageSize: 1,
+ pageNumber: 1,
+ createdAfter: pageLoadingTime,
+ orderBy: 'created',
+ orderByDirec: 'desc',
+ messageScope: 'system',
+ });
+
+ setLastSystemWideNotification(data?.[0]);
+ } catch (e: unknown) {
+ setError(e as Error);
+ }
+ }, [notificationsApi, pageLoadingTime]);
+
+ usePollingEffect(pollCallback, [], pollingInterval);
+
+ if (!!error) {
+ return ;
+ }
+
+ if (unreadCount) {
+ return (
+ <>
+
+
+
+
+ {lastSystemWideNotification &&
+ !lastSystemWideNotification.readByUser &&
+ closedNotificationId !== lastSystemWideNotification.id && (
+
+ setClosedNotificationId(lastSystemWideNotification.id)
+ }
+ />
+ )}
+ >
+ );
+ }
+
+ return ;
+};
diff --git a/plugins/notifications/src/components/NotificationsActiveIcon/SystemNotificationAlert.tsx b/plugins/notifications/src/components/NotificationsActiveIcon/SystemNotificationAlert.tsx
new file mode 100644
index 0000000000..de40cd8149
--- /dev/null
+++ b/plugins/notifications/src/components/NotificationsActiveIcon/SystemNotificationAlert.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+
+import { useRouteRef } from '@backstage/core-plugin-api';
+
+import { IconButton, Link, makeStyles, Snackbar } from '@material-ui/core';
+import CloseIcon from '@material-ui/icons/Close';
+
+import { notificationsRootRouteRef } from '../../routes';
+
+const useStyles = makeStyles(_theme => ({
+ systemAlertAction: {
+ marginRight: '1rem',
+ },
+}));
+
+export type SystemNotificationAlertProps = {
+ message: string;
+ onCloseNotification: () => void;
+};
+
+export const SystemNotificationAlert = ({
+ message,
+ onCloseNotification,
+}: SystemNotificationAlertProps) => {
+ const styles = useStyles();
+ const notificationsRoute = useRouteRef(notificationsRootRouteRef);
+
+ return (
+
+
+ Show
+
+
+
+
+ >
+ }
+ />
+ );
+};
diff --git a/plugins/notifications/src/components/NotificationsActiveIcon/index.ts b/plugins/notifications/src/components/NotificationsActiveIcon/index.ts
new file mode 100644
index 0000000000..0b758d0073
--- /dev/null
+++ b/plugins/notifications/src/components/NotificationsActiveIcon/index.ts
@@ -0,0 +1 @@
+export * from './NotificationsActiveIcon';
diff --git a/plugins/notifications/src/components/NotificationsSidebarItem.tsx b/plugins/notifications/src/components/NotificationsSidebarItem.tsx
deleted file mode 100644
index d777255ced..0000000000
--- a/plugins/notifications/src/components/NotificationsSidebarItem.tsx
+++ /dev/null
@@ -1,128 +0,0 @@
-import React from 'react';
-
-import { SidebarItem } from '@backstage/core-components';
-import { useApi } from '@backstage/core-plugin-api';
-
-import {
- IconButton,
- Link,
- makeStyles,
- Snackbar,
- Tooltip,
-} from '@material-ui/core';
-import CloseIcon from '@material-ui/icons/Close';
-import NotificationsIcon from '@material-ui/icons/Notifications';
-import NotificationsOffIcon from '@material-ui/icons/NotificationsOff';
-
-import { notificationsApiRef } from '../api';
-import { NOTIFICATIONS_ROUTE } from '../constants';
-import { Notification } from '../openapi';
-import { usePollingEffect } from './usePollingEffect';
-
-const NotificationsErrorIcon = () => (
-
-
-
-);
-
-export type NotificationsSidebarItemProps = {
- /**
- * Number of milliseconds between polling the notifications backend.
- * If negative or zero, the poling is not started.
- * Example: 5000
- */
- pollingInterval?: number;
- className?: string;
-};
-
-const useStyles = makeStyles(_theme => ({
- systemAlertAction: {
- marginRight: '1rem',
- },
-}));
-
-export const NotificationsSidebarItem = ({
- pollingInterval,
- className,
-}: NotificationsSidebarItemProps) => {
- const styles = useStyles();
- const notificationsApi = useApi(notificationsApiRef);
-
- const [error, setError] = React.useState(undefined);
- const [unreadCount, setUnreadCount] = React.useState(0);
- const [pageLoadingTime] = React.useState(new Date(Date.now()));
- const [lastSystemWideNotification, setLastSystemWideNotification] =
- React.useState();
- const [closedNotificationId, setClosedNotificationId] =
- React.useState();
-
- const pollCallback = React.useCallback(async () => {
- try {
- setUnreadCount(
- await notificationsApi.getNotificationsCount({
- read: false,
- messageScope: 'user',
- }),
- );
-
- const data = await notificationsApi.getNotifications({
- pageSize: 1,
- pageNumber: 1,
- createdAfter: pageLoadingTime,
- orderBy: 'created',
- orderByDirec: 'desc',
- messageScope: 'system',
- });
-
- setLastSystemWideNotification(data?.[0]);
- } catch (e: unknown) {
- setError(e as Error);
- }
- }, [notificationsApi, pageLoadingTime]);
-
- usePollingEffect(pollCallback, [], pollingInterval);
-
- let icon = NotificationsIcon;
- if (!!error) {
- icon = NotificationsErrorIcon;
- }
-
- return (
- <>
-
- {lastSystemWideNotification && !lastSystemWideNotification.readByUser && (
-
-
- Show
-
-
- setClosedNotificationId(lastSystemWideNotification.id)
- }
- >
-
-
- >
- }
- />
- )}
- >
- );
-};
diff --git a/plugins/notifications/src/constants.ts b/plugins/notifications/src/constants.ts
index fe0c79a340..53a0804ed7 100644
--- a/plugins/notifications/src/constants.ts
+++ b/plugins/notifications/src/constants.ts
@@ -1,3 +1,2 @@
-export const NOTIFICATIONS_ROUTE = 'notifications';
-
export const DebounceDelayMs = 1000;
+export const DefaultPollingIntervalMs = 5 * 1000;
diff --git a/plugins/notifications/src/index.ts b/plugins/notifications/src/index.ts
index 58b3ceeb4c..9579592aa5 100644
--- a/plugins/notifications/src/index.ts
+++ b/plugins/notifications/src/index.ts
@@ -12,10 +12,8 @@ export {
export { type Notification } from './openapi';
// selected constants for export
-export { NOTIFICATIONS_ROUTE } from './constants';
+export { notificationsRootRouteRef } from './routes';
// selected components for export
-export { NotificationsSidebarItem } from './components/NotificationsSidebarItem';
export { usePollingEffect } from './components/usePollingEffect';
-
-export { default as NotificationsIcon } from '@material-ui/icons/Notifications';
+export { NotificationsActiveIcon } from './components/NotificationsActiveIcon';
diff --git a/plugins/notifications/src/plugin.ts b/plugins/notifications/src/plugin.ts
index 9a9560bbaf..df8a3e0778 100644
--- a/plugins/notifications/src/plugin.ts
+++ b/plugins/notifications/src/plugin.ts
@@ -7,12 +7,12 @@ import {
} from '@backstage/core-plugin-api';
import { NotificationsApiImpl, notificationsApiRef } from './api';
-import { rootRouteRef } from './routes';
+import { notificationsRootRouteRef } from './routes';
export const notificationsPlugin = createPlugin({
id: 'notifications',
routes: {
- root: rootRouteRef,
+ root: notificationsRootRouteRef,
},
apis: [
createApiFactory({
@@ -33,6 +33,6 @@ export const NotificationsPage = notificationsPlugin.provide(
name: 'NotificationsPage',
component: () =>
import('./components/NotificationsPage').then(m => m.NotificationsPage),
- mountPoint: rootRouteRef,
+ mountPoint: notificationsRootRouteRef,
}),
);
diff --git a/plugins/notifications/src/routes.ts b/plugins/notifications/src/routes.ts
index d07f175254..fbe0487184 100644
--- a/plugins/notifications/src/routes.ts
+++ b/plugins/notifications/src/routes.ts
@@ -1,7 +1,5 @@
import { createRouteRef } from '@backstage/core-plugin-api';
-import { NOTIFICATIONS_ROUTE } from './constants';
-
-export const rootRouteRef = createRouteRef({
- id: NOTIFICATIONS_ROUTE,
+export const notificationsRootRouteRef = createRouteRef({
+ id: 'notifications',
});