feat: add createdAfter filtering to the Notifications
Signed-off-by: Marek Libra <marek.libra@gmail.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-notifications-backend': patch
|
||||
'@backstage/plugin-notifications': patch
|
||||
---
|
||||
|
||||
The Notifications can be newly filtered based on the Created Date.
|
||||
@@ -106,6 +106,10 @@ export class DatabaseNotificationsStore implements NotificationsStore {
|
||||
query.orderBy('created', options.sortOrder ?? 'desc');
|
||||
}
|
||||
|
||||
if (options.createdAfter) {
|
||||
query.where('created', '>=', options.createdAfter.valueOf());
|
||||
}
|
||||
|
||||
if (options.limit) {
|
||||
query.limit(options.limit);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ export type NotificationGetOptions = {
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
read?: boolean;
|
||||
saved?: boolean;
|
||||
createdAfter?: Date;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -204,6 +204,13 @@ export async function createRouter(
|
||||
opts.read = false;
|
||||
// or keep undefined
|
||||
}
|
||||
if (req.query.created_after) {
|
||||
const sinceEpoch = Date.parse(req.query.created_after.toString());
|
||||
if (isNaN(sinceEpoch)) {
|
||||
throw new InputError('Unexpected date format');
|
||||
}
|
||||
opts.createdAfter = new Date(sinceEpoch);
|
||||
}
|
||||
|
||||
const notifications = await store.getNotifications(opts);
|
||||
res.send(notifications);
|
||||
|
||||
@@ -21,6 +21,7 @@ export type GetNotificationsOptions = {
|
||||
limit?: number;
|
||||
search?: string;
|
||||
read?: boolean;
|
||||
createdAfter?: Date;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -30,6 +30,7 @@ export type GetNotificationsOptions = {
|
||||
limit?: number;
|
||||
search?: string;
|
||||
read?: boolean;
|
||||
createdAfter?: Date;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -54,7 +54,9 @@ export class NotificationsClient implements NotificationsApi {
|
||||
if (options?.read !== undefined) {
|
||||
queryString.append('read', options.read ? 'true' : 'false');
|
||||
}
|
||||
|
||||
if (options?.createdAfter !== undefined) {
|
||||
queryString.append('created_after', options.createdAfter.toISOString());
|
||||
}
|
||||
const urlSegment = `?${queryString}`;
|
||||
|
||||
return await this.request<Notification[]>(urlSegment);
|
||||
|
||||
+31
-29
@@ -28,12 +28,13 @@ import {
|
||||
export type NotificationsFiltersProps = {
|
||||
unreadOnly?: boolean;
|
||||
onUnreadOnlyChanged: (checked: boolean | undefined) => void;
|
||||
// createdAfter?: string;
|
||||
createdAfter?: string;
|
||||
onCreatedAfterChanged: (value: string) => void;
|
||||
|
||||
// sorting?: {
|
||||
// orderBy: GetNotificationsOrderByEnum;
|
||||
// orderByDirec: GetNotificationsOrderByDirecEnum;
|
||||
// };
|
||||
// onCreatedAfterChanged: (value: string) => void;
|
||||
// setSorting: ({
|
||||
// orderBy,
|
||||
// orderByDirec,
|
||||
@@ -43,22 +44,22 @@ export type NotificationsFiltersProps = {
|
||||
// }) => void;
|
||||
};
|
||||
|
||||
// export const CreatedAfterOptions: {
|
||||
// [key: string]: { label: string; getDate: () => Date };
|
||||
// } = {
|
||||
// last24h: {
|
||||
// label: 'Last 24h',
|
||||
// getDate: () => new Date(Date.now() - 24 * 3600 * 1000),
|
||||
// },
|
||||
// lastWeek: {
|
||||
// label: 'Last week',
|
||||
// getDate: () => new Date(Date.now() - 7 * 24 * 3600 * 1000),
|
||||
// },
|
||||
// all: {
|
||||
// label: 'Any time',
|
||||
// getDate: () => new Date(0),
|
||||
// },
|
||||
// };
|
||||
export const CreatedAfterOptions: {
|
||||
[key: string]: { label: string; getDate: () => Date };
|
||||
} = {
|
||||
last24h: {
|
||||
label: 'Last 24h',
|
||||
getDate: () => new Date(Date.now() - 24 * 3600 * 1000),
|
||||
},
|
||||
lastWeek: {
|
||||
label: 'Last week',
|
||||
getDate: () => new Date(Date.now() - 7 * 24 * 3600 * 1000),
|
||||
},
|
||||
all: {
|
||||
label: 'Any time',
|
||||
getDate: () => new Date(0),
|
||||
},
|
||||
};
|
||||
|
||||
// export const SortByOptions: {
|
||||
// [key: string]: {
|
||||
@@ -108,20 +109,20 @@ export type NotificationsFiltersProps = {
|
||||
// };
|
||||
|
||||
export const NotificationsFilters = ({
|
||||
unreadOnly,
|
||||
// createdAfter,
|
||||
// sorting,
|
||||
// onCreatedAfterChanged,
|
||||
// setSorting,
|
||||
unreadOnly,
|
||||
onUnreadOnlyChanged,
|
||||
}: // setSorting,
|
||||
NotificationsFiltersProps) => {
|
||||
createdAfter,
|
||||
onCreatedAfterChanged,
|
||||
}: NotificationsFiltersProps) => {
|
||||
// const sortBy = getSortBy(sorting);
|
||||
|
||||
// const handleOnCreatedAfterChanged = (
|
||||
// event: React.ChangeEvent<{ name?: string; value: unknown }>,
|
||||
// ) => {
|
||||
// onCreatedAfterChanged(event.target.value as string);
|
||||
// };
|
||||
const handleOnCreatedAfterChanged = (
|
||||
event: React.ChangeEvent<{ name?: string; value: unknown }>,
|
||||
) => {
|
||||
onCreatedAfterChanged(event.target.value as string);
|
||||
};
|
||||
|
||||
const handleOnUnreadOnlyChanged = (
|
||||
event: React.ChangeEvent<{ name?: string; value: unknown }>,
|
||||
@@ -169,7 +170,6 @@ NotificationsFiltersProps) => {
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
{/* TODO: extend BE to support following:
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth variant="outlined" size="small">
|
||||
<InputLabel id="notifications-filter-view">
|
||||
@@ -190,6 +190,8 @@ NotificationsFiltersProps) => {
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
{/*
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth variant="outlined" size="small">
|
||||
<InputLabel id="notifications-filter-sort">Sort by</InputLabel>
|
||||
|
||||
@@ -20,11 +20,15 @@ import {
|
||||
PageWithHeader,
|
||||
ResponseErrorPanel,
|
||||
} from '@backstage/core-components';
|
||||
import { NotificationsTable } from '../NotificationsTable';
|
||||
import { useNotificationsApi } from '../../hooks';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import { useSignal } from '@backstage/plugin-signals-react';
|
||||
import { NotificationsFilters } from '../NotificationsFilters';
|
||||
|
||||
import { NotificationsTable } from '../NotificationsTable';
|
||||
import { useNotificationsApi } from '../../hooks';
|
||||
import {
|
||||
CreatedAfterOptions,
|
||||
NotificationsFilters,
|
||||
} from '../NotificationsFilters';
|
||||
import { GetNotificationsOptions } from '../../api';
|
||||
|
||||
export const NotificationsPage = () => {
|
||||
@@ -32,6 +36,7 @@ export const NotificationsPage = () => {
|
||||
const { lastSignal } = useSignal('notifications');
|
||||
const [unreadOnly, setUnreadOnly] = React.useState<boolean | undefined>(true);
|
||||
const [containsText, setContainsText] = React.useState<string>();
|
||||
const [createdAfter, setCreatedAfter] = React.useState<string>('lastWeek');
|
||||
|
||||
const { error, value, retry, loading } = useNotificationsApi(
|
||||
// TODO: add pagination and other filters
|
||||
@@ -40,9 +45,15 @@ export const NotificationsPage = () => {
|
||||
if (unreadOnly !== undefined) {
|
||||
options.read = !unreadOnly;
|
||||
}
|
||||
|
||||
const createdAfterDate = CreatedAfterOptions[createdAfter].getDate();
|
||||
if (createdAfterDate.valueOf() > 0) {
|
||||
options.createdAfter = createdAfterDate;
|
||||
}
|
||||
|
||||
return api.getNotifications(options);
|
||||
},
|
||||
[containsText, unreadOnly],
|
||||
[containsText, unreadOnly, createdAfter],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -72,10 +83,10 @@ export const NotificationsPage = () => {
|
||||
<Grid container>
|
||||
<Grid item xs={2}>
|
||||
<NotificationsFilters
|
||||
// createdAfter={createdAfter}
|
||||
unreadOnly={unreadOnly}
|
||||
onUnreadOnlyChanged={setUnreadOnly}
|
||||
// onCreatedAfterChanged={setCreatedAfter}
|
||||
createdAfter={createdAfter}
|
||||
onCreatedAfterChanged={setCreatedAfter}
|
||||
// setSorting={setSorting}
|
||||
// sorting={sorting}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user