@backstage/plugin-notifications 0.1.3-next.0 → 0.2.0-next.1

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,22 @@
1
1
  # @backstage/plugin-notifications
2
2
 
3
+ ## 0.2.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - ec40998: On the Notifications page, the user can trigger "Save" or "Mark as read" actions once for multiple selected notifications.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/plugin-signals-react@0.0.3-next.0
13
+ - @backstage/core-components@0.14.4-next.0
14
+ - @backstage/core-plugin-api@1.9.1
15
+ - @backstage/errors@1.2.4
16
+ - @backstage/theme@0.5.2
17
+ - @backstage/types@1.1.1
18
+ - @backstage/plugin-notifications-common@0.0.2
19
+
3
20
  ## 0.1.3-next.0
4
21
 
5
22
  ### 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/FormControlLabel';
25
+ import '@material-ui/core/styles';
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
- setRefresh(true);
245
+ throttledSetRefresh(true);
238
246
  }
239
- }, [lastSignal]);
247
+ }, [lastSignal, throttledSetRefresh]);
240
248
  const onUpdate = () => {
241
- setRefresh(true);
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-Bu8bbvQt.esm.js.map
285
+ //# sourceMappingURL=index-ijQzv-25.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-ijQzv-25.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, useMemo } from 'react';
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 FormControlLabel from '@material-ui/core/FormControlLabel';
19
+ import { makeStyles } from '@material-ui/core/styles';
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"
@@ -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-Bu8bbvQt.esm.js').then((m) => m.NotificationsPage),
121
+ component: () => import('./esm/index-ijQzv-25.esm.js').then((m) => m.NotificationsPage),
119
122
  mountPoint: rootRouteRef
120
123
  })
121
124
  );
@@ -281,6 +284,81 @@ const SeverityIcon = ({
281
284
  }
282
285
  };
283
286
 
287
+ const useStyles = makeStyles({
288
+ label: {
289
+ marginLeft: "0px",
290
+ maxWidth: "2rem",
291
+ "& span": {
292
+ paddingRight: "0px"
293
+ }
294
+ }
295
+ });
296
+ const SelectAll = ({
297
+ count,
298
+ totalCount,
299
+ onSelectAll
300
+ }) => {
301
+ const classes = useStyles();
302
+ return /* @__PURE__ */ React.createElement(
303
+ FormControlLabel,
304
+ {
305
+ label: count > 0 ? `(${count})` : void 0,
306
+ className: classes.label,
307
+ control: /* @__PURE__ */ React.createElement(
308
+ Checkbox,
309
+ {
310
+ color: "primary",
311
+ disabled: !totalCount,
312
+ checked: count > 0,
313
+ indeterminate: count > 0 && totalCount !== count,
314
+ onChange: onSelectAll
315
+ }
316
+ )
317
+ }
318
+ );
319
+ };
320
+
321
+ const BulkActions = ({
322
+ selectedNotifications,
323
+ notifications,
324
+ onSwitchReadStatus,
325
+ onSwitchSavedStatus
326
+ }) => {
327
+ const isDisabled = selectedNotifications.size === 0;
328
+ const bulkNotifications = notifications.filter(
329
+ (notification) => selectedNotifications.has(notification.id)
330
+ );
331
+ const isOneRead = !!bulkNotifications.find(
332
+ (notification) => !!notification.read
333
+ );
334
+ const isOneSaved = !!bulkNotifications.find(
335
+ (notification) => !!notification.saved
336
+ );
337
+ const markAsReadText = isOneRead ? "Return selected among unread" : "Mark selected as read";
338
+ const IconComponent = isOneRead ? MarkAsUnreadIcon : MarkAsReadIcon;
339
+ const markAsSavedText = isOneSaved ? "Undo save for selected" : "Save selected for later";
340
+ const SavedIconComponent = isOneSaved ? MarkAsUnsavedIcon : MarkAsSavedIcon;
341
+ 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(
342
+ IconButton,
343
+ {
344
+ disabled: isDisabled,
345
+ onClick: () => {
346
+ onSwitchSavedStatus([...selectedNotifications], !isOneSaved);
347
+ }
348
+ },
349
+ /* @__PURE__ */ React.createElement(SavedIconComponent, { "aria-label": markAsSavedText })
350
+ )))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Tooltip, { title: markAsReadText }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
351
+ IconButton,
352
+ {
353
+ disabled: isDisabled,
354
+ onClick: () => {
355
+ onSwitchReadStatus([...selectedNotifications], !isOneRead);
356
+ }
357
+ },
358
+ /* @__PURE__ */ React.createElement(IconComponent, { "aria-label": markAsReadText })
359
+ )))));
360
+ };
361
+
284
362
  const ThrottleDelayMs = 1e3;
285
363
  const NotificationsTable = ({
286
364
  isLoading,
@@ -294,103 +372,127 @@ const NotificationsTable = ({
294
372
  totalCount
295
373
  }) => {
296
374
  const notificationsApi = useApi(notificationsApiRef);
375
+ const [selectedNotifications, setSelectedNotifications] = React.useState(
376
+ /* @__PURE__ */ new Set()
377
+ );
378
+ const onNotificationsSelectChange = React.useCallback(
379
+ (ids, checked) => {
380
+ let newSelect;
381
+ if (checked) {
382
+ newSelect = /* @__PURE__ */ new Set([...selectedNotifications, ...ids]);
383
+ } else {
384
+ newSelect = new Set(selectedNotifications);
385
+ ids.forEach((id) => newSelect.delete(id));
386
+ }
387
+ setSelectedNotifications(newSelect);
388
+ },
389
+ [selectedNotifications, setSelectedNotifications]
390
+ );
297
391
  const onSwitchReadStatus = React.useCallback(
298
- (notification) => {
392
+ (ids, newStatus) => {
299
393
  notificationsApi.updateNotifications({
300
- ids: [notification.id],
301
- read: !notification.read
302
- }).then(() => onUpdate());
394
+ ids,
395
+ read: newStatus
396
+ }).then(onUpdate);
303
397
  },
304
398
  [notificationsApi, onUpdate]
305
399
  );
306
400
  const onSwitchSavedStatus = React.useCallback(
307
- (notification) => {
401
+ (ids, newStatus) => {
308
402
  notificationsApi.updateNotifications({
309
- ids: [notification.id],
310
- saved: !notification.saved
311
- }).then(() => onUpdate());
403
+ ids,
404
+ saved: newStatus
405
+ }).then(onUpdate);
312
406
  },
313
407
  [notificationsApi, onUpdate]
314
408
  );
315
- const throttledContainsTextHandler = useMemo(
409
+ const throttledContainsTextHandler = React.useMemo(
316
410
  () => throttle(setContainsText, ThrottleDelayMs),
317
411
  [setContainsText]
318
412
  );
413
+ React.useEffect(() => {
414
+ const allShownIds = new Set(notifications.map((n) => n.id));
415
+ const intersect = [...selectedNotifications].filter(
416
+ (id) => allShownIds.has(id)
417
+ );
418
+ if (selectedNotifications.size !== intersect.length) {
419
+ setSelectedNotifications(new Set(intersect));
420
+ }
421
+ }, [notifications, selectedNotifications]);
319
422
  const compactColumns = React.useMemo(
320
423
  () => [
321
424
  {
425
+ /* selection column */
322
426
  width: "1rem",
323
- render: (notification) => {
324
- var _a;
325
- return /* @__PURE__ */ React.createElement(SeverityIcon, { severity: (_a = notification.payload) == null ? void 0 : _a.severity });
326
- }
427
+ title: /* @__PURE__ */ React.createElement(
428
+ SelectAll,
429
+ {
430
+ count: selectedNotifications.size,
431
+ totalCount: notifications.length,
432
+ onSelectAll: () => onNotificationsSelectChange(
433
+ notifications.map((notification) => notification.id),
434
+ selectedNotifications.size !== notifications.length
435
+ )
436
+ }
437
+ ),
438
+ render: (notification) => /* @__PURE__ */ React.createElement(
439
+ Checkbox,
440
+ {
441
+ color: "primary",
442
+ checked: selectedNotifications.has(notification.id),
443
+ onChange: (_, checked) => onNotificationsSelectChange([notification.id], checked)
444
+ }
445
+ )
327
446
  },
328
447
  {
448
+ /* compact-data column */
329
449
  customFilterAndSearch: () => true,
330
450
  render: (notification) => {
331
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__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 }))));
451
+ var _a;
452
+ 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
453
  }
333
454
  },
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
- // &nbsp;More info
348
- // </Link>
349
- // </Grid>
350
- // </Grid>
351
- // )
352
- // );
353
- // },
354
- // },
355
455
  {
356
- // actions
456
+ /* actions column */
357
457
  width: "1rem",
358
- render: (notification) => {
359
- const markAsReadText = !!notification.read ? "Return among unread" : "Mark as read";
360
- const IconComponent = !!notification.read ? MarkAsUnreadIcon : MarkAsReadIcon;
361
- const markAsSavedText = !!notification.saved ? "Undo save" : "Save for later";
362
- const SavedIconComponent = !!notification.saved ? MarkAsUnsavedIcon : MarkAsSavedIcon;
363
- return /* @__PURE__ */ React.createElement(Grid, { container: true, wrap: "nowrap" }, /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Tooltip, { title: markAsSavedText }, /* @__PURE__ */ React.createElement(
364
- IconButton,
365
- {
366
- onClick: () => {
367
- onSwitchSavedStatus(notification);
368
- }
369
- },
370
- /* @__PURE__ */ React.createElement(SavedIconComponent, { "aria-label": markAsSavedText })
371
- ))), /* @__PURE__ */ React.createElement(Grid, { item: true }, /* @__PURE__ */ React.createElement(Tooltip, { title: markAsReadText }, /* @__PURE__ */ React.createElement(
372
- IconButton,
373
- {
374
- onClick: () => {
375
- onSwitchReadStatus(notification);
376
- }
377
- },
378
- /* @__PURE__ */ React.createElement(IconComponent, { "aria-label": markAsReadText })
379
- ))));
380
- }
458
+ title: /* @__PURE__ */ React.createElement(
459
+ BulkActions,
460
+ {
461
+ notifications,
462
+ selectedNotifications,
463
+ onSwitchReadStatus,
464
+ onSwitchSavedStatus
465
+ }
466
+ ),
467
+ render: (notification) => /* @__PURE__ */ React.createElement(
468
+ BulkActions,
469
+ {
470
+ notifications: [notification],
471
+ selectedNotifications: /* @__PURE__ */ new Set([notification.id]),
472
+ onSwitchReadStatus,
473
+ onSwitchSavedStatus
474
+ }
475
+ )
381
476
  }
382
477
  ],
383
- [onSwitchReadStatus, onSwitchSavedStatus]
478
+ [
479
+ onSwitchReadStatus,
480
+ onSwitchSavedStatus,
481
+ selectedNotifications,
482
+ onNotificationsSelectChange,
483
+ notifications
484
+ ]
384
485
  );
385
486
  return /* @__PURE__ */ React.createElement(
386
487
  Table,
387
488
  {
388
489
  isLoading,
389
490
  options: {
491
+ padding: "dense",
390
492
  search: true,
391
493
  paging: true,
392
494
  pageSize,
393
- header: false,
495
+ header: true,
394
496
  sorting: false
395
497
  },
396
498
  onPageChange,
@@ -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}&nbsp;&bull;&nbsp;</>\n )}\n {notification.payload.topic && (\n <>{notification.payload.topic}&nbsp;&bull;&nbsp;</>\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 // &nbsp;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":";;;;;;;;;;;;;;;;;;;;;;;AAiBO,MAAM,eAAe,cAAe,CAAA;AAAA,EACzC,EAAI,EAAA,eAAA;AACN,CAAC,CAAA;;ACIM,MAAM,sBAAsB,YAA+B,CAAA;AAAA,EAChE,EAAI,EAAA,8BAAA;AACN,CAAC;;;;;;;;ACIM,MAAM,mBAAgD,CAAA;AAAA,EAIpD,YAAY,OAGhB,EAAA;AANH,IAAiB,aAAA,CAAA,IAAA,EAAA,cAAA,CAAA,CAAA;AACjB,IAAiB,aAAA,CAAA,IAAA,EAAA,UAAA,CAAA,CAAA;AAMf,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA,CAAA;AAC5B,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA,CAAA;AAAA,GAC1B;AAAA,EAEA,MAAM,iBACJ,OACmC,EAAA;AA3CvC,IAAA,IAAA,EAAA,CAAA;AA4CI,IAAM,MAAA,WAAA,GAAc,IAAI,eAAgB,EAAA,CAAA;AACxC,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,WAAU,KAAW,CAAA,EAAA;AAChC,MAAA,WAAA,CAAY,OAAO,OAAS,EAAA,OAAA,CAAQ,KAAM,CAAA,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA;AAAA,KACxD;AACA,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,YAAW,KAAW,CAAA,EAAA;AACjC,MAAA,WAAA,CAAY,OAAO,QAAU,EAAA,OAAA,CAAQ,MAAO,CAAA,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA;AAAA,KAC1D;AACA,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,UAAS,KAAW,CAAA,EAAA;AAC/B,MAAY,WAAA,CAAA,MAAA;AAAA,QACV,YAAA;AAAA,QACA,GAAG,OAAQ,CAAA,IAAI,KAAI,EAAS,GAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,SAAA,KAAT,YAAsB,MAAM,CAAA,CAAA;AAAA,OACjD,CAAA;AAAA,KACF;AACA,IAAA,IAAI,mCAAS,MAAQ,EAAA;AACnB,MAAY,WAAA,CAAA,MAAA,CAAO,QAAU,EAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AAAA,KAC7C;AACA,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,UAAS,KAAW,CAAA,EAAA;AAC/B,MAAA,WAAA,CAAY,MAAO,CAAA,MAAA,EAAQ,OAAQ,CAAA,IAAA,GAAO,SAAS,OAAO,CAAA,CAAA;AAAA,KAC5D;AACA,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,WAAU,KAAW,CAAA,EAAA;AAChC,MAAA,WAAA,CAAY,MAAO,CAAA,OAAA,EAAS,OAAQ,CAAA,KAAA,GAAQ,SAAS,OAAO,CAAA,CAAA;AAAA,KAC9D;AACA,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,kBAAiB,KAAW,CAAA,EAAA;AACvC,MAAA,WAAA,CAAY,MAAO,CAAA,cAAA,EAAgB,OAAQ,CAAA,YAAA,CAAa,aAAa,CAAA,CAAA;AAAA,KACvE;AACA,IAAI,IAAA,CAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAS,qBAAoB,KAAW,CAAA,EAAA;AAC1C,MAAY,WAAA,CAAA,MAAA,CAAO,kBAAoB,EAAA,OAAA,CAAQ,eAAe,CAAA,CAAA;AAAA,KAChE;AACA,IAAM,MAAA,UAAA,GAAa,IAAI,WAAW,CAAA,CAAA,CAAA;AAElC,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAkC,UAAU,CAAA,CAAA;AAAA,GAChE;AAAA,EAEA,MAAM,gBAAgB,EAAmC,EAAA;AACvD,IAAA,OAAO,MAAM,IAAA,CAAK,OAAsB,CAAA,CAAA,EAAG,EAAE,CAAE,CAAA,CAAA,CAAA;AAAA,GACjD;AAAA,EAEA,MAAM,SAAyC,GAAA;AAC7C,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAA4B,QAAQ,CAAA,CAAA;AAAA,GACxD;AAAA,EAEA,MAAM,oBACJ,OACyB,EAAA;AACzB,IAAO,OAAA,MAAM,IAAK,CAAA,OAAA,CAAwB,QAAU,EAAA;AAAA,MAClD,MAAQ,EAAA,MAAA;AAAA,MACR,IAAA,EAAM,IAAK,CAAA,SAAA,CAAU,OAAO,CAAA;AAAA,MAC5B,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAmB,EAAA;AAAA,KAC/C,CAAA,CAAA;AAAA,GACH;AAAA,EAEA,MAAc,OAAW,CAAA,IAAA,EAAc,IAAwB,EAAA;AAC7D,IAAA,MAAM,UAAU,CAAG,EAAA,MAAM,KAAK,YAAa,CAAA,UAAA,CAAW,eAAe,CAAC,CAAA,CAAA,CAAA,CAAA;AACtE,IAAA,MAAM,GAAM,GAAA,IAAI,GAAI,CAAA,IAAA,EAAM,OAAO,CAAA,CAAA;AAEjC,IAAM,MAAA,QAAA,GAAW,MAAM,IAAK,CAAA,QAAA,CAAS,MAAM,GAAI,CAAA,QAAA,IAAY,IAAI,CAAA,CAAA;AAE/D,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,MAAM,aAAc,CAAA,YAAA,CAAa,QAAQ,CAAA,CAAA;AAAA,KACjD;AAEA,IAAA,OAAO,SAAS,IAAK,EAAA,CAAA;AAAA,GACvB;AACF;;AC/EO,MAAM,sBAAsB,YAAa,CAAA;AAAA,EAC9C,EAAI,EAAA,eAAA;AAAA,EACJ,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,YAAA;AAAA,GACR;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,gBAAiB,CAAA;AAAA,MACf,GAAK,EAAA,mBAAA;AAAA,MACL,IAAM,EAAA,EAAE,YAAc,EAAA,eAAA,EAAiB,UAAU,WAAY,EAAA;AAAA,MAC7D,OAAA,EAAS,CAAC,EAAE,YAAc,EAAA,QAAA,EACxB,KAAA,IAAI,mBAAoB,CAAA,EAAE,YAAc,EAAA,QAAA,EAAU,CAAA;AAAA,KACrD,CAAA;AAAA,GACH;AACF,CAAC,EAAA;AAGM,MAAM,oBAAoB,mBAAoB,CAAA,OAAA;AAAA,EACnD,uBAAwB,CAAA;AAAA,IACtB,IAAM,EAAA,mBAAA;AAAA,IACN,SAAA,EAAW,MACT,OAAO,6BAAgC,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,iBAAiB,CAAA;AAAA,IACxE,UAAY,EAAA,YAAA;AAAA,GACb,CAAA;AACH;;AC9BO,SAAS,mBACd,CAAA,CAAA,EACA,IAAc,GAAA,EACd,EAAA;AACA,EAAM,MAAA,gBAAA,GAAmB,OAAO,mBAAmB,CAAA,CAAA;AAEnD,EAAA,OAAO,cAAc,YAAY;AAC/B,IAAO,OAAA,MAAM,EAAE,gBAAgB,CAAA,CAAA;AAAA,KAC9B,IAAI,CAAA,CAAA;AACT;;ACZO,SAAS,mBAAsB,GAAA;AACpC,EAAA,MAAM,CAAC,yBAAA,EAA2B,4BAA4B,CAAA,GAC5D,SAAS,SAAS,CAAA,CAAA;AACpB,EAAA,MAAM,CAAC,gBAAkB,EAAA,mBAAmB,CAAI,GAAA,QAAA,CAAyB,EAAE,CAAA,CAAA;AAE3E,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,cAAA,IAAkB,MAAU,IAAA,yBAAA,KAA8B,SAAW,EAAA;AACvE,MAAA,MAAA,CAAO,YAAa,CAAA,iBAAA,EAAoB,CAAA,IAAA,CAAK,CAAc,UAAA,KAAA;AACzD,QAAA,4BAAA,CAA6B,UAAU,CAAA,CAAA;AAAA,OACxC,CAAA,CAAA;AAAA,KACH;AAAA,GACF,EAAG,CAAC,yBAAyB,CAAC,CAAA,CAAA;AAE9B,EAAS,QAAA,CAAA,gBAAA,CAAiB,oBAAoB,MAAM;AAClD,IAAI,IAAA,QAAA,CAAS,oBAAoB,SAAW,EAAA;AAC1C,MAAA,gBAAA,CAAiB,OAAQ,CAAA,CAAA,CAAA,KAAK,CAAE,CAAA,KAAA,EAAO,CAAA,CAAA;AACvC,MAAA,mBAAA,CAAoB,EAAE,CAAA,CAAA;AAAA,KACxB;AAAA,GACD,CAAA,CAAA;AAED,EAAA,MAAM,mBAAsB,GAAA,WAAA;AAAA,IAC1B,CAAC,OAAmE,KAAA;AAClE,MAAA,IAAI,8BAA8B,SAAW,EAAA;AAC3C,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAEA,MAAA,MAAM,YAAe,GAAA,IAAI,YAAa,CAAA,OAAA,CAAQ,KAAO,EAAA;AAAA,QACnD,MAAM,OAAQ,CAAA,WAAA;AAAA,OACf,CAAA,CAAA;AAED,MAAA,YAAA,CAAa,UAAU,CAAS,KAAA,KAAA;AAC9B,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,YAAA,CAAa,KAAM,EAAA,CAAA;AACnB,QAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,UAAO,MAAA,CAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,EAAM,QAAQ,CAAA,CAAA;AAAA,SACpC;AAAA,OACF,CAAA;AAEA,MAAO,OAAA,YAAA,CAAA;AAAA,KACT;AAAA,IACA,CAAC,yBAAyB,CAAA;AAAA,GAC5B,CAAA;AAEA,EAAA,OAAO,EAAE,mBAAoB,EAAA,CAAA;AAC/B;;AC5CO,SAAS,eAAkB,GAAA;AAChC,EAAA,MAAM,CAAC,KAAO,EAAA,QAAQ,CAAI,GAAA,QAAA,CAAS,SAAS,KAAK,CAAA,CAAA;AACjD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,CAAC,CAAA,CAAA;AAEpC,EAAM,MAAA,SAAA,GAAY,CAAC,KAAkB,KAAA;AACnC,IAAA,OAAO,KAAU,KAAA,CAAA,GAAI,EAAK,GAAA,CAAA,CAAA,EAAI,KAAK,CAAA,EAAA,CAAA,CAAA;AAAA,GACrC,CAAA;AAEA,EAAM,MAAA,UAAA,GAAa,CAAC,YAAyB,KAAA;AAC3C,IAAO,OAAA,YAAA,CAAa,OAAQ,CAAA,YAAA,EAAc,EAAE,CAAA,CAAA;AAAA,GAC9C,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,CAAS,KAAQ,GAAA,KAAA,CAAA;AAAA,GACnB,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AAEV,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,SAAA,GAAY,WAAW,KAAK,CAAA,CAAA;AAClC,IAAA,QAAA,CAAS,GAAG,SAAU,CAAA,KAAK,CAAC,CAAA,EAAG,SAAS,CAAE,CAAA,CAAA,CAAA;AAC1C,IAAA,OAAO,MAAM;AACX,MAAS,QAAA,CAAA,KAAA,GAAQ,WAAW,KAAK,CAAA,CAAA;AAAA,KACnC,CAAA;AAAA,GACC,EAAA,CAAC,KAAO,EAAA,KAAK,CAAC,CAAA,CAAA;AAEjB,EAAM,MAAA,YAAA,GAAe,QAAS,CAAA,aAAA,CAAc,OAAO,CAAA,CAAA;AACnD,EAAA,IAAI,YAAc,EAAA;AAChB,IAAA,IAAI,iBAAiB,MAAM;AACzB,MAAA,QAAA,CAAS,SAAS,KAAK,CAAA,CAAA;AAAA,KACxB,CAAE,CAAA,OAAA,CAAQ,YAAc,EAAA;AAAA,MACvB,OAAS,EAAA,IAAA;AAAA,MACT,aAAe,EAAA,IAAA;AAAA,MACf,SAAW,EAAA,IAAA;AAAA,KACZ,CAAA,CAAA;AAAA,GACH;AAEA,EAAA,MAAM,oBAAuB,GAAA,WAAA;AAAA,IAC3B,CAAC,QAAqB,KAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,IACvC,EAAC;AAAA,GACH,CAAA;AAEA,EAAA,OAAO,EAAE,oBAAqB,EAAA,CAAA;AAChC;;AC/Ba,MAAA,wBAAA,GAA2B,CAAC,KAGnC,KAAA;AACJ,EAAM,MAAA,EAAE,uBAA0B,GAAA,KAAA,EAAO,mBAAsB,GAAA,IAAA,EAC7D,GAAA,KAAA,IAAA,IAAA,GAAA,KAAA,GAAS,EAAE,uBAAA,EAAyB,KAAO,EAAA,mBAAA,EAAqB,IAAK,EAAA,CAAA;AAEvE,EAAA,MAAM,EAAE,OAAA,EAAS,KAAO,EAAA,KAAA,EAAO,OAAU,GAAA,mBAAA;AAAA,IAAoB,CAAA,GAAA,KAC3D,IAAI,SAAU,EAAA;AAAA,GAChB,CAAA;AACA,EAAM,MAAA,gBAAA,GAAmB,OAAO,mBAAmB,CAAA,CAAA;AACnD,EAAA,MAAM,CAAC,WAAa,EAAA,cAAc,CAAI,GAAA,KAAA,CAAM,SAAS,CAAC,CAAA,CAAA;AACtD,EAAM,MAAA,kBAAA,GAAqB,YAAY,YAAY,CAAA,CAAA;AAEnD,EAAA,MAAM,EAAE,UAAA,EAAe,GAAA,SAAA,CAA8B,eAAe,CAAA,CAAA;AACpE,EAAM,MAAA,EAAE,mBAAoB,EAAA,GAAI,mBAAoB,EAAA,CAAA;AACpD,EAAA,MAAM,CAAC,OAAS,EAAA,UAAU,CAAI,GAAA,KAAA,CAAM,SAAS,KAAK,CAAA,CAAA;AAClD,EAAM,MAAA,EAAE,oBAAqB,EAAA,GAAI,eAAgB,EAAA,CAAA;AAEjD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAS,EAAA;AACX,MAAM,KAAA,EAAA,CAAA;AACN,MAAA,UAAA,CAAW,KAAK,CAAA,CAAA;AAAA,KAClB;AAAA,GACC,EAAA,CAAC,OAAS,EAAA,KAAK,CAAC,CAAA,CAAA;AAEnB,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,qBAAA,GAAwB,CAAC,MAA+B,KAAA;AAC5D,MAAA,IAAI,CAAC,uBAAA,IAA2B,MAAO,CAAA,MAAA,KAAW,kBAAoB,EAAA;AACpE,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,gBAAA,CACG,eAAgB,CAAA,MAAA,CAAO,eAAe,CAAA,CACtC,KAAK,CAAgB,YAAA,KAAA;AA9D9B,QAAA,IAAA,EAAA,CAAA;AA+DU,QAAA,IAAI,CAAC,YAAc,EAAA;AACjB,UAAA,OAAA;AAAA,SACF;AACA,QAAoB,mBAAA,CAAA;AAAA,UAClB,KAAA,EAAO,aAAa,OAAQ,CAAA,KAAA;AAAA,UAC5B,WAAa,EAAA,CAAA,EAAA,GAAA,YAAA,CAAa,OAAQ,CAAA,WAAA,KAArB,IAAoC,GAAA,EAAA,GAAA,EAAA;AAAA,UACjD,IAAA,EAAM,aAAa,OAAQ,CAAA,IAAA;AAAA,SAC5B,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AAAA,KACL,CAAA;AAEA,IAAI,IAAA,UAAA,IAAc,WAAW,MAAQ,EAAA;AACnC,MAAA,qBAAA,CAAsB,UAAU,CAAA,CAAA;AAChC,MAAA,UAAA,CAAW,IAAI,CAAA,CAAA;AAAA,KACjB;AAAA,GACC,EAAA;AAAA,IACD,UAAA;AAAA,IACA,mBAAA;AAAA,IACA,uBAAA;AAAA,IACA,gBAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,KAAA,IAAS,KAAO,EAAA;AAC/B,MAAA,cAAA,CAAe,MAAM,MAAM,CAAA,CAAA;AAC3B,MAAA,IAAI,mBAAqB,EAAA;AACvB,QAAA,oBAAA,CAAqB,MAAM,MAAM,CAAA,CAAA;AAAA,OACnC;AAAA,KACF;AAAA,KACC,CAAC,OAAA,EAAS,OAAO,KAAO,EAAA,mBAAA,EAAqB,oBAAoB,CAAC,CAAA,CAAA;AAGrE,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,IAAM,EAAA,iBAAA;AAAA,MACN,IAAI,kBAAmB,EAAA;AAAA,MACvB,IAAK,EAAA,eAAA;AAAA,MACL,gBAAkB,EAAA,CAAC,KAAS,IAAA,CAAC,CAAC,WAAA;AAAA,KAAA;AAAA,GAChC,CAAA;AAEJ;;ACjFO,MAAM,eAAe,CAAC;AAAA,EAC3B,QAAA;AACF,CAEM,KAAA;AACJ,EAAA,QAAQ,QAAU;AAAA,IAChB,KAAK,UAAA;AACH,MAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,YAAa,EAAA,EAAA,SAAA,EAAU,SAAU,EAAA,CAAA,CAAA;AAAA,IAC3C,KAAK,MAAA;AACH,MAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,SAAA,EAAU,SAAU,EAAA,CAAA,CAAA;AAAA,IACvC,KAAK,KAAA;AACH,MAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,SAAA,EAAU,SAAU,EAAA,CAAA,CAAA;AAAA,IACtC,KAAK,QAAA,CAAA;AAAA,IACL;AACE,MAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAU,SAAU,EAAA,CAAA,CAAA;AAAA,GAC3C;AACF,CAAA;;ACGA,MAAM,eAAkB,GAAA,GAAA,CAAA;AAejB,MAAM,qBAAqB,CAAC;AAAA,EACjC,SAAA;AAAA,EACA,gBAAgB,EAAC;AAAA,EACjB,QAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,mBAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AACF,CAA+B,KAAA;AAC7B,EAAM,MAAA,gBAAA,GAAmB,OAAO,mBAAmB,CAAA,CAAA;AAEnD,EAAA,MAAM,qBAAqB,KAAM,CAAA,WAAA;AAAA,IAC/B,CAAC,YAA+B,KAAA;AAC9B,MAAA,gBAAA,CACG,mBAAoB,CAAA;AAAA,QACnB,GAAA,EAAK,CAAC,YAAA,CAAa,EAAE,CAAA;AAAA,QACrB,IAAA,EAAM,CAAC,YAAa,CAAA,IAAA;AAAA,OACrB,CAAA,CACA,IAAK,CAAA,MAAM,UAAU,CAAA,CAAA;AAAA,KAC1B;AAAA,IACA,CAAC,kBAAkB,QAAQ,CAAA;AAAA,GAC7B,CAAA;AAEA,EAAA,MAAM,sBAAsB,KAAM,CAAA,WAAA;AAAA,IAChC,CAAC,YAA+B,KAAA;AAC9B,MAAA,gBAAA,CACG,mBAAoB,CAAA;AAAA,QACnB,GAAA,EAAK,CAAC,YAAA,CAAa,EAAE,CAAA;AAAA,QACrB,KAAA,EAAO,CAAC,YAAa,CAAA,KAAA;AAAA,OACtB,CAAA,CACA,IAAK,CAAA,MAAM,UAAU,CAAA,CAAA;AAAA,KAC1B;AAAA,IACA,CAAC,kBAAkB,QAAQ,CAAA;AAAA,GAC7B,CAAA;AAEA,EAAA,MAAM,4BAA+B,GAAA,OAAA;AAAA,IACnC,MAAM,QAAS,CAAA,eAAA,EAAiB,eAAe,CAAA;AAAA,IAC/C,CAAC,eAAe,CAAA;AAAA,GAClB,CAAA;AAEA,EAAA,MAAM,iBAAiB,KAAM,CAAA,OAAA;AAAA,IAC3B,MAAmC;AAAA,MACjC;AAAA,QACE,KAAO,EAAA,MAAA;AAAA,QACP,MAAA,EAAQ,CAAC,YAA4B,KAAA;AAtG7C,UAAA,IAAA,EAAA,CAAA;AAuGU,UAAA,uBAAA,KAAA,CAAA,aAAA,CAAC,YAAa,EAAA,EAAA,QAAA,EAAA,CAAU,EAAa,GAAA,YAAA,CAAA,OAAA,KAAb,mBAAsB,QAAU,EAAA,CAAA,CAAA;AAAA,SAAA;AAAA,OAE5D;AAAA,MACA;AAAA,QACE,uBAAuB,MACrB,IAAA;AAAA,QACF,MAAA,EAAQ,CAAC,YAA+B,KAAA;AAEtC,UAAA,uBAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,GACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,WACjB,EAAA,EAAA,YAAA,CAAa,OAAQ,CAAA,IAAA,mBACnB,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,EAAI,EAAA,YAAA,CAAa,OAAQ,CAAA,IAAA,EAAA,EAC5B,YAAa,CAAA,OAAA,CAAQ,KACxB,CAAA,GAEA,YAAa,CAAA,OAAA,CAAQ,KAEzB,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,OAAA,EAAA,EACjB,YAAa,CAAA,OAAA,CAAQ,WACxB,CAAA,kBACC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,OAAQ,EAAA,SAAA,EAAA,EACjB,YAAa,CAAA,MAAA,oBACT,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAA,YAAA,CAAa,MAAO,EAAA,gBAAkB,CAE1C,EAAA,YAAA,CAAa,OAAQ,CAAA,KAAA,oBACjB,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAA,YAAA,CAAa,OAAQ,CAAA,KAAA,EAAM,gBAAkB,CAAA,EAEjD,YAAa,CAAA,OAAA,oBACX,KAAA,CAAA,aAAA,CAAA,YAAA,EAAA,EAAa,KAAO,EAAA,YAAA,CAAa,OAAS,EAAA,CAE/C,CACF,CACF,CAAA,CAAA;AAAA,SAEJ;AAAA,OACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsBA;AAAA;AAAA,QAEE,KAAO,EAAA,MAAA;AAAA,QACP,MAAA,EAAQ,CAAC,YAA+B,KAAA;AACtC,UAAA,MAAM,cAAiB,GAAA,CAAC,CAAC,YAAA,CAAa,OAClC,qBACA,GAAA,cAAA,CAAA;AACJ,UAAA,MAAM,aAAgB,GAAA,CAAC,CAAC,YAAA,CAAa,OACjC,gBACA,GAAA,cAAA,CAAA;AAEJ,UAAA,MAAM,eAAkB,GAAA,CAAC,CAAC,YAAA,CAAa,QACnC,WACA,GAAA,gBAAA,CAAA;AAEJ,UAAA,MAAM,kBAAqB,GAAA,CAAC,CAAC,YAAA,CAAa,QACtC,iBACA,GAAA,eAAA,CAAA;AAEJ,UAAA,uBACG,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,SAAS,EAAA,IAAA,EAAC,IAAK,EAAA,QAAA,EAAA,kBAClB,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,IAAI,EAAA,IAAA,EAAA,kBACP,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,EAAQ,OAAO,eACd,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAS,MAAM;AACb,gBAAA,mBAAA,CAAoB,YAAY,CAAA,CAAA;AAAA,eAClC;AAAA,aAAA;AAAA,4BAEA,KAAA,CAAA,aAAA,CAAC,kBAAmB,EAAA,EAAA,YAAA,EAAY,eAAiB,EAAA,CAAA;AAAA,WAErD,CACF,CAAA,kBAEC,KAAA,CAAA,aAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IACR,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,KAAA,EAAO,cACd,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAS,MAAM;AACb,gBAAA,kBAAA,CAAmB,YAAY,CAAA,CAAA;AAAA,eACjC;AAAA,aAAA;AAAA,4BAEA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,EAAA,YAAA,EAAY,cAAgB,EAAA,CAAA;AAAA,WAE/C,CACF,CACF,CAAA,CAAA;AAAA,SAEJ;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,oBAAoB,mBAAmB,CAAA;AAAA,GAC1C,CAAA;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,OAAS,EAAA;AAAA,QACP,MAAQ,EAAA,IAAA;AAAA,QACR,MAAQ,EAAA,IAAA;AAAA,QACR,QAAA;AAAA,QACA,MAAQ,EAAA,KAAA;AAAA,QACR,OAAS,EAAA,KAAA;AAAA,OACX;AAAA,MACA,YAAA;AAAA,MACA,mBAAA;AAAA,MACA,IAAA;AAAA,MACA,UAAA;AAAA,MACA,cAAgB,EAAA,4BAAA;AAAA,MAChB,IAAM,EAAA,aAAA;AAAA,MACN,OAAS,EAAA,cAAA;AAAA,KAAA;AAAA,GACX,CAAA;AAEJ;;;;"}
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('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 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}&nbsp;&bull;&nbsp;</>\n )}\n {notification.payload.topic && (\n <>{notification.payload.topic}&nbsp;&bull;&nbsp;</>\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":["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.1.3-next.0",
4
- "main": "dist/index.esm.js",
5
- "types": "dist/index.d.ts",
6
- "license": "Apache-2.0",
3
+ "version": "0.2.0-next.1",
4
+ "backstage": {
5
+ "role": "frontend-plugin"
6
+ },
7
7
  "publishConfig": {
8
8
  "access": "public",
9
9
  "main": "dist/index.esm.js",
@@ -14,25 +14,28 @@
14
14
  "url": "https://github.com/backstage/backstage",
15
15
  "directory": "plugins/notifications"
16
16
  },
17
- "backstage": {
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
34
  "@backstage/core-components": "^0.14.4-next.0",
32
35
  "@backstage/core-plugin-api": "^1.9.1",
33
36
  "@backstage/errors": "^1.2.4",
34
37
  "@backstage/plugin-notifications-common": "^0.0.2",
35
- "@backstage/plugin-signals-react": "^0.0.2",
38
+ "@backstage/plugin-signals-react": "^0.0.3-next.0",
36
39
  "@backstage/theme": "^0.5.2",
37
40
  "@backstage/types": "^1.1.1",
38
41
  "@material-ui/core": "^4.9.13",
@@ -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-next.0",
52
- "@backstage/core-app-api": "^1.12.3",
53
- "@backstage/dev-utils": "^1.0.31-next.0",
54
- "@backstage/test-utils": "^1.5.3",
50
+ "@backstage/cli": "^0.26.3-next.1",
51
+ "@backstage/core-app-api": "^1.12.4-next.0",
52
+ "@backstage/dev-utils": "^1.0.31-next.1",
53
+ "@backstage/test-utils": "^1.5.4-next.0",
55
54
  "@testing-library/jest-dom": "^6.0.0",
56
55
  "@testing-library/react": "^14.0.0",
57
56
  "@testing-library/user-event": "^14.0.0",
58
57
  "msw": "^1.0.0"
59
58
  },
60
- "files": [
61
- "dist"
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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"}