@backstage/plugin-notifications 0.1.3-next.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @backstage/plugin-notifications
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 939b4ec: Notifications-backend URL query parameter changed from `minimal_severity` to `minimumSeverity`.
|
|
8
|
+
- ec40998: On the Notifications page, the user can trigger "Save" or "Mark as read" actions once for multiple selected notifications.
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- abfbcfc: Updated dependency `@testing-library/react` to `^15.0.0`.
|
|
13
|
+
- 9a41a7b: Migrate signals and notifications to the new backend in local development
|
|
14
|
+
- 939b4ec: The severity icons now get their colors from the theme.
|
|
15
|
+
- Updated dependencies
|
|
16
|
+
- @backstage/plugin-notifications-common@0.0.3
|
|
17
|
+
- @backstage/core-components@0.14.4
|
|
18
|
+
- @backstage/core-plugin-api@1.9.2
|
|
19
|
+
- @backstage/theme@0.5.3
|
|
20
|
+
- @backstage/plugin-signals-react@0.0.3
|
|
21
|
+
- @backstage/errors@1.2.4
|
|
22
|
+
- @backstage/types@1.1.1
|
|
23
|
+
|
|
24
|
+
## 0.2.0-next.1
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- ec40998: On the Notifications page, the user can trigger "Save" or "Mark as read" actions once for multiple selected notifications.
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- Updated dependencies
|
|
33
|
+
- @backstage/plugin-signals-react@0.0.3-next.0
|
|
34
|
+
- @backstage/core-components@0.14.4-next.0
|
|
35
|
+
- @backstage/core-plugin-api@1.9.1
|
|
36
|
+
- @backstage/errors@1.2.4
|
|
37
|
+
- @backstage/theme@0.5.2
|
|
38
|
+
- @backstage/types@1.1.1
|
|
39
|
+
- @backstage/plugin-notifications-common@0.0.2
|
|
40
|
+
|
|
3
41
|
## 0.1.3-next.0
|
|
4
42
|
|
|
5
43
|
### Patch Changes
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useEffect } from 'react';
|
|
2
|
+
import throttle from 'lodash/throttle';
|
|
2
3
|
import { ResponseErrorPanel, PageWithHeader, Content } from '@backstage/core-components';
|
|
3
4
|
import Grid from '@material-ui/core/Grid';
|
|
4
5
|
import { useSignal } from '@backstage/plugin-signals-react';
|
|
@@ -13,19 +14,21 @@ import '@backstage/core-plugin-api';
|
|
|
13
14
|
import '@backstage/errors';
|
|
14
15
|
import 'react-use/esm/useAsyncRetry';
|
|
15
16
|
import '@material-ui/icons/Notifications';
|
|
16
|
-
import 'lodash/throttle';
|
|
17
17
|
import 'react-relative-time';
|
|
18
18
|
import '@material-ui/core/Box';
|
|
19
|
+
import '@material-ui/core/Checkbox';
|
|
20
|
+
import '@material-ui/icons/CheckOutlined';
|
|
21
|
+
import '@material-ui/icons/ErrorOutline';
|
|
22
|
+
import '@material-ui/icons/WarningOutlined';
|
|
23
|
+
import '@material-ui/icons/InfoOutlined';
|
|
24
|
+
import '@material-ui/core/styles';
|
|
25
|
+
import '@material-ui/core/FormControlLabel';
|
|
19
26
|
import '@material-ui/core/IconButton';
|
|
20
27
|
import '@material-ui/core/Tooltip';
|
|
21
28
|
import '@material-ui/icons/Markunread';
|
|
22
29
|
import '@material-ui/icons/CheckCircle';
|
|
23
30
|
import '@material-ui/icons/LabelOff';
|
|
24
31
|
import '@material-ui/icons/Label';
|
|
25
|
-
import '@material-ui/icons/CheckOutlined';
|
|
26
|
-
import '@material-ui/icons/ErrorOutline';
|
|
27
|
-
import '@material-ui/icons/WarningOutlined';
|
|
28
|
-
import '@material-ui/icons/InfoOutlined';
|
|
29
32
|
|
|
30
33
|
const CreatedAfterOptions = {
|
|
31
34
|
last24h: {
|
|
@@ -181,6 +184,7 @@ const NotificationsFilters = ({
|
|
|
181
184
|
)))));
|
|
182
185
|
};
|
|
183
186
|
|
|
187
|
+
const ThrottleDelayMs = 2e3;
|
|
184
188
|
const NotificationsPage = () => {
|
|
185
189
|
const [refresh, setRefresh] = React.useState(false);
|
|
186
190
|
const { lastSignal } = useSignal("notifications");
|
|
@@ -226,19 +230,23 @@ const NotificationsPage = () => {
|
|
|
226
230
|
severity
|
|
227
231
|
]
|
|
228
232
|
);
|
|
233
|
+
const throttledSetRefresh = React.useMemo(
|
|
234
|
+
() => throttle(setRefresh, ThrottleDelayMs),
|
|
235
|
+
[setRefresh]
|
|
236
|
+
);
|
|
229
237
|
useEffect(() => {
|
|
230
|
-
if (refresh) {
|
|
238
|
+
if (refresh && !loading) {
|
|
231
239
|
retry();
|
|
232
240
|
setRefresh(false);
|
|
233
241
|
}
|
|
234
|
-
}, [refresh, setRefresh, retry]);
|
|
242
|
+
}, [refresh, setRefresh, retry, loading]);
|
|
235
243
|
useEffect(() => {
|
|
236
244
|
if (lastSignal && lastSignal.action) {
|
|
237
|
-
|
|
245
|
+
throttledSetRefresh(true);
|
|
238
246
|
}
|
|
239
|
-
}, [lastSignal]);
|
|
247
|
+
}, [lastSignal, throttledSetRefresh]);
|
|
240
248
|
const onUpdate = () => {
|
|
241
|
-
|
|
249
|
+
throttledSetRefresh(true);
|
|
242
250
|
};
|
|
243
251
|
if (error) {
|
|
244
252
|
return /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error });
|
|
@@ -274,4 +282,4 @@ const NotificationsPage = () => {
|
|
|
274
282
|
};
|
|
275
283
|
|
|
276
284
|
export { NotificationsPage };
|
|
277
|
-
//# sourceMappingURL=index-
|
|
285
|
+
//# sourceMappingURL=index-D44DlZtS.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-D44DlZtS.esm.js","sources":["../../src/components/NotificationsFilters/NotificationsFilters.tsx","../../src/components/NotificationsPage/NotificationsPage.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\n\nimport Divider from '@material-ui/core/Divider';\nimport FormControl from '@material-ui/core/FormControl';\nimport Grid from '@material-ui/core/Grid';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport Typography from '@material-ui/core/Typography';\nimport { GetNotificationsOptions } from '../../api';\nimport { NotificationSeverity } from '@backstage/plugin-notifications-common';\n\nexport type SortBy = Required<\n Pick<GetNotificationsOptions, 'sort' | 'sortOrder'>\n>;\n\nexport type NotificationsFiltersProps = {\n unreadOnly?: boolean;\n onUnreadOnlyChanged: (checked: boolean | undefined) => void;\n createdAfter?: string;\n onCreatedAfterChanged: (value: string) => void;\n sorting: SortBy;\n onSortingChanged: (sortBy: SortBy) => void;\n saved?: boolean;\n onSavedChanged: (checked: boolean | undefined) => void;\n severity: NotificationSeverity;\n onSeverityChanged: (severity: NotificationSeverity) => void;\n};\n\nexport const CreatedAfterOptions: {\n [key: string]: { label: string; getDate: () => Date };\n} = {\n last24h: {\n label: 'Last 24h',\n getDate: () => new Date(Date.now() - 24 * 3600 * 1000),\n },\n lastWeek: {\n label: 'Last week',\n getDate: () => new Date(Date.now() - 7 * 24 * 3600 * 1000),\n },\n all: {\n label: 'Any time',\n getDate: () => new Date(0),\n },\n};\n\nexport const SortByOptions: {\n [key: string]: {\n label: string;\n sortBy: SortBy;\n };\n} = {\n newest: {\n label: 'Newest on top',\n sortBy: {\n sort: 'created',\n sortOrder: 'desc',\n },\n },\n oldest: {\n label: 'Oldest on top',\n sortBy: {\n sort: 'created',\n sortOrder: 'asc',\n },\n },\n topic: {\n label: 'Topic',\n sortBy: {\n sort: 'topic',\n sortOrder: 'asc',\n },\n },\n origin: {\n label: 'Origin',\n sortBy: {\n sort: 'origin',\n sortOrder: 'asc',\n },\n },\n};\n\nconst getSortByText = (sortBy?: SortBy): string => {\n if (sortBy?.sort === 'created' && sortBy?.sortOrder === 'asc') {\n return 'oldest';\n }\n if (sortBy?.sort === 'topic') {\n return 'topic';\n }\n if (sortBy?.sort === 'origin') {\n return 'origin';\n }\n\n return 'newest';\n};\n\nconst AllSeverityOptions: { [key in NotificationSeverity]: string } = {\n critical: 'Critical',\n high: 'High',\n normal: 'Normal',\n low: 'Low',\n};\n\nexport const NotificationsFilters = ({\n sorting,\n onSortingChanged,\n unreadOnly,\n onUnreadOnlyChanged,\n createdAfter,\n onCreatedAfterChanged,\n saved,\n onSavedChanged,\n severity,\n onSeverityChanged,\n}: NotificationsFiltersProps) => {\n const sortByText = getSortByText(sorting);\n\n const handleOnCreatedAfterChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n onCreatedAfterChanged(event.target.value as string);\n };\n\n const handleOnViewChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n if (event.target.value === 'unread') {\n onUnreadOnlyChanged(true);\n onSavedChanged(undefined);\n } else if (event.target.value === 'read') {\n onUnreadOnlyChanged(false);\n onSavedChanged(undefined);\n } else if (event.target.value === 'saved') {\n onUnreadOnlyChanged(undefined);\n onSavedChanged(true);\n } else {\n // All\n onUnreadOnlyChanged(undefined);\n onSavedChanged(undefined);\n }\n };\n\n const handleOnSortByChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n const idx = (event.target.value as string) || 'newest';\n const option = SortByOptions[idx];\n onSortingChanged({ ...option.sortBy });\n };\n\n let viewValue = 'all';\n if (saved) {\n viewValue = 'saved';\n } else if (unreadOnly) {\n viewValue = 'unread';\n } else if (unreadOnly === false) {\n viewValue = 'read';\n }\n\n const handleOnSeverityChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n const value: NotificationSeverity =\n (event.target.value as NotificationSeverity) || 'normal';\n onSeverityChanged(value);\n };\n\n return (\n <>\n <Grid container>\n <Grid item xs={12}>\n <Typography variant=\"h6\">Filters</Typography>\n <Divider variant=\"fullWidth\" />\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-view\">View</InputLabel>\n <Select\n labelId=\"notifications-filter-view\"\n label=\"View\"\n value={viewValue}\n onChange={handleOnViewChanged}\n >\n <MenuItem value=\"unread\">New only</MenuItem>\n <MenuItem value=\"saved\">Saved</MenuItem>\n <MenuItem value=\"read\">Marked as read</MenuItem>\n <MenuItem value=\"all\">All</MenuItem>\n </Select>\n </FormControl>\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-created\">\n Created after\n </InputLabel>\n\n <Select\n label=\"Created after\"\n labelId=\"notifications-filter-created\"\n placeholder=\"Notifications since\"\n value={createdAfter}\n onChange={handleOnCreatedAfterChanged}\n >\n {Object.keys(CreatedAfterOptions).map((key: string) => (\n <MenuItem value={key} key={key}>\n {CreatedAfterOptions[key].label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-sort\">Sort by</InputLabel>\n\n <Select\n label=\"Sort by\"\n labelId=\"notifications-filter-sort\"\n placeholder=\"Field to sort by\"\n value={sortByText}\n onChange={handleOnSortByChanged}\n >\n {Object.keys(SortByOptions).map((key: string) => (\n <MenuItem value={key} key={key}>\n {SortByOptions[key].label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-severity\">Severity</InputLabel>\n\n <Select\n label=\"Severity\"\n labelId=\"notifications-filter-severity\"\n value={severity}\n onChange={handleOnSeverityChanged}\n >\n {Object.keys(AllSeverityOptions).map((key: string) => (\n <MenuItem value={key} key={key}>\n {AllSeverityOptions[key as NotificationSeverity]}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n </Grid>\n </>\n );\n};\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport throttle from 'lodash/throttle';\nimport {\n Content,\n PageWithHeader,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport Grid from '@material-ui/core/Grid';\nimport { useSignal } from '@backstage/plugin-signals-react';\n\nimport { NotificationsTable } from '../NotificationsTable';\nimport { useNotificationsApi } from '../../hooks';\nimport {\n CreatedAfterOptions,\n NotificationsFilters,\n SortBy,\n SortByOptions,\n} from '../NotificationsFilters';\nimport { GetNotificationsOptions } from '../../api';\nimport { NotificationSeverity } from '@backstage/plugin-notifications-common';\n\nconst ThrottleDelayMs = 2000;\n\nexport const NotificationsPage = () => {\n const [refresh, setRefresh] = React.useState(false);\n const { lastSignal } = useSignal('notifications');\n const [unreadOnly, setUnreadOnly] = React.useState<boolean | undefined>(true);\n const [saved, setSaved] = React.useState<boolean | undefined>(undefined);\n const [pageNumber, setPageNumber] = React.useState(0);\n const [pageSize, setPageSize] = React.useState(5);\n const [containsText, setContainsText] = React.useState<string>();\n const [createdAfter, setCreatedAfter] = React.useState<string>('lastWeek');\n const [sorting, setSorting] = React.useState<SortBy>(\n SortByOptions.newest.sortBy,\n );\n const [severity, setSeverity] = React.useState<NotificationSeverity>('low');\n\n const { error, value, retry, loading } = useNotificationsApi(\n api => {\n const options: GetNotificationsOptions = {\n search: containsText,\n limit: pageSize,\n offset: pageNumber * pageSize,\n minimumSeverity: severity,\n ...(sorting || {}),\n };\n if (unreadOnly !== undefined) {\n options.read = !unreadOnly;\n }\n if (saved !== undefined) {\n options.saved = saved;\n }\n\n const createdAfterDate = CreatedAfterOptions[createdAfter].getDate();\n if (createdAfterDate.valueOf() > 0) {\n options.createdAfter = createdAfterDate;\n }\n\n return api.getNotifications(options);\n },\n [\n containsText,\n unreadOnly,\n createdAfter,\n pageNumber,\n pageSize,\n sorting,\n saved,\n severity,\n ],\n );\n\n const throttledSetRefresh = React.useMemo(\n () => throttle(setRefresh, ThrottleDelayMs),\n [setRefresh],\n );\n\n useEffect(() => {\n if (refresh && !loading) {\n retry();\n setRefresh(false);\n }\n }, [refresh, setRefresh, retry, loading]);\n\n useEffect(() => {\n if (lastSignal && lastSignal.action) {\n throttledSetRefresh(true);\n }\n }, [lastSignal, throttledSetRefresh]);\n\n const onUpdate = () => {\n throttledSetRefresh(true);\n };\n\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <PageWithHeader title=\"Notifications\" themeId=\"tool\">\n <Content>\n <Grid container>\n <Grid item xs={2}>\n <NotificationsFilters\n unreadOnly={unreadOnly}\n onUnreadOnlyChanged={setUnreadOnly}\n createdAfter={createdAfter}\n onCreatedAfterChanged={setCreatedAfter}\n onSortingChanged={setSorting}\n sorting={sorting}\n saved={saved}\n onSavedChanged={setSaved}\n severity={severity}\n onSeverityChanged={setSeverity}\n />\n </Grid>\n <Grid item xs={10}>\n <NotificationsTable\n isLoading={loading}\n notifications={value?.notifications}\n onUpdate={onUpdate}\n setContainsText={setContainsText}\n onPageChange={setPageNumber}\n onRowsPerPageChange={setPageSize}\n page={pageNumber}\n pageSize={pageSize}\n totalCount={value?.totalCount}\n />\n </Grid>\n </Grid>\n </Content>\n </PageWithHeader>\n );\n};\n"],"names":[],"mappings":"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"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRouteRef, createApiRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, createRoutableExtension, useApi, useRouteRef } from '@backstage/core-plugin-api';
|
|
2
2
|
import { ResponseError } from '@backstage/errors';
|
|
3
3
|
import useAsyncRetry from 'react-use/esm/useAsyncRetry';
|
|
4
|
-
import React, { useState, useEffect, useCallback
|
|
4
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
5
5
|
import { SidebarItem, Link, Table } from '@backstage/core-components';
|
|
6
6
|
import NotificationsIcon from '@material-ui/icons/Notifications';
|
|
7
7
|
import { useSignal } from '@backstage/plugin-signals-react';
|
|
@@ -9,17 +9,20 @@ import throttle from 'lodash/throttle';
|
|
|
9
9
|
import RelativeTime from 'react-relative-time';
|
|
10
10
|
import Box from '@material-ui/core/Box';
|
|
11
11
|
import Grid from '@material-ui/core/Grid';
|
|
12
|
+
import Checkbox from '@material-ui/core/Checkbox';
|
|
13
|
+
import Typography from '@material-ui/core/Typography';
|
|
14
|
+
import NormalIcon from '@material-ui/icons/CheckOutlined';
|
|
15
|
+
import CriticalIcon from '@material-ui/icons/ErrorOutline';
|
|
16
|
+
import HighIcon from '@material-ui/icons/WarningOutlined';
|
|
17
|
+
import LowIcon from '@material-ui/icons/InfoOutlined';
|
|
18
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
19
|
+
import FormControlLabel from '@material-ui/core/FormControlLabel';
|
|
12
20
|
import IconButton from '@material-ui/core/IconButton';
|
|
13
21
|
import Tooltip from '@material-ui/core/Tooltip';
|
|
14
|
-
import Typography from '@material-ui/core/Typography';
|
|
15
22
|
import MarkAsUnreadIcon from '@material-ui/icons/Markunread';
|
|
16
23
|
import MarkAsReadIcon from '@material-ui/icons/CheckCircle';
|
|
17
24
|
import MarkAsUnsavedIcon from '@material-ui/icons/LabelOff';
|
|
18
25
|
import MarkAsSavedIcon from '@material-ui/icons/Label';
|
|
19
|
-
import NormalIcon from '@material-ui/icons/CheckOutlined';
|
|
20
|
-
import CriticalIcon from '@material-ui/icons/ErrorOutline';
|
|
21
|
-
import HighIcon from '@material-ui/icons/WarningOutlined';
|
|
22
|
-
import LowIcon from '@material-ui/icons/InfoOutlined';
|
|
23
26
|
|
|
24
27
|
const rootRouteRef = createRouteRef({
|
|
25
28
|
id: "notifications"
|
|
@@ -70,7 +73,7 @@ class NotificationsClient {
|
|
|
70
73
|
queryString.append("createdAfter", options.createdAfter.toISOString());
|
|
71
74
|
}
|
|
72
75
|
if ((options == null ? void 0 : options.minimumSeverity) !== void 0) {
|
|
73
|
-
queryString.append("
|
|
76
|
+
queryString.append("minimumSeverity", options.minimumSeverity);
|
|
74
77
|
}
|
|
75
78
|
const urlSegment = `?${queryString}`;
|
|
76
79
|
return await this.request(urlSegment);
|
|
@@ -115,7 +118,7 @@ const notificationsPlugin = createPlugin({
|
|
|
115
118
|
const NotificationsPage = notificationsPlugin.provide(
|
|
116
119
|
createRoutableExtension({
|
|
117
120
|
name: "NotificationsPage",
|
|
118
|
-
component: () => import('./esm/index-
|
|
121
|
+
component: () => import('./esm/index-D44DlZtS.esm.js').then((m) => m.NotificationsPage),
|
|
119
122
|
mountPoint: rootRouteRef
|
|
120
123
|
})
|
|
121
124
|
);
|
|
@@ -265,20 +268,110 @@ const NotificationsSidebarItem = (props) => {
|
|
|
265
268
|
);
|
|
266
269
|
};
|
|
267
270
|
|
|
271
|
+
const useStyles$1 = makeStyles((theme) => ({
|
|
272
|
+
critical: {
|
|
273
|
+
color: theme.palette.status.error
|
|
274
|
+
},
|
|
275
|
+
high: {
|
|
276
|
+
color: theme.palette.status.warning
|
|
277
|
+
},
|
|
278
|
+
normal: {
|
|
279
|
+
color: theme.palette.status.ok
|
|
280
|
+
},
|
|
281
|
+
low: {
|
|
282
|
+
color: theme.palette.status.running
|
|
283
|
+
}
|
|
284
|
+
}));
|
|
268
285
|
const SeverityIcon = ({
|
|
269
286
|
severity
|
|
270
287
|
}) => {
|
|
288
|
+
const classes = useStyles$1();
|
|
271
289
|
switch (severity) {
|
|
272
290
|
case "critical":
|
|
273
|
-
return /* @__PURE__ */ React.createElement(CriticalIcon, {
|
|
291
|
+
return /* @__PURE__ */ React.createElement(CriticalIcon, { className: classes.critical });
|
|
274
292
|
case "high":
|
|
275
|
-
return /* @__PURE__ */ React.createElement(HighIcon, {
|
|
293
|
+
return /* @__PURE__ */ React.createElement(HighIcon, { className: classes.high });
|
|
276
294
|
case "low":
|
|
277
|
-
return /* @__PURE__ */ React.createElement(LowIcon, {
|
|
295
|
+
return /* @__PURE__ */ React.createElement(LowIcon, { className: classes.low });
|
|
278
296
|
case "normal":
|
|
279
297
|
default:
|
|
280
|
-
return /* @__PURE__ */ React.createElement(NormalIcon, {
|
|
298
|
+
return /* @__PURE__ */ React.createElement(NormalIcon, { className: classes.normal });
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const useStyles = makeStyles({
|
|
303
|
+
label: {
|
|
304
|
+
marginLeft: "0px",
|
|
305
|
+
maxWidth: "2rem",
|
|
306
|
+
"& span": {
|
|
307
|
+
paddingRight: "0px"
|
|
308
|
+
}
|
|
281
309
|
}
|
|
310
|
+
});
|
|
311
|
+
const SelectAll = ({
|
|
312
|
+
count,
|
|
313
|
+
totalCount,
|
|
314
|
+
onSelectAll
|
|
315
|
+
}) => {
|
|
316
|
+
const classes = useStyles();
|
|
317
|
+
return /* @__PURE__ */ React.createElement(
|
|
318
|
+
FormControlLabel,
|
|
319
|
+
{
|
|
320
|
+
label: count > 0 ? `(${count})` : void 0,
|
|
321
|
+
className: classes.label,
|
|
322
|
+
control: /* @__PURE__ */ React.createElement(
|
|
323
|
+
Checkbox,
|
|
324
|
+
{
|
|
325
|
+
color: "primary",
|
|
326
|
+
disabled: !totalCount,
|
|
327
|
+
checked: count > 0,
|
|
328
|
+
indeterminate: count > 0 && totalCount !== count,
|
|
329
|
+
onChange: onSelectAll
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const BulkActions = ({
|
|
337
|
+
selectedNotifications,
|
|
338
|
+
notifications,
|
|
339
|
+
onSwitchReadStatus,
|
|
340
|
+
onSwitchSavedStatus
|
|
341
|
+
}) => {
|
|
342
|
+
const isDisabled = selectedNotifications.size === 0;
|
|
343
|
+
const bulkNotifications = notifications.filter(
|
|
344
|
+
(notification) => selectedNotifications.has(notification.id)
|
|
345
|
+
);
|
|
346
|
+
const isOneRead = !!bulkNotifications.find(
|
|
347
|
+
(notification) => !!notification.read
|
|
348
|
+
);
|
|
349
|
+
const isOneSaved = !!bulkNotifications.find(
|
|
350
|
+
(notification) => !!notification.saved
|
|
351
|
+
);
|
|
352
|
+
const markAsReadText = isOneRead ? "Return selected among unread" : "Mark selected as read";
|
|
353
|
+
const IconComponent = isOneRead ? MarkAsUnreadIcon : MarkAsReadIcon;
|
|
354
|
+
const markAsSavedText = isOneSaved ? "Undo save for selected" : "Save selected for later";
|
|
355
|
+
const SavedIconComponent = isOneSaved ? MarkAsUnsavedIcon : MarkAsSavedIcon;
|
|
356
|
+
return /* @__PURE__ */ React.createElement(Grid, { container: true, wrap: "nowrap" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Tooltip, { title: markAsSavedText }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
357
|
+
IconButton,
|
|
358
|
+
{
|
|
359
|
+
disabled: isDisabled,
|
|
360
|
+
onClick: () => {
|
|
361
|
+
onSwitchSavedStatus([...selectedNotifications], !isOneSaved);
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
/* @__PURE__ */ React.createElement(SavedIconComponent, { "aria-label": markAsSavedText })
|
|
365
|
+
)))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Tooltip, { title: markAsReadText }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
366
|
+
IconButton,
|
|
367
|
+
{
|
|
368
|
+
disabled: isDisabled,
|
|
369
|
+
onClick: () => {
|
|
370
|
+
onSwitchReadStatus([...selectedNotifications], !isOneRead);
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
/* @__PURE__ */ React.createElement(IconComponent, { "aria-label": markAsReadText })
|
|
374
|
+
)))));
|
|
282
375
|
};
|
|
283
376
|
|
|
284
377
|
const ThrottleDelayMs = 1e3;
|
|
@@ -294,103 +387,127 @@ const NotificationsTable = ({
|
|
|
294
387
|
totalCount
|
|
295
388
|
}) => {
|
|
296
389
|
const notificationsApi = useApi(notificationsApiRef);
|
|
390
|
+
const [selectedNotifications, setSelectedNotifications] = React.useState(
|
|
391
|
+
/* @__PURE__ */ new Set()
|
|
392
|
+
);
|
|
393
|
+
const onNotificationsSelectChange = React.useCallback(
|
|
394
|
+
(ids, checked) => {
|
|
395
|
+
let newSelect;
|
|
396
|
+
if (checked) {
|
|
397
|
+
newSelect = /* @__PURE__ */ new Set([...selectedNotifications, ...ids]);
|
|
398
|
+
} else {
|
|
399
|
+
newSelect = new Set(selectedNotifications);
|
|
400
|
+
ids.forEach((id) => newSelect.delete(id));
|
|
401
|
+
}
|
|
402
|
+
setSelectedNotifications(newSelect);
|
|
403
|
+
},
|
|
404
|
+
[selectedNotifications, setSelectedNotifications]
|
|
405
|
+
);
|
|
297
406
|
const onSwitchReadStatus = React.useCallback(
|
|
298
|
-
(
|
|
407
|
+
(ids, newStatus) => {
|
|
299
408
|
notificationsApi.updateNotifications({
|
|
300
|
-
ids
|
|
301
|
-
read:
|
|
302
|
-
}).then(
|
|
409
|
+
ids,
|
|
410
|
+
read: newStatus
|
|
411
|
+
}).then(onUpdate);
|
|
303
412
|
},
|
|
304
413
|
[notificationsApi, onUpdate]
|
|
305
414
|
);
|
|
306
415
|
const onSwitchSavedStatus = React.useCallback(
|
|
307
|
-
(
|
|
416
|
+
(ids, newStatus) => {
|
|
308
417
|
notificationsApi.updateNotifications({
|
|
309
|
-
ids
|
|
310
|
-
saved:
|
|
311
|
-
}).then(
|
|
418
|
+
ids,
|
|
419
|
+
saved: newStatus
|
|
420
|
+
}).then(onUpdate);
|
|
312
421
|
},
|
|
313
422
|
[notificationsApi, onUpdate]
|
|
314
423
|
);
|
|
315
|
-
const throttledContainsTextHandler = useMemo(
|
|
424
|
+
const throttledContainsTextHandler = React.useMemo(
|
|
316
425
|
() => throttle(setContainsText, ThrottleDelayMs),
|
|
317
426
|
[setContainsText]
|
|
318
427
|
);
|
|
428
|
+
React.useEffect(() => {
|
|
429
|
+
const allShownIds = new Set(notifications.map((n) => n.id));
|
|
430
|
+
const intersect = [...selectedNotifications].filter(
|
|
431
|
+
(id) => allShownIds.has(id)
|
|
432
|
+
);
|
|
433
|
+
if (selectedNotifications.size !== intersect.length) {
|
|
434
|
+
setSelectedNotifications(new Set(intersect));
|
|
435
|
+
}
|
|
436
|
+
}, [notifications, selectedNotifications]);
|
|
319
437
|
const compactColumns = React.useMemo(
|
|
320
438
|
() => [
|
|
321
439
|
{
|
|
440
|
+
/* selection column */
|
|
322
441
|
width: "1rem",
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
442
|
+
title: /* @__PURE__ */ React.createElement(
|
|
443
|
+
SelectAll,
|
|
444
|
+
{
|
|
445
|
+
count: selectedNotifications.size,
|
|
446
|
+
totalCount: notifications.length,
|
|
447
|
+
onSelectAll: () => onNotificationsSelectChange(
|
|
448
|
+
notifications.map((notification) => notification.id),
|
|
449
|
+
selectedNotifications.size !== notifications.length
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
),
|
|
453
|
+
render: (notification) => /* @__PURE__ */ React.createElement(
|
|
454
|
+
Checkbox,
|
|
455
|
+
{
|
|
456
|
+
color: "primary",
|
|
457
|
+
checked: selectedNotifications.has(notification.id),
|
|
458
|
+
onChange: (_, checked) => onNotificationsSelectChange([notification.id], checked)
|
|
459
|
+
}
|
|
460
|
+
)
|
|
327
461
|
},
|
|
328
462
|
{
|
|
463
|
+
/* compact-data column */
|
|
329
464
|
customFilterAndSearch: () => true,
|
|
330
465
|
render: (notification) => {
|
|
331
|
-
|
|
466
|
+
var _a;
|
|
467
|
+
return /* @__PURE__ */ React.createElement(Grid, { container: true }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(SeverityIcon, { severity: (_a = notification.payload) == null ? void 0 : _a.severity })), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "subtitle2" }, notification.payload.link ? /* @__PURE__ */ React.createElement(Link, { to: notification.payload.link }, notification.payload.title) : notification.payload.title), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, notification.payload.description), /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, notification.origin && /* @__PURE__ */ React.createElement(React.Fragment, null, notification.origin, "\xA0\u2022\xA0"), notification.payload.topic && /* @__PURE__ */ React.createElement(React.Fragment, null, notification.payload.topic, "\xA0\u2022\xA0"), notification.created && /* @__PURE__ */ React.createElement(RelativeTime, { value: notification.created })))));
|
|
332
468
|
}
|
|
333
469
|
},
|
|
334
|
-
// {
|
|
335
|
-
// // TODO: additional action links
|
|
336
|
-
// width: '25%',
|
|
337
|
-
// render: (notification: Notification) => {
|
|
338
|
-
// return (
|
|
339
|
-
// notification.payload.link && (
|
|
340
|
-
// <Grid container>
|
|
341
|
-
// {/* TODO: render additionalLinks of different titles */}
|
|
342
|
-
// <Grid item>
|
|
343
|
-
// <Link
|
|
344
|
-
// key={notification.payload.link}
|
|
345
|
-
// to={notification.payload.link}
|
|
346
|
-
// >
|
|
347
|
-
// More info
|
|
348
|
-
// </Link>
|
|
349
|
-
// </Grid>
|
|
350
|
-
// </Grid>
|
|
351
|
-
// )
|
|
352
|
-
// );
|
|
353
|
-
// },
|
|
354
|
-
// },
|
|
355
470
|
{
|
|
356
|
-
|
|
471
|
+
/* actions column */
|
|
357
472
|
width: "1rem",
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
/* @__PURE__ */ React.createElement(IconComponent, { "aria-label": markAsReadText })
|
|
379
|
-
))));
|
|
380
|
-
}
|
|
473
|
+
title: /* @__PURE__ */ React.createElement(
|
|
474
|
+
BulkActions,
|
|
475
|
+
{
|
|
476
|
+
notifications,
|
|
477
|
+
selectedNotifications,
|
|
478
|
+
onSwitchReadStatus,
|
|
479
|
+
onSwitchSavedStatus
|
|
480
|
+
}
|
|
481
|
+
),
|
|
482
|
+
render: (notification) => /* @__PURE__ */ React.createElement(
|
|
483
|
+
BulkActions,
|
|
484
|
+
{
|
|
485
|
+
notifications: [notification],
|
|
486
|
+
selectedNotifications: /* @__PURE__ */ new Set([notification.id]),
|
|
487
|
+
onSwitchReadStatus,
|
|
488
|
+
onSwitchSavedStatus
|
|
489
|
+
}
|
|
490
|
+
)
|
|
381
491
|
}
|
|
382
492
|
],
|
|
383
|
-
[
|
|
493
|
+
[
|
|
494
|
+
onSwitchReadStatus,
|
|
495
|
+
onSwitchSavedStatus,
|
|
496
|
+
selectedNotifications,
|
|
497
|
+
onNotificationsSelectChange,
|
|
498
|
+
notifications
|
|
499
|
+
]
|
|
384
500
|
);
|
|
385
501
|
return /* @__PURE__ */ React.createElement(
|
|
386
502
|
Table,
|
|
387
503
|
{
|
|
388
504
|
isLoading,
|
|
389
505
|
options: {
|
|
506
|
+
padding: "dense",
|
|
390
507
|
search: true,
|
|
391
508
|
paging: true,
|
|
392
509
|
pageSize,
|
|
393
|
-
header:
|
|
510
|
+
header: true,
|
|
394
511
|
sorting: false
|
|
395
512
|
},
|
|
396
513
|
onPageChange,
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/routes.ts","../src/api/NotificationsApi.ts","../src/api/NotificationsClient.ts","../src/plugin.ts","../src/hooks/useNotificationsApi.ts","../src/hooks/useWebNotifications.ts","../src/hooks/useTitleCounter.ts","../src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx","../src/components/NotificationsTable/SeverityIcon.tsx","../src/components/NotificationsTable/NotificationsTable.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'notifications',\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createApiRef } from '@backstage/core-plugin-api';\nimport {\n Notification,\n NotificationSeverity,\n NotificationStatus,\n} from '@backstage/plugin-notifications-common';\n\n/** @public */\nexport const notificationsApiRef = createApiRef<NotificationsApi>({\n id: 'plugin.notifications.service',\n});\n\n/** @public */\nexport type GetNotificationsOptions = {\n offset?: number;\n limit?: number;\n search?: string;\n read?: boolean;\n saved?: boolean;\n createdAfter?: Date;\n sort?: 'created' | 'topic' | 'origin';\n sortOrder?: 'asc' | 'desc';\n minimumSeverity?: NotificationSeverity;\n};\n\n/** @public */\nexport type UpdateNotificationsOptions = {\n ids: string[];\n read?: boolean;\n saved?: boolean;\n};\n\n/** @public */\nexport type GetNotificationsResponse = {\n notifications: Notification[];\n totalCount: number;\n};\n\n/** @public */\nexport interface NotificationsApi {\n getNotifications(\n options?: GetNotificationsOptions,\n ): Promise<GetNotificationsResponse>;\n\n getNotification(id: string): Promise<Notification>;\n\n getStatus(): Promise<NotificationStatus>;\n\n updateNotifications(\n options: UpdateNotificationsOptions,\n ): Promise<Notification[]>;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n GetNotificationsOptions,\n GetNotificationsResponse,\n NotificationsApi,\n UpdateNotificationsOptions,\n} from './NotificationsApi';\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport {\n Notification,\n NotificationStatus,\n} from '@backstage/plugin-notifications-common';\n\n/** @public */\nexport class NotificationsClient implements NotificationsApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n public constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getNotifications(\n options?: GetNotificationsOptions,\n ): Promise<GetNotificationsResponse> {\n const queryString = new URLSearchParams();\n if (options?.limit !== undefined) {\n queryString.append('limit', options.limit.toString(10));\n }\n if (options?.offset !== undefined) {\n queryString.append('offset', options.offset.toString(10));\n }\n if (options?.sort !== undefined) {\n queryString.append(\n 'orderField',\n `${options.sort},${options?.sortOrder ?? 'desc'}`,\n );\n }\n if (options?.search) {\n queryString.append('search', options.search);\n }\n if (options?.read !== undefined) {\n queryString.append('read', options.read ? 'true' : 'false');\n }\n if (options?.saved !== undefined) {\n queryString.append('saved', options.saved ? 'true' : 'false');\n }\n if (options?.createdAfter !== undefined) {\n queryString.append('createdAfter', options.createdAfter.toISOString());\n }\n if (options?.minimumSeverity !== undefined) {\n queryString.append('minimal_severity', options.minimumSeverity);\n }\n const urlSegment = `?${queryString}`;\n\n return await this.request<GetNotificationsResponse>(urlSegment);\n }\n\n async getNotification(id: string): Promise<Notification> {\n return await this.request<Notification>(`${id}`);\n }\n\n async getStatus(): Promise<NotificationStatus> {\n return await this.request<NotificationStatus>('status');\n }\n\n async updateNotifications(\n options: UpdateNotificationsOptions,\n ): Promise<Notification[]> {\n return await this.request<Notification[]>('update', {\n method: 'POST',\n body: JSON.stringify(options),\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n private async request<T>(path: string, init?: any): Promise<T> {\n const baseUrl = `${await this.discoveryApi.getBaseUrl('notifications')}/`;\n const url = new URL(path, baseUrl);\n\n const response = await this.fetchApi.fetch(url.toString(), init);\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json() as Promise<T>;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef } from './routes';\nimport { notificationsApiRef } from './api/NotificationsApi';\nimport { NotificationsClient } from './api';\n\n/** @public */\nexport const notificationsPlugin = createPlugin({\n id: 'notifications',\n routes: {\n root: rootRouteRef,\n },\n apis: [\n createApiFactory({\n api: notificationsApiRef,\n deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },\n factory: ({ discoveryApi, fetchApi }) =>\n new NotificationsClient({ discoveryApi, fetchApi }),\n }),\n ],\n});\n\n/** @public */\nexport const NotificationsPage = notificationsPlugin.provide(\n createRoutableExtension({\n name: 'NotificationsPage',\n component: () =>\n import('./components/NotificationsPage').then(m => m.NotificationsPage),\n mountPoint: rootRouteRef,\n }),\n);\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotificationsApi, notificationsApiRef } from '../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\n\n/** @public */\nexport function useNotificationsApi<T>(\n f: (api: NotificationsApi) => Promise<T>,\n deps: any[] = [],\n) {\n const notificationsApi = useApi(notificationsApiRef);\n\n return useAsyncRetry(async () => {\n return await f(notificationsApi);\n }, deps);\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useState } from 'react';\n\n/** @public */\nexport function useWebNotifications() {\n const [webNotificationPermission, setWebNotificationPermission] =\n useState('default');\n const [webNotifications, setWebNotifications] = useState<Notification[]>([]);\n\n useEffect(() => {\n if ('Notification' in window && webNotificationPermission === 'default') {\n window.Notification.requestPermission().then(permission => {\n setWebNotificationPermission(permission);\n });\n }\n }, [webNotificationPermission]);\n\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n webNotifications.forEach(n => n.close());\n setWebNotifications([]);\n }\n });\n\n const sendWebNotification = useCallback(\n (options: { title: string; description: string; link?: string }) => {\n if (webNotificationPermission !== 'granted') {\n return null;\n }\n\n const notification = new Notification(options.title, {\n body: options.description,\n });\n\n notification.onclick = event => {\n event.preventDefault();\n notification.close();\n if (options.link) {\n window.open(options.link, '_blank');\n }\n };\n\n return notification;\n },\n [webNotificationPermission],\n );\n\n return { sendWebNotification };\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useState } from 'react';\n\n/** @public */\nexport function useTitleCounter() {\n const [title, setTitle] = useState(document.title);\n const [count, setCount] = useState(0);\n\n const getPrefix = (value: number) => {\n return value === 0 ? '' : `(${value}) `;\n };\n\n const cleanTitle = (currentTitle: string) => {\n return currentTitle.replace(/^\\(\\d+\\)\\s/, '');\n };\n\n useEffect(() => {\n document.title = title;\n }, [title]);\n\n useEffect(() => {\n const baseTitle = cleanTitle(title);\n setTitle(`${getPrefix(count)}${baseTitle}`);\n return () => {\n document.title = cleanTitle(title);\n };\n }, [title, count]);\n\n const titleElement = document.querySelector('title');\n if (titleElement) {\n new MutationObserver(() => {\n setTitle(document.title);\n }).observe(titleElement, {\n subtree: true,\n characterData: true,\n childList: true,\n });\n }\n\n const setNotificationCount = useCallback(\n (newCount: number) => setCount(newCount),\n [],\n );\n\n return { setNotificationCount };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useEffect } from 'react';\nimport { useNotificationsApi } from '../../hooks';\nimport { SidebarItem } from '@backstage/core-components';\nimport NotificationsIcon from '@material-ui/icons/Notifications';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { rootRouteRef } from '../../routes';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport { NotificationSignal } from '@backstage/plugin-notifications-common';\nimport { useWebNotifications } from '../../hooks/useWebNotifications';\nimport { useTitleCounter } from '../../hooks/useTitleCounter';\nimport { notificationsApiRef } from '../../api';\n\n/** @public */\nexport const NotificationsSidebarItem = (props?: {\n webNotificationsEnabled?: boolean;\n titleCounterEnabled?: boolean;\n}) => {\n const { webNotificationsEnabled = false, titleCounterEnabled = true } =\n props ?? { webNotificationsEnabled: false, titleCounterEnabled: true };\n\n const { loading, error, value, retry } = useNotificationsApi(api =>\n api.getStatus(),\n );\n const notificationsApi = useApi(notificationsApiRef);\n const [unreadCount, setUnreadCount] = React.useState(0);\n const notificationsRoute = useRouteRef(rootRouteRef);\n // TODO: Do we want to add long polling in case signals are not available\n const { lastSignal } = useSignal<NotificationSignal>('notifications');\n const { sendWebNotification } = useWebNotifications();\n const [refresh, setRefresh] = React.useState(false);\n const { setNotificationCount } = useTitleCounter();\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, retry]);\n\n useEffect(() => {\n const handleWebNotification = (signal: NotificationSignal) => {\n if (!webNotificationsEnabled || signal.action !== 'new_notification') {\n return;\n }\n\n notificationsApi\n .getNotification(signal.notification_id)\n .then(notification => {\n if (!notification) {\n return;\n }\n sendWebNotification({\n title: notification.payload.title,\n description: notification.payload.description ?? '',\n link: notification.payload.link,\n });\n });\n };\n\n if (lastSignal && lastSignal.action) {\n handleWebNotification(lastSignal);\n setRefresh(true);\n }\n }, [\n lastSignal,\n sendWebNotification,\n webNotificationsEnabled,\n notificationsApi,\n ]);\n\n useEffect(() => {\n if (!loading && !error && value) {\n setUnreadCount(value.unread);\n if (titleCounterEnabled) {\n setNotificationCount(value.unread);\n }\n }\n }, [loading, error, value, titleCounterEnabled, setNotificationCount]);\n\n // TODO: Figure out if the count can be added to hasNotifications\n return (\n <SidebarItem\n icon={NotificationsIcon}\n to={notificationsRoute()}\n text=\"Notifications\"\n hasNotifications={!error && !!unreadCount}\n />\n );\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { NotificationSeverity } from '@backstage/plugin-notifications-common';\nimport NormalIcon from '@material-ui/icons/CheckOutlined';\nimport CriticalIcon from '@material-ui/icons/ErrorOutline';\nimport HighIcon from '@material-ui/icons/WarningOutlined';\nimport LowIcon from '@material-ui/icons/InfoOutlined';\n\nexport const SeverityIcon = ({\n severity,\n}: {\n severity?: NotificationSeverity;\n}) => {\n switch (severity) {\n case 'critical':\n return <CriticalIcon htmlColor=\"#C9190B\" />;\n case 'high':\n return <HighIcon htmlColor=\"#F0AB00\" />;\n case 'low':\n return <LowIcon htmlColor=\"#2B9AF3\" />;\n case 'normal':\n default:\n return <NormalIcon htmlColor=\"#5BA352\" />;\n }\n};\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useMemo } from 'react';\nimport throttle from 'lodash/throttle';\n// @ts-ignore\nimport RelativeTime from 'react-relative-time';\nimport Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport { Notification } from '@backstage/plugin-notifications-common';\n\nimport { notificationsApiRef } from '../../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n Link,\n Table,\n TableProps,\n TableColumn,\n} from '@backstage/core-components';\n\nimport MarkAsUnreadIcon from '@material-ui/icons/Markunread' /* TODO: use Drafts and MarkAsUnread once we have mui 5 icons */;\nimport MarkAsReadIcon from '@material-ui/icons/CheckCircle';\nimport MarkAsUnsavedIcon from '@material-ui/icons/LabelOff' /* TODO: use BookmarkRemove and BookmarkAdd once we have mui 5 icons */;\nimport MarkAsSavedIcon from '@material-ui/icons/Label';\nimport { SeverityIcon } from './SeverityIcon';\n\nconst ThrottleDelayMs = 1000;\n\n/** @public */\nexport type NotificationsTableProps = Pick<\n TableProps,\n 'onPageChange' | 'onRowsPerPageChange' | 'page' | 'totalCount'\n> & {\n isLoading?: boolean;\n notifications?: Notification[];\n onUpdate: () => void;\n setContainsText: (search: string) => void;\n pageSize: number;\n};\n\n/** @public */\nexport const NotificationsTable = ({\n isLoading,\n notifications = [],\n onUpdate,\n setContainsText,\n onPageChange,\n onRowsPerPageChange,\n page,\n pageSize,\n totalCount,\n}: NotificationsTableProps) => {\n const notificationsApi = useApi(notificationsApiRef);\n\n const onSwitchReadStatus = React.useCallback(\n (notification: Notification) => {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: !notification.read,\n })\n .then(() => onUpdate());\n },\n [notificationsApi, onUpdate],\n );\n\n const onSwitchSavedStatus = React.useCallback(\n (notification: Notification) => {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n saved: !notification.saved,\n })\n .then(() => onUpdate());\n },\n [notificationsApi, onUpdate],\n );\n\n const throttledContainsTextHandler = useMemo(\n () => throttle(setContainsText, ThrottleDelayMs),\n [setContainsText],\n );\n\n const compactColumns = React.useMemo(\n (): TableColumn<Notification>[] => [\n {\n width: '1rem',\n render: (notification: Notification) => (\n <SeverityIcon severity={notification.payload?.severity} />\n ),\n },\n {\n customFilterAndSearch: () =>\n true /* Keep it on backend due to pagination. If recent flickering is an issue, implement search here as well. */,\n render: (notification: Notification) => {\n // Compact content\n return (\n <>\n <Box>\n <Typography variant=\"subtitle2\">\n {notification.payload.link ? (\n <Link to={notification.payload.link}>\n {notification.payload.title}\n </Link>\n ) : (\n notification.payload.title\n )}\n </Typography>\n <Typography variant=\"body2\">\n {notification.payload.description}\n </Typography>\n <Typography variant=\"caption\">\n {notification.origin && (\n <>{notification.origin} • </>\n )}\n {notification.payload.topic && (\n <>{notification.payload.topic} • </>\n )}\n {notification.created && (\n <RelativeTime value={notification.created} />\n )}\n </Typography>\n </Box>\n </>\n );\n },\n },\n // {\n // // TODO: additional action links\n // width: '25%',\n // render: (notification: Notification) => {\n // return (\n // notification.payload.link && (\n // <Grid container>\n // {/* TODO: render additionalLinks of different titles */}\n // <Grid item>\n // <Link\n // key={notification.payload.link}\n // to={notification.payload.link}\n // >\n // More info\n // </Link>\n // </Grid>\n // </Grid>\n // )\n // );\n // },\n // },\n {\n // actions\n width: '1rem',\n render: (notification: Notification) => {\n const markAsReadText = !!notification.read\n ? 'Return among unread'\n : 'Mark as read';\n const IconComponent = !!notification.read\n ? MarkAsUnreadIcon\n : MarkAsReadIcon;\n\n const markAsSavedText = !!notification.saved\n ? 'Undo save'\n : 'Save for later';\n\n const SavedIconComponent = !!notification.saved\n ? MarkAsUnsavedIcon\n : MarkAsSavedIcon;\n\n return (\n <Grid container wrap=\"nowrap\">\n <Grid item>\n <Tooltip title={markAsSavedText}>\n <IconButton\n onClick={() => {\n onSwitchSavedStatus(notification);\n }}\n >\n <SavedIconComponent aria-label={markAsSavedText} />\n </IconButton>\n </Tooltip>\n </Grid>\n\n <Grid item>\n <Tooltip title={markAsReadText}>\n <IconButton\n onClick={() => {\n onSwitchReadStatus(notification);\n }}\n >\n <IconComponent aria-label={markAsReadText} />\n </IconButton>\n </Tooltip>\n </Grid>\n </Grid>\n );\n },\n },\n ],\n [onSwitchReadStatus, onSwitchSavedStatus],\n );\n\n return (\n <Table<Notification>\n isLoading={isLoading}\n options={{\n search: true,\n paging: true,\n pageSize,\n header: false,\n sorting: false,\n }}\n onPageChange={onPageChange}\n onRowsPerPageChange={onRowsPerPageChange}\n page={page}\n totalCount={totalCount}\n onSearchChange={throttledContainsTextHandler}\n data={notifications}\n columns={compactColumns}\n />\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/routes.ts","../src/api/NotificationsApi.ts","../src/api/NotificationsClient.ts","../src/plugin.ts","../src/hooks/useNotificationsApi.ts","../src/hooks/useWebNotifications.ts","../src/hooks/useTitleCounter.ts","../src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx","../src/components/NotificationsTable/SeverityIcon.tsx","../src/components/NotificationsTable/SelectAll.tsx","../src/components/NotificationsTable/BulkActions.tsx","../src/components/NotificationsTable/NotificationsTable.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'notifications',\n});\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { createApiRef } from '@backstage/core-plugin-api';\nimport {\n Notification,\n NotificationSeverity,\n NotificationStatus,\n} from '@backstage/plugin-notifications-common';\n\n/** @public */\nexport const notificationsApiRef = createApiRef<NotificationsApi>({\n id: 'plugin.notifications.service',\n});\n\n/** @public */\nexport type GetNotificationsOptions = {\n offset?: number;\n limit?: number;\n search?: string;\n read?: boolean;\n saved?: boolean;\n createdAfter?: Date;\n sort?: 'created' | 'topic' | 'origin';\n sortOrder?: 'asc' | 'desc';\n minimumSeverity?: NotificationSeverity;\n};\n\n/** @public */\nexport type UpdateNotificationsOptions = {\n ids: string[];\n read?: boolean;\n saved?: boolean;\n};\n\n/** @public */\nexport type GetNotificationsResponse = {\n notifications: Notification[];\n totalCount: number;\n};\n\n/** @public */\nexport interface NotificationsApi {\n getNotifications(\n options?: GetNotificationsOptions,\n ): Promise<GetNotificationsResponse>;\n\n getNotification(id: string): Promise<Notification>;\n\n getStatus(): Promise<NotificationStatus>;\n\n updateNotifications(\n options: UpdateNotificationsOptions,\n ): Promise<Notification[]>;\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n GetNotificationsOptions,\n GetNotificationsResponse,\n NotificationsApi,\n UpdateNotificationsOptions,\n} from './NotificationsApi';\nimport { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport { ResponseError } from '@backstage/errors';\nimport {\n Notification,\n NotificationStatus,\n} from '@backstage/plugin-notifications-common';\n\n/** @public */\nexport class NotificationsClient implements NotificationsApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n\n public constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n }\n\n async getNotifications(\n options?: GetNotificationsOptions,\n ): Promise<GetNotificationsResponse> {\n const queryString = new URLSearchParams();\n if (options?.limit !== undefined) {\n queryString.append('limit', options.limit.toString(10));\n }\n if (options?.offset !== undefined) {\n queryString.append('offset', options.offset.toString(10));\n }\n if (options?.sort !== undefined) {\n queryString.append(\n 'orderField',\n `${options.sort},${options?.sortOrder ?? 'desc'}`,\n );\n }\n if (options?.search) {\n queryString.append('search', options.search);\n }\n if (options?.read !== undefined) {\n queryString.append('read', options.read ? 'true' : 'false');\n }\n if (options?.saved !== undefined) {\n queryString.append('saved', options.saved ? 'true' : 'false');\n }\n if (options?.createdAfter !== undefined) {\n queryString.append('createdAfter', options.createdAfter.toISOString());\n }\n if (options?.minimumSeverity !== undefined) {\n queryString.append('minimumSeverity', options.minimumSeverity);\n }\n const urlSegment = `?${queryString}`;\n\n return await this.request<GetNotificationsResponse>(urlSegment);\n }\n\n async getNotification(id: string): Promise<Notification> {\n return await this.request<Notification>(`${id}`);\n }\n\n async getStatus(): Promise<NotificationStatus> {\n return await this.request<NotificationStatus>('status');\n }\n\n async updateNotifications(\n options: UpdateNotificationsOptions,\n ): Promise<Notification[]> {\n return await this.request<Notification[]>('update', {\n method: 'POST',\n body: JSON.stringify(options),\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n private async request<T>(path: string, init?: any): Promise<T> {\n const baseUrl = `${await this.discoveryApi.getBaseUrl('notifications')}/`;\n const url = new URL(path, baseUrl);\n\n const response = await this.fetchApi.fetch(url.toString(), init);\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json() as Promise<T>;\n }\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef } from './routes';\nimport { notificationsApiRef } from './api/NotificationsApi';\nimport { NotificationsClient } from './api';\n\n/** @public */\nexport const notificationsPlugin = createPlugin({\n id: 'notifications',\n routes: {\n root: rootRouteRef,\n },\n apis: [\n createApiFactory({\n api: notificationsApiRef,\n deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef },\n factory: ({ discoveryApi, fetchApi }) =>\n new NotificationsClient({ discoveryApi, fetchApi }),\n }),\n ],\n});\n\n/** @public */\nexport const NotificationsPage = notificationsPlugin.provide(\n createRoutableExtension({\n name: 'NotificationsPage',\n component: () =>\n import('./components/NotificationsPage').then(m => m.NotificationsPage),\n mountPoint: rootRouteRef,\n }),\n);\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NotificationsApi, notificationsApiRef } from '../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\n\n/** @public */\nexport function useNotificationsApi<T>(\n f: (api: NotificationsApi) => Promise<T>,\n deps: any[] = [],\n) {\n const notificationsApi = useApi(notificationsApiRef);\n\n return useAsyncRetry(async () => {\n return await f(notificationsApi);\n }, deps);\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useState } from 'react';\n\n/** @public */\nexport function useWebNotifications() {\n const [webNotificationPermission, setWebNotificationPermission] =\n useState('default');\n const [webNotifications, setWebNotifications] = useState<Notification[]>([]);\n\n useEffect(() => {\n if ('Notification' in window && webNotificationPermission === 'default') {\n window.Notification.requestPermission().then(permission => {\n setWebNotificationPermission(permission);\n });\n }\n }, [webNotificationPermission]);\n\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n webNotifications.forEach(n => n.close());\n setWebNotifications([]);\n }\n });\n\n const sendWebNotification = useCallback(\n (options: { title: string; description: string; link?: string }) => {\n if (webNotificationPermission !== 'granted') {\n return null;\n }\n\n const notification = new Notification(options.title, {\n body: options.description,\n });\n\n notification.onclick = event => {\n event.preventDefault();\n notification.close();\n if (options.link) {\n window.open(options.link, '_blank');\n }\n };\n\n return notification;\n },\n [webNotificationPermission],\n );\n\n return { sendWebNotification };\n}\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useCallback, useEffect, useState } from 'react';\n\n/** @public */\nexport function useTitleCounter() {\n const [title, setTitle] = useState(document.title);\n const [count, setCount] = useState(0);\n\n const getPrefix = (value: number) => {\n return value === 0 ? '' : `(${value}) `;\n };\n\n const cleanTitle = (currentTitle: string) => {\n return currentTitle.replace(/^\\(\\d+\\)\\s/, '');\n };\n\n useEffect(() => {\n document.title = title;\n }, [title]);\n\n useEffect(() => {\n const baseTitle = cleanTitle(title);\n setTitle(`${getPrefix(count)}${baseTitle}`);\n return () => {\n document.title = cleanTitle(title);\n };\n }, [title, count]);\n\n const titleElement = document.querySelector('title');\n if (titleElement) {\n new MutationObserver(() => {\n setTitle(document.title);\n }).observe(titleElement, {\n subtree: true,\n characterData: true,\n childList: true,\n });\n }\n\n const setNotificationCount = useCallback(\n (newCount: number) => setCount(newCount),\n [],\n );\n\n return { setNotificationCount };\n}\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React, { useEffect } from 'react';\nimport { useNotificationsApi } from '../../hooks';\nimport { SidebarItem } from '@backstage/core-components';\nimport NotificationsIcon from '@material-ui/icons/Notifications';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { rootRouteRef } from '../../routes';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport { NotificationSignal } from '@backstage/plugin-notifications-common';\nimport { useWebNotifications } from '../../hooks/useWebNotifications';\nimport { useTitleCounter } from '../../hooks/useTitleCounter';\nimport { notificationsApiRef } from '../../api';\n\n/** @public */\nexport const NotificationsSidebarItem = (props?: {\n webNotificationsEnabled?: boolean;\n titleCounterEnabled?: boolean;\n}) => {\n const { webNotificationsEnabled = false, titleCounterEnabled = true } =\n props ?? { webNotificationsEnabled: false, titleCounterEnabled: true };\n\n const { loading, error, value, retry } = useNotificationsApi(api =>\n api.getStatus(),\n );\n const notificationsApi = useApi(notificationsApiRef);\n const [unreadCount, setUnreadCount] = React.useState(0);\n const notificationsRoute = useRouteRef(rootRouteRef);\n // TODO: Do we want to add long polling in case signals are not available\n const { lastSignal } = useSignal<NotificationSignal>('notifications');\n const { sendWebNotification } = useWebNotifications();\n const [refresh, setRefresh] = React.useState(false);\n const { setNotificationCount } = useTitleCounter();\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, retry]);\n\n useEffect(() => {\n const handleWebNotification = (signal: NotificationSignal) => {\n if (!webNotificationsEnabled || signal.action !== 'new_notification') {\n return;\n }\n\n notificationsApi\n .getNotification(signal.notification_id)\n .then(notification => {\n if (!notification) {\n return;\n }\n sendWebNotification({\n title: notification.payload.title,\n description: notification.payload.description ?? '',\n link: notification.payload.link,\n });\n });\n };\n\n if (lastSignal && lastSignal.action) {\n handleWebNotification(lastSignal);\n setRefresh(true);\n }\n }, [\n lastSignal,\n sendWebNotification,\n webNotificationsEnabled,\n notificationsApi,\n ]);\n\n useEffect(() => {\n if (!loading && !error && value) {\n setUnreadCount(value.unread);\n if (titleCounterEnabled) {\n setNotificationCount(value.unread);\n }\n }\n }, [loading, error, value, titleCounterEnabled, setNotificationCount]);\n\n // TODO: Figure out if the count can be added to hasNotifications\n return (\n <SidebarItem\n icon={NotificationsIcon}\n to={notificationsRoute()}\n text=\"Notifications\"\n hasNotifications={!error && !!unreadCount}\n />\n );\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { NotificationSeverity } from '@backstage/plugin-notifications-common';\nimport NormalIcon from '@material-ui/icons/CheckOutlined';\nimport CriticalIcon from '@material-ui/icons/ErrorOutline';\nimport HighIcon from '@material-ui/icons/WarningOutlined';\nimport LowIcon from '@material-ui/icons/InfoOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\n\nconst useStyles = makeStyles(theme => ({\n critical: {\n color: theme.palette.status.error,\n },\n high: {\n color: theme.palette.status.warning,\n },\n normal: {\n color: theme.palette.status.ok,\n },\n low: {\n color: theme.palette.status.running,\n },\n}));\n\nexport const SeverityIcon = ({\n severity,\n}: {\n severity?: NotificationSeverity;\n}) => {\n const classes = useStyles();\n\n switch (severity) {\n case 'critical':\n return <CriticalIcon className={classes.critical} />;\n case 'high':\n return <HighIcon className={classes.high} />;\n case 'low':\n return <LowIcon className={classes.low} />;\n case 'normal':\n default:\n return <NormalIcon className={classes.normal} />;\n }\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport Checkbox from '@material-ui/core/Checkbox';\nimport FormControlLabel from '@material-ui/core/FormControlLabel';\nimport { makeStyles } from '@material-ui/core/styles';\n\nconst useStyles = makeStyles({\n label: {\n marginLeft: '0px',\n maxWidth: '2rem',\n '& span': {\n paddingRight: '0px',\n },\n },\n});\n\nexport const SelectAll = ({\n count,\n totalCount,\n onSelectAll,\n}: {\n count: number;\n totalCount: number;\n onSelectAll: () => void;\n}) => {\n const classes = useStyles();\n\n return (\n <FormControlLabel\n label={count > 0 ? `(${count})` : undefined}\n className={classes.label}\n control={\n <Checkbox\n color=\"primary\"\n disabled={!totalCount}\n checked={count > 0}\n indeterminate={count > 0 && totalCount !== count}\n onChange={onSelectAll}\n />\n }\n />\n );\n};\n","/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport { Notification } from '@backstage/plugin-notifications-common';\nimport Grid from '@material-ui/core/Grid';\nimport IconButton from '@material-ui/core/IconButton';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport MarkAsUnreadIcon from '@material-ui/icons/Markunread' /* TODO: use Drafts and MarkAsUnread once we have mui 5 icons */;\nimport MarkAsReadIcon from '@material-ui/icons/CheckCircle';\nimport MarkAsUnsavedIcon from '@material-ui/icons/LabelOff' /* TODO: use BookmarkRemove and BookmarkAdd once we have mui 5 icons */;\nimport MarkAsSavedIcon from '@material-ui/icons/Label';\n\nexport const BulkActions = ({\n selectedNotifications,\n notifications,\n onSwitchReadStatus,\n onSwitchSavedStatus,\n}: {\n selectedNotifications: Set<Notification['id']>;\n notifications: Notification[];\n onSwitchReadStatus: (ids: Notification['id'][], newStatus: boolean) => void;\n onSwitchSavedStatus: (ids: Notification['id'][], newStatus: boolean) => void;\n}) => {\n const isDisabled = selectedNotifications.size === 0;\n const bulkNotifications = notifications.filter(notification =>\n selectedNotifications.has(notification.id),\n );\n\n const isOneRead = !!bulkNotifications.find(\n (notification: Notification) => !!notification.read,\n );\n const isOneSaved = !!bulkNotifications.find(\n (notification: Notification) => !!notification.saved,\n );\n\n const markAsReadText = isOneRead\n ? 'Return selected among unread'\n : 'Mark selected as read';\n const IconComponent = isOneRead ? MarkAsUnreadIcon : MarkAsReadIcon;\n\n const markAsSavedText = isOneSaved\n ? 'Undo save for selected'\n : 'Save selected for later';\n const SavedIconComponent = isOneSaved ? MarkAsUnsavedIcon : MarkAsSavedIcon;\n\n return (\n <Grid container wrap=\"nowrap\">\n <Grid item>\n <Tooltip title={markAsSavedText}>\n <div>\n {/* The <div> here is a workaround for the Tooltip which does not work for a \"disabled\" child */}\n <IconButton\n disabled={isDisabled}\n onClick={() => {\n onSwitchSavedStatus([...selectedNotifications], !isOneSaved);\n }}\n >\n <SavedIconComponent aria-label={markAsSavedText} />\n </IconButton>\n </div>\n </Tooltip>\n </Grid>\n\n <Grid item>\n <Tooltip title={markAsReadText}>\n <div>\n <IconButton\n disabled={isDisabled}\n onClick={() => {\n onSwitchReadStatus([...selectedNotifications], !isOneRead);\n }}\n >\n <IconComponent aria-label={markAsReadText} />\n </IconButton>\n </div>\n </Tooltip>\n </Grid>\n </Grid>\n );\n};\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\nimport throttle from 'lodash/throttle';\n// @ts-ignore\nimport RelativeTime from 'react-relative-time';\nimport Box from '@material-ui/core/Box';\nimport Grid from '@material-ui/core/Grid';\nimport CheckBox from '@material-ui/core/Checkbox';\nimport Typography from '@material-ui/core/Typography';\nimport { Notification } from '@backstage/plugin-notifications-common';\n\nimport { notificationsApiRef } from '../../api';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n Link,\n Table,\n TableProps,\n TableColumn,\n} from '@backstage/core-components';\n\nimport { SeverityIcon } from './SeverityIcon';\nimport { SelectAll } from './SelectAll';\nimport { BulkActions } from './BulkActions';\n\nconst ThrottleDelayMs = 1000;\n\n/** @public */\nexport type NotificationsTableProps = Pick<\n TableProps,\n 'onPageChange' | 'onRowsPerPageChange' | 'page' | 'totalCount'\n> & {\n isLoading?: boolean;\n notifications?: Notification[];\n onUpdate: () => void;\n setContainsText: (search: string) => void;\n pageSize: number;\n};\n\n/** @public */\nexport const NotificationsTable = ({\n isLoading,\n notifications = [],\n onUpdate,\n setContainsText,\n onPageChange,\n onRowsPerPageChange,\n page,\n pageSize,\n totalCount,\n}: NotificationsTableProps) => {\n const notificationsApi = useApi(notificationsApiRef);\n const [selectedNotifications, setSelectedNotifications] = React.useState(\n new Set<Notification['id']>(),\n );\n\n const onNotificationsSelectChange = React.useCallback(\n (ids: Notification['id'][], checked: boolean) => {\n let newSelect: Set<Notification['id']>;\n if (checked) {\n newSelect = new Set([...selectedNotifications, ...ids]);\n } else {\n newSelect = new Set(selectedNotifications);\n ids.forEach(id => newSelect.delete(id));\n }\n setSelectedNotifications(newSelect);\n },\n [selectedNotifications, setSelectedNotifications],\n );\n\n const onSwitchReadStatus = React.useCallback(\n (ids: Notification['id'][], newStatus: boolean) => {\n notificationsApi\n .updateNotifications({\n ids,\n read: newStatus,\n })\n .then(onUpdate);\n },\n [notificationsApi, onUpdate],\n );\n\n const onSwitchSavedStatus = React.useCallback(\n (ids: Notification['id'][], newStatus: boolean) => {\n notificationsApi\n .updateNotifications({\n ids,\n saved: newStatus,\n })\n .then(onUpdate);\n },\n [notificationsApi, onUpdate],\n );\n\n const throttledContainsTextHandler = React.useMemo(\n () => throttle(setContainsText, ThrottleDelayMs),\n [setContainsText],\n );\n\n React.useEffect(() => {\n const allShownIds = new Set(notifications.map(n => n.id));\n const intersect = [...selectedNotifications].filter(id =>\n allShownIds.has(id),\n );\n if (selectedNotifications.size !== intersect.length) {\n setSelectedNotifications(new Set(intersect));\n }\n }, [notifications, selectedNotifications]);\n\n const compactColumns = React.useMemo(\n (): TableColumn<Notification>[] => [\n {\n /* selection column */\n width: '1rem',\n title: (\n <SelectAll\n count={selectedNotifications.size}\n totalCount={notifications.length}\n onSelectAll={() =>\n onNotificationsSelectChange(\n notifications.map(notification => notification.id),\n selectedNotifications.size !== notifications.length,\n )\n }\n />\n ),\n render: (notification: Notification) => (\n <CheckBox\n color=\"primary\"\n checked={selectedNotifications.has(notification.id)}\n onChange={(_, checked) =>\n onNotificationsSelectChange([notification.id], checked)\n }\n />\n ),\n },\n {\n /* compact-data column */\n customFilterAndSearch: () =>\n true /* Keep sorting&filtering on backend due to pagination. */,\n render: (notification: Notification) => {\n // Compact content\n return (\n <Grid container>\n <Grid item>\n <SeverityIcon severity={notification.payload?.severity} />\n </Grid>\n <Grid item>\n <Box>\n <Typography variant=\"subtitle2\">\n {notification.payload.link ? (\n <Link to={notification.payload.link}>\n {notification.payload.title}\n </Link>\n ) : (\n notification.payload.title\n )}\n </Typography>\n <Typography variant=\"body2\">\n {notification.payload.description}\n </Typography>\n <Typography variant=\"caption\">\n {notification.origin && (\n <>{notification.origin} • </>\n )}\n {notification.payload.topic && (\n <>{notification.payload.topic} • </>\n )}\n {notification.created && (\n <RelativeTime value={notification.created} />\n )}\n </Typography>\n </Box>\n </Grid>\n </Grid>\n );\n },\n },\n {\n /* actions column */\n width: '1rem',\n title: (\n <BulkActions\n notifications={notifications}\n selectedNotifications={selectedNotifications}\n onSwitchReadStatus={onSwitchReadStatus}\n onSwitchSavedStatus={onSwitchSavedStatus}\n />\n ),\n render: (notification: Notification) => (\n <BulkActions\n notifications={[notification]}\n selectedNotifications={new Set([notification.id])}\n onSwitchReadStatus={onSwitchReadStatus}\n onSwitchSavedStatus={onSwitchSavedStatus}\n />\n ),\n },\n ],\n [\n onSwitchReadStatus,\n onSwitchSavedStatus,\n selectedNotifications,\n onNotificationsSelectChange,\n notifications,\n ],\n );\n\n return (\n <Table<Notification>\n isLoading={isLoading}\n options={{\n padding: 'dense',\n search: true,\n paging: true,\n pageSize,\n header: true,\n sorting: false,\n }}\n onPageChange={onPageChange}\n onRowsPerPageChange={onRowsPerPageChange}\n page={page}\n totalCount={totalCount}\n onSearchChange={throttledContainsTextHandler}\n data={notifications}\n columns={compactColumns}\n />\n );\n};\n"],"names":["useStyles","CheckBox"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-notifications",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"backstage": {
|
|
5
|
+
"role": "frontend-plugin"
|
|
6
|
+
},
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public",
|
|
9
9
|
"main": "dist/index.esm.js",
|
|
@@ -14,26 +14,29 @@
|
|
|
14
14
|
"url": "https://github.com/backstage/backstage",
|
|
15
15
|
"directory": "plugins/notifications"
|
|
16
16
|
},
|
|
17
|
-
"
|
|
18
|
-
"role": "frontend-plugin"
|
|
19
|
-
},
|
|
17
|
+
"license": "Apache-2.0",
|
|
20
18
|
"sideEffects": false,
|
|
19
|
+
"main": "dist/index.esm.js",
|
|
20
|
+
"types": "dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
21
24
|
"scripts": {
|
|
22
|
-
"start": "backstage-cli package start",
|
|
23
25
|
"build": "backstage-cli package build",
|
|
24
|
-
"lint": "backstage-cli package lint",
|
|
25
|
-
"test": "backstage-cli package test",
|
|
26
26
|
"clean": "backstage-cli package clean",
|
|
27
|
+
"lint": "backstage-cli package lint",
|
|
27
28
|
"prepack": "backstage-cli package prepack",
|
|
28
|
-
"postpack": "backstage-cli package postpack"
|
|
29
|
+
"postpack": "backstage-cli package postpack",
|
|
30
|
+
"start": "backstage-cli package start",
|
|
31
|
+
"test": "backstage-cli package test"
|
|
29
32
|
},
|
|
30
33
|
"dependencies": {
|
|
31
|
-
"@backstage/core-components": "^0.14.4
|
|
32
|
-
"@backstage/core-plugin-api": "^1.9.
|
|
34
|
+
"@backstage/core-components": "^0.14.4",
|
|
35
|
+
"@backstage/core-plugin-api": "^1.9.2",
|
|
33
36
|
"@backstage/errors": "^1.2.4",
|
|
34
|
-
"@backstage/plugin-notifications-common": "^0.0.
|
|
35
|
-
"@backstage/plugin-signals-react": "^0.0.
|
|
36
|
-
"@backstage/theme": "^0.5.
|
|
37
|
+
"@backstage/plugin-notifications-common": "^0.0.3",
|
|
38
|
+
"@backstage/plugin-signals-react": "^0.0.3",
|
|
39
|
+
"@backstage/theme": "^0.5.3",
|
|
37
40
|
"@backstage/types": "^1.1.1",
|
|
38
41
|
"@material-ui/core": "^4.9.13",
|
|
39
42
|
"@material-ui/icons": "^4.9.1",
|
|
@@ -43,22 +46,19 @@
|
|
|
43
46
|
"react-relative-time": "^0.0.9",
|
|
44
47
|
"react-use": "^17.2.4"
|
|
45
48
|
},
|
|
46
|
-
"peerDependencies": {
|
|
47
|
-
"react": "^16.13.1 || ^17.0.0",
|
|
48
|
-
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
49
|
-
},
|
|
50
49
|
"devDependencies": {
|
|
51
|
-
"@backstage/cli": "^0.26.3
|
|
52
|
-
"@backstage/core-app-api": "^1.12.
|
|
53
|
-
"@backstage/dev-utils": "^1.0.31
|
|
54
|
-
"@backstage/test-utils": "^1.5.
|
|
50
|
+
"@backstage/cli": "^0.26.3",
|
|
51
|
+
"@backstage/core-app-api": "^1.12.4",
|
|
52
|
+
"@backstage/dev-utils": "^1.0.31",
|
|
53
|
+
"@backstage/test-utils": "^1.5.4",
|
|
55
54
|
"@testing-library/jest-dom": "^6.0.0",
|
|
56
|
-
"@testing-library/react": "^
|
|
55
|
+
"@testing-library/react": "^15.0.0",
|
|
57
56
|
"@testing-library/user-event": "^14.0.0",
|
|
58
57
|
"msw": "^1.0.0"
|
|
59
58
|
},
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"react": "^16.13.1 || ^17.0.0",
|
|
61
|
+
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
62
|
+
},
|
|
63
63
|
"module": "./dist/index.esm.js"
|
|
64
64
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-Bu8bbvQt.esm.js","sources":["../../src/components/NotificationsFilters/NotificationsFilters.tsx","../../src/components/NotificationsPage/NotificationsPage.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport React from 'react';\n\nimport Divider from '@material-ui/core/Divider';\nimport FormControl from '@material-ui/core/FormControl';\nimport Grid from '@material-ui/core/Grid';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport Typography from '@material-ui/core/Typography';\nimport { GetNotificationsOptions } from '../../api';\nimport { NotificationSeverity } from '@backstage/plugin-notifications-common';\n\nexport type SortBy = Required<\n Pick<GetNotificationsOptions, 'sort' | 'sortOrder'>\n>;\n\nexport type NotificationsFiltersProps = {\n unreadOnly?: boolean;\n onUnreadOnlyChanged: (checked: boolean | undefined) => void;\n createdAfter?: string;\n onCreatedAfterChanged: (value: string) => void;\n sorting: SortBy;\n onSortingChanged: (sortBy: SortBy) => void;\n saved?: boolean;\n onSavedChanged: (checked: boolean | undefined) => void;\n severity: NotificationSeverity;\n onSeverityChanged: (severity: NotificationSeverity) => void;\n};\n\nexport const CreatedAfterOptions: {\n [key: string]: { label: string; getDate: () => Date };\n} = {\n last24h: {\n label: 'Last 24h',\n getDate: () => new Date(Date.now() - 24 * 3600 * 1000),\n },\n lastWeek: {\n label: 'Last week',\n getDate: () => new Date(Date.now() - 7 * 24 * 3600 * 1000),\n },\n all: {\n label: 'Any time',\n getDate: () => new Date(0),\n },\n};\n\nexport const SortByOptions: {\n [key: string]: {\n label: string;\n sortBy: SortBy;\n };\n} = {\n newest: {\n label: 'Newest on top',\n sortBy: {\n sort: 'created',\n sortOrder: 'desc',\n },\n },\n oldest: {\n label: 'Oldest on top',\n sortBy: {\n sort: 'created',\n sortOrder: 'asc',\n },\n },\n topic: {\n label: 'Topic',\n sortBy: {\n sort: 'topic',\n sortOrder: 'asc',\n },\n },\n origin: {\n label: 'Origin',\n sortBy: {\n sort: 'origin',\n sortOrder: 'asc',\n },\n },\n};\n\nconst getSortByText = (sortBy?: SortBy): string => {\n if (sortBy?.sort === 'created' && sortBy?.sortOrder === 'asc') {\n return 'oldest';\n }\n if (sortBy?.sort === 'topic') {\n return 'topic';\n }\n if (sortBy?.sort === 'origin') {\n return 'origin';\n }\n\n return 'newest';\n};\n\nconst AllSeverityOptions: { [key in NotificationSeverity]: string } = {\n critical: 'Critical',\n high: 'High',\n normal: 'Normal',\n low: 'Low',\n};\n\nexport const NotificationsFilters = ({\n sorting,\n onSortingChanged,\n unreadOnly,\n onUnreadOnlyChanged,\n createdAfter,\n onCreatedAfterChanged,\n saved,\n onSavedChanged,\n severity,\n onSeverityChanged,\n}: NotificationsFiltersProps) => {\n const sortByText = getSortByText(sorting);\n\n const handleOnCreatedAfterChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n onCreatedAfterChanged(event.target.value as string);\n };\n\n const handleOnViewChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n if (event.target.value === 'unread') {\n onUnreadOnlyChanged(true);\n onSavedChanged(undefined);\n } else if (event.target.value === 'read') {\n onUnreadOnlyChanged(false);\n onSavedChanged(undefined);\n } else if (event.target.value === 'saved') {\n onUnreadOnlyChanged(undefined);\n onSavedChanged(true);\n } else {\n // All\n onUnreadOnlyChanged(undefined);\n onSavedChanged(undefined);\n }\n };\n\n const handleOnSortByChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n const idx = (event.target.value as string) || 'newest';\n const option = SortByOptions[idx];\n onSortingChanged({ ...option.sortBy });\n };\n\n let viewValue = 'all';\n if (saved) {\n viewValue = 'saved';\n } else if (unreadOnly) {\n viewValue = 'unread';\n } else if (unreadOnly === false) {\n viewValue = 'read';\n }\n\n const handleOnSeverityChanged = (\n event: React.ChangeEvent<{ name?: string; value: unknown }>,\n ) => {\n const value: NotificationSeverity =\n (event.target.value as NotificationSeverity) || 'normal';\n onSeverityChanged(value);\n };\n\n return (\n <>\n <Grid container>\n <Grid item xs={12}>\n <Typography variant=\"h6\">Filters</Typography>\n <Divider variant=\"fullWidth\" />\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-view\">View</InputLabel>\n <Select\n labelId=\"notifications-filter-view\"\n label=\"View\"\n value={viewValue}\n onChange={handleOnViewChanged}\n >\n <MenuItem value=\"unread\">New only</MenuItem>\n <MenuItem value=\"saved\">Saved</MenuItem>\n <MenuItem value=\"read\">Marked as read</MenuItem>\n <MenuItem value=\"all\">All</MenuItem>\n </Select>\n </FormControl>\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-created\">\n Created after\n </InputLabel>\n\n <Select\n label=\"Created after\"\n labelId=\"notifications-filter-created\"\n placeholder=\"Notifications since\"\n value={createdAfter}\n onChange={handleOnCreatedAfterChanged}\n >\n {Object.keys(CreatedAfterOptions).map((key: string) => (\n <MenuItem value={key} key={key}>\n {CreatedAfterOptions[key].label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-sort\">Sort by</InputLabel>\n\n <Select\n label=\"Sort by\"\n labelId=\"notifications-filter-sort\"\n placeholder=\"Field to sort by\"\n value={sortByText}\n onChange={handleOnSortByChanged}\n >\n {Object.keys(SortByOptions).map((key: string) => (\n <MenuItem value={key} key={key}>\n {SortByOptions[key].label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n\n <Grid item xs={12}>\n <FormControl fullWidth variant=\"outlined\" size=\"small\">\n <InputLabel id=\"notifications-filter-severity\">Severity</InputLabel>\n\n <Select\n label=\"Severity\"\n labelId=\"notifications-filter-severity\"\n value={severity}\n onChange={handleOnSeverityChanged}\n >\n {Object.keys(AllSeverityOptions).map((key: string) => (\n <MenuItem value={key} key={key}>\n {AllSeverityOptions[key as NotificationSeverity]}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n </Grid>\n </>\n );\n};\n","/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useEffect } from 'react';\nimport {\n Content,\n PageWithHeader,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport Grid from '@material-ui/core/Grid';\nimport { useSignal } from '@backstage/plugin-signals-react';\n\nimport { NotificationsTable } from '../NotificationsTable';\nimport { useNotificationsApi } from '../../hooks';\nimport {\n CreatedAfterOptions,\n NotificationsFilters,\n SortBy,\n SortByOptions,\n} from '../NotificationsFilters';\nimport { GetNotificationsOptions } from '../../api';\nimport { NotificationSeverity } from '@backstage/plugin-notifications-common';\n\nexport const NotificationsPage = () => {\n const [refresh, setRefresh] = React.useState(false);\n const { lastSignal } = useSignal('notifications');\n const [unreadOnly, setUnreadOnly] = React.useState<boolean | undefined>(true);\n const [saved, setSaved] = React.useState<boolean | undefined>(undefined);\n const [pageNumber, setPageNumber] = React.useState(0);\n const [pageSize, setPageSize] = React.useState(5);\n const [containsText, setContainsText] = React.useState<string>();\n const [createdAfter, setCreatedAfter] = React.useState<string>('lastWeek');\n const [sorting, setSorting] = React.useState<SortBy>(\n SortByOptions.newest.sortBy,\n );\n const [severity, setSeverity] = React.useState<NotificationSeverity>('low');\n\n const { error, value, retry, loading } = useNotificationsApi(\n api => {\n const options: GetNotificationsOptions = {\n search: containsText,\n limit: pageSize,\n offset: pageNumber * pageSize,\n minimumSeverity: severity,\n ...(sorting || {}),\n };\n if (unreadOnly !== undefined) {\n options.read = !unreadOnly;\n }\n if (saved !== undefined) {\n options.saved = saved;\n }\n\n const createdAfterDate = CreatedAfterOptions[createdAfter].getDate();\n if (createdAfterDate.valueOf() > 0) {\n options.createdAfter = createdAfterDate;\n }\n\n return api.getNotifications(options);\n },\n [\n containsText,\n unreadOnly,\n createdAfter,\n pageNumber,\n pageSize,\n sorting,\n saved,\n severity,\n ],\n );\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, setRefresh, retry]);\n\n useEffect(() => {\n if (lastSignal && lastSignal.action) {\n setRefresh(true);\n }\n }, [lastSignal]);\n\n const onUpdate = () => {\n setRefresh(true);\n };\n\n if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <PageWithHeader title=\"Notifications\" themeId=\"tool\">\n <Content>\n <Grid container>\n <Grid item xs={2}>\n <NotificationsFilters\n unreadOnly={unreadOnly}\n onUnreadOnlyChanged={setUnreadOnly}\n createdAfter={createdAfter}\n onCreatedAfterChanged={setCreatedAfter}\n onSortingChanged={setSorting}\n sorting={sorting}\n saved={saved}\n onSavedChanged={setSaved}\n severity={severity}\n onSeverityChanged={setSeverity}\n />\n </Grid>\n <Grid item xs={10}>\n <NotificationsTable\n isLoading={loading}\n notifications={value?.notifications}\n onUpdate={onUpdate}\n setContainsText={setContainsText}\n onPageChange={setPageNumber}\n onRowsPerPageChange={setPageSize}\n page={pageNumber}\n pageSize={pageSize}\n totalCount={value?.totalCount}\n />\n </Grid>\n </Grid>\n </Content>\n </PageWithHeader>\n );\n};\n"],"names":[],"mappings":"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"}
|