feat: allow specifying mui icon for notification
Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
@@ -30,6 +30,7 @@ export default async function createPlugin(
|
||||
title: 'Test',
|
||||
description: 'This is test notification',
|
||||
link: '/catalog',
|
||||
icon: 'SwapHorizRounded',
|
||||
});
|
||||
notifications++;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import * as muiIcons from '@material-ui/icons';
|
||||
|
||||
// @public (undocumented)
|
||||
type Notification_2 = {
|
||||
id: string;
|
||||
@@ -10,7 +12,7 @@ type Notification_2 = {
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
icon?: string;
|
||||
icon?: NotificationIcon;
|
||||
image?: string;
|
||||
created: Date;
|
||||
read?: Date;
|
||||
@@ -18,6 +20,9 @@ type Notification_2 = {
|
||||
};
|
||||
export { Notification_2 as Notification };
|
||||
|
||||
// @public (undocumented)
|
||||
export type NotificationIcon = keyof typeof muiIcons;
|
||||
|
||||
// @public (undocumented)
|
||||
export type NotificationIds = {
|
||||
ids: string[];
|
||||
|
||||
@@ -28,5 +28,8 @@
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
],
|
||||
"dependencies": {
|
||||
"@material-ui/icons": "^4.9.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as muiIcons from '@material-ui/icons';
|
||||
|
||||
/** @public */
|
||||
export type NotificationType = 'read' | 'unread' | 'saved';
|
||||
|
||||
/** @public */
|
||||
export type NotificationIcon = keyof typeof muiIcons;
|
||||
|
||||
/** @public */
|
||||
export type Notification = {
|
||||
id: string;
|
||||
@@ -24,8 +29,7 @@ export type Notification = {
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
// TODO: Icon should be typed so that we know what to render
|
||||
icon?: string;
|
||||
icon?: NotificationIcon;
|
||||
image?: string;
|
||||
created: Date;
|
||||
read?: Date;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
```ts
|
||||
import { Notification as Notification_2 } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationIcon } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationStatus } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationType } from '@backstage/plugin-notifications-common';
|
||||
import { PluginDatabaseManager } from '@backstage/backend-common';
|
||||
@@ -57,7 +58,7 @@ export type NotificationSendOptions = {
|
||||
description: string;
|
||||
link: string;
|
||||
image?: string;
|
||||
icon?: string;
|
||||
icon?: NotificationIcon;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Notification } from '@backstage/plugin-notifications-common';
|
||||
import {
|
||||
Notification,
|
||||
NotificationIcon,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
import { CatalogApi, CatalogClient } from '@backstage/catalog-client';
|
||||
import { NotificationsStore } from '../database/NotificationsStore';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
@@ -43,7 +46,7 @@ export type NotificationSendOptions = {
|
||||
description: string;
|
||||
link: string;
|
||||
image?: string;
|
||||
icon?: string;
|
||||
icon?: NotificationIcon;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
@@ -68,9 +71,16 @@ export class NotificationService {
|
||||
|
||||
async send(options: NotificationSendOptions): Promise<Notification[]> {
|
||||
const { entityRef, title, description, link, icon, image } = options;
|
||||
const users = await this.getUsersForEntityRef(entityRef);
|
||||
const notifications = [];
|
||||
let users = [];
|
||||
try {
|
||||
users = await this.getUsersForEntityRef(entityRef);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const store = await this.getStore();
|
||||
|
||||
for (const user of users) {
|
||||
const notification = {
|
||||
id: uuid(),
|
||||
|
||||
@@ -22,13 +22,7 @@ import {
|
||||
} from '@backstage/core-components';
|
||||
import { NotificationsTable } from '../NotificationsTable';
|
||||
import { useNotificationsApi } from '../../hooks';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
makeStyles,
|
||||
Paper,
|
||||
TableContainer,
|
||||
} from '@material-ui/core';
|
||||
import { Button, Grid, makeStyles } from '@material-ui/core';
|
||||
import Bookmark from '@material-ui/icons/Bookmark';
|
||||
import Check from '@material-ui/icons/Check';
|
||||
import Inbox from '@material-ui/icons/Inbox';
|
||||
@@ -90,14 +84,12 @@ export const NotificationsPage = () => {
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
<TableContainer component={Paper}>
|
||||
<NotificationsTable
|
||||
notifications={value}
|
||||
type={type}
|
||||
loading={loading}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</TableContainer>
|
||||
<NotificationsTable
|
||||
notifications={value}
|
||||
type={type}
|
||||
loading={loading}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import NotificationsIcon from '@material-ui/icons/Notifications';
|
||||
import { Notification } from '@backstage/plugin-notifications-common';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import * as muiIcons from '@material-ui/icons';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
|
||||
/** @internal */
|
||||
export const NotificationIcon = (props: { notification: Notification }) => {
|
||||
const { notification } = props;
|
||||
if (notification.icon && notification.icon in muiIcons) {
|
||||
const Icon = muiIcons[notification.icon];
|
||||
return <Icon fontSize="small" />;
|
||||
}
|
||||
|
||||
if (notification.image) {
|
||||
return (
|
||||
<Avatar
|
||||
src={notification.image}
|
||||
style={{ width: '20px', height: '20px' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <NotificationsIcon fontSize="small" />;
|
||||
};
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
NotificationType,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import NotificationsIcon from '@material-ui/icons/Notifications';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import Check from '@material-ui/icons/Check';
|
||||
import Bookmark from '@material-ui/icons/Bookmark';
|
||||
@@ -42,6 +41,8 @@ import CloseIcon from '@material-ui/icons/Close';
|
||||
import { Skeleton } from '@material-ui/lab';
|
||||
// @ts-ignore
|
||||
import RelativeTime from 'react-relative-time';
|
||||
import { NotificationIcon } from './NotificationIcon';
|
||||
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
notificationRow: {
|
||||
@@ -53,7 +54,7 @@ const useStyles = makeStyles(theme => ({
|
||||
display: 'none',
|
||||
},
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.linkHover,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
'& .hideOnHover': {
|
||||
display: 'none',
|
||||
},
|
||||
@@ -110,8 +111,6 @@ export const NotificationsTable = (props: {
|
||||
return <Skeleton variant="rect" height={200} />;
|
||||
}
|
||||
|
||||
// TODO: Show timestamp relative time (react-relative-time npm package)
|
||||
// TODO: Add signals listener and refresh data on message
|
||||
return (
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
@@ -174,16 +173,19 @@ export const NotificationsTable = (props: {
|
||||
{props.notifications?.map(notification => {
|
||||
return (
|
||||
<TableRow key={notification.id} className={styles.notificationRow}>
|
||||
<TableCell width={100} style={{ verticalAlign: 'center' }}>
|
||||
<TableCell width="90px" style={{ verticalAlign: 'center' }}>
|
||||
<Checkbox
|
||||
className={styles.checkBox}
|
||||
size="small"
|
||||
checked={isChecked(notification.id)}
|
||||
onClick={() => onCheckBoxClick(notification.id)}
|
||||
/>
|
||||
{notification.icon ?? <NotificationsIcon fontSize="small" />}
|
||||
<NotificationIcon notification={notification} />
|
||||
</TableCell>
|
||||
<TableCell onClick={() => navigate(notification.link)}>
|
||||
<TableCell
|
||||
onClick={() => navigate(notification.link)}
|
||||
style={{ paddingLeft: 0 }}
|
||||
>
|
||||
<Typography variant="subtitle2">{notification.title}</Typography>
|
||||
<Typography variant="body2">
|
||||
{notification.description}
|
||||
@@ -194,6 +196,14 @@ export const NotificationsTable = (props: {
|
||||
<RelativeTime value={notification.created} />
|
||||
</Box>
|
||||
<Box className="showOnHover">
|
||||
<Tooltip title={notification.link}>
|
||||
<IconButton
|
||||
className={styles.actionButton}
|
||||
onClick={() => navigate(notification.link)}
|
||||
>
|
||||
<ArrowForwardIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={notification.read ? 'Move to inbox' : 'Mark as done'}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user