@backstage/plugin-notifications 0.2.4-next.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +2 -29
- package/dist/components/NotificationsPage/NotificationsPage.esm.js +3 -2
- package/dist/components/NotificationsPage/NotificationsPage.esm.js.map +1 -1
- package/dist/components/NotificationsSideBarItem/NotificationsSideBarItem.esm.js +21 -4
- package/dist/components/NotificationsSideBarItem/NotificationsSideBarItem.esm.js.map +1 -1
- package/dist/components/NotificationsTable/NotificationsTable.esm.js +37 -6
- package/dist/components/NotificationsTable/NotificationsTable.esm.js.map +1 -1
- package/dist/hooks/useTitleCounter.esm.js.map +1 -1
- package/dist/hooks/useWebNotifications.esm.js +14 -9
- package/dist/hooks/useWebNotifications.esm.js.map +1 -1
- package/dist/index.d.ts +8 -23
- package/dist/index.esm.js +4 -2
- package/dist/index.esm.js.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# @backstage/plugin-notifications
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0410fc9: By default, set notification as read when opening snackbar or web notification link
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 80b84f7: Fixed issue with notification reloading on page change
|
|
12
|
+
- b58e452: Broadcast notifications are now decorated with an icon.
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- @backstage/core-components@0.14.10
|
|
15
|
+
- @backstage/core-plugin-api@1.9.3
|
|
16
|
+
- @backstage/errors@1.2.4
|
|
17
|
+
- @backstage/theme@0.5.6
|
|
18
|
+
- @backstage/types@1.1.1
|
|
19
|
+
- @backstage/plugin-notifications-common@0.0.5
|
|
20
|
+
- @backstage/plugin-signals-react@0.0.4
|
|
21
|
+
|
|
22
|
+
## 0.3.0-next.1
|
|
23
|
+
|
|
24
|
+
### Minor Changes
|
|
25
|
+
|
|
26
|
+
- 0410fc9: By default, set notification as read when opening snackbar or web notification link
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- 80b84f7: Fixed issue with notification reloading on page change
|
|
31
|
+
- Updated dependencies
|
|
32
|
+
- @backstage/core-components@0.14.10-next.0
|
|
33
|
+
- @backstage/core-plugin-api@1.9.3
|
|
34
|
+
- @backstage/errors@1.2.4
|
|
35
|
+
- @backstage/theme@0.5.6
|
|
36
|
+
- @backstage/types@1.1.1
|
|
37
|
+
- @backstage/plugin-notifications-common@0.0.5
|
|
38
|
+
- @backstage/plugin-signals-react@0.0.4
|
|
39
|
+
|
|
3
40
|
## 0.2.4-next.0
|
|
4
41
|
|
|
5
42
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,38 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Welcome to the notifications plugin!
|
|
4
4
|
|
|
5
|
-
_This plugin was created through the Backstage CLI_
|
|
6
|
-
|
|
7
5
|
## Getting started
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
See the documentation for installation instructions.
|
|
11
|
-
|
|
12
|
-
To add the notifications main menu, add the following to your `packages/app/src/components/Root/Root.tsx`:
|
|
13
|
-
|
|
14
|
-
```tsx
|
|
15
|
-
import { NotificationsSidebarItem } from '@backstage/plugin-notifications';
|
|
16
|
-
|
|
17
|
-
<SidebarPage>
|
|
18
|
-
<Sidebar>
|
|
19
|
-
<SidebarGroup>
|
|
20
|
-
// ...
|
|
21
|
-
<NotificationsSidebarItem />
|
|
22
|
-
</SidebarGroup>
|
|
23
|
-
</Sidebar>
|
|
24
|
-
</SidebarPage>;
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Also add the route to notifications to `packages/app/src/App.tsx`:
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import { NotificationsPage } from '@backstage/plugin-notifications';
|
|
7
|
+
To install, please refer the [Getting Started](https://backstage.io/docs/notifications) Backstage Notifications and Signals documentation section.
|
|
31
8
|
|
|
32
|
-
|
|
33
|
-
// ...
|
|
34
|
-
<Route path="/notifications" element={<NotificationsPage />} />
|
|
35
|
-
</FlatRoutes>;
|
|
36
|
-
```
|
|
9
|
+
Please mind installing the `@backstage/plugin-notifications-backend` and `@backstage/plugin-notifications-node` packages before this frontend plugin.
|
|
37
10
|
|
|
38
11
|
## Real-time notifications
|
|
39
12
|
|
|
@@ -6,9 +6,10 @@ import { ConfirmProvider } from 'material-ui-confirm';
|
|
|
6
6
|
import { useSignal } from '@backstage/plugin-signals-react';
|
|
7
7
|
import { NotificationsTable } from '../NotificationsTable/NotificationsTable.esm.js';
|
|
8
8
|
import { useNotificationsApi } from '../../hooks/useNotificationsApi.esm.js';
|
|
9
|
-
import '../../routes.esm.js';
|
|
10
9
|
import '@backstage/core-plugin-api';
|
|
11
|
-
import '
|
|
10
|
+
import '../../api/NotificationsApi.esm.js';
|
|
11
|
+
import '@backstage/errors';
|
|
12
|
+
import '../../routes.esm.js';
|
|
12
13
|
import '../../hooks/useTitleCounter.esm.js';
|
|
13
14
|
import { SortByOptions, NotificationsFilters, CreatedAfterOptions } from '../NotificationsFilters/NotificationsFilters.esm.js';
|
|
14
15
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsPage.esm.js","sources":["../../../src/components/NotificationsPage/NotificationsPage.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 */\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 { ConfirmProvider } from 'material-ui-confirm';\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, GetNotificationsResponse } from '../../api';\nimport {\n NotificationSeverity,\n NotificationStatus,\n} from '@backstage/plugin-notifications-common';\n\nconst ThrottleDelayMs = 2000;\n\n/** @public */\nexport type NotificationsPageProps = {\n /** Mark notification as read when opening the link it contains, defaults to false */\n markAsReadOnLinkOpen?: boolean;\n title?: string;\n themeId?: string;\n subtitle?: string;\n tooltip?: string;\n type?: string;\n typeLink?: string;\n};\n\nexport const NotificationsPage = (props?: NotificationsPageProps) => {\n const {\n title = 'Notifications',\n themeId = 'tool',\n subtitle,\n tooltip,\n type,\n typeLink,\n markAsReadOnLinkOpen,\n } = props ?? {};\n\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>('all');\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 [GetNotificationsResponse, NotificationStatus]\n >(\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 Promise.all([api.getNotifications(options), api.getStatus()]);\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 const notifications = value?.[0]?.notifications;\n const totalCount = value?.[0]?.totalCount;\n const isUnread = !!value?.[1]?.unread;\n\n return (\n <PageWithHeader\n title={title}\n themeId={themeId}\n tooltip={tooltip}\n subtitle={subtitle}\n type={type}\n typeLink={typeLink}\n >\n <Content>\n <ConfirmProvider>\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 isUnread={isUnread}\n markAsReadOnLinkOpen={markAsReadOnLinkOpen}\n notifications={notifications}\n onUpdate={onUpdate}\n setContainsText={setContainsText}\n onPageChange={setPageNumber}\n onRowsPerPageChange={setPageSize}\n page={pageNumber}\n pageSize={pageSize}\n totalCount={totalCount}\n />\n </Grid>\n </Grid>\n </ConfirmProvider>\n </Content>\n </PageWithHeader>\n );\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"NotificationsPage.esm.js","sources":["../../../src/components/NotificationsPage/NotificationsPage.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 */\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 { ConfirmProvider } from 'material-ui-confirm';\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, GetNotificationsResponse } from '../../api';\nimport {\n NotificationSeverity,\n NotificationStatus,\n} from '@backstage/plugin-notifications-common';\n\nconst ThrottleDelayMs = 2000;\n\n/** @public */\nexport type NotificationsPageProps = {\n /** Mark notification as read when opening the link it contains, defaults to false */\n markAsReadOnLinkOpen?: boolean;\n title?: string;\n themeId?: string;\n subtitle?: string;\n tooltip?: string;\n type?: string;\n typeLink?: string;\n};\n\nexport const NotificationsPage = (props?: NotificationsPageProps) => {\n const {\n title = 'Notifications',\n themeId = 'tool',\n subtitle,\n tooltip,\n type,\n typeLink,\n markAsReadOnLinkOpen,\n } = props ?? {};\n\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>('all');\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 [GetNotificationsResponse, NotificationStatus]\n >(\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 Promise.all([api.getNotifications(options), api.getStatus()]);\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 const notifications = value?.[0]?.notifications;\n const totalCount = value?.[0]?.totalCount;\n const isUnread = !!value?.[1]?.unread;\n\n return (\n <PageWithHeader\n title={title}\n themeId={themeId}\n tooltip={tooltip}\n subtitle={subtitle}\n type={type}\n typeLink={typeLink}\n >\n <Content>\n <ConfirmProvider>\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 isUnread={isUnread}\n markAsReadOnLinkOpen={markAsReadOnLinkOpen}\n notifications={notifications}\n onUpdate={onUpdate}\n setContainsText={setContainsText}\n onPageChange={setPageNumber}\n onRowsPerPageChange={setPageSize}\n page={pageNumber}\n pageSize={pageSize}\n totalCount={totalCount}\n />\n </Grid>\n </Grid>\n </ConfirmProvider>\n </Content>\n </PageWithHeader>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -57,9 +57,11 @@ const NotificationsSidebarItem = (props) => {
|
|
|
57
57
|
const notificationsApi = useApi(notificationsApiRef);
|
|
58
58
|
const alertApi = useApi(alertApiRef);
|
|
59
59
|
const [unreadCount, setUnreadCount] = React.useState(0);
|
|
60
|
-
const notificationsRoute = useRouteRef(rootRouteRef);
|
|
60
|
+
const notificationsRoute = useRouteRef(rootRouteRef)();
|
|
61
61
|
const { lastSignal } = useSignal("notifications");
|
|
62
|
-
const { sendWebNotification } = useWebNotifications(
|
|
62
|
+
const { sendWebNotification, requestUserPermission } = useWebNotifications(
|
|
63
|
+
webNotificationsEnabled
|
|
64
|
+
);
|
|
63
65
|
const [refresh, setRefresh] = React.useState(false);
|
|
64
66
|
const { setNotificationCount } = useTitleCounter();
|
|
65
67
|
const getSnackbarProperties = useCallback(
|
|
@@ -68,8 +70,19 @@ const NotificationsSidebarItem = (props) => {
|
|
|
68
70
|
IconButton,
|
|
69
71
|
{
|
|
70
72
|
component: Link,
|
|
71
|
-
to: notification.payload.link ?? notificationsRoute
|
|
73
|
+
to: notification.payload.link ?? notificationsRoute,
|
|
72
74
|
onClick: () => {
|
|
75
|
+
if (notification.payload.link) {
|
|
76
|
+
notificationsApi.updateNotifications({
|
|
77
|
+
ids: [notification.id],
|
|
78
|
+
read: true
|
|
79
|
+
}).catch(() => {
|
|
80
|
+
alertApi.post({
|
|
81
|
+
message: "Failed to mark notification as read",
|
|
82
|
+
severity: "error"
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
73
86
|
closeSnackbar(snackBarId);
|
|
74
87
|
}
|
|
75
88
|
},
|
|
@@ -124,6 +137,7 @@ const NotificationsSidebarItem = (props) => {
|
|
|
124
137
|
const { action } = getSnackbarProperties(notification);
|
|
125
138
|
const snackBarText = notification.payload.title.length > 50 ? `${notification.payload.title.substring(0, 50)}...` : notification.payload.title;
|
|
126
139
|
enqueueSnackbar(snackBarText, {
|
|
140
|
+
key: notification.id,
|
|
127
141
|
variant: notification.payload.severity,
|
|
128
142
|
anchorOrigin: { vertical: "bottom", horizontal: "right" },
|
|
129
143
|
action,
|
|
@@ -180,7 +194,10 @@ const NotificationsSidebarItem = (props) => {
|
|
|
180
194
|
), /* @__PURE__ */ React.createElement(
|
|
181
195
|
SidebarItem,
|
|
182
196
|
{
|
|
183
|
-
to: notificationsRoute
|
|
197
|
+
to: notificationsRoute,
|
|
198
|
+
onClick: () => {
|
|
199
|
+
requestUserPermission();
|
|
200
|
+
},
|
|
184
201
|
hasNotifications: !error && !!unreadCount,
|
|
185
202
|
text,
|
|
186
203
|
icon,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsSideBarItem.esm.js","sources":["../../../src/components/NotificationsSideBarItem/NotificationsSideBarItem.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 React, { useCallback, useEffect } from 'react';\nimport { useNotificationsApi } from '../../hooks';\nimport { Link, SidebarItem } from '@backstage/core-components';\nimport NotificationsIcon from '@material-ui/icons/Notifications';\nimport {\n alertApiRef,\n IconComponent,\n useApi,\n useRouteRef,\n} from '@backstage/core-plugin-api';\nimport { rootRouteRef } from '../../routes';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport {\n Notification,\n NotificationSignal,\n} from '@backstage/plugin-notifications-common';\nimport { useWebNotifications } from '../../hooks/useWebNotifications';\nimport { useTitleCounter } from '../../hooks/useTitleCounter';\nimport { notificationsApiRef } from '../../api';\nimport {\n closeSnackbar,\n enqueueSnackbar,\n MaterialDesignContent,\n OptionsWithExtraProps,\n SnackbarKey,\n SnackbarProvider,\n VariantType,\n} from 'notistack';\nimport { SeverityIcon } from '../NotificationsTable/SeverityIcon';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport MarkAsReadIcon from '@material-ui/icons/CheckCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport { styled } from '@material-ui/core/styles';\n\nconst StyledMaterialDesignContent = styled(MaterialDesignContent)(\n ({ theme }) => ({\n '&.notistack-MuiContent-low': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-normal': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-high': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-critical': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n }),\n);\n\ndeclare module 'notistack' {\n interface VariantOverrides {\n // Custom variants for the snackbar\n low: true;\n normal: true;\n high: true;\n critical: true;\n }\n}\n\n/** @public */\nexport const NotificationsSidebarItem = (props?: {\n webNotificationsEnabled?: boolean;\n titleCounterEnabled?: boolean;\n snackbarEnabled?: boolean;\n snackbarAutoHideDuration?: number | null;\n className?: string;\n icon?: IconComponent;\n text?: string;\n disableHighlight?: boolean;\n noTrack?: boolean;\n}) => {\n const {\n webNotificationsEnabled = false,\n titleCounterEnabled = true,\n snackbarEnabled = true,\n snackbarAutoHideDuration = 10000,\n icon = NotificationsIcon,\n text = 'Notifications',\n ...restProps\n } = props ?? {\n webNotificationsEnabled: false,\n titleCounterEnabled: true,\n snackbarEnabled: true,\n snackbarAutoHideDuration: 10000,\n };\n\n const { loading, error, value, retry } = useNotificationsApi(api =>\n api.getStatus(),\n );\n const notificationsApi = useApi(notificationsApiRef);\n const alertApi = useApi(alertApiRef);\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(webNotificationsEnabled);\n const [refresh, setRefresh] = React.useState(false);\n const { setNotificationCount } = useTitleCounter();\n\n const getSnackbarProperties = useCallback(\n (notification: Notification) => {\n const action = (snackBarId: SnackbarKey) => (\n <>\n <IconButton\n component={Link}\n to={notification.payload.link ?? notificationsRoute()}\n onClick={() => {\n closeSnackbar(snackBarId);\n }}\n >\n <OpenInNew fontSize=\"small\" />\n </IconButton>\n <IconButton\n onClick={() => {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .then(() => {\n closeSnackbar(snackBarId);\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }}\n >\n <MarkAsReadIcon fontSize=\"small\" />\n </IconButton>\n </>\n );\n\n return { action };\n },\n [notificationsRoute, notificationsApi, alertApi],\n );\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, retry]);\n\n useEffect(() => {\n const handleNotificationSignal = (signal: NotificationSignal) => {\n if (\n (!webNotificationsEnabled && !snackbarEnabled) ||\n signal.action !== 'new_notification'\n ) {\n return;\n }\n\n notificationsApi\n .getNotification(signal.notification_id)\n .then(notification => {\n if (!notification) {\n return;\n }\n if (webNotificationsEnabled) {\n sendWebNotification({\n id: notification.id,\n title: notification.payload.title,\n description: notification.payload.description ?? '',\n link: notification.payload.link,\n });\n }\n if (snackbarEnabled) {\n const { action } = getSnackbarProperties(notification);\n const snackBarText =\n notification.payload.title.length > 50\n ? `${notification.payload.title.substring(0, 50)}...`\n : notification.payload.title;\n enqueueSnackbar(snackBarText, {\n variant: notification.payload.severity,\n anchorOrigin: { vertical: 'bottom', horizontal: 'right' },\n action,\n autoHideDuration: snackbarAutoHideDuration,\n } as OptionsWithExtraProps<VariantType>);\n }\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to fetch notification',\n severity: 'error',\n });\n });\n };\n\n if (lastSignal && lastSignal.action) {\n handleNotificationSignal(lastSignal);\n setRefresh(true);\n }\n }, [\n lastSignal,\n sendWebNotification,\n webNotificationsEnabled,\n snackbarEnabled,\n snackbarAutoHideDuration,\n notificationsApi,\n alertApi,\n getSnackbarProperties,\n ]);\n\n useEffect(() => {\n if (!loading && !error && value) {\n setUnreadCount(value.unread);\n }\n }, [loading, error, value]);\n\n useEffect(() => {\n if (titleCounterEnabled) {\n setNotificationCount(unreadCount);\n }\n }, [titleCounterEnabled, unreadCount, setNotificationCount]);\n\n // TODO: Figure out if the count can be added to hasNotifications\n return (\n <>\n {snackbarEnabled && (\n <SnackbarProvider\n iconVariant={{\n normal: <SeverityIcon severity=\"normal\" />,\n critical: <SeverityIcon severity=\"critical\" />,\n high: <SeverityIcon severity=\"high\" />,\n low: <SeverityIcon severity=\"low\" />,\n }}\n Components={{\n normal: StyledMaterialDesignContent,\n critical: StyledMaterialDesignContent,\n high: StyledMaterialDesignContent,\n low: StyledMaterialDesignContent,\n }}\n />\n )}\n <SidebarItem\n to={notificationsRoute()}\n hasNotifications={!error && !!unreadCount}\n text={text}\n icon={icon}\n {...restProps}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NotificationsSideBarItem.esm.js","sources":["../../../src/components/NotificationsSideBarItem/NotificationsSideBarItem.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 React, { useCallback, useEffect } from 'react';\nimport { useNotificationsApi } from '../../hooks';\nimport { Link, SidebarItem } from '@backstage/core-components';\nimport NotificationsIcon from '@material-ui/icons/Notifications';\nimport {\n alertApiRef,\n IconComponent,\n useApi,\n useRouteRef,\n} from '@backstage/core-plugin-api';\nimport { rootRouteRef } from '../../routes';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport {\n Notification,\n NotificationSignal,\n} from '@backstage/plugin-notifications-common';\nimport { useWebNotifications } from '../../hooks/useWebNotifications';\nimport { useTitleCounter } from '../../hooks/useTitleCounter';\nimport { notificationsApiRef } from '../../api';\nimport {\n closeSnackbar,\n enqueueSnackbar,\n MaterialDesignContent,\n OptionsWithExtraProps,\n SnackbarKey,\n SnackbarProvider,\n VariantType,\n} from 'notistack';\nimport { SeverityIcon } from '../NotificationsTable/SeverityIcon';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport MarkAsReadIcon from '@material-ui/icons/CheckCircle';\nimport IconButton from '@material-ui/core/IconButton';\nimport { styled } from '@material-ui/core/styles';\n\nconst StyledMaterialDesignContent = styled(MaterialDesignContent)(\n ({ theme }) => ({\n '&.notistack-MuiContent-low': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-normal': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-high': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n '&.notistack-MuiContent-critical': {\n backgroundColor: theme.palette.background.default,\n color: theme.palette.text.primary,\n },\n }),\n);\n\ndeclare module 'notistack' {\n interface VariantOverrides {\n // Custom variants for the snackbar\n low: true;\n normal: true;\n high: true;\n critical: true;\n }\n}\n\n/** @public */\nexport const NotificationsSidebarItem = (props?: {\n webNotificationsEnabled?: boolean;\n titleCounterEnabled?: boolean;\n snackbarEnabled?: boolean;\n snackbarAutoHideDuration?: number | null;\n className?: string;\n icon?: IconComponent;\n text?: string;\n disableHighlight?: boolean;\n noTrack?: boolean;\n}) => {\n const {\n webNotificationsEnabled = false,\n titleCounterEnabled = true,\n snackbarEnabled = true,\n snackbarAutoHideDuration = 10000,\n icon = NotificationsIcon,\n text = 'Notifications',\n ...restProps\n } = props ?? {\n webNotificationsEnabled: false,\n titleCounterEnabled: true,\n snackbarEnabled: true,\n snackbarAutoHideDuration: 10000,\n };\n\n const { loading, error, value, retry } = useNotificationsApi(api =>\n api.getStatus(),\n );\n const notificationsApi = useApi(notificationsApiRef);\n const alertApi = useApi(alertApiRef);\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, requestUserPermission } = useWebNotifications(\n webNotificationsEnabled,\n );\n const [refresh, setRefresh] = React.useState(false);\n const { setNotificationCount } = useTitleCounter();\n\n const getSnackbarProperties = useCallback(\n (notification: Notification) => {\n const action = (snackBarId: SnackbarKey) => (\n <>\n <IconButton\n component={Link}\n to={notification.payload.link ?? notificationsRoute}\n onClick={() => {\n if (notification.payload.link) {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }\n closeSnackbar(snackBarId);\n }}\n >\n <OpenInNew fontSize=\"small\" />\n </IconButton>\n <IconButton\n onClick={() => {\n notificationsApi\n .updateNotifications({\n ids: [notification.id],\n read: true,\n })\n .then(() => {\n closeSnackbar(snackBarId);\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to mark notification as read',\n severity: 'error',\n });\n });\n }}\n >\n <MarkAsReadIcon fontSize=\"small\" />\n </IconButton>\n </>\n );\n\n return { action };\n },\n [notificationsRoute, notificationsApi, alertApi],\n );\n\n useEffect(() => {\n if (refresh) {\n retry();\n setRefresh(false);\n }\n }, [refresh, retry]);\n\n useEffect(() => {\n const handleNotificationSignal = (signal: NotificationSignal) => {\n if (\n (!webNotificationsEnabled && !snackbarEnabled) ||\n signal.action !== 'new_notification'\n ) {\n return;\n }\n notificationsApi\n .getNotification(signal.notification_id)\n .then(notification => {\n if (!notification) {\n return;\n }\n if (webNotificationsEnabled) {\n sendWebNotification({\n id: notification.id,\n title: notification.payload.title,\n description: notification.payload.description ?? '',\n link: notification.payload.link,\n });\n }\n if (snackbarEnabled) {\n const { action } = getSnackbarProperties(notification);\n const snackBarText =\n notification.payload.title.length > 50\n ? `${notification.payload.title.substring(0, 50)}...`\n : notification.payload.title;\n enqueueSnackbar(snackBarText, {\n key: notification.id,\n variant: notification.payload.severity,\n anchorOrigin: { vertical: 'bottom', horizontal: 'right' },\n action,\n autoHideDuration: snackbarAutoHideDuration,\n } as OptionsWithExtraProps<VariantType>);\n }\n })\n .catch(() => {\n alertApi.post({\n message: 'Failed to fetch notification',\n severity: 'error',\n });\n });\n };\n\n if (lastSignal && lastSignal.action) {\n handleNotificationSignal(lastSignal);\n setRefresh(true);\n }\n }, [\n lastSignal,\n sendWebNotification,\n webNotificationsEnabled,\n snackbarEnabled,\n snackbarAutoHideDuration,\n notificationsApi,\n alertApi,\n getSnackbarProperties,\n ]);\n\n useEffect(() => {\n if (!loading && !error && value) {\n setUnreadCount(value.unread);\n }\n }, [loading, error, value]);\n\n useEffect(() => {\n if (titleCounterEnabled) {\n setNotificationCount(unreadCount);\n }\n }, [titleCounterEnabled, unreadCount, setNotificationCount]);\n\n // TODO: Figure out if the count can be added to hasNotifications\n return (\n <>\n {snackbarEnabled && (\n <SnackbarProvider\n iconVariant={{\n normal: <SeverityIcon severity=\"normal\" />,\n critical: <SeverityIcon severity=\"critical\" />,\n high: <SeverityIcon severity=\"high\" />,\n low: <SeverityIcon severity=\"low\" />,\n }}\n Components={{\n normal: StyledMaterialDesignContent,\n critical: StyledMaterialDesignContent,\n high: StyledMaterialDesignContent,\n low: StyledMaterialDesignContent,\n }}\n />\n )}\n <SidebarItem\n to={notificationsRoute}\n onClick={() => {\n requestUserPermission();\n }}\n hasNotifications={!error && !!unreadCount}\n text={text}\n icon={icon}\n {...restProps}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@ import Checkbox from '@material-ui/core/Checkbox';
|
|
|
7
7
|
import Typography from '@material-ui/core/Typography';
|
|
8
8
|
import { makeStyles } from '@material-ui/core/styles';
|
|
9
9
|
import { useConfirm } from 'material-ui-confirm';
|
|
10
|
+
import BroadcastIcon from '@material-ui/icons/RssFeed';
|
|
10
11
|
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
11
12
|
import { Link, Table } from '@backstage/core-components';
|
|
12
13
|
import { notificationsApiRef } from '../../api/NotificationsApi.esm.js';
|
|
@@ -16,15 +17,23 @@ import { SelectAll } from './SelectAll.esm.js';
|
|
|
16
17
|
import { BulkActions } from './BulkActions.esm.js';
|
|
17
18
|
|
|
18
19
|
const ThrottleDelayMs = 1e3;
|
|
19
|
-
const useStyles = makeStyles({
|
|
20
|
+
const useStyles = makeStyles((theme) => ({
|
|
20
21
|
description: {
|
|
21
22
|
maxHeight: "5rem",
|
|
22
23
|
overflow: "auto"
|
|
23
24
|
},
|
|
24
25
|
severityItem: {
|
|
25
26
|
alignContent: "center"
|
|
27
|
+
},
|
|
28
|
+
broadcastIcon: {
|
|
29
|
+
fontSize: "1rem",
|
|
30
|
+
verticalAlign: "text-bottom"
|
|
31
|
+
},
|
|
32
|
+
notificationInfoRow: {
|
|
33
|
+
marginLeft: theme.spacing(0.5),
|
|
34
|
+
marginRight: theme.spacing(0.5)
|
|
26
35
|
}
|
|
27
|
-
});
|
|
36
|
+
}));
|
|
28
37
|
const NotificationsTable = ({
|
|
29
38
|
markAsReadOnLinkOpen,
|
|
30
39
|
isLoading,
|
|
@@ -150,7 +159,27 @@ const NotificationsTable = ({
|
|
|
150
159
|
}
|
|
151
160
|
},
|
|
152
161
|
notification.payload.title
|
|
153
|
-
) : notification.payload.title), notification.payload.description ? /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.description }, notification.payload.description) : null, /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, notification.
|
|
162
|
+
) : notification.payload.title), notification.payload.description ? /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: classes.description }, notification.payload.description) : null, /* @__PURE__ */ React.createElement(Typography, { variant: "caption" }, !notification.user && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(BroadcastIcon, { className: classes.broadcastIcon })), notification.origin && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
163
|
+
Typography,
|
|
164
|
+
{
|
|
165
|
+
variant: "inherit",
|
|
166
|
+
className: classes.notificationInfoRow
|
|
167
|
+
},
|
|
168
|
+
notification.origin
|
|
169
|
+
), "\u2022"), notification.payload.topic && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
170
|
+
Typography,
|
|
171
|
+
{
|
|
172
|
+
variant: "inherit",
|
|
173
|
+
className: classes.notificationInfoRow
|
|
174
|
+
},
|
|
175
|
+
notification.payload.topic
|
|
176
|
+
), "\u2022"), notification.created && /* @__PURE__ */ React.createElement(
|
|
177
|
+
RelativeTime,
|
|
178
|
+
{
|
|
179
|
+
value: notification.created,
|
|
180
|
+
className: classes.notificationInfoRow
|
|
181
|
+
}
|
|
182
|
+
)))));
|
|
154
183
|
}
|
|
155
184
|
},
|
|
156
185
|
{
|
|
@@ -179,16 +208,18 @@ const NotificationsTable = ({
|
|
|
179
208
|
}
|
|
180
209
|
];
|
|
181
210
|
}, [
|
|
182
|
-
markAsReadOnLinkOpen,
|
|
183
|
-
selectedNotifications,
|
|
184
211
|
notifications,
|
|
212
|
+
selectedNotifications,
|
|
185
213
|
isUnread,
|
|
186
214
|
onSwitchReadStatus,
|
|
187
215
|
onSwitchSavedStatus,
|
|
188
216
|
onMarkAllRead,
|
|
189
217
|
onNotificationsSelectChange,
|
|
190
218
|
classes.severityItem,
|
|
191
|
-
classes.description
|
|
219
|
+
classes.description,
|
|
220
|
+
classes.broadcastIcon,
|
|
221
|
+
classes.notificationInfoRow,
|
|
222
|
+
markAsReadOnLinkOpen
|
|
192
223
|
]);
|
|
193
224
|
return /* @__PURE__ */ React.createElement(
|
|
194
225
|
Table,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationsTable.esm.js","sources":["../../../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 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 { makeStyles } from '@material-ui/core/styles';\nimport { Notification } from '@backstage/plugin-notifications-common';\nimport { useConfirm } from 'material-ui-confirm';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n Link,\n Table,\n TableColumn,\n TableProps,\n} from '@backstage/core-components';\n\nimport { notificationsApiRef } from '../../api';\n\nimport { SeverityIcon } from './SeverityIcon';\nimport { SelectAll } from './SelectAll';\nimport { BulkActions } from './BulkActions';\n\nconst ThrottleDelayMs = 1000;\n\nconst useStyles = makeStyles({\n description: {\n maxHeight: '5rem',\n overflow: 'auto',\n },\n severityItem: {\n alignContent: 'center',\n },\n});\n\n/** @public */\nexport type NotificationsTableProps = Pick<\n TableProps,\n 'onPageChange' | 'onRowsPerPageChange' | 'page' | 'totalCount'\n> & {\n markAsReadOnLinkOpen?: boolean;\n isLoading?: boolean;\n isUnread: boolean;\n notifications?: Notification[];\n onUpdate: () => void;\n setContainsText: (search: string) => void;\n pageSize: number;\n};\n\n/** @public */\nexport const NotificationsTable = ({\n markAsReadOnLinkOpen,\n isLoading,\n notifications = [],\n isUnread,\n onUpdate,\n setContainsText,\n onPageChange,\n onRowsPerPageChange,\n page,\n pageSize,\n totalCount,\n}: NotificationsTableProps) => {\n const classes = useStyles();\n const notificationsApi = useApi(notificationsApiRef);\n const alertApi = useApi(alertApiRef);\n const confirm = useConfirm();\n\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 onMarkAllRead = React.useCallback(() => {\n confirm({\n title: 'Are you sure?',\n description: (\n <>\n Mark <b>all</b> notifications as <b>read</b>.\n </>\n ),\n confirmationText: 'Mark All',\n })\n .then(async () => {\n const ids = (\n await notificationsApi.getNotifications({ read: false })\n ).notifications?.map(notification => notification.id);\n\n return notificationsApi\n .updateNotifications({\n ids,\n read: true,\n })\n .then(onUpdate);\n })\n .catch(e => {\n if (e) {\n // if e === undefined, the Cancel button has been hit\n alertApi.post({\n message: 'Failed to mark all notifications as read',\n severity: 'error',\n });\n }\n });\n }, [alertApi, confirm, notificationsApi, onUpdate]);\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((): TableColumn<Notification>[] => {\n const showToolbar = notifications.length > 0;\n\n return [\n {\n /* selection column */\n width: '1rem',\n title: showToolbar ? (\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 ) : undefined,\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 className={classes.severityItem}>\n <SeverityIcon severity={notification.payload?.severity} />\n </Grid>\n <Grid item xs={11}>\n <Box>\n <Typography variant=\"subtitle2\">\n {notification.payload.link ? (\n <Link\n to={notification.payload.link}\n onClick={() => {\n if (markAsReadOnLinkOpen && !notification.read) {\n onSwitchReadStatus([notification.id], true);\n }\n }}\n >\n {notification.payload.title}\n </Link>\n ) : (\n notification.payload.title\n )}\n </Typography>\n {notification.payload.description ? (\n <Typography variant=\"body2\" className={classes.description}>\n {notification.payload.description}\n </Typography>\n ) : null}\n <Typography variant=\"caption\">\n {notification.origin && (\n <>{notification.origin} • </>\n )}\n {notification.payload.topic && (\n <>{notification.payload.topic} • </>\n )}\n {notification.created && (\n <RelativeTime value={notification.created} />\n )}\n </Typography>\n </Box>\n </Grid>\n </Grid>\n );\n },\n },\n {\n /* actions column */\n width: '1rem',\n title: showToolbar ? (\n <BulkActions\n notifications={notifications}\n selectedNotifications={selectedNotifications}\n isUnread={isUnread}\n onSwitchReadStatus={onSwitchReadStatus}\n onSwitchSavedStatus={onSwitchSavedStatus}\n onMarkAllRead={onMarkAllRead}\n />\n ) : undefined,\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 }, [\n markAsReadOnLinkOpen,\n selectedNotifications,\n notifications,\n isUnread,\n onSwitchReadStatus,\n onSwitchSavedStatus,\n onMarkAllRead,\n onNotificationsSelectChange,\n classes.severityItem,\n classes.description,\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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"}
|
|
1
|
+
{"version":3,"file":"NotificationsTable.esm.js","sources":["../../../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 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 { makeStyles } from '@material-ui/core/styles';\nimport { Notification } from '@backstage/plugin-notifications-common';\nimport { useConfirm } from 'material-ui-confirm';\nimport BroadcastIcon from '@material-ui/icons/RssFeed';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n Link,\n Table,\n TableColumn,\n TableProps,\n} from '@backstage/core-components';\n\nimport { notificationsApiRef } from '../../api';\n\nimport { SeverityIcon } from './SeverityIcon';\nimport { SelectAll } from './SelectAll';\nimport { BulkActions } from './BulkActions';\n\nconst ThrottleDelayMs = 1000;\n\nconst useStyles = makeStyles(theme => ({\n description: {\n maxHeight: '5rem',\n overflow: 'auto',\n },\n severityItem: {\n alignContent: 'center',\n },\n broadcastIcon: {\n fontSize: '1rem',\n verticalAlign: 'text-bottom',\n },\n notificationInfoRow: {\n marginLeft: theme.spacing(0.5),\n marginRight: theme.spacing(0.5),\n },\n}));\n\n/** @public */\nexport type NotificationsTableProps = Pick<\n TableProps,\n 'onPageChange' | 'onRowsPerPageChange' | 'page' | 'totalCount'\n> & {\n markAsReadOnLinkOpen?: boolean;\n isLoading?: boolean;\n isUnread: boolean;\n notifications?: Notification[];\n onUpdate: () => void;\n setContainsText: (search: string) => void;\n pageSize: number;\n};\n\n/** @public */\nexport const NotificationsTable = ({\n markAsReadOnLinkOpen,\n isLoading,\n notifications = [],\n isUnread,\n onUpdate,\n setContainsText,\n onPageChange,\n onRowsPerPageChange,\n page,\n pageSize,\n totalCount,\n}: NotificationsTableProps) => {\n const classes = useStyles();\n const notificationsApi = useApi(notificationsApiRef);\n const alertApi = useApi(alertApiRef);\n const confirm = useConfirm();\n\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 onMarkAllRead = React.useCallback(() => {\n confirm({\n title: 'Are you sure?',\n description: (\n <>\n Mark <b>all</b> notifications as <b>read</b>.\n </>\n ),\n confirmationText: 'Mark All',\n })\n .then(async () => {\n const ids = (\n await notificationsApi.getNotifications({ read: false })\n ).notifications?.map(notification => notification.id);\n\n return notificationsApi\n .updateNotifications({\n ids,\n read: true,\n })\n .then(onUpdate);\n })\n .catch(e => {\n if (e) {\n // if e === undefined, the Cancel button has been hit\n alertApi.post({\n message: 'Failed to mark all notifications as read',\n severity: 'error',\n });\n }\n });\n }, [alertApi, confirm, notificationsApi, onUpdate]);\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((): TableColumn<Notification>[] => {\n const showToolbar = notifications.length > 0;\n\n return [\n {\n /* selection column */\n width: '1rem',\n title: showToolbar ? (\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 ) : undefined,\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 className={classes.severityItem}>\n <SeverityIcon severity={notification.payload?.severity} />\n </Grid>\n <Grid item xs={11}>\n <Box>\n <Typography variant=\"subtitle2\">\n {notification.payload.link ? (\n <Link\n to={notification.payload.link}\n onClick={() => {\n if (markAsReadOnLinkOpen && !notification.read) {\n onSwitchReadStatus([notification.id], true);\n }\n }}\n >\n {notification.payload.title}\n </Link>\n ) : (\n notification.payload.title\n )}\n </Typography>\n {notification.payload.description ? (\n <Typography variant=\"body2\" className={classes.description}>\n {notification.payload.description}\n </Typography>\n ) : null}\n\n <Typography variant=\"caption\">\n {!notification.user && (\n <>\n <BroadcastIcon className={classes.broadcastIcon} />\n </>\n )}\n {notification.origin && (\n <>\n <Typography\n variant=\"inherit\"\n className={classes.notificationInfoRow}\n >\n {notification.origin}\n </Typography>\n •\n </>\n )}\n {notification.payload.topic && (\n <>\n <Typography\n variant=\"inherit\"\n className={classes.notificationInfoRow}\n >\n {notification.payload.topic}\n </Typography>\n •\n </>\n )}\n {notification.created && (\n <RelativeTime\n value={notification.created}\n className={classes.notificationInfoRow}\n />\n )}\n </Typography>\n </Box>\n </Grid>\n </Grid>\n );\n },\n },\n {\n /* actions column */\n width: '1rem',\n title: showToolbar ? (\n <BulkActions\n notifications={notifications}\n selectedNotifications={selectedNotifications}\n isUnread={isUnread}\n onSwitchReadStatus={onSwitchReadStatus}\n onSwitchSavedStatus={onSwitchSavedStatus}\n onMarkAllRead={onMarkAllRead}\n />\n ) : undefined,\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 notifications,\n selectedNotifications,\n isUnread,\n onSwitchReadStatus,\n onSwitchSavedStatus,\n onMarkAllRead,\n onNotificationsSelectChange,\n classes.severityItem,\n classes.description,\n classes.broadcastIcon,\n classes.notificationInfoRow,\n markAsReadOnLinkOpen,\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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTitleCounter.esm.js","sources":["../../src/hooks/useTitleCounter.ts"],"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 { useCallback, useEffect, useState } from 'react';\nimport throttle from 'lodash/throttle';\n\nconst getPrefix = (value: number) => (value === 0 ? '' : `(${value}) `);\n\nconst cleanTitle = (currentTitle: string) =>\n currentTitle.replace(/^\\(\\d+\\)\\s/, '');\n\nconst throttledSetTitle = throttle((shownTitle: string) => {\n document.title = shownTitle;\n}, 100);\n\n/** @
|
|
1
|
+
{"version":3,"file":"useTitleCounter.esm.js","sources":["../../src/hooks/useTitleCounter.ts"],"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 { useCallback, useEffect, useState } from 'react';\nimport throttle from 'lodash/throttle';\n\nconst getPrefix = (value: number) => (value === 0 ? '' : `(${value}) `);\n\nconst cleanTitle = (currentTitle: string) =>\n currentTitle.replace(/^\\(\\d+\\)\\s/, '');\n\nconst throttledSetTitle = throttle((shownTitle: string) => {\n document.title = shownTitle;\n}, 100);\n\n/** @internal */\nexport function useTitleCounter() {\n const [title, setTitle] = useState(document.title);\n const [count, setCount] = useState(0);\n\n useEffect(() => {\n const baseTitle = cleanTitle(title);\n const shownTitle = `${getPrefix(count)}${baseTitle}`;\n if (document.title !== shownTitle) {\n throttledSetTitle(shownTitle);\n }\n return () => {\n document.title = cleanTitle(title);\n };\n }, [count, title]);\n\n useEffect(() => {\n const titleElement = document.querySelector('title');\n let observer: MutationObserver | undefined;\n if (titleElement) {\n observer = new MutationObserver(mutations => {\n if (mutations?.[0]?.target?.textContent) {\n setTitle(mutations[0].target.textContent);\n }\n });\n observer.observe(titleElement, {\n characterData: true,\n childList: true,\n });\n }\n return () => {\n if (observer) {\n observer.disconnect();\n }\n };\n }, []);\n\n const setNotificationCount = useCallback(\n (newCount: number) => setCount(newCount),\n [],\n );\n\n return { setNotificationCount };\n}\n"],"names":[],"mappings":";;;AAkBA,MAAM,YAAY,CAAC,KAAA,KAAmB,UAAU,CAAI,GAAA,EAAA,GAAK,IAAI,KAAK,CAAA,EAAA,CAAA,CAAA;AAElE,MAAM,aAAa,CAAC,YAAA,KAClB,YAAa,CAAA,OAAA,CAAQ,cAAc,EAAE,CAAA,CAAA;AAEvC,MAAM,iBAAA,GAAoB,QAAS,CAAA,CAAC,UAAuB,KAAA;AACzD,EAAA,QAAA,CAAS,KAAQ,GAAA,UAAA,CAAA;AACnB,CAAA,EAAG,GAAG,CAAA,CAAA;AAGC,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,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,SAAA,GAAY,WAAW,KAAK,CAAA,CAAA;AAClC,IAAA,MAAM,aAAa,CAAG,EAAA,SAAA,CAAU,KAAK,CAAC,GAAG,SAAS,CAAA,CAAA,CAAA;AAClD,IAAI,IAAA,QAAA,CAAS,UAAU,UAAY,EAAA;AACjC,MAAA,iBAAA,CAAkB,UAAU,CAAA,CAAA;AAAA,KAC9B;AACA,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,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,YAAA,GAAe,QAAS,CAAA,aAAA,CAAc,OAAO,CAAA,CAAA;AACnD,IAAI,IAAA,QAAA,CAAA;AACJ,IAAA,IAAI,YAAc,EAAA;AAChB,MAAW,QAAA,GAAA,IAAI,iBAAiB,CAAa,SAAA,KAAA;AAC3C,QAAA,IAAI,SAAY,GAAA,CAAC,CAAG,EAAA,MAAA,EAAQ,WAAa,EAAA;AACvC,UAAA,QAAA,CAAS,SAAU,CAAA,CAAC,CAAE,CAAA,MAAA,CAAO,WAAW,CAAA,CAAA;AAAA,SAC1C;AAAA,OACD,CAAA,CAAA;AACD,MAAA,QAAA,CAAS,QAAQ,YAAc,EAAA;AAAA,QAC7B,aAAe,EAAA,IAAA;AAAA,QACf,SAAW,EAAA,IAAA;AAAA,OACZ,CAAA,CAAA;AAAA,KACH;AACA,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,QAAU,EAAA;AACZ,QAAA,QAAA,CAAS,UAAW,EAAA,CAAA;AAAA,OACtB;AAAA,KACF,CAAA;AAAA,GACF,EAAG,EAAE,CAAA,CAAA;AAEL,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;;;;"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { useState,
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import { useRouteRef, useApi } from '@backstage/core-plugin-api';
|
|
3
|
+
import { notificationsApiRef } from '../api/NotificationsApi.esm.js';
|
|
4
|
+
import '@backstage/errors';
|
|
2
5
|
import { rootRouteRef } from '../routes.esm.js';
|
|
3
|
-
import { useRouteRef } from '@backstage/core-plugin-api';
|
|
4
|
-
import { useNavigate } from 'react-router-dom';
|
|
5
6
|
|
|
6
7
|
function useWebNotifications(enabled) {
|
|
7
8
|
const [webNotificationPermission, setWebNotificationPermission] = useState("default");
|
|
8
|
-
const notificationsRoute = useRouteRef(rootRouteRef);
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const notificationsRoute = useRouteRef(rootRouteRef)();
|
|
10
|
+
const notificationsApi = useApi(notificationsApiRef);
|
|
11
|
+
const requestUserPermission = useCallback(() => {
|
|
11
12
|
if (enabled && "Notification" in window && webNotificationPermission === "default") {
|
|
12
13
|
window.Notification.requestPermission().then((permission) => {
|
|
13
14
|
setWebNotificationPermission(permission);
|
|
@@ -28,16 +29,20 @@ function useWebNotifications(enabled) {
|
|
|
28
29
|
event.preventDefault();
|
|
29
30
|
if (options.link) {
|
|
30
31
|
window.open(options.link, "_blank");
|
|
32
|
+
notificationsApi.updateNotifications({
|
|
33
|
+
ids: [options.id],
|
|
34
|
+
read: true
|
|
35
|
+
});
|
|
31
36
|
} else {
|
|
32
|
-
|
|
37
|
+
window.open(notificationsRoute);
|
|
33
38
|
}
|
|
34
39
|
notification.close();
|
|
35
40
|
};
|
|
36
41
|
return notification;
|
|
37
42
|
},
|
|
38
|
-
[webNotificationPermission,
|
|
43
|
+
[webNotificationPermission, notificationsApi, notificationsRoute]
|
|
39
44
|
);
|
|
40
|
-
return { sendWebNotification };
|
|
45
|
+
return { sendWebNotification, requestUserPermission };
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
export { useWebNotifications };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWebNotifications.esm.js","sources":["../../src/hooks/useWebNotifications.ts"],"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 { useCallback,
|
|
1
|
+
{"version":3,"file":"useWebNotifications.esm.js","sources":["../../src/hooks/useWebNotifications.ts"],"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 { useCallback, useState } from 'react';\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport { notificationsApiRef } from '../api';\nimport { rootRouteRef } from '../routes';\n\n/** @internal */\nexport function useWebNotifications(enabled: boolean) {\n const [webNotificationPermission, setWebNotificationPermission] =\n useState('default');\n const notificationsRoute = useRouteRef(rootRouteRef)();\n const notificationsApi = useApi(notificationsApiRef);\n\n const requestUserPermission = useCallback(() => {\n if (\n enabled &&\n 'Notification' in window &&\n webNotificationPermission === 'default'\n ) {\n window.Notification.requestPermission().then(permission => {\n setWebNotificationPermission(permission);\n });\n }\n }, [enabled, webNotificationPermission]);\n\n const sendWebNotification = useCallback(\n (options: {\n id: string;\n title: string;\n description: string;\n link?: string;\n }) => {\n if (webNotificationPermission !== 'granted') {\n return null;\n }\n\n const notification = new Notification(options.title, {\n body: options.description,\n tag: options.id, // Prevent duplicates from multiple tabs\n });\n\n notification.onclick = event => {\n event.preventDefault();\n if (options.link) {\n window.open(options.link, '_blank');\n notificationsApi.updateNotifications({\n ids: [options.id],\n read: true,\n });\n } else {\n window.open(notificationsRoute);\n }\n notification.close();\n };\n\n return notification;\n },\n [webNotificationPermission, notificationsApi, notificationsRoute],\n );\n\n return { sendWebNotification, requestUserPermission };\n}\n"],"names":[],"mappings":";;;;;;AAqBO,SAAS,oBAAoB,OAAkB,EAAA;AACpD,EAAA,MAAM,CAAC,yBAAA,EAA2B,4BAA4B,CAAA,GAC5D,SAAS,SAAS,CAAA,CAAA;AACpB,EAAM,MAAA,kBAAA,GAAqB,WAAY,CAAA,YAAY,CAAE,EAAA,CAAA;AACrD,EAAM,MAAA,gBAAA,GAAmB,OAAO,mBAAmB,CAAA,CAAA;AAEnD,EAAM,MAAA,qBAAA,GAAwB,YAAY,MAAM;AAC9C,IAAA,IACE,OACA,IAAA,cAAA,IAAkB,MAClB,IAAA,yBAAA,KAA8B,SAC9B,EAAA;AACA,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,GACC,EAAA,CAAC,OAAS,EAAA,yBAAyB,CAAC,CAAA,CAAA;AAEvC,EAAA,MAAM,mBAAsB,GAAA,WAAA;AAAA,IAC1B,CAAC,OAKK,KAAA;AACJ,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,QACd,KAAK,OAAQ,CAAA,EAAA;AAAA;AAAA,OACd,CAAA,CAAA;AAED,MAAA,YAAA,CAAa,UAAU,CAAS,KAAA,KAAA;AAC9B,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,UAAO,MAAA,CAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,EAAM,QAAQ,CAAA,CAAA;AAClC,UAAA,gBAAA,CAAiB,mBAAoB,CAAA;AAAA,YACnC,GAAA,EAAK,CAAC,OAAA,CAAQ,EAAE,CAAA;AAAA,YAChB,IAAM,EAAA,IAAA;AAAA,WACP,CAAA,CAAA;AAAA,SACI,MAAA;AACL,UAAA,MAAA,CAAO,KAAK,kBAAkB,CAAA,CAAA;AAAA,SAChC;AACA,QAAA,YAAA,CAAa,KAAM,EAAA,CAAA;AAAA,OACrB,CAAA;AAEA,MAAO,OAAA,YAAA,CAAA;AAAA,KACT;AAAA,IACA,CAAC,yBAA2B,EAAA,gBAAA,EAAkB,kBAAkB,CAAA;AAAA,GAClE,CAAA;AAEA,EAAO,OAAA,EAAE,qBAAqB,qBAAsB,EAAA,CAAA;AACtD;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import React__default from 'react';
|
|
4
4
|
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
5
5
|
import { DiscoveryApi, FetchApi, IconComponent } from '@backstage/core-plugin-api';
|
|
6
|
-
import { NotificationSeverity, Notification
|
|
6
|
+
import { NotificationSeverity, Notification, NotificationStatus } from '@backstage/plugin-notifications-common';
|
|
7
7
|
import { TableProps } from '@backstage/core-components';
|
|
8
8
|
|
|
9
9
|
/** @public */
|
|
@@ -47,15 +47,15 @@ type UpdateNotificationsOptions = {
|
|
|
47
47
|
};
|
|
48
48
|
/** @public */
|
|
49
49
|
type GetNotificationsResponse = {
|
|
50
|
-
notifications: Notification
|
|
50
|
+
notifications: Notification[];
|
|
51
51
|
totalCount: number;
|
|
52
52
|
};
|
|
53
53
|
/** @public */
|
|
54
54
|
interface NotificationsApi {
|
|
55
55
|
getNotifications(options?: GetNotificationsOptions): Promise<GetNotificationsResponse>;
|
|
56
|
-
getNotification(id: string): Promise<Notification
|
|
56
|
+
getNotification(id: string): Promise<Notification>;
|
|
57
57
|
getStatus(): Promise<NotificationStatus>;
|
|
58
|
-
updateNotifications(options: UpdateNotificationsOptions): Promise<Notification
|
|
58
|
+
updateNotifications(options: UpdateNotificationsOptions): Promise<Notification[]>;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/** @public */
|
|
@@ -67,9 +67,9 @@ declare class NotificationsClient implements NotificationsApi {
|
|
|
67
67
|
fetchApi: FetchApi;
|
|
68
68
|
});
|
|
69
69
|
getNotifications(options?: GetNotificationsOptions): Promise<GetNotificationsResponse>;
|
|
70
|
-
getNotification(id: string): Promise<Notification
|
|
70
|
+
getNotification(id: string): Promise<Notification>;
|
|
71
71
|
getStatus(): Promise<NotificationStatus>;
|
|
72
|
-
updateNotifications(options: UpdateNotificationsOptions): Promise<Notification
|
|
72
|
+
updateNotifications(options: UpdateNotificationsOptions): Promise<Notification[]>;
|
|
73
73
|
private request;
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -96,21 +96,6 @@ declare function useNotificationsApi<T>(f: (api: NotificationsApi) => Promise<T>
|
|
|
96
96
|
value: T;
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
/** @public */
|
|
100
|
-
declare function useWebNotifications(enabled: boolean): {
|
|
101
|
-
sendWebNotification: (options: {
|
|
102
|
-
id: string;
|
|
103
|
-
title: string;
|
|
104
|
-
description: string;
|
|
105
|
-
link?: string;
|
|
106
|
-
}) => Notification | null;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
/** @public */
|
|
110
|
-
declare function useTitleCounter(): {
|
|
111
|
-
setNotificationCount: (newCount: number) => void;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
99
|
declare module 'notistack' {
|
|
115
100
|
interface VariantOverrides {
|
|
116
101
|
low: true;
|
|
@@ -137,7 +122,7 @@ type NotificationsTableProps = Pick<TableProps, 'onPageChange' | 'onRowsPerPageC
|
|
|
137
122
|
markAsReadOnLinkOpen?: boolean;
|
|
138
123
|
isLoading?: boolean;
|
|
139
124
|
isUnread: boolean;
|
|
140
|
-
notifications?: Notification
|
|
125
|
+
notifications?: Notification[];
|
|
141
126
|
onUpdate: () => void;
|
|
142
127
|
setContainsText: (search: string) => void;
|
|
143
128
|
pageSize: number;
|
|
@@ -145,4 +130,4 @@ type NotificationsTableProps = Pick<TableProps, 'onPageChange' | 'onRowsPerPageC
|
|
|
145
130
|
/** @public */
|
|
146
131
|
declare const NotificationsTable: ({ markAsReadOnLinkOpen, isLoading, notifications, isUnread, onUpdate, setContainsText, onPageChange, onRowsPerPageChange, page, pageSize, totalCount, }: NotificationsTableProps) => React__default.JSX.Element;
|
|
147
132
|
|
|
148
|
-
export { type GetNotificationsOptions, type GetNotificationsResponse, type NotificationsApi, NotificationsClient, NotificationsPage, type NotificationsPageProps, NotificationsSidebarItem, NotificationsTable, type NotificationsTableProps, type UpdateNotificationsOptions, notificationsApiRef, notificationsPlugin, useNotificationsApi
|
|
133
|
+
export { type GetNotificationsOptions, type GetNotificationsResponse, type NotificationsApi, NotificationsClient, NotificationsPage, type NotificationsPageProps, NotificationsSidebarItem, NotificationsTable, type NotificationsTableProps, type UpdateNotificationsOptions, notificationsApiRef, notificationsPlugin, useNotificationsApi };
|
package/dist/index.esm.js
CHANGED
|
@@ -2,8 +2,10 @@ export { NotificationsPage, notificationsPlugin } from './plugin.esm.js';
|
|
|
2
2
|
export { notificationsApiRef } from './api/NotificationsApi.esm.js';
|
|
3
3
|
export { NotificationsClient } from './api/NotificationsClient.esm.js';
|
|
4
4
|
export { useNotificationsApi } from './hooks/useNotificationsApi.esm.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import 'react';
|
|
6
|
+
import '@backstage/core-plugin-api';
|
|
7
|
+
import './routes.esm.js';
|
|
8
|
+
import './hooks/useTitleCounter.esm.js';
|
|
7
9
|
export { NotificationsSidebarItem } from './components/NotificationsSideBarItem/NotificationsSideBarItem.esm.js';
|
|
8
10
|
export { NotificationsTable } from './components/NotificationsTable/NotificationsTable.esm.js';
|
|
9
11
|
//# sourceMappingURL=index.esm.js.map
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-notifications",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"backstage": {
|
|
5
5
|
"role": "frontend-plugin",
|
|
6
6
|
"pluginId": "notifications",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"test": "backstage-cli package test"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@backstage/core-components": "^0.14.10
|
|
41
|
+
"@backstage/core-components": "^0.14.10",
|
|
42
42
|
"@backstage/core-plugin-api": "^1.9.3",
|
|
43
43
|
"@backstage/errors": "^1.2.4",
|
|
44
44
|
"@backstage/plugin-notifications-common": "^0.0.5",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"react-use": "^17.2.4"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@backstage/cli": "^0.27.0
|
|
60
|
-
"@backstage/core-app-api": "^1.14.
|
|
61
|
-
"@backstage/dev-utils": "^1.0.
|
|
62
|
-
"@backstage/plugin-signals": "^0.0.9
|
|
63
|
-
"@backstage/test-utils": "^1.5.
|
|
59
|
+
"@backstage/cli": "^0.27.0",
|
|
60
|
+
"@backstage/core-app-api": "^1.14.2",
|
|
61
|
+
"@backstage/dev-utils": "^1.0.37",
|
|
62
|
+
"@backstage/plugin-signals": "^0.0.9",
|
|
63
|
+
"@backstage/test-utils": "^1.5.10",
|
|
64
64
|
"@testing-library/jest-dom": "^6.0.0",
|
|
65
65
|
"@testing-library/react": "^15.0.0",
|
|
66
66
|
"@testing-library/user-event": "^14.0.0",
|