@backstage/cli 0.33.2-next.0 → 0.34.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/lib/version.cjs.js +20 -14
  3. package/dist/packages/cli/package.json.cjs.js +1 -1
  4. package/dist/packages/core-components/package.json.cjs.js +1 -1
  5. package/dist/packages/frontend-defaults/package.json.cjs.js +6 -0
  6. package/dist/packages/frontend-plugin-api/package.json.cjs.js +6 -0
  7. package/dist/packages/frontend-test-utils/package.json.cjs.js +6 -0
  8. package/package.json +2 -2
  9. package/templates/new-frontend-plugin/.eslintrc.js.hbs +1 -0
  10. package/templates/new-frontend-plugin/README.md.hbs +20 -0
  11. package/templates/new-frontend-plugin/dev/index.tsx +10 -0
  12. package/templates/new-frontend-plugin/package.json.hbs +49 -0
  13. package/templates/new-frontend-plugin/portable-template.yaml +5 -0
  14. package/templates/new-frontend-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs +28 -0
  15. package/templates/new-frontend-plugin/src/components/ExampleComponent/ExampleComponent.tsx.hbs +37 -0
  16. package/templates/new-frontend-plugin/src/components/ExampleComponent/index.ts +1 -0
  17. package/templates/new-frontend-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx.hbs +19 -0
  18. package/templates/new-frontend-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx.hbs +308 -0
  19. package/templates/new-frontend-plugin/src/components/ExampleFetchComponent/index.ts +1 -0
  20. package/templates/new-frontend-plugin/src/index.ts.hbs +1 -0
  21. package/templates/new-frontend-plugin/src/plugin.test.ts.hbs +7 -0
  22. package/templates/new-frontend-plugin/src/plugin.tsx.hbs +26 -0
  23. package/templates/new-frontend-plugin/src/routes.ts +3 -0
  24. package/templates/new-frontend-plugin/src/setupTests.ts +1 -0
  25. package/templates/new-frontend-plugin-module/.eslintrc.js.hbs +1 -0
  26. package/templates/new-frontend-plugin-module/README.md.hbs +5 -0
  27. package/templates/new-frontend-plugin-module/package.json.hbs +35 -0
  28. package/templates/new-frontend-plugin-module/portable-template.yaml +5 -0
  29. package/templates/new-frontend-plugin-module/src/index.ts.hbs +1 -0
  30. package/templates/new-frontend-plugin-module/src/module.tsx.hbs +8 -0
  31. package/templates/new-frontend-plugin-module/src/setupTests.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @backstage/cli
2
2
 
3
+ ## 0.34.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - 38b4243: Added plugin and module templates for the new frontend system. These templates are not included by default, but can be included by adding `@backstage/cli/templates/new-frontend-plugin` and `@backstage/cli/templates/new-frontend-plugin-module` as [custom templates](https://backstage.io/docs/tooling/cli/templates#installing-custom-templates).
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/catalog-model@1.7.5
13
+ - @backstage/cli-common@0.1.15
14
+ - @backstage/cli-node@0.2.13
15
+ - @backstage/config@1.3.3
16
+ - @backstage/config-loader@1.10.2
17
+ - @backstage/errors@1.2.7
18
+ - @backstage/eslint-plugin@0.1.11
19
+ - @backstage/integration@1.17.1
20
+ - @backstage/release-manifests@0.0.13
21
+ - @backstage/types@1.2.1
22
+
3
23
  ## 0.33.2-next.0
4
24
 
5
25
  ### Patch Changes
@@ -13,13 +13,16 @@ var _package$7 = require('../packages/core-components/package.json.cjs.js');
13
13
  var _package$8 = require('../packages/core-plugin-api/package.json.cjs.js');
14
14
  var _package$9 = require('../packages/dev-utils/package.json.cjs.js');
15
15
  var _package$a = require('../packages/errors/package.json.cjs.js');
16
- var _package$b = require('../packages/test-utils/package.json.cjs.js');
17
- var _package$d = require('../plugins/scaffolder-node/package.json.cjs.js');
18
- var _package$e = require('../plugins/scaffolder-node-test-utils/package.json.cjs.js');
19
- var _package$f = require('../plugins/auth-backend/package.json.cjs.js');
20
- var _package$g = require('../plugins/auth-backend-module-guest-provider/package.json.cjs.js');
21
- var _package$h = require('../plugins/catalog-node/package.json.cjs.js');
22
- var _package$c = require('../packages/theme/package.json.cjs.js');
16
+ var _package$b = require('../packages/frontend-defaults/package.json.cjs.js');
17
+ var _package$c = require('../packages/frontend-plugin-api/package.json.cjs.js');
18
+ var _package$d = require('../packages/frontend-test-utils/package.json.cjs.js');
19
+ var _package$e = require('../packages/test-utils/package.json.cjs.js');
20
+ var _package$g = require('../plugins/scaffolder-node/package.json.cjs.js');
21
+ var _package$h = require('../plugins/scaffolder-node-test-utils/package.json.cjs.js');
22
+ var _package$i = require('../plugins/auth-backend/package.json.cjs.js');
23
+ var _package$j = require('../plugins/auth-backend-module-guest-provider/package.json.cjs.js');
24
+ var _package$k = require('../plugins/catalog-node/package.json.cjs.js');
25
+ var _package$f = require('../packages/theme/package.json.cjs.js');
23
26
  var _package = require('../packages/backend-defaults/package.json.cjs.js');
24
27
 
25
28
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -39,13 +42,16 @@ const packageVersions = {
39
42
  "@backstage/core-plugin-api": _package$8.version,
40
43
  "@backstage/dev-utils": _package$9.version,
41
44
  "@backstage/errors": _package$a.version,
42
- "@backstage/test-utils": _package$b.version,
43
- "@backstage/theme": _package$c.version,
44
- "@backstage/plugin-scaffolder-node": _package$d.version,
45
- "@backstage/plugin-scaffolder-node-test-utils": _package$e.version,
46
- "@backstage/plugin-auth-backend": _package$f.version,
47
- "@backstage/plugin-auth-backend-module-guest-provider": _package$g.version,
48
- "@backstage/plugin-catalog-node": _package$h.version
45
+ "@backstage/frontend-defaults": _package$b.version,
46
+ "@backstage/frontend-plugin-api": _package$c.version,
47
+ "@backstage/frontend-test-utils": _package$d.version,
48
+ "@backstage/test-utils": _package$e.version,
49
+ "@backstage/theme": _package$f.version,
50
+ "@backstage/plugin-scaffolder-node": _package$g.version,
51
+ "@backstage/plugin-scaffolder-node-test-utils": _package$h.version,
52
+ "@backstage/plugin-auth-backend": _package$i.version,
53
+ "@backstage/plugin-auth-backend-module-guest-provider": _package$j.version,
54
+ "@backstage/plugin-catalog-node": _package$k.version
49
55
  };
50
56
  function findVersion() {
51
57
  const pkgContent = fs__default.default.readFileSync(paths.paths.resolveOwn("package.json"), "utf8");
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.33.2-next.0";
3
+ var version = "0.34.0-next.1";
4
4
  var dependencies = {
5
5
  "@backstage/catalog-model": "workspace:^",
6
6
  "@backstage/cli-common": "workspace:^",
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var version = "0.17.5-next.0";
3
+ var version = "0.17.5-next.1";
4
4
 
5
5
  exports.version = version;
6
6
  //# sourceMappingURL=package.json.cjs.js.map
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ var version = "0.3.0-next.2";
4
+
5
+ exports.version = version;
6
+ //# sourceMappingURL=package.json.cjs.js.map
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ var version = "0.11.0-next.1";
4
+
5
+ exports.version = version;
6
+ //# sourceMappingURL=package.json.cjs.js.map
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ var version = "0.3.5-next.2";
4
+
5
+ exports.version = version;
6
+ //# sourceMappingURL=package.json.cjs.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/cli",
3
- "version": "0.33.2-next.0",
3
+ "version": "0.34.0-next.1",
4
4
  "description": "CLI for developing Backstage plugins and apps",
5
5
  "backstage": {
6
6
  "role": "cli"
@@ -168,7 +168,7 @@
168
168
  "@backstage/catalog-client": "1.11.0-next.0",
169
169
  "@backstage/config": "1.3.3",
170
170
  "@backstage/core-app-api": "1.18.0",
171
- "@backstage/core-components": "0.17.5-next.0",
171
+ "@backstage/core-components": "0.17.5-next.1",
172
172
  "@backstage/core-plugin-api": "1.10.9",
173
173
  "@backstage/dev-utils": "1.1.13-next.1",
174
174
  "@backstage/errors": "1.2.7",
@@ -0,0 +1 @@
1
+ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,20 @@
1
+ # {{pluginId}}
2
+
3
+ Welcome to the {{pluginId}} plugin!
4
+
5
+ _This plugin was created through the Backstage CLI_
6
+
7
+ ## Getting started
8
+
9
+ Your plugin has been added to the app in this repository, meaning you'll be able
10
+ to access it by running `yarn start` in the root directory, and then navigating
11
+ to [/{{pluginId}}](http://localhost:3000/{{pluginId}}).
12
+
13
+ This plugin is built with Backstage's [new frontend
14
+ system](https://backstage.io/docs/frontend-system/architecture/index), and you
15
+ can find more information about building plugins in the [plugin builder
16
+ documentation](https://backstage.io/docs/frontend-system/building-plugins/index).
17
+
18
+ You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
19
+ This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
20
+ It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
@@ -0,0 +1,10 @@
1
+ import { createApp } from '@backstage/frontend-defaults';
2
+ import ReactDOM from 'react-dom';
3
+
4
+ import plugin from '../src';
5
+
6
+ const app = createApp({
7
+ features: [plugin],
8
+ });
9
+
10
+ ReactDOM.render(app.createRoot(), document.getElementById('root'));
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "main": "src/index.ts",
4
+ "types": "src/index.ts",
5
+ "publishConfig": {
6
+ "access": "public",
7
+ "main": "dist/index.esm.js",
8
+ "types": "dist/index.d.ts"
9
+ },
10
+ "backstage": {
11
+ "role": "frontend-plugin",
12
+ "pluginId": "{{pluginId}}"
13
+ },
14
+ "sideEffects": false,
15
+ "scripts": {
16
+ "start": "backstage-cli package start",
17
+ "build": "backstage-cli package build",
18
+ "lint": "backstage-cli package lint",
19
+ "test": "backstage-cli package test",
20
+ "clean": "backstage-cli package clean",
21
+ "prepack": "backstage-cli package prepack",
22
+ "postpack": "backstage-cli package postpack"
23
+ },
24
+ "dependencies": {
25
+ "@backstage/core-components": "{{versionQuery '@backstage/core-components'}}",
26
+ "@backstage/frontend-plugin-api": "{{versionQuery '@backstage/frontend-plugin-api'}}",
27
+ "@backstage/theme": "{{versionQuery '@backstage/theme'}}",
28
+ "@material-ui/core": "{{versionQuery '@material-ui/core' '4.12.2'}}",
29
+ "@material-ui/icons": "{{versionQuery '@material-ui/icons' '4.9.1'}}",
30
+ "@material-ui/lab": "{{versionQuery '@material-ui/lab' '4.0.0-alpha.61'}}",
31
+ "react-use": "{{versionQuery 'react-use' '17.2.4'}}"
32
+ },
33
+ "peerDependencies": {
34
+ "react": "{{versionQuery 'react' '^16.13.1 || ^17.0.0 || ^18.0.0'}}"
35
+ },
36
+ "devDependencies": {
37
+ "@backstage/cli": "{{versionQuery '@backstage/cli'}}",
38
+ "@backstage/frontend-defaults": "{{versionQuery '@backstage/frontend-defaults'}}",
39
+ "@backstage/frontend-test-utils": "{{versionQuery '@backstage/frontend-test-utils'}}",
40
+ "@testing-library/jest-dom": "{{versionQuery '@testing-library/jest-dom' '6.0.0'}}",
41
+ "@testing-library/react": "{{versionQuery '@testing-library/react' '14.0.0'}}",
42
+ "@testing-library/user-event": "{{versionQuery '@testing-library/user-event' '14.0.0'}}",
43
+ "msw": "{{versionQuery 'msw' '1.0.0'}}",
44
+ "react": "{{versionQuery 'react' '^16.13.1 || ^17.0.0 || ^18.0.0'}}"
45
+ },
46
+ "files": [
47
+ "dist"
48
+ ]
49
+ }
@@ -0,0 +1,5 @@
1
+ name: frontend-plugin
2
+ role: frontend-plugin
3
+ description: A new frontend plugin
4
+ values:
5
+ pluginVar: '{{ camelCase pluginId }}Plugin'
@@ -0,0 +1,28 @@
1
+ import { ExampleComponent } from './ExampleComponent';
2
+ import { rest } from 'msw';
3
+ import { setupServer } from 'msw/node';
4
+ import { screen } from '@testing-library/react';
5
+ import {
6
+ registerMswTestHooks,
7
+ renderInTestApp,
8
+ } from '@backstage/frontend-test-utils';
9
+
10
+ describe('ExampleComponent', () => {
11
+ const server = setupServer();
12
+ // Enable sane handlers for network requests
13
+ registerMswTestHooks(server);
14
+
15
+ // setup mock response
16
+ beforeEach(() => {
17
+ server.use(
18
+ rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))),
19
+ );
20
+ });
21
+
22
+ it('should render', async () => {
23
+ await renderInTestApp(<ExampleComponent />);
24
+ expect(
25
+ screen.getByText('Welcome to {{pluginId}}!'),
26
+ ).toBeInTheDocument();
27
+ });
28
+ });
@@ -0,0 +1,37 @@
1
+ import { Typography, Grid } from '@material-ui/core';
2
+ import {
3
+ InfoCard,
4
+ Header,
5
+ Page,
6
+ Content,
7
+ ContentHeader,
8
+ HeaderLabel,
9
+ SupportButton,
10
+ } from '@backstage/core-components';
11
+ import { ExampleFetchComponent } from '../ExampleFetchComponent';
12
+
13
+ export const ExampleComponent = () => (
14
+ <Page themeId="tool">
15
+ <Header title="Welcome to {{pluginId}}!" subtitle="Optional subtitle">
16
+ <HeaderLabel label="Owner" value="Team X" />
17
+ <HeaderLabel label="Lifecycle" value="Alpha" />
18
+ </Header>
19
+ <Content>
20
+ <ContentHeader title="Plugin title">
21
+ <SupportButton>A description of your plugin goes here.</SupportButton>
22
+ </ContentHeader>
23
+ <Grid container spacing={3} direction="column">
24
+ <Grid item>
25
+ <InfoCard title="Information card">
26
+ <Typography variant="body1">
27
+ All content should be wrapped in a card like this.
28
+ </Typography>
29
+ </InfoCard>
30
+ </Grid>
31
+ <Grid item>
32
+ <ExampleFetchComponent />
33
+ </Grid>
34
+ </Grid>
35
+ </Content>
36
+ </Page>
37
+ );
@@ -0,0 +1 @@
1
+ export { ExampleComponent } from './ExampleComponent';
@@ -0,0 +1,19 @@
1
+ import { renderInTestApp } from '@backstage/frontend-test-utils';
2
+ import { ExampleFetchComponent } from './ExampleFetchComponent';
3
+
4
+ describe('ExampleFetchComponent', () => {
5
+ it('renders the user table', async () => {
6
+ const { getAllByText, getByAltText, getByText, findByRole } =
7
+ await renderInTestApp(<ExampleFetchComponent />);
8
+
9
+ // Wait for the table to render
10
+ const table = await findByRole('table');
11
+ const nationality = getAllByText('GB');
12
+ // Assert that the table contains the expected user data
13
+ expect(table).toBeInTheDocument();
14
+ expect(getByAltText('Carolyn')).toBeInTheDocument();
15
+ expect(getByText('Carolyn Moore')).toBeInTheDocument();
16
+ expect(getByText('carolyn.moore@example.com')).toBeInTheDocument();
17
+ expect(nationality[0]).toBeInTheDocument();
18
+ });
19
+ });
@@ -0,0 +1,308 @@
1
+ import { makeStyles } from '@material-ui/core/styles';
2
+ import {
3
+ Table,
4
+ TableColumn,
5
+ Progress,
6
+ ResponseErrorPanel,
7
+ } from '@backstage/core-components';
8
+ import useAsync from 'react-use/lib/useAsync';
9
+
10
+ export const exampleUsers = {
11
+ results: [
12
+ {
13
+ gender: 'female',
14
+ name: {
15
+ title: 'Miss',
16
+ first: 'Carolyn',
17
+ last: 'Moore',
18
+ },
19
+ email: 'carolyn.moore@example.com',
20
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Carolyn',
21
+ nat: 'GB',
22
+ },
23
+ {
24
+ gender: 'female',
25
+ name: {
26
+ title: 'Ms',
27
+ first: 'Esma',
28
+ last: 'Berberoğlu',
29
+ },
30
+ email: 'esma.berberoglu@example.com',
31
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Esma',
32
+ nat: 'TR',
33
+ },
34
+ {
35
+ gender: 'female',
36
+ name: {
37
+ title: 'Ms',
38
+ first: 'Isabella',
39
+ last: 'Rhodes',
40
+ },
41
+ email: 'isabella.rhodes@example.com',
42
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella',
43
+ nat: 'GB',
44
+ },
45
+ {
46
+ gender: 'male',
47
+ name: {
48
+ title: 'Mr',
49
+ first: 'Derrick',
50
+ last: 'Carter',
51
+ },
52
+ email: 'derrick.carter@example.com',
53
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Derrick',
54
+ nat: 'IE',
55
+ },
56
+ {
57
+ gender: 'female',
58
+ name: {
59
+ title: 'Miss',
60
+ first: 'Mattie',
61
+ last: 'Lambert',
62
+ },
63
+ email: 'mattie.lambert@example.com',
64
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Mattie',
65
+ nat: 'AU',
66
+ },
67
+ {
68
+ gender: 'male',
69
+ name: {
70
+ title: 'Mr',
71
+ first: 'Mijat',
72
+ last: 'Rakić',
73
+ },
74
+ email: 'mijat.rakic@example.com',
75
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Mijat',
76
+ nat: 'RS',
77
+ },
78
+ {
79
+ gender: 'male',
80
+ name: {
81
+ title: 'Mr',
82
+ first: 'Javier',
83
+ last: 'Reid',
84
+ },
85
+ email: 'javier.reid@example.com',
86
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Javier',
87
+ nat: 'US',
88
+ },
89
+ {
90
+ gender: 'female',
91
+ name: {
92
+ title: 'Ms',
93
+ first: 'Isabella',
94
+ last: 'Li',
95
+ },
96
+ email: 'isabella.li@example.com',
97
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Isabella',
98
+ nat: 'CA',
99
+ },
100
+ {
101
+ gender: 'female',
102
+ name: {
103
+ title: 'Mrs',
104
+ first: 'Stephanie',
105
+ last: 'Garrett',
106
+ },
107
+ email: 'stephanie.garrett@example.com',
108
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Stephanie',
109
+ nat: 'AU',
110
+ },
111
+ {
112
+ gender: 'female',
113
+ name: {
114
+ title: 'Ms',
115
+ first: 'Antonia',
116
+ last: 'Núñez',
117
+ },
118
+ email: 'antonia.nunez@example.com',
119
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Antonia',
120
+ nat: 'ES',
121
+ },
122
+ {
123
+ gender: 'male',
124
+ name: {
125
+ title: 'Mr',
126
+ first: 'Donald',
127
+ last: 'Young',
128
+ },
129
+ email: 'donald.young@example.com',
130
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Donald',
131
+ nat: 'US',
132
+ },
133
+ {
134
+ gender: 'male',
135
+ name: {
136
+ title: 'Mr',
137
+ first: 'Iegor',
138
+ last: 'Holodovskiy',
139
+ },
140
+ email: 'iegor.holodovskiy@example.com',
141
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Iegor',
142
+ nat: 'UA',
143
+ },
144
+ {
145
+ gender: 'female',
146
+ name: {
147
+ title: 'Madame',
148
+ first: 'Jessica',
149
+ last: 'David',
150
+ },
151
+ email: 'jessica.david@example.com',
152
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Jessica',
153
+ nat: 'CH',
154
+ },
155
+ {
156
+ gender: 'female',
157
+ name: {
158
+ title: 'Ms',
159
+ first: 'Eve',
160
+ last: 'Martinez',
161
+ },
162
+ email: 'eve.martinez@example.com',
163
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Eve',
164
+ nat: 'FR',
165
+ },
166
+ {
167
+ gender: 'male',
168
+ name: {
169
+ title: 'Mr',
170
+ first: 'Caleb',
171
+ last: 'Silva',
172
+ },
173
+ email: 'caleb.silva@example.com',
174
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Caleb',
175
+ nat: 'US',
176
+ },
177
+ {
178
+ gender: 'female',
179
+ name: {
180
+ title: 'Miss',
181
+ first: 'Marcia',
182
+ last: 'Jenkins',
183
+ },
184
+ email: 'marcia.jenkins@example.com',
185
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Marcia',
186
+ nat: 'US',
187
+ },
188
+ {
189
+ gender: 'female',
190
+ name: {
191
+ title: 'Mrs',
192
+ first: 'Mackenzie',
193
+ last: 'Jones',
194
+ },
195
+ email: 'mackenzie.jones@example.com',
196
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Mackenzie',
197
+ nat: 'NZ',
198
+ },
199
+ {
200
+ gender: 'male',
201
+ name: {
202
+ title: 'Mr',
203
+ first: 'Jeremiah',
204
+ last: 'Gutierrez',
205
+ },
206
+ email: 'jeremiah.gutierrez@example.com',
207
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Jeremiah',
208
+ nat: 'AU',
209
+ },
210
+ {
211
+ gender: 'female',
212
+ name: {
213
+ title: 'Ms',
214
+ first: 'Luciara',
215
+ last: 'Souza',
216
+ },
217
+ email: 'luciara.souza@example.com',
218
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Luciara',
219
+ nat: 'BR',
220
+ },
221
+ {
222
+ gender: 'male',
223
+ name: {
224
+ title: 'Mr',
225
+ first: 'Valgi',
226
+ last: 'da Cunha',
227
+ },
228
+ email: 'valgi.dacunha@example.com',
229
+ picture: 'https://api.dicebear.com/6.x/open-peeps/svg?seed=Valgi',
230
+ nat: 'BR',
231
+ },
232
+ ],
233
+ };
234
+
235
+ const useStyles = makeStyles({
236
+ avatar: {
237
+ height: 32,
238
+ width: 32,
239
+ borderRadius: '50%',
240
+ },
241
+ });
242
+
243
+ type User = {
244
+ gender: string; // "male"
245
+ name: {
246
+ title: string; // "Mr",
247
+ first: string; // "Duane",
248
+ last: string; // "Reed"
249
+ };
250
+ email: string; // "duane.reed@example.com"
251
+ picture: string; // "https://api.dicebear.com/6.x/open-peeps/svg?seed=Duane"
252
+ nat: string; // "AU"
253
+ };
254
+
255
+ type DenseTableProps = {
256
+ users: User[];
257
+ };
258
+
259
+ export const DenseTable = ({ users }: DenseTableProps) => {
260
+ const classes = useStyles();
261
+
262
+ const columns: TableColumn[] = [
263
+ { title: 'Avatar', field: 'avatar' },
264
+ { title: 'Name', field: 'name' },
265
+ { title: 'Email', field: 'email' },
266
+ { title: 'Nationality', field: 'nationality' },
267
+ ];
268
+
269
+ const data = users.map(user => {
270
+ return {
271
+ avatar: (
272
+ <img
273
+ src={user.picture}
274
+ className={classes.avatar}
275
+ alt={user.name.first}
276
+ />
277
+ ),
278
+ name: `${user.name.first} ${user.name.last}`,
279
+ email: user.email,
280
+ nationality: user.nat,
281
+ };
282
+ });
283
+
284
+ return (
285
+ <Table
286
+ title="Example User List"
287
+ options=\{{ search: false, paging: false }}
288
+ columns={columns}
289
+ data={data}
290
+ />
291
+ );
292
+ };
293
+
294
+ export const ExampleFetchComponent = () => {
295
+
296
+ const { value, loading, error } = useAsync(async (): Promise<User[]> => {
297
+ // Would use fetch in a real world example
298
+ return exampleUsers.results;
299
+ }, []);
300
+
301
+ if (loading) {
302
+ return <Progress />;
303
+ } else if (error) {
304
+ return <ResponseErrorPanel error={error} />;
305
+ }
306
+
307
+ return <DenseTable users={value || []} />;
308
+ };
@@ -0,0 +1 @@
1
+ export { ExampleFetchComponent } from './ExampleFetchComponent';
@@ -0,0 +1 @@
1
+ export { {{ pluginVar }} as default } from './plugin';
@@ -0,0 +1,7 @@
1
+ import { {{ pluginVar }} } from './plugin';
2
+
3
+ describe('{{pluginId}}', () => {
4
+ it('should export plugin', () => {
5
+ expect({{ pluginVar }}).toBeDefined();
6
+ });
7
+ });
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import {
3
+ createFrontendPlugin,
4
+ PageBlueprint,
5
+ } from '@backstage/frontend-plugin-api';
6
+
7
+ import { rootRouteRef } from './routes';
8
+
9
+ export const page = PageBlueprint.make({
10
+ params: {
11
+ path: '/{{pluginId}}',
12
+ routeRef: rootRouteRef,
13
+ loader: () =>
14
+ import('./components/ExampleComponent').then(m =>
15
+ <m.ExampleComponent />,
16
+ ),
17
+ },
18
+ });
19
+
20
+ export const {{ pluginVar }} = createFrontendPlugin({
21
+ id: '{{pluginId}}',
22
+ extensions: [page],
23
+ routes: {
24
+ root: rootRouteRef,
25
+ }
26
+ });
@@ -0,0 +1,3 @@
1
+ import { createRouteRef } from '@backstage/frontend-plugin-api';
2
+
3
+ export const rootRouteRef = createRouteRef();
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
@@ -0,0 +1 @@
1
+ module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,5 @@
1
+ # {{packageName}}
2
+
3
+ The {{moduleId}} frontend module for the {{pluginId}} plugin.
4
+
5
+ _This plugin was created through the Backstage CLI_
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "description": "The {{moduleId}} frontend module for the {{pluginId}} plugin.",
4
+ "main": "src/index.ts",
5
+ "types": "src/index.ts",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "main": "dist/index.cjs.js",
9
+ "module": "dist/index.esm.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "backstage": {
13
+ "role": "frontend-plugin-module",
14
+ "pluginId": "{{pluginId}}"
15
+ },
16
+ "sideEffects": false,
17
+ "scripts": {
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/frontend-plugin-api": "{{versionQuery '@backstage/frontend-plugin-api'}}"
27
+ },
28
+ "devDependencies": {
29
+ "@backstage/cli": "{{versionQuery '@backstage/cli'}}",
30
+ "@testing-library/jest-dom": "{{versionQuery '@testing-library/jest-dom' '6.0.0'}}"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ]
35
+ }
@@ -0,0 +1,5 @@
1
+ name: frontend-plugin-module
2
+ role: frontend-plugin-module
3
+ description: A new frontend module that extends an existing frontend plugin
4
+ values:
5
+ moduleVar: '{{ camelCase pluginId }}Module{{ upperFirst ( camelCase moduleId ) }}'
@@ -0,0 +1 @@
1
+ export { {{ moduleVar }} as default } from './plugin';
@@ -0,0 +1,8 @@
1
+ import { createFrontendModule } from '@backstage/frontend-plugin-api';
2
+
3
+ export const {{ moduleVar }} = createFrontendModule({
4
+ pluginId: '{{ pluginId }}',
5
+ extensions: [
6
+ /* TODO */
7
+ ],
8
+ });
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';