add custom ui plugin
This commit is contained in:
parent
f8b55bdcbc
commit
26cf0bc5d6
18 changed files with 8005 additions and 0 deletions
|
@ -44,6 +44,7 @@
|
|||
"@backstage/plugin-techdocs-react": "^1.1.3",
|
||||
"@backstage/plugin-user-settings": "^0.7.0",
|
||||
"@backstage/theme": "^0.2.17",
|
||||
"@internal/plugin-workflows": "^0.1.0",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"history": "^5.0.0",
|
||||
|
|
|
@ -33,6 +33,7 @@ import { AppRouter, FlatRoutes } from '@backstage/core-app-api';
|
|||
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
|
||||
import { RequirePermission } from '@backstage/plugin-permission-react';
|
||||
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
|
||||
import { WorkflowsPage } from '@internal/plugin-workflows';
|
||||
|
||||
const app = createApp({
|
||||
apis,
|
||||
|
@ -91,6 +92,7 @@ const routes = (
|
|||
</Route>
|
||||
<Route path="/settings" element={<UserSettingsPage />} />
|
||||
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
|
||||
<Route path="/workflows" element={<WorkflowsPage />} />
|
||||
</FlatRoutes>
|
||||
);
|
||||
|
||||
|
|
1
plugins/workflows/.eslintrc.js
Normal file
1
plugins/workflows/.eslintrc.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
13
plugins/workflows/README.md
Normal file
13
plugins/workflows/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# workflows
|
||||
|
||||
Welcome to the workflows plugin!
|
||||
|
||||
_This plugin was created through the Backstage CLI_
|
||||
|
||||
## Getting started
|
||||
|
||||
Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/workflows](http://localhost:3000/workflows).
|
||||
|
||||
You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
|
||||
This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
|
||||
It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
|
12
plugins/workflows/dev/index.tsx
Normal file
12
plugins/workflows/dev/index.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import { createDevApp } from '@backstage/dev-utils';
|
||||
import { workflowsPlugin, WorkflowsPage } from '../src/plugin';
|
||||
|
||||
createDevApp()
|
||||
.registerPlugin(workflowsPlugin)
|
||||
.addPage({
|
||||
element: <WorkflowsPage />,
|
||||
title: 'Root Page',
|
||||
path: '/workflows'
|
||||
})
|
||||
.render();
|
52
plugins/workflows/package.json
Normal file
52
plugins/workflows/package.json
Normal file
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "@internal/plugin-workflows",
|
||||
"version": "0.1.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"backstage": {
|
||||
"role": "frontend-plugin"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-components": "^0.12.4",
|
||||
"@backstage/core-plugin-api": "^1.4.0",
|
||||
"@backstage/theme": "^0.2.17",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"react-use": "^17.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.13.1 || ^17.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.22.2",
|
||||
"@backstage/core-app-api": "^1.5.0",
|
||||
"@backstage/dev-utils": "^1.0.12",
|
||||
"@backstage/test-utils": "^1.2.5",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/node": "*",
|
||||
"msw": "^0.49.0",
|
||||
"cross-fetch": "^3.1.5"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react';
|
||||
import { ExampleComponent } from './ExampleComponent';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { screen } from '@testing-library/react';
|
||||
import {
|
||||
setupRequestMockHandlers,
|
||||
renderInTestApp,
|
||||
} from "@backstage/test-utils";
|
||||
|
||||
describe('ExampleComponent', () => {
|
||||
const server = setupServer();
|
||||
// Enable sane handlers for network requests
|
||||
setupRequestMockHandlers(server);
|
||||
|
||||
// setup mock response
|
||||
beforeEach(() => {
|
||||
server.use(
|
||||
rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))),
|
||||
);
|
||||
});
|
||||
|
||||
it('should render', async () => {
|
||||
await renderInTestApp(<ExampleComponent />);
|
||||
expect(screen.getByText('Welcome to workflows!')).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,50 @@
|
|||
import React from 'react';
|
||||
import {Typography, Grid, IconButton} from '@material-ui/core';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import ClearIcon from '@material-ui/icons/Clear'
|
||||
import LinkOffRounded from "@material-ui/icons/LinkOffRounded";
|
||||
import {
|
||||
InfoCard,
|
||||
Header,
|
||||
Page,
|
||||
Content,
|
||||
ContentHeader,
|
||||
HeaderLabel,
|
||||
SupportButton,
|
||||
} from '@backstage/core-components';
|
||||
import { ExampleFetchComponent } from '../ExampleFetchComponent';
|
||||
|
||||
export const ExampleComponent = () => (
|
||||
<Page themeId="tool">
|
||||
<Header title="Blueprint information">
|
||||
<HeaderLabel label="Owner" value="Team X" />
|
||||
<HeaderLabel label="Lifecycle" value="Alpha" />
|
||||
</Header>
|
||||
<Content>
|
||||
{/*<ContentHeader title="Blueprint information">*/}
|
||||
{/* <SupportButton>A description of your plugin goes here.</SupportButton>*/}
|
||||
{/*</ContentHeader>*/}
|
||||
<Grid container spacing={3} direction="column">
|
||||
<Grid item>
|
||||
<InfoCard title="Blueprint management">
|
||||
<Typography color="textSecondary">
|
||||
Manage this blueprint deployment
|
||||
</Typography>
|
||||
<IconButton aria-label="delete" size="medium">
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
<IconButton aria-label="clear" size="medium">
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
<IconButton aria-label="link" size="medium">
|
||||
<LinkOffRounded />
|
||||
</IconButton>
|
||||
</InfoCard>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<ExampleFetchComponent />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Content>
|
||||
</Page>
|
||||
);
|
|
@ -0,0 +1 @@
|
|||
export { ExampleComponent } from './ExampleComponent';
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { ExampleFetchComponent } from './ExampleFetchComponent';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { setupRequestMockHandlers } from '@backstage/test-utils';
|
||||
|
||||
describe('ExampleFetchComponent', () => {
|
||||
const server = setupServer();
|
||||
// Enable sane handlers for network requests
|
||||
setupRequestMockHandlers(server);
|
||||
|
||||
// setup mock response
|
||||
beforeEach(() => {
|
||||
server.use(
|
||||
rest.get('https://randomuser.me/*', (_, res, ctx) =>
|
||||
res(ctx.status(200), ctx.delay(2000), ctx.json({})),
|
||||
),
|
||||
);
|
||||
});
|
||||
it('should render', async () => {
|
||||
await render(<ExampleFetchComponent />);
|
||||
expect(await screen.findByTestId('progress')).toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,86 @@
|
|||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Table, TableColumn, Progress } from '@backstage/core-components';
|
||||
import {tfstate} from "./terraform"
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
type TFState = {
|
||||
terraform_version: string
|
||||
resources: {
|
||||
name: string
|
||||
provider: string
|
||||
type: string
|
||||
instances: {
|
||||
attributes: {
|
||||
arn: string
|
||||
id: string
|
||||
}
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
|
||||
type Resource = {
|
||||
name: string
|
||||
provider: string
|
||||
type: string
|
||||
arn?: string
|
||||
id?: string
|
||||
}
|
||||
|
||||
type TFTableProps = {
|
||||
resources: Resource[]
|
||||
}
|
||||
|
||||
export const TFTable = (props: TFTableProps) => {
|
||||
|
||||
const columns: TableColumn[] = [
|
||||
{ title: 'Name', field: 'name' },
|
||||
{ title: 'Provider', field: 'provider' },
|
||||
{ title: 'Type', field: 'type' },
|
||||
{ title: 'Arn', field: 'arn' },
|
||||
{ title: 'ID', field: 'id' },
|
||||
];
|
||||
|
||||
return (
|
||||
<Table
|
||||
title="Resources provisioned by Terraform"
|
||||
options={{ search: true, paging: false }}
|
||||
columns={columns}
|
||||
data={props.resources}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const ExampleFetchComponent = () => {
|
||||
|
||||
const tfdata = tfstate as TFState
|
||||
const resources = tfdata.resources.map(value => {
|
||||
const out: Resource = {
|
||||
name: value.name,
|
||||
provider: value.provider,
|
||||
type: value.type,
|
||||
}
|
||||
if (value.instances.length > 0) {
|
||||
out.arn = value.instances[0].attributes.arn
|
||||
out.id = value.instances[0].attributes.id
|
||||
}
|
||||
return out
|
||||
})
|
||||
|
||||
return <TFTable resources={resources}/>
|
||||
|
||||
// const { value, loading, error } = useAsync(async (): Promise<User[]> => {
|
||||
// const response = await fetch('https://randomuser.me/api/?results=20');
|
||||
// const data = await response.json();
|
||||
// return data.results;
|
||||
// }, []);
|
||||
//
|
||||
// if (loading) {
|
||||
// return <Progress />;
|
||||
// } else if (error) {
|
||||
// return <Alert severity="error">{error.message}</Alert>;
|
||||
// }
|
||||
//
|
||||
// return <DenseTable users={value || []} />;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
export { ExampleFetchComponent } from './ExampleFetchComponent';
|
7700
plugins/workflows/src/components/ExampleFetchComponent/terraform.ts
Normal file
7700
plugins/workflows/src/components/ExampleFetchComponent/terraform.ts
Normal file
File diff suppressed because it is too large
Load diff
1
plugins/workflows/src/index.ts
Normal file
1
plugins/workflows/src/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { workflowsPlugin, WorkflowsPage } from './plugin';
|
7
plugins/workflows/src/plugin.test.ts
Normal file
7
plugins/workflows/src/plugin.test.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { workflowsPlugin } from './plugin';
|
||||
|
||||
describe('workflows', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(workflowsPlugin).toBeDefined();
|
||||
});
|
||||
});
|
19
plugins/workflows/src/plugin.ts
Normal file
19
plugins/workflows/src/plugin.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';
|
||||
|
||||
import { rootRouteRef } from './routes';
|
||||
|
||||
export const workflowsPlugin = createPlugin({
|
||||
id: 'workflows',
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
},
|
||||
});
|
||||
|
||||
export const WorkflowsPage = workflowsPlugin.provide(
|
||||
createRoutableExtension({
|
||||
name: 'WorkflowsPage',
|
||||
component: () =>
|
||||
import('./components/ExampleComponent').then(m => m.ExampleComponent),
|
||||
mountPoint: rootRouteRef,
|
||||
}),
|
||||
);
|
5
plugins/workflows/src/routes.ts
Normal file
5
plugins/workflows/src/routes.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { createRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const rootRouteRef = createRouteRef({
|
||||
id: 'workflows',
|
||||
});
|
2
plugins/workflows/src/setupTests.ts
Normal file
2
plugins/workflows/src/setupTests.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
import '@testing-library/jest-dom';
|
||||
import 'cross-fetch/polyfill';
|
Loading…
Reference in a new issue