Merge pull request #31532 from drodil/notifications_ui_improvements2

fix(notifications): ui improvements
This commit is contained in:
Fredrik Adelöw
2025-12-13 19:44:47 +01:00
committed by GitHub
6 changed files with 97 additions and 30 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-notifications': patch
---
Move long notification descriptions behind `Show more/less` button.
This improves readability of the notifications list by preventing long descriptions from taking up too much space
or rendering very small scrollable areas.
@@ -14,14 +14,11 @@
* limitations under the License.
*/
import { ChangeEvent } from 'react';
import Divider from '@material-ui/core/Divider';
import FormControl from '@material-ui/core/FormControl';
import Grid from '@material-ui/core/Grid';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import Typography from '@material-ui/core/Typography';
import { GetNotificationsOptions } from '../../api';
import { NotificationSeverity } from '@backstage/plugin-notifications-common';
@@ -200,11 +197,6 @@ export const NotificationsFilters = ({
return (
<>
<Grid container>
<Grid item xs={12}>
<Typography variant="h6">Filters</Typography>
<Divider variant="fullWidth" />
</Grid>
<Grid item xs={12}>
<FormControl fullWidth variant="outlined" size="small">
<InputLabel id="notifications-filter-view">View</InputLabel>
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { useState, useMemo, useEffect } from 'react';
import { useEffect, useMemo, useState } from 'react';
import throttle from 'lodash/throttle';
import {
Content,
@@ -156,13 +156,17 @@ export const NotificationsPage = (props?: NotificationsPageProps) => {
const isUnread = !!value?.[1]?.unread;
const allTopics = value?.[2]?.topics;
let tableTitle = `All notifications (${totalCount})`;
let tableTitle = `All notifications `;
if (saved) {
tableTitle = `Saved notifications (${totalCount})`;
tableTitle = `Saved notifications`;
} else if (unreadOnly === true) {
tableTitle = `Unread notifications (${totalCount})`;
tableTitle = `Unread notifications`;
} else if (unreadOnly === false) {
tableTitle = `Read notifications (${totalCount})`;
tableTitle = `Read notifications`;
}
if (totalCount) {
tableTitle += ` (${totalCount})`;
}
return (
@@ -0,0 +1,61 @@
/*
* Copyright 2025 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 Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import { useState } from 'react';
const MAX_LENGTH = 100;
export const NotificationDescription = (props: { description: string }) => {
const { description } = props;
const [shown, setShown] = useState(false);
const isLong = description.length > MAX_LENGTH;
if (!isLong) {
return <Typography variant="body2">{description}</Typography>;
}
if (shown) {
return (
<Typography variant="body2">
{description}{' '}
<Button
variant="text"
size="small"
onClick={() => {
setShown(false);
}}
>
Show less
</Button>
</Typography>
);
}
return (
<Typography variant="body2">
{description.substring(0, MAX_LENGTH)}...{' '}
<Button
variant="text"
size="small"
onClick={() => {
setShown(true);
}}
>
Show more
</Button>
</Typography>
);
};
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useState, useCallback, useMemo, useEffect } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import throttle from 'lodash/throttle';
// @ts-ignore
import RelativeTime from 'react-relative-time';
@@ -37,14 +37,11 @@ import { notificationsApiRef } from '../../api';
import { SelectAll } from './SelectAll';
import { BulkActions } from './BulkActions';
import { NotificationIcon } from './NotificationIcon';
import { NotificationDescription } from './NotificationDescription';
const ThrottleDelayMs = 1000;
const useStyles = makeStyles(theme => ({
description: {
maxHeight: '5rem',
overflow: 'auto',
},
severityItem: {
alignContent: 'center',
},
@@ -53,8 +50,10 @@ const useStyles = makeStyles(theme => ({
verticalAlign: 'text-bottom',
},
notificationInfoRow: {
marginLeft: theme.spacing(0.5),
marginRight: theme.spacing(0.5),
'&:not(:first-child)': {
marginLeft: theme.spacing(0.5),
},
},
}));
@@ -240,9 +239,9 @@ export const NotificationsTable = ({
)}
</Typography>
{notification.payload.description ? (
<Typography variant="body2" className={classes.description}>
{notification.payload.description}
</Typography>
<NotificationDescription
description={notification.payload.description}
/>
) : null}
<Typography variant="caption">
@@ -318,7 +317,6 @@ export const NotificationsTable = ({
onMarkAllRead,
onNotificationsSelectChange,
classes.severityItem,
classes.description,
classes.broadcastIcon,
classes.notificationInfoRow,
markAsReadOnLinkOpen,
@@ -16,6 +16,7 @@
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import { makeStyles } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip';
const useStyles = makeStyles({
label: {
@@ -23,6 +24,7 @@ const useStyles = makeStyles({
maxWidth: '2rem',
'& span': {
paddingRight: '0px',
marginRight: '2px',
},
},
});
@@ -43,13 +45,15 @@ export const SelectAll = ({
label={count > 0 ? `(${count})` : undefined}
className={classes.label}
control={
<Checkbox
color="primary"
disabled={!totalCount}
checked={count > 0}
indeterminate={count > 0 && totalCount !== count}
onChange={onSelectAll}
/>
<Tooltip title="Select all">
<Checkbox
color="primary"
disabled={!totalCount}
checked={count > 0}
indeterminate={count > 0 && totalCount !== count}
onChange={onSelectAll}
/>
</Tooltip>
}
/>
);