Skip to content

Commit

Permalink
Create frontend plugin frontend-plugin-demo-2
Browse files Browse the repository at this point in the history
  • Loading branch information
debsmita1 committed Aug 5, 2024
1 parent 13883bc commit a7c1c2f
Show file tree
Hide file tree
Showing 23 changed files with 450 additions and 0 deletions.
1 change: 1 addition & 0 deletions plugins/frontend-plugin-demo-2/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
70 changes: 70 additions & 0 deletions plugins/frontend-plugin-demo-2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frontend-plugin-demo-2

Welcome to the frontend-plugin-demo-2 plugin!

_This plugin was created through the Software Template. Please ensure you run it within your Backstage directory._


## Getting started

1. Go to the plugin directory and run `yarn install`


### To access the plugin in isolation:

1. Go to the plugin directory

2. Run `yarn start`

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.


### To access it from the Root of your backstage directory:


1. Add the package in the `packages/app/package.json`

```
"@janus-idp/backstage-plugin-frontend-plugin-demo-2": "^0.1.0",
```


2. Add Route in `packages/app/src/App.tsx`:

```tsx title="packages/app/src/App.tsx"
/* highlight-add-next-line */
import { PluginPage } from '@janus-idp/backstage-plugin-frontend-plugin-demo-2';

<Route path="/frontend-plugin-demo-2" element={<PluginPage />} />
```

3. Add your plugin as a Sidebar Item in `packages/app/src/components/Root/Root.tsx`:

```tsx title="packages/app/src/components/Root/Root.tsx"
/* highlight-add-next-line */
import { PluginIcon } from '@janus-idp/backstage-plugin-frontend-plugin-demo-2';

export const Root = ({ children }: PropsWithChildren<{}>) => (
<SidebarPage>
<Sidebar>
...
<PluginIcon />
...
<Sidebar>
</SidebarPage>
);
```

4. Set-up the Backstage Proxy. Follow https://backstage.io/docs/integrations/github/locations#token-scopes for creating personal access token

```yaml title="app-config.yaml"
proxy:
...
'/github':
target: 'https://api.github.com'
headers:
Authorization: 'token ${GITHUB_TOKEN}'
```

5. Start your application from the root directory, and then navigate to [/frontend-plugin-demo-2](http://localhost:3000/frontend-plugin-demo-2).
8 changes: 8 additions & 0 deletions plugins/frontend-plugin-demo-2/app-config.janus-idp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
dynamicPlugins:
frontend:
janus-idp.backstage-plugin-frontend-plugin-demo-2:
apiFactories: []
appIcons: []
dynamicRoutes: []
mountPoints: []
routeBindings: []
1 change: 1 addition & 0 deletions plugins/frontend-plugin-demo-2/config.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export interface Config {}
26 changes: 26 additions & 0 deletions plugins/frontend-plugin-demo-2/dev/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import { discoveryApiRef } from "@backstage/core-plugin-api";
import { createDevApp } from "@backstage/dev-utils";
import { TestApiProvider } from "@backstage/test-utils";
import PermIdentityOutlinedIcon from "@mui/icons-material/PermIdentityOutlined";
import { plugin, PluginPage } from "../src/plugin";

const mockedDiscoveryApi = {
getBaseUrl: async (_param: any) => {
return "http://localhost:7007/api/proxy";
},
};

createDevApp()
.registerPlugin(plugin)
.addPage({
element: (
<TestApiProvider apis={[[discoveryApiRef, mockedDiscoveryApi]]}>
<PluginPage />
</TestApiProvider>
),
title: "frontend-plugin-demo-2",
path: "/frontend-plugin-demo-2",
icon: () => <PermIdentityOutlinedIcon />,
})
.render();
70 changes: 70 additions & 0 deletions plugins/frontend-plugin-demo-2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"name": "@janus-idp/backstage-plugin-frontend-plugin-demo-2",
"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"
},
"sideEffects": false,
"scripts": {
"build": "backstage-cli package build",
"clean": "backstage-cli package clean",
"export-dynamic": "janus-cli package export-dynamic-plugin",
"lint": "backstage-cli package lint",
"postpack": "backstage-cli package postpack",
"postversion": "yarn run export-dynamic",
"prepack": "backstage-cli package prepack",
"start": "backstage-cli package start",
"test": "backstage-cli package test --passWithNoTests --coverage",
"tsc": "tsc"
},
"dependencies": {
"@backstage/core-components": "^0.14.4",
"@backstage/core-plugin-api": "^1.9.2",
"@backstage/theme": "^0.5.5",
"@material-ui/core": "^4.9.13",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.61",
"@mui/icons-material": "^5.15.21",
"react-use": "^17.2.4"
},
"peerDependencies": {
"react": "16.13.1 || ^17.0.0 || ^18.0.0",
"react-router-dom": "^6.0.0"
},
"devDependencies": {
"@backstage/cli": "0.26.6",
"@backstage/core-app-api": "1.12.5",
"@backstage/dev-utils": "1.0.32",
"@backstage/test-utils": "1.5.5",
"@janus-idp/cli": "1.11.1",
"@testing-library/jest-dom": "6.0.0",
"@testing-library/react": "14.0.0",
"@testing-library/user-event": "14.0.0",
"msw": "1.0.0"
},
"files": [
"dist",
"config.d.ts",
"dist-scalprum",
"app-config.janus-idp.yaml"
],
"configSchema": "config.d.ts",
"repository": {
"type": "git",
"url": "[object Object]",
"directory": "frontend-plugin-demo-2"
},
"keywords": [
"backstage",
"plugin"
]
}
Original file line number Diff line number Diff line change
@@ -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 frontend-plugin-demo-2!')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import { Typography, Grid, makeStyles } from "@material-ui/core";
import {
InfoCard,
Header,
Page,
Content,
ContentHeader,
HeaderLabel,
SupportButton,
} from "@backstage/core-components";
import { ExampleFetchComponent } from "../ExampleFetchComponent";

const usePaperStyles = makeStyles((theme) => ({
body: {
backgroundColor: theme.palette.background.paper,
},
}));

export const ExampleComponent = () => {
const classes = usePaperStyles();
return (
<Page themeId="tool">
<Header
title="Welcome to frontend-plugin-demo-2"
subtitle="Optional subtitle"
>
<HeaderLabel label="Owner" value="Team X" />
<HeaderLabel label="Lifecycle" value="Alpha" />
</Header>
<Content className={classes.body}>
<ContentHeader title="Plugin title">
<SupportButton>A description of your plugin goes here.</SupportButton>
</ContentHeader>
<Grid container spacing={3} direction="column">
<Grid item>
<InfoCard title="Information card">
<Typography variant="body1">
All content should be wrapped in a card like this.
</Typography>
</InfoCard>
</Grid>
<Grid item>
<ExampleFetchComponent />
</Grid>
</Grid>
</Content>
</Page>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ExampleComponent } from './ExampleComponent';
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';

import { SidebarItem } from '@backstage/core-components';
import PermIdentityOutlinedIcon from '@mui/icons-material/PermIdentityOutlined';
import { IconComponent } from '@backstage/core-plugin-api';


export const ExampleComponentIcon = () => {

return (
<SidebarItem text="frontend-plugin-demo-2" to="/frontend-plugin-demo-2" icon={PermIdentityOutlinedIcon as IconComponent} />
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { ExampleFetchComponent } from './ExampleFetchComponent';

describe('ExampleFetchComponent', () => {
it('renders the user table', async () => {
render(<ExampleFetchComponent />);

// Wait for the table to render
const table = await screen.findByRole('table');
const nationality = screen.getAllByText("GB")
// Assert that the table contains the expected user data
expect(table).toBeInTheDocument();
expect(screen.getByAltText('Carolyn')).toBeInTheDocument();
expect(screen.getByText('Carolyn Moore')).toBeInTheDocument();
expect(screen.getByText('carolyn.moore@example.com')).toBeInTheDocument();
expect(nationality[0]).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from "react";
import useAsync from "react-use/lib/useAsync";
import {
Table,
TableColumn,
Progress,
ResponseErrorPanel,
} from "@backstage/core-components";
import { discoveryApiRef, useApi } from "@backstage/core-plugin-api";
import { Avatar, Chip } from "@material-ui/core";
import { useTheme } from "@material-ui/core/styles";
import { getChipStyle } from "../../utils/getChipStyle";

type User = {
repoUrl: string;
githubId: string;
type: string;
};

export const DenseTable = ({ users }: any) => {
const theme = useTheme();
const chipStyle = getChipStyle(theme);
const columns: TableColumn[] = [
{ title: "GithubId", field: "githubId" },
{ title: "Repository URL", field: "repoUrl" },
{ title: "Type", field: "type" },
];

const data = users.map((user: any) => {
return {
id: user.login,
githubId: (
<Chip
style={chipStyle}
avatar={<Avatar alt={user.login} src={user.avatar_url} />}
label={user.login}
variant="outlined"
/>
),
repoUrl: user.html_url,
type: user.type,
};
});

return (
<Table
title="Github Users"
options={{ search: false, paging: true }}
columns={columns}
data={data}
/>
);
};

export const ExampleFetchComponent = () => {
const discoveryApi = useApi(discoveryApiRef);
const proxyURL = discoveryApi.getBaseUrl("proxy");

const { value, loading, error } = useAsync(async (): Promise<User[]> => {
const res = await fetch(`${await proxyURL}/github/users`);
const users = await res.json();
return users;
}, []);

if (loading) {
return <Progress />;
} else if (error) {
return <ResponseErrorPanel error={error} />;
}

return <DenseTable users={value || []} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ExampleFetchComponent } from './ExampleFetchComponent';
14 changes: 14 additions & 0 deletions plugins/frontend-plugin-demo-2/src/components/Router.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import { Route, Routes } from 'react-router-dom';

import { ExampleComponent } from './ExampleComponent';

/**
*
* @public
*/
export const Router = () => (
<Routes>
<Route path="*" element={<ExampleComponent />} />
</Routes>
);
4 changes: 4 additions & 0 deletions plugins/frontend-plugin-demo-2/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { Router } from './Router';
export * from './ExampleComponent';
export { ExampleComponentIcon } from './ExampleComponentIcon';

1 change: 1 addition & 0 deletions plugins/frontend-plugin-demo-2/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { plugin, PluginPage, PluginIcon } from './plugin';
Loading

0 comments on commit a7c1c2f

Please sign in to comment.