Skip to content

Commit

Permalink
fix(notifications): style badge 'attention' if unread danger/warn not…
Browse files Browse the repository at this point in the history
…ifications (#255)

* fix(notifications): style badge 'attention' if unread danger/warn notifications

* feat(notifications): display danger/warning notifications as toasts and also store in drawer
  • Loading branch information
andrewazores authored Aug 27, 2021
1 parent 3ae2b0c commit 95f7d9d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 7 deletions.
46 changes: 42 additions & 4 deletions src/app/AppLayout/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,19 @@
* SOFTWARE.
*/
import * as React from 'react';
import * as _ from 'lodash';
import { ServiceContext } from '@app/Shared/Services/Services';
import { NotificationCenter } from '@app/Notifications/NotificationCenter';
import { IAppRoute, routes } from '@app/routes';
import { AboutModal, Button, Nav, NavItem, NavList, NotificationBadge, Page, PageHeader,
import { AboutModal, Alert, AlertGroup, AlertVariant, AlertActionCloseButton,
Button, Nav, NavItem, NavList, NotificationBadge, Page, PageHeader,
PageHeaderTools, PageHeaderToolsGroup, PageHeaderToolsItem, PageSidebar,
SkipToContent, Text, TextContent, TextList, TextListItem } from '@patternfly/react-core';
SkipToContent, Text, TextContent, TextList, TextListItem
} from '@patternfly/react-core';
import { BellIcon, CogIcon, HelpIcon } from '@patternfly/react-icons';
import { map } from 'rxjs/operators';
import { matchPath, NavLink, useHistory, useLocation } from 'react-router-dom';
import { NotificationsContext } from '../Notifications/Notifications';
import { Notification, NotificationsContext } from '../Notifications/Notifications';
import { AuthModal } from './AuthModal';
import { SslErrorModal } from './SslErrorModal';

Expand All @@ -69,7 +73,9 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({children}) => {
const [aboutModalOpen, setAboutModalOpen] = React.useState(false);
const [isNotificationDrawerExpanded, setNotificationDrawerExpanded] = React.useState(false);
const [cryostatVersion, setCryostatVersion] = React.useState('unknown');
const [notifications, setNotifications] = React.useState([] as Notification[]);
const [unreadNotificationsCount, setUnreadNotificationsCount] = React.useState(0);
const [errorNotificationsCount, setErrorNotificationsCount] = React.useState(0);
const location = useLocation();

React.useEffect(() => {
Expand All @@ -84,14 +90,32 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({children}) => {
return () => sub.unsubscribe();
})

React.useEffect(() => {
const sub = notificationsContext.notifications().subscribe(setNotifications);
return () => sub.unsubscribe();
}, []);

React.useEffect(() => {
const sub = notificationsContext.unreadNotifications().subscribe(s => setUnreadNotificationsCount(s.length));
return () => sub.unsubscribe();
}, [notificationsContext, notificationsContext.unreadNotifications, unreadNotificationsCount, setUnreadNotificationsCount]);

React.useEffect(() => {
const sub = notificationsContext
.unreadNotifications()
.pipe(map((notifications: Notification[]) =>
_.filter(notifications, n => n.variant === AlertVariant.danger || n.variant === AlertVariant.warning)
))
.subscribe(s => setErrorNotificationsCount(s.length));
return () => sub.unsubscribe();
}, [notificationsContext, notificationsContext.unreadNotifications, unreadNotificationsCount, setUnreadNotificationsCount]);

const dismissAuthModal = () => {
setShowAuthModal(false);
};
const handleMarkNotificationRead = React.useCallback(key => {
notificationsContext.setRead(key, true);
}, [notificationsContext]);

React.useEffect(() => {
const sub = serviceContext.target.sslFailure().subscribe(() => {
Expand Down Expand Up @@ -134,7 +158,7 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({children}) => {
<PageHeaderToolsItem visibility={{ default: 'visible' }} isSelected={isNotificationDrawerExpanded} >
<NotificationBadge
count={unreadNotificationsCount}
variant={ unreadNotificationsCount === 0 ? 'read' : 'unread' }
variant={errorNotificationsCount > 0 ? 'attention' : unreadNotificationsCount === 0 ? 'read' : 'unread'}
onClick={handleNotificationCenterToggle} aria-label='Notifications'
>
<BellIcon />
Expand Down Expand Up @@ -247,6 +271,20 @@ const AppLayout: React.FunctionComponent<IAppLayout> = ({children}) => {
);
const NotificationDrawer = React.useMemo(() => (<NotificationCenter onClose={handleCloseNotificationCenter} />), []);
return (<>
<AlertGroup isToast>
{
notifications
.filter(n => !n.read && (n.variant === AlertVariant.danger || n.variant === AlertVariant.warning))
.map(( { key, title, message, variant } ) => (
<Alert
variant={variant}
title={title}
actionClose={<AlertActionCloseButton onClose={() => handleMarkNotificationRead(key)} />}
>{message}
</Alert>
))
}
</AlertGroup>
<Page
mainContainerId="primary-app-container"
header={Header}
Expand Down
8 changes: 5 additions & 3 deletions src/app/Notifications/NotificationCenter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
* SOFTWARE.
*/
import * as React from 'react';
import { Dropdown, DropdownItem, DropdownPosition, KebabToggle, NotificationDrawer, NotificationDrawerBody, NotificationDrawerHeader,
NotificationDrawerList, NotificationDrawerListItem, NotificationDrawerListItemBody,
NotificationDrawerListItemHeader, Text, TextVariants } from '@patternfly/react-core';
import { Dropdown, DropdownItem, DropdownPosition, KebabToggle,
NotificationDrawer, NotificationDrawerBody, NotificationDrawerHeader,
NotificationDrawerList, NotificationDrawerListItem,
NotificationDrawerListItemBody, NotificationDrawerListItemHeader, Text,
TextVariants } from '@patternfly/react-core';
import { Notification, NotificationsContext } from './Notifications';

export interface NotificationCenterProps {
Expand Down

0 comments on commit 95f7d9d

Please sign in to comment.