Skip to content

Commit dbfd016

Browse files
committed
Notification demo
Signed-off-by: Andre Wanlin <[email protected]> Added settings and test button Signed-off-by: Andre Wanlin <[email protected]> Refactored based on feedback Signed-off-by: Andre Wanlin <[email protected]> Updated lock file Signed-off-by: Andre Wanlin <[email protected]> clean up Signed-off-by: Andre Wanlin <[email protected]> Fix knip errors Signed-off-by: Andre Wanlin <[email protected]> Fixed lock file Signed-off-by: Andre Wanlin <[email protected]> Removed test Signed-off-by: Andre Wanlin <[email protected]> Fix knip again Signed-off-by: Andre Wanlin <[email protected]>
1 parent 5917349 commit dbfd016

File tree

17 files changed

+311
-5
lines changed

17 files changed

+311
-5
lines changed

app-config.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,6 @@ explore:
173173
url: '/graphiql'
174174
image: '/graphiql.png'
175175
tags: ['graphql', 'dev']
176+
177+
notificationsTester:
178+
enabled: true

demo-template/template/template.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ spec:
151151
workflowId: pages.yml
152152
branchOrTagName: main
153153
token: ${{ secrets.USER_OAUTH_TOKEN or false }}
154+
- id: notify
155+
name: Notify
156+
action: notification:send
157+
input:
158+
recipients: entity
159+
entityRefs:
160+
- user:default/guest
161+
title: 'Template executed'
162+
info: 'Your template has been executed'
163+
severity: 'normal'
154164

155165
output:
156166
links:

packages/app/config.d.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface Config {
2+
/**
3+
* @visibility frontend
4+
*/
5+
notificationsTester?: {
6+
/**
7+
* Flag to enable or disable the tester
8+
* Default is enabled
9+
*
10+
* @visibility frontend
11+
*/
12+
enabled: boolean;
13+
};
14+
}

packages/app/package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,10 @@
7575
"last 1 firefox version",
7676
"last 1 safari version"
7777
]
78-
}
78+
},
79+
"files": [
80+
"dist",
81+
"config.d.ts"
82+
],
83+
"configSchema": "config.d.ts"
7984
}

packages/app/src/App.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ import React from 'react';
3535
import { Root } from './components/Root';
3636
import { SearchPage } from '@backstage/plugin-search';
3737
import { TechRadarPage } from '@backstage-community/plugin-tech-radar';
38-
import { UserSettingsPage } from '@backstage/plugin-user-settings';
38+
import {
39+
SettingsLayout,
40+
UserSettingsPage,
41+
} from '@backstage/plugin-user-settings';
3942
import { apertureTheme } from './theme/aperture';
4043
import { apis } from './apis';
4144
import { createApp } from '@backstage/app-defaults';
@@ -57,6 +60,7 @@ import {
5760
} from '@backstage/plugin-techdocs-module-addons-contrib';
5861
import { Mermaid } from 'backstage-plugin-techdocs-addon-mermaid';
5962
import { SignalsDisplay } from '@backstage/plugin-signals';
63+
import { NotificationSettings } from './components/settings/NotificationSettings';
6064

6165
const app = createApp({
6266
apis,
@@ -169,7 +173,11 @@ const routes = (
169173
<Route path="/search" element={<SearchPage />}>
170174
{searchPage}
171175
</Route>
172-
<Route path="/settings" element={<UserSettingsPage />} />
176+
<Route path="/settings" element={<UserSettingsPage />}>
177+
<SettingsLayout.Route path="/notifications" title="Notifications">
178+
<NotificationSettings />
179+
</SettingsLayout.Route>
180+
</Route>
173181
<Route
174182
path="/tech-radar"
175183
element={<TechRadarPage width={1500} height={800} />}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Box, Button, Grid, Typography } from '@material-ui/core';
2+
import {
3+
configApiRef,
4+
discoveryApiRef,
5+
errorApiRef,
6+
fetchApiRef,
7+
useApi,
8+
} from '@backstage/core-plugin-api';
9+
10+
import { InfoCard } from '@backstage/core-components';
11+
import React from 'react';
12+
import { UserNotificationSettingsCard } from '@backstage/plugin-notifications';
13+
14+
export const NotificationSettings = () => {
15+
const config = useApi(configApiRef);
16+
const fetchApi = useApi(fetchApiRef);
17+
const discovery = useApi(discoveryApiRef);
18+
const errorApi = useApi(errorApiRef);
19+
20+
const isEnabled =
21+
config.getOptionalBoolean('notificationsTester.enabled') ?? true;
22+
23+
const handleNotifyClick = async () => {
24+
const notificationTesterUrl = await discovery.getBaseUrl(
25+
'notifications-tester',
26+
);
27+
const response = await fetchApi.fetch(`${notificationTesterUrl}/test`, {
28+
method: 'POST',
29+
});
30+
if (!response.ok) {
31+
errorApi.post(
32+
new Error(`Failed to send notification: ${response.status}`),
33+
);
34+
}
35+
};
36+
37+
return (
38+
<Grid container justifyContent="center" spacing={2}>
39+
<Grid item xs={9}>
40+
<UserNotificationSettingsCard
41+
originNames={{ 'plugin:scaffolder': 'Scaffolder' }}
42+
/>
43+
</Grid>
44+
{isEnabled && (
45+
<Grid item xs={3}>
46+
<InfoCard title="Send Test Notification">
47+
<Button
48+
variant="contained"
49+
color="primary"
50+
onClick={async () => await handleNotifyClick()}
51+
>
52+
Notify
53+
</Button>
54+
<Box pt={2}>
55+
<Typography variant="subtitle2">
56+
Note: this card is not part of the default Notifications Setting
57+
and was added to be able to try out the Notification system for
58+
this Demo site.
59+
</Typography>
60+
</Box>
61+
</InfoCard>
62+
</Grid>
63+
)}
64+
</Grid>
65+
);
66+
};

packages/backend/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@backstage/plugin-proxy-backend": "backstage:^",
3535
"@backstage/plugin-scaffolder-backend": "backstage:^",
3636
"@backstage/plugin-scaffolder-backend-module-github": "backstage:^",
37+
"@backstage/plugin-scaffolder-backend-module-notifications": "^0.1.8",
3738
"@backstage/plugin-search-backend": "backstage:^",
3839
"@backstage/plugin-search-backend-module-catalog": "backstage:^",
3940
"@backstage/plugin-search-backend-module-explore": "backstage:^",
@@ -43,6 +44,7 @@
4344
"@frontside/backstage-plugin-graphql-backend": "^0.1.2",
4445
"@frontside/backstage-plugin-graphql-backend-module-catalog": "^0.3.0",
4546
"@internal/plugin-catalog-backend-module-backstage": "workspace:^",
47+
"@internal/plugin-notifications-tester-backend": "workspace:^",
4648
"app": "^0.0.0",
4749
"better-sqlite3": "^11.0.0"
4850
},

packages/backend/src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ backend.add(import('@backstage/plugin-kubernetes-backend'));
2424
backend.add(import('@backstage/plugin-proxy-backend'));
2525
backend.add(import('@backstage/plugin-scaffolder-backend'));
2626
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
27+
backend.add(
28+
import('@backstage/plugin-scaffolder-backend-module-notifications'),
29+
);
2730
backend.add(import('@backstage/plugin-search-backend'));
2831
backend.add(import('@backstage/plugin-search-backend-module-catalog'));
2932
backend.add(import('@backstage/plugin-search-backend-module-explore'));
@@ -40,4 +43,5 @@ backend.add(import('@backstage/plugin-events-backend'));
4043
backend.add(import('@backstage/plugin-signals-backend'));
4144
backend.add(import('@backstage/plugin-notifications-backend'));
4245

46+
backend.add(import('@internal/plugin-notifications-tester-backend'));
4347
backend.start();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# notifications-tester
2+
3+
This plugin backend was templated using the Backstage CLI. You should replace this text with a description of your plugin backend.
4+
5+
## Installation
6+
7+
This plugin is installed via the `@internal/plugin-notifications-tester-backend` package. To install it to your backend package, run the following command:
8+
9+
```bash
10+
# From your root directory
11+
yarn --cwd packages/backend add @internal/plugin-notifications-tester-backend
12+
```
13+
14+
Then add the plugin to your backend in `packages/backend/src/index.ts`:
15+
16+
```ts
17+
const backend = createBackend();
18+
// ...
19+
backend.add(import('@internal/plugin-notifications-tester-backend'));
20+
```
21+
22+
## Development
23+
24+
This plugin backend can be started in a standalone mode from directly in this
25+
package with `yarn start`. It is a limited setup that is most convenient when
26+
developing the plugin backend itself.
27+
28+
If you want to run the entire project, including the frontend, run `yarn dev` from the root directory.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface Config {
2+
/**
3+
* @visibility frontend
4+
*/
5+
notificationsTester?: {
6+
/**
7+
* Flag to enable or disable the tester
8+
* Default is enabled
9+
*
10+
* @visibility frontend
11+
*/
12+
enabled: boolean;
13+
};
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@internal/plugin-notifications-tester-backend",
3+
"version": "0.1.0",
4+
"license": "Apache-2.0",
5+
"private": true,
6+
"main": "src/index.ts",
7+
"types": "src/index.ts",
8+
"publishConfig": {
9+
"access": "public",
10+
"main": "dist/index.cjs.js",
11+
"types": "dist/index.d.ts"
12+
},
13+
"backstage": {
14+
"role": "backend-plugin"
15+
},
16+
"scripts": {
17+
"start": "backstage-cli package start",
18+
"build": "backstage-cli package build",
19+
"lint": "backstage-cli package lint",
20+
"test": "backstage-cli package test",
21+
"clean": "backstage-cli package clean",
22+
"prepack": "backstage-cli package prepack",
23+
"postpack": "backstage-cli package postpack"
24+
},
25+
"dependencies": {
26+
"@backstage/backend-plugin-api": "^1.2.1",
27+
"@backstage/config": "^1.3.2",
28+
"@backstage/plugin-notifications-node": "^0.2.13",
29+
"express": "^4.17.1",
30+
"express-promise-router": "^4.1.0"
31+
},
32+
"devDependencies": {
33+
"@backstage/cli": "^0.31.0",
34+
"@types/express": "^4.17.6"
35+
},
36+
"files": [
37+
"dist",
38+
"config.d.ts"
39+
],
40+
"configSchema": "config.d.ts"
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { notificationsTesterPlugin as default } from './plugin';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
coreServices,
3+
createBackendPlugin,
4+
} from '@backstage/backend-plugin-api';
5+
import { createRouter } from './router';
6+
import { notificationService } from '@backstage/plugin-notifications-node';
7+
8+
/**
9+
* notificationsTesterPlugin backend plugin
10+
*
11+
* @public
12+
*/
13+
export const notificationsTesterPlugin = createBackendPlugin({
14+
pluginId: 'notifications-tester',
15+
register(env) {
16+
env.registerInit({
17+
deps: {
18+
config: coreServices.rootConfig,
19+
logger: coreServices.logger,
20+
httpRouter: coreServices.httpRouter,
21+
notifications: notificationService,
22+
},
23+
async init({ config, logger, notifications, httpRouter }) {
24+
httpRouter.use(
25+
await createRouter({
26+
config,
27+
logger,
28+
notifications,
29+
}),
30+
);
31+
},
32+
});
33+
},
34+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Config } from '@backstage/config';
2+
import { LoggerService } from '@backstage/backend-plugin-api';
3+
import {
4+
NotificationSendOptions,
5+
NotificationService,
6+
} from '@backstage/plugin-notifications-node';
7+
8+
import express from 'express';
9+
import Router from 'express-promise-router';
10+
11+
const TEST_NOTIFICATION: NotificationSendOptions = {
12+
recipients: { type: 'entity', entityRef: 'user:default/guest' },
13+
payload: {
14+
title: 'Test Notification',
15+
severity: 'normal',
16+
topic: 'Sending Test',
17+
},
18+
};
19+
20+
export async function createRouter({
21+
config,
22+
logger,
23+
notifications,
24+
}: {
25+
config: Config;
26+
logger: LoggerService;
27+
notifications: NotificationService;
28+
}): Promise<express.Router> {
29+
const router = Router();
30+
router.use(express.json());
31+
32+
router.post('/test', async (_req, res) => {
33+
if (config.getBoolean('notificationsTester.enabled')) {
34+
logger.info(`Sending test notification`);
35+
notifications.send(TEST_NOTIFICATION);
36+
} else {
37+
logger.info(`Tested currently disabled, no notification sent`);
38+
}
39+
40+
res.status(200);
41+
});
42+
43+
return router;
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

0 commit comments

Comments
 (0)