From 3aad657c73413c29960f98040319b3a7f9645d41 Mon Sep 17 00:00:00 2001 From: Niklas Granander Date: Thu, 1 Jul 2021 17:18:33 +0200 Subject: [PATCH] Create a basic component hierarchy and a placeholder API client Signed-off-by: Niklas Granander --- plugins/xcmetrics/src/api/XCMetricsClient.ts | 38 +++++++ .../ExampleFetchComponent => api}/index.ts | 4 +- plugins/xcmetrics/src/api/types.ts | 26 +++++ .../ExampleComponent.test.tsx | 44 -------- .../ExampleFetchComponent.test.tsx | 40 ------- .../ExampleFetchComponent.tsx | 105 ------------------ .../OverviewComponent.test.tsx | 35 ++++++ .../OverviewComponent/OverviewComponent.tsx | 54 +++++++++ .../index.ts | 2 +- .../XCMetricsPage.tsx} | 31 +----- .../src/components/XCMetricsPage/index.ts | 16 +++ plugins/xcmetrics/src/plugin.ts | 17 ++- plugins/xcmetrics/src/routes.ts | 2 +- 13 files changed, 193 insertions(+), 221 deletions(-) create mode 100644 plugins/xcmetrics/src/api/XCMetricsClient.ts rename plugins/xcmetrics/src/{components/ExampleFetchComponent => api}/index.ts (90%) create mode 100644 plugins/xcmetrics/src/api/types.ts delete mode 100644 plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.test.tsx delete mode 100644 plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx delete mode 100644 plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx create mode 100644 plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx create mode 100644 plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx rename plugins/xcmetrics/src/components/{ExampleComponent => OverviewComponent}/index.ts (91%) rename plugins/xcmetrics/src/components/{ExampleComponent/ExampleComponent.tsx => XCMetricsPage/XCMetricsPage.tsx} (51%) create mode 100644 plugins/xcmetrics/src/components/XCMetricsPage/index.ts diff --git a/plugins/xcmetrics/src/api/XCMetricsClient.ts b/plugins/xcmetrics/src/api/XCMetricsClient.ts new file mode 100644 index 0000000000..54107337f9 --- /dev/null +++ b/plugins/xcmetrics/src/api/XCMetricsClient.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { XCMetricsApi } from './types'; + +interface Options { + discoveryApi: DiscoveryApi; +} + +export class XCMetricsClient implements XCMetricsApi { + private readonly discoveryApi: DiscoveryApi; + + constructor(options: Options) { + this.discoveryApi = options.discoveryApi; + } + + async getBuilds(): Promise { + const backendUrl = `${await this.discoveryApi.getBaseUrl( + 'proxy', + )}/xcmetrics/build`; + const response = await fetch(backendUrl); + return JSON.stringify(await response.json(), null, 2); + } +} diff --git a/plugins/xcmetrics/src/components/ExampleFetchComponent/index.ts b/plugins/xcmetrics/src/api/index.ts similarity index 90% rename from plugins/xcmetrics/src/components/ExampleFetchComponent/index.ts rename to plugins/xcmetrics/src/api/index.ts index c17896a0f4..f3483ca443 100644 --- a/plugins/xcmetrics/src/components/ExampleFetchComponent/index.ts +++ b/plugins/xcmetrics/src/api/index.ts @@ -13,4 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { ExampleFetchComponent } from './ExampleFetchComponent'; + +export * from './types'; +export * from './XCMetricsClient'; diff --git a/plugins/xcmetrics/src/api/types.ts b/plugins/xcmetrics/src/api/types.ts new file mode 100644 index 0000000000..1f7fd4ebc3 --- /dev/null +++ b/plugins/xcmetrics/src/api/types.ts @@ -0,0 +1,26 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createApiRef } from '@backstage/core-plugin-api'; + +export interface XCMetricsApi { + getBuilds(): Promise; +} + +export const xcmetricsApiRef = createApiRef({ + id: 'plugin.xcmetrics.api', + description: 'Used by the XCMetrics plugin to make requests', +}); diff --git a/plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.test.tsx b/plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.test.tsx deleted file mode 100644 index 449baff57d..0000000000 --- a/plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.test.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { ExampleComponent } from './ExampleComponent'; -import { ThemeProvider } from '@material-ui/core'; -import { lightTheme } from '@backstage/theme'; -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; -import { msw, renderInTestApp } from '@backstage/test-utils'; - -describe('ExampleComponent', () => { - const server = setupServer(); - // Enable sane handlers for network requests - msw.setupDefaultHandlers(server); - - // setup mock response - beforeEach(() => { - server.use( - rest.get('/*', (_, res, ctx) => res(ctx.status(200), ctx.json({}))), - ); - }); - - it('should render', async () => { - const rendered = await renderInTestApp( - - - , - ); - expect(rendered.getByText('Welcome to xcmetrics!')).toBeInTheDocument(); - }); -}); diff --git a/plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx b/plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx deleted file mode 100644 index e3c2e033bf..0000000000 --- a/plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.test.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { render } from '@testing-library/react'; -import { ExampleFetchComponent } from './ExampleFetchComponent'; -import { rest } from 'msw'; -import { setupServer } from 'msw/node'; -import { msw } from '@backstage/test-utils'; - -describe('ExampleFetchComponent', () => { - const server = setupServer(); - // Enable sane handlers for network requests - msw.setupDefaultHandlers(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 () => { - const rendered = render(); - expect(await rendered.findByTestId('progress')).toBeInTheDocument(); - }); -}); diff --git a/plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx b/plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx deleted file mode 100644 index d7b9716439..0000000000 --- a/plugins/xcmetrics/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2021 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; -import { Table, TableColumn, Progress } from '@backstage/core-components'; -import Alert from '@material-ui/lab/Alert'; -import { useAsync } from 'react-use'; - -const useStyles = makeStyles({ - avatar: { - height: 32, - width: 32, - borderRadius: '50%', - }, -}); - -type User = { - gender: string; // "male" - name: { - title: string; // "Mr", - first: string; // "Duane", - last: string; // "Reed" - }; - location: object; // {street: {number: 5060, name: "Hickory Creek Dr"}, city: "Albany", state: "New South Wales",…} - email: string; // "duane.reed@example.com" - login: object; // {uuid: "4b785022-9a23-4ab9-8a23-cb3fb43969a9", username: "blackdog796", password: "patch",…} - dob: object; // {date: "1983-06-22T12:30:23.016Z", age: 37} - registered: object; // {date: "2006-06-13T18:48:28.037Z", age: 14} - phone: string; // "07-2154-5651" - cell: string; // "0405-592-879" - id: { - name: string; // "TFN", - value: string; // "796260432" - }; - picture: { medium: string }; // {medium: "https://randomuser.me/api/portraits/men/95.jpg",…} - nat: string; // "AU" -}; - -type DenseTableProps = { - users: User[]; -}; - -export const DenseTable = ({ users }: DenseTableProps) => { - const classes = useStyles(); - - const columns: TableColumn[] = [ - { title: 'Avatar', field: 'avatar' }, - { title: 'Name', field: 'name' }, - { title: 'Email', field: 'email' }, - { title: 'Nationality', field: 'nationality' }, - ]; - - const data = users.map(user => { - return { - avatar: ( - {user.name.first} - ), - name: `${user.name.first} ${user.name.last}`, - email: user.email, - nationality: user.nat, - }; - }); - - return ( - - ); -}; - -export const ExampleFetchComponent = () => { - const { value, loading, error } = useAsync(async (): Promise => { - const response = await fetch('https://randomuser.me/api/?results=20'); - const data = await response.json(); - return data.results; - }, []); - - if (loading) { - return ; - } else if (error) { - return {error.message}; - } - - return ; -}; diff --git a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx new file mode 100644 index 0000000000..4f00ff311a --- /dev/null +++ b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx @@ -0,0 +1,35 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { OverviewComponent } from './OverviewComponent'; +import { renderInTestApp } from '@backstage/test-utils'; +import { XCMetricsApi, xcmetricsApiRef } from '../../api'; +import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; + +describe('OverviewComponent', () => { + it('should render', async () => { + const mockApi: jest.Mocked = { + getBuilds: jest.fn().mockResolvedValue(''), + }; + + const rendered = await renderInTestApp( + + + , + ); + expect(rendered.getByText('XCMetrics Dashboard')).toBeInTheDocument(); + }); +}); diff --git a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx new file mode 100644 index 0000000000..8bdf370627 --- /dev/null +++ b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Grid } from '@material-ui/core'; +import { + InfoCard, + ContentHeader, + SupportButton, + Progress, +} from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import { xcmetricsApiRef } from '../../api'; +import { useAsync } from 'react-use'; +import { Alert } from '@material-ui/lab'; + +export const OverviewComponent = () => { + const client = useApi(xcmetricsApiRef); + const { value, loading, error } = useAsync(async (): Promise => { + return client.getBuilds(); + }, []); + + return ( + <> + + Dashboard for XCMetrics + + + + + {loading && } + {error && {error.message}} + {value &&
{value}
} +
+
+ + + +
+ + ); +}; diff --git a/plugins/xcmetrics/src/components/ExampleComponent/index.ts b/plugins/xcmetrics/src/components/OverviewComponent/index.ts similarity index 91% rename from plugins/xcmetrics/src/components/ExampleComponent/index.ts rename to plugins/xcmetrics/src/components/OverviewComponent/index.ts index 212740dcdb..58b284e6f1 100644 --- a/plugins/xcmetrics/src/components/ExampleComponent/index.ts +++ b/plugins/xcmetrics/src/components/OverviewComponent/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { ExampleComponent } from './ExampleComponent'; +export * from './OverviewComponent'; diff --git a/plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.tsx b/plugins/xcmetrics/src/components/XCMetricsPage/XCMetricsPage.tsx similarity index 51% rename from plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.tsx rename to plugins/xcmetrics/src/components/XCMetricsPage/XCMetricsPage.tsx index 84fb3441f6..0c1b1d1dde 100644 --- a/plugins/xcmetrics/src/components/ExampleComponent/ExampleComponent.tsx +++ b/plugins/xcmetrics/src/components/XCMetricsPage/XCMetricsPage.tsx @@ -14,40 +14,17 @@ * limitations under the License. */ import React from 'react'; -import { Typography, Grid } from '@material-ui/core'; -import { - InfoCard, - Header, - Page, - Content, - ContentHeader, - HeaderLabel, - SupportButton, -} from '@backstage/core-components'; -import { ExampleFetchComponent } from '../ExampleFetchComponent'; +import { Content, Header, HeaderLabel, Page } from '@backstage/core-components'; +import { OverviewComponent } from '../OverviewComponent'; -export const ExampleComponent = () => ( +export const XCMetricsPage = () => (
- - A description of your plugin goes here. - - - - - - All content should be wrapped in a card like this. - - - - - - - +
); diff --git a/plugins/xcmetrics/src/components/XCMetricsPage/index.ts b/plugins/xcmetrics/src/components/XCMetricsPage/index.ts new file mode 100644 index 0000000000..2ffdb84d40 --- /dev/null +++ b/plugins/xcmetrics/src/components/XCMetricsPage/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './XCMetricsPage'; diff --git a/plugins/xcmetrics/src/plugin.ts b/plugins/xcmetrics/src/plugin.ts index 51fee5dc54..d01392a110 100644 --- a/plugins/xcmetrics/src/plugin.ts +++ b/plugins/xcmetrics/src/plugin.ts @@ -14,10 +14,12 @@ * limitations under the License. */ import { + createApiFactory, createPlugin, createRoutableExtension, + discoveryApiRef, } from '@backstage/core-plugin-api'; - +import { xcmetricsApiRef, XCMetricsClient } from './api'; import { rootRouteRef } from './routes'; export const xcmetricsPlugin = createPlugin({ @@ -25,12 +27,23 @@ export const xcmetricsPlugin = createPlugin({ routes: { root: rootRouteRef, }, + apis: [ + createApiFactory({ + api: xcmetricsApiRef, + deps: { + discoveryApi: discoveryApiRef, + }, + factory({ discoveryApi }) { + return new XCMetricsClient({ discoveryApi }); + }, + }), + ], }); export const XcmetricsPage = xcmetricsPlugin.provide( createRoutableExtension({ component: () => - import('./components/ExampleComponent').then(m => m.ExampleComponent), + import('./components/XCMetricsPage').then(m => m.XCMetricsPage), mountPoint: rootRouteRef, }), ); diff --git a/plugins/xcmetrics/src/routes.ts b/plugins/xcmetrics/src/routes.ts index 7a63a024d3..7acd62c363 100644 --- a/plugins/xcmetrics/src/routes.ts +++ b/plugins/xcmetrics/src/routes.ts @@ -16,5 +16,5 @@ import { createRouteRef } from '@backstage/core-plugin-api'; export const rootRouteRef = createRouteRef({ - title: 'xcmetrics', + title: 'XCMetrics', });