@backstage/cli-module-new 0.1.1 → 0.1.2
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 +33 -2
- package/dist/lib/execution/executePortableTemplate.cjs.js +4 -4
- package/dist/lib/execution/executePortableTemplate.cjs.js.map +1 -1
- package/dist/lib/preparation/loadPortableTemplate.cjs.js +8 -8
- package/dist/lib/preparation/loadPortableTemplate.cjs.js.map +1 -1
- package/dist/lib/preparation/loadPortableTemplateConfig.cjs.js +19 -19
- package/dist/lib/preparation/loadPortableTemplateConfig.cjs.js.map +1 -1
- package/dist/lib/version.cjs.js +38 -36
- package/dist/lib/version.cjs.js.map +1 -1
- package/dist/packages/backend-defaults/package.json.cjs.js +1 -1
- package/dist/packages/backend-plugin-api/package.json.cjs.js +1 -1
- package/dist/packages/backend-test-utils/package.json.cjs.js +1 -1
- package/dist/packages/catalog-client/package.json.cjs.js +1 -1
- package/dist/packages/cli/package.json.cjs.js +1 -1
- package/dist/packages/cli-module-new/package.json.cjs.js +1 -1
- package/dist/packages/config/package.json.cjs.js +1 -1
- package/dist/packages/core-app-api/package.json.cjs.js +1 -1
- package/dist/packages/core-components/package.json.cjs.js +1 -1
- package/dist/packages/core-plugin-api/package.json.cjs.js +1 -1
- package/dist/packages/dev-utils/package.json.cjs.js +1 -1
- package/dist/packages/errors/package.json.cjs.js +1 -1
- package/dist/packages/frontend-defaults/package.json.cjs.js +1 -1
- package/dist/packages/frontend-dev-utils/package.json.cjs.js +1 -1
- package/dist/packages/frontend-plugin-api/package.json.cjs.js +1 -1
- package/dist/packages/frontend-test-utils/package.json.cjs.js +1 -1
- package/dist/packages/test-utils/package.json.cjs.js +1 -1
- package/dist/packages/theme/package.json.cjs.js +1 -1
- package/dist/packages/ui/package.json.cjs.js +6 -0
- package/dist/packages/ui/package.json.cjs.js.map +1 -0
- package/dist/plugins/auth-backend/package.json.cjs.js +1 -1
- package/dist/plugins/auth-backend-module-guest-provider/package.json.cjs.js +1 -1
- package/dist/plugins/catalog-node/package.json.cjs.js +1 -1
- package/dist/plugins/scaffolder-node/package.json.cjs.js +1 -1
- package/dist/plugins/scaffolder-node-test-utils/package.json.cjs.js +1 -1
- package/package.json +8 -8
- package/templates/frontend-plugin/README.md.hbs +1 -1
- package/templates/frontend-plugin/package.json.hbs +1 -3
- package/templates/frontend-plugin/src/components/TodoList/TodoList.test.tsx +18 -0
- package/templates/frontend-plugin/src/components/TodoList/TodoList.tsx +42 -0
- package/templates/frontend-plugin/src/components/TodoList/index.ts +2 -0
- package/templates/frontend-plugin/src/components/TodoPage/TodoPage.test.tsx.hbs +43 -0
- package/templates/frontend-plugin/src/components/TodoPage/TodoPage.tsx.hbs +52 -0
- package/templates/frontend-plugin/src/components/TodoPage/index.ts +1 -0
- package/templates/frontend-plugin/src/plugin.tsx.hbs +3 -3
- package/templates/frontend-plugin-module/src/index.ts.hbs +1 -1
- package/templates/legacy-frontend-plugin/portable-template.yaml +1 -1
- package/templates/frontend-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs +0 -28
- package/templates/frontend-plugin/src/components/ExampleComponent/ExampleComponent.tsx.hbs +0 -37
- package/templates/frontend-plugin/src/components/ExampleComponent/index.ts +0 -1
- package/templates/frontend-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx.hbs +0 -19
- package/templates/frontend-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx.hbs +0 -308
- package/templates/frontend-plugin/src/components/ExampleFetchComponent/index.ts +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/cli-module-new",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CLI module for Backstage CLI",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "cli-module"
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"test": "backstage-cli package test"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@backstage/cli-common": "^0.2.
|
|
38
|
-
"@backstage/cli-node": "^0.3.
|
|
39
|
-
"@backstage/errors": "^1.
|
|
37
|
+
"@backstage/cli-common": "^0.2.1",
|
|
38
|
+
"@backstage/cli-node": "^0.3.1",
|
|
39
|
+
"@backstage/errors": "^1.3.0",
|
|
40
40
|
"chalk": "^4.0.0",
|
|
41
41
|
"cleye": "^2.3.0",
|
|
42
42
|
"fs-extra": "^11.2.0",
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"zod-validation-error": "^4.0.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@backstage/backend-test-utils": "^1.11.
|
|
55
|
-
"@backstage/cli": "^0.36.
|
|
56
|
-
"@backstage/core-plugin-api": "^1.12.
|
|
57
|
-
"@backstage/test-utils": "^1.7.
|
|
54
|
+
"@backstage/backend-test-utils": "^1.11.2",
|
|
55
|
+
"@backstage/cli": "^0.36.1",
|
|
56
|
+
"@backstage/core-plugin-api": "^1.12.5",
|
|
57
|
+
"@backstage/test-utils": "^1.7.17",
|
|
58
58
|
"@types/fs-extra": "^11.0.0",
|
|
59
59
|
"@types/inquirer": "^8.1.3",
|
|
60
60
|
"@types/lodash": "^4.14.151",
|
|
@@ -10,7 +10,7 @@ Your plugin has been added to the app in this repository, meaning you'll be able
|
|
|
10
10
|
to access it by running `yarn start` in the root directory, and then navigating
|
|
11
11
|
to [/{{pluginId}}](http://localhost:3000/{{pluginId}}).
|
|
12
12
|
|
|
13
|
-
This plugin is built with Backstage's [
|
|
13
|
+
This plugin is built with Backstage's [frontend
|
|
14
14
|
system](https://backstage.io/docs/frontend-system/architecture/index), and you
|
|
15
15
|
can find more information about building plugins in the [plugin builder
|
|
16
16
|
documentation](https://backstage.io/docs/frontend-system/building-plugins/index).
|
|
@@ -25,9 +25,7 @@
|
|
|
25
25
|
"@backstage/core-components": "{{versionQuery '@backstage/core-components'}}",
|
|
26
26
|
"@backstage/frontend-plugin-api": "{{versionQuery '@backstage/frontend-plugin-api'}}",
|
|
27
27
|
"@backstage/theme": "{{versionQuery '@backstage/theme'}}",
|
|
28
|
-
"@
|
|
29
|
-
"@material-ui/icons": "{{versionQuery '@material-ui/icons' '4.9.1'}}",
|
|
30
|
-
"@material-ui/lab": "{{versionQuery '@material-ui/lab' '4.0.0-alpha.61'}}",
|
|
28
|
+
"@backstage/ui": "{{versionQuery '@backstage/ui'}}",
|
|
31
29
|
"react-use": "{{versionQuery 'react-use' '17.2.4'}}"
|
|
32
30
|
},
|
|
33
31
|
"peerDependencies": {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { screen } from '@testing-library/react';
|
|
2
|
+
import { renderInTestApp } from '@backstage/frontend-test-utils';
|
|
3
|
+
import { TodoList } from './TodoList';
|
|
4
|
+
|
|
5
|
+
describe('TodoList', () => {
|
|
6
|
+
it('renders a list of todos', async () => {
|
|
7
|
+
const todos = [
|
|
8
|
+
{ id: '1', title: 'First task', createdBy: 'user:default/guest', createdAt: '2025-01-01T00:00:00.000Z' },
|
|
9
|
+
{ id: '2', title: 'Second task', createdBy: 'user:default/admin', createdAt: '2025-01-02T00:00:00.000Z' },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
await renderInTestApp(<TodoList todos={todos} />);
|
|
13
|
+
|
|
14
|
+
expect(await screen.findByText('First task')).toBeInTheDocument();
|
|
15
|
+
expect(await screen.findByText('Second task')).toBeInTheDocument();
|
|
16
|
+
expect(await screen.findByText('user:default/guest')).toBeInTheDocument();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Table, useTable, CellText, type ColumnConfig } from '@backstage/ui';
|
|
2
|
+
|
|
3
|
+
export type TodoItem = {
|
|
4
|
+
title: string;
|
|
5
|
+
id: string;
|
|
6
|
+
createdBy: string;
|
|
7
|
+
createdAt: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const columns: ColumnConfig<TodoItem>[] = [
|
|
11
|
+
{
|
|
12
|
+
id: 'title',
|
|
13
|
+
label: 'Title',
|
|
14
|
+
cell: item => <CellText title={item.title} />,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 'createdBy',
|
|
18
|
+
label: 'Created by',
|
|
19
|
+
cell: item => <CellText title={item.createdBy} />,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 'createdAt',
|
|
23
|
+
label: 'Created at',
|
|
24
|
+
cell: item => <CellText title={new Date(item.createdAt).toLocaleString()} />,
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export const TodoList = ({ todos }: { todos: TodoItem[] }) => {
|
|
29
|
+
const { tableProps } = useTable({
|
|
30
|
+
mode: 'complete',
|
|
31
|
+
data: todos,
|
|
32
|
+
paginationOptions: { pageSize: todos.length || 1 },
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Table
|
|
37
|
+
columnConfig={columns}
|
|
38
|
+
{...tableProps}
|
|
39
|
+
pagination={{ type: 'none' }}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { screen } from '@testing-library/react';
|
|
2
|
+
import { rest } from 'msw';
|
|
3
|
+
import { setupServer } from 'msw/node';
|
|
4
|
+
import {
|
|
5
|
+
registerMswTestHooks,
|
|
6
|
+
renderInTestApp,
|
|
7
|
+
} from '@backstage/frontend-test-utils';
|
|
8
|
+
import { TodoPage } from './TodoPage';
|
|
9
|
+
|
|
10
|
+
describe('TodoPage', () => {
|
|
11
|
+
const server = setupServer();
|
|
12
|
+
registerMswTestHooks(server);
|
|
13
|
+
|
|
14
|
+
it('renders todos from the backend', async () => {
|
|
15
|
+
server.use(
|
|
16
|
+
rest.get('*/api/{{pluginId}}/todos', (_, res, ctx) =>
|
|
17
|
+
res(
|
|
18
|
+
ctx.json({
|
|
19
|
+
items: [
|
|
20
|
+
{ id: '1', title: 'Mocked task', createdBy: 'user:default/guest', createdAt: '2025-01-01T00:00:00.000Z' },
|
|
21
|
+
],
|
|
22
|
+
}),
|
|
23
|
+
),
|
|
24
|
+
),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
await renderInTestApp(<TodoPage />);
|
|
28
|
+
|
|
29
|
+
expect(await screen.findByText('Mocked task')).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('falls back to example data when the backend fails', async () => {
|
|
33
|
+
server.use(
|
|
34
|
+
rest.get('*/api/{{pluginId}}/todos', (_, res, ctx) =>
|
|
35
|
+
res(ctx.status(500), ctx.json({ message: 'Internal Server Error' })),
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
await renderInTestApp(<TodoPage />);
|
|
40
|
+
|
|
41
|
+
expect(await screen.findByText('Install the backend plugin')).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Progress } from '@backstage/core-components';
|
|
2
|
+
import {
|
|
3
|
+
useApi,
|
|
4
|
+
fetchApiRef,
|
|
5
|
+
} from '@backstage/frontend-plugin-api';
|
|
6
|
+
import { Header, Container } from '@backstage/ui';
|
|
7
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
8
|
+
import { TodoList } from '../TodoList';
|
|
9
|
+
import type { TodoItem } from '../TodoList';
|
|
10
|
+
|
|
11
|
+
const exampleTodos: TodoItem[] = [
|
|
12
|
+
{ id: '1', title: 'Install the backend plugin', createdBy: 'user:default/guest', createdAt: new Date().toISOString() },
|
|
13
|
+
{ id: '2', title: 'Connect the frontend to real data', createdBy: 'user:default/guest', createdAt: new Date().toISOString() },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// TEMPLATE NOTE:
|
|
17
|
+
// This is a simple example of fetching data from the backend plugin.
|
|
18
|
+
// You can replace this with your own data fetching logic or use a
|
|
19
|
+
// generated client from an OpenAPI schema.
|
|
20
|
+
function useTodos() {
|
|
21
|
+
const { fetch } = useApi(fetchApiRef);
|
|
22
|
+
|
|
23
|
+
return useAsync(async (): Promise<TodoItem[]> => {
|
|
24
|
+
const response = await fetch(`plugin://{{pluginId}}/todos`);
|
|
25
|
+
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Failed to fetch todos: ${response.status} ${response.statusText}`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const data = await response.json();
|
|
33
|
+
return data.items;
|
|
34
|
+
}, [fetch]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const TodoPage = () => {
|
|
38
|
+
const { value: todos, loading, error } = useTodos();
|
|
39
|
+
|
|
40
|
+
if (loading) {
|
|
41
|
+
return <Progress />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<Header title="Welcome to {{pluginId}}!" />
|
|
47
|
+
<Container>
|
|
48
|
+
<TodoList todos={error ? exampleTodos : (todos ?? [])} />
|
|
49
|
+
</Container>
|
|
50
|
+
</>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TodoPage } from './TodoPage';
|
|
@@ -10,9 +10,9 @@ export const page = PageBlueprint.make({
|
|
|
10
10
|
path: '/{{pluginId}}',
|
|
11
11
|
routeRef: rootRouteRef,
|
|
12
12
|
loader: () =>
|
|
13
|
-
import('./components/
|
|
14
|
-
<m.
|
|
15
|
-
),
|
|
13
|
+
import('./components/TodoPage').then(m => (
|
|
14
|
+
<m.TodoPage />
|
|
15
|
+
)),
|
|
16
16
|
},
|
|
17
17
|
});
|
|
18
18
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { {{ moduleVar }} as default } from './
|
|
1
|
+
export { {{ moduleVar }} as default } from './module';
|
package/templates/frontend-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ExampleComponent } from './ExampleComponent';
|
|
@@ -1,19 +0,0 @@
|
|
|
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
|
-
});
|