Merge pull request #6805 from ngranander/xcmetrics-refactor
Internal refactor of XCMetrics plugin
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-xcmetrics': patch
|
||||
---
|
||||
|
||||
Internal refactoring
|
||||
+5
-5
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { AccordionComponent } from './AccordionComponent';
|
||||
import { Accordion } from './Accordion';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('AccordionComponent', () => {
|
||||
describe('Accordion', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<AccordionComponent
|
||||
<Accordion
|
||||
id="accordionId"
|
||||
heading="heading"
|
||||
secondaryHeading="secondaryHeading"
|
||||
@@ -34,13 +34,13 @@ describe('AccordionComponent', () => {
|
||||
|
||||
it('should show content when clicked', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<AccordionComponent
|
||||
<Accordion
|
||||
id="accordionId"
|
||||
heading="heading"
|
||||
secondaryHeading="secondaryHeading"
|
||||
>
|
||||
Content
|
||||
</AccordionComponent>,
|
||||
</Accordion>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText('Content')).not.toBeVisible();
|
||||
+7
-9
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
Accordion as MuiAccordion,
|
||||
AccordionSummary as MuiAccordionSummary,
|
||||
Typography,
|
||||
AccordionDetails,
|
||||
makeStyles,
|
||||
@@ -45,17 +45,15 @@ interface AccordionProps {
|
||||
unmountOnExit?: boolean;
|
||||
}
|
||||
|
||||
export const AccordionComponent = (
|
||||
props: PropsWithChildren<AccordionProps>,
|
||||
) => {
|
||||
export const Accordion = (props: PropsWithChildren<AccordionProps>) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
<MuiAccordion
|
||||
disabled={props.disabled}
|
||||
TransitionProps={{ unmountOnExit: props.unmountOnExit ?? false }}
|
||||
>
|
||||
<AccordionSummary
|
||||
<MuiAccordionSummary
|
||||
expandIcon={<ExpandMoreIcon />}
|
||||
aria-controls={`${props.id}-content`}
|
||||
id={`${props.id}-header`}
|
||||
@@ -64,8 +62,8 @@ export const AccordionComponent = (
|
||||
<Typography className={classes.secondaryHeading}>
|
||||
{props.secondaryHeading}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
</MuiAccordionSummary>
|
||||
<AccordionDetails>{props.children}</AccordionDetails>
|
||||
</Accordion>
|
||||
</MuiAccordion>
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './BuildListComponent';
|
||||
export { Accordion } from './Accordion';
|
||||
+12
-12
@@ -16,29 +16,29 @@
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { BuildDetailsComponent, withRequest } from './BuildDetailsComponent';
|
||||
import { BuildDetails, withRequest } from './BuildDetails';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../AccordionComponent', () => ({
|
||||
AccordionComponent: ({ heading }: { heading: string }) => (
|
||||
jest.mock('../Accordion', () => ({
|
||||
Accordion: ({ heading }: { heading: string }) => (
|
||||
<div>accordion-{heading}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../BuildTimelineComponent', () => ({
|
||||
BuildTimelineComponent: () => 'BuildTimelineComponent',
|
||||
jest.mock('../BuildTimeline', () => ({
|
||||
BuildTimeline: () => 'BuildTimeline',
|
||||
}));
|
||||
|
||||
describe('BuildDetailsComponent', () => {
|
||||
describe('BuildDetails', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildDetailsComponent buildData={client.mockBuildResponse} />
|
||||
<BuildDetails buildData={client.mockBuildResponse} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -56,15 +56,15 @@ describe('BuildDetailsComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('BuildDetailsComponent with request', () => {
|
||||
const BuildDetails = withRequest(BuildDetailsComponent);
|
||||
describe('BuildDetails with request', () => {
|
||||
const BuildDetailsWithRequest = withRequest(BuildDetails);
|
||||
|
||||
it('should fetch the build and render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildDetails buildId={client.mockBuild.id} />
|
||||
<BuildDetailsWithRequest buildId={client.mockBuild.id} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -81,7 +81,7 @@ describe('BuildDetailsComponent with request', () => {
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildDetails buildId={client.mockBuild.id} />
|
||||
<BuildDetailsWithRequest buildId={client.mockBuild.id} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -95,7 +95,7 @@ describe('BuildDetailsComponent with request', () => {
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildDetails buildId={client.mockBuild.id} />
|
||||
<BuildDetailsWithRequest buildId={client.mockBuild.id} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
+19
-19
@@ -21,11 +21,11 @@ import { Alert } from '@material-ui/lab';
|
||||
import { useAsync } from 'react-use';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { formatDuration, formatStatus, formatTime } from '../../utils';
|
||||
import { StatusIconComponent as StatusIcon } from '../StatusIconComponent';
|
||||
import { StatusIcon } from '../StatusIcon';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { AccordionComponent } from '../AccordionComponent';
|
||||
import { BuildTimelineComponent } from '../BuildTimelineComponent';
|
||||
import { PreformattedTextComponent } from '../PreformattedTextComponent';
|
||||
import { Accordion } from '../Accordion';
|
||||
import { BuildTimeline } from '../BuildTimeline';
|
||||
import { PreformattedText } from '../PreformattedText';
|
||||
|
||||
const useStyles = makeStyles((theme: BackstageTheme) =>
|
||||
createStyles({
|
||||
@@ -41,7 +41,7 @@ interface BuildDetailsProps {
|
||||
showId?: boolean;
|
||||
}
|
||||
|
||||
export const BuildDetailsComponent = ({
|
||||
export const BuildDetails = ({
|
||||
buildData: { build, targets, xcode },
|
||||
showId,
|
||||
}: BuildDetailsProps) => {
|
||||
@@ -92,7 +92,7 @@ export const BuildDetailsComponent = ({
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
<AccordionComponent
|
||||
<Accordion
|
||||
id="buildHost"
|
||||
heading="Host"
|
||||
secondaryHeading={build.machineName}
|
||||
@@ -101,9 +101,9 @@ export const BuildDetailsComponent = ({
|
||||
{!hostResult.loading && hostResult.value && (
|
||||
<StructuredMetadataTable metadata={hostResult.value} />
|
||||
)}
|
||||
</AccordionComponent>
|
||||
</Accordion>
|
||||
|
||||
<AccordionComponent
|
||||
<Accordion
|
||||
id="buildErrors"
|
||||
heading="Errors"
|
||||
secondaryHeading={build.errorCount}
|
||||
@@ -114,7 +114,7 @@ export const BuildDetailsComponent = ({
|
||||
{!errorsResult.loading &&
|
||||
errorsResult.value?.map((error, idx) => (
|
||||
<div key={error.id}>
|
||||
<PreformattedTextComponent
|
||||
<PreformattedText
|
||||
title="Error Details"
|
||||
text={error.detail}
|
||||
maxChars={190}
|
||||
@@ -126,9 +126,9 @@ export const BuildDetailsComponent = ({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</AccordionComponent>
|
||||
</Accordion>
|
||||
|
||||
<AccordionComponent
|
||||
<Accordion
|
||||
id="buildWarnings"
|
||||
heading="Warnings"
|
||||
secondaryHeading={build.warningCount}
|
||||
@@ -139,7 +139,7 @@ export const BuildDetailsComponent = ({
|
||||
{!warningsResult.loading &&
|
||||
warningsResult.value?.map((warning, idx) => (
|
||||
<div key={warning.id}>
|
||||
<PreformattedTextComponent
|
||||
<PreformattedText
|
||||
title="Warning Details"
|
||||
text={warning.detail ?? warning.title}
|
||||
maxChars={190}
|
||||
@@ -151,9 +151,9 @@ export const BuildDetailsComponent = ({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</AccordionComponent>
|
||||
</Accordion>
|
||||
|
||||
<AccordionComponent
|
||||
<Accordion
|
||||
id="buildMetadata"
|
||||
heading="Metadata"
|
||||
disabled={!metadataResult.loading && !metadataResult.value}
|
||||
@@ -162,11 +162,11 @@ export const BuildDetailsComponent = ({
|
||||
{!metadataResult.loading && metadataResult.value && (
|
||||
<StructuredMetadataTable metadata={metadataResult.value} />
|
||||
)}
|
||||
</AccordionComponent>
|
||||
</Accordion>
|
||||
|
||||
<AccordionComponent id="buildTimeline" heading="Timeline" unmountOnExit>
|
||||
<BuildTimelineComponent targets={targets} />
|
||||
</AccordionComponent>
|
||||
<Accordion id="buildTimeline" heading="Timeline" unmountOnExit>
|
||||
<BuildTimeline targets={targets} />
|
||||
</Accordion>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
@@ -177,7 +177,7 @@ type WithRequestProps = Omit<BuildDetailsProps, 'buildData'> & {
|
||||
};
|
||||
|
||||
export const withRequest =
|
||||
(Component: typeof BuildDetailsComponent) =>
|
||||
(Component: typeof BuildDetails) =>
|
||||
({ buildId, ...props }: WithRequestProps) => {
|
||||
const client = useApi(xcmetricsApiRef);
|
||||
const {
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { AccordionComponent } from './AccordionComponent';
|
||||
export { BuildDetails, withRequest } from './BuildDetails';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export { BuildDetailsComponent, withRequest } from './BuildDetailsComponent';
|
||||
+10
-12
@@ -16,29 +16,29 @@
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { BuildListComponent } from './BuildListComponent';
|
||||
import { BuildList } from './BuildList';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../BuildListFilterComponent', () => ({
|
||||
BuildListFilterComponent: () => 'BuildListFilterComponent',
|
||||
jest.mock('../BuildListFilter', () => ({
|
||||
BuildListFilter: () => 'BuildListFilter',
|
||||
}));
|
||||
|
||||
jest.mock('../BuildDetailsComponent', () => ({
|
||||
jest.mock('../BuildDetails', () => ({
|
||||
withRequest: (component: any) => component,
|
||||
BuildDetailsComponent: () => 'BuildDetailsComponent',
|
||||
BuildDetails: () => 'BuildDetails',
|
||||
}));
|
||||
|
||||
describe('BuildListComponent', () => {
|
||||
describe('BuildList', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListComponent />
|
||||
<BuildList />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -53,16 +53,14 @@ describe('BuildListComponent', () => {
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListComponent />
|
||||
<BuildList />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
userEvent.click(
|
||||
(await rendered.findAllByLabelText('Detail panel visiblity toggle'))[0],
|
||||
);
|
||||
expect(
|
||||
await rendered.findByText('BuildDetailsComponent'),
|
||||
).toBeInTheDocument();
|
||||
expect(await rendered.findByText('BuildDetails')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show errors', async () => {
|
||||
@@ -75,7 +73,7 @@ describe('BuildListComponent', () => {
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListComponent />
|
||||
<BuildList />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
+5
-5
@@ -18,10 +18,10 @@ import { Table } from '@backstage/core-components';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { BuildFilters, xcmetricsApiRef } from '../../api';
|
||||
import { createStyles, Grid, makeStyles } from '@material-ui/core';
|
||||
import { BuildListFilterComponent as Filters } from '../BuildListFilterComponent';
|
||||
import { BuildListFilter as Filters } from '../BuildListFilter';
|
||||
import { DateTime } from 'luxon';
|
||||
import { buildPageColumns } from '../BuildTableColumns';
|
||||
import { BuildDetailsComponent, withRequest } from '../BuildDetailsComponent';
|
||||
import { BuildDetails, withRequest } from '../BuildDetails';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
const useStyles = makeStyles((theme: BackstageTheme) =>
|
||||
@@ -33,7 +33,7 @@ const useStyles = makeStyles((theme: BackstageTheme) =>
|
||||
}),
|
||||
);
|
||||
|
||||
export const BuildListComponent = () => {
|
||||
export const BuildList = () => {
|
||||
const classes = useStyles();
|
||||
const client = useApi(xcmetricsApiRef);
|
||||
const tableRef = useRef<any>();
|
||||
@@ -81,10 +81,10 @@ export const BuildListComponent = () => {
|
||||
});
|
||||
}}
|
||||
detailPanel={rowData => {
|
||||
const BuildDetails = withRequest(BuildDetailsComponent);
|
||||
const BuildDetailsWithRequest = withRequest(BuildDetails);
|
||||
return (
|
||||
<div className={classes.detailPanel}>
|
||||
<BuildDetails buildId={(rowData as any).rowData.id} />
|
||||
<BuildDetailsWithRequest buildId={(rowData as any).rowData.id} />
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './DatePickerComponent';
|
||||
export { BuildList } from './BuildList';
|
||||
+8
-10
@@ -17,15 +17,15 @@ import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { BuildListFilterComponent } from './BuildListFilterComponent';
|
||||
import { BuildListFilter } from './BuildListFilter';
|
||||
import { BuildFilters, xcmetricsApiRef } from '../../api';
|
||||
import { RenderResult } from '@testing-library/react';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../DatePickerComponent', () => ({
|
||||
DatePickerComponent: () => 'DatePickerComponent',
|
||||
jest.mock('../DatePicker', () => ({
|
||||
DatePicker: () => 'DatePicker',
|
||||
}));
|
||||
|
||||
const initialValues = {
|
||||
@@ -40,7 +40,7 @@ const renderWithFiltersVisible = async (
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListFilterComponent
|
||||
<BuildListFilter
|
||||
initialValues={initialValues}
|
||||
onFilterChange={callback ?? jest.fn()}
|
||||
/>
|
||||
@@ -64,13 +64,13 @@ const setProjectFilter = async (rendered: RenderResult, option: string) => {
|
||||
userEvent.click(options[options.length - 1]);
|
||||
};
|
||||
|
||||
describe('BuildListFilterComponent', () => {
|
||||
describe('BuildListFilter', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<BuildListFilterComponent
|
||||
<BuildListFilter
|
||||
initialValues={initialValues}
|
||||
onFilterChange={jest.fn()}
|
||||
/>
|
||||
@@ -83,14 +83,12 @@ describe('BuildListFilterComponent', () => {
|
||||
it('should toggle between showing and hiding filters', async () => {
|
||||
const rendered = await renderWithFiltersVisible();
|
||||
|
||||
expect(
|
||||
(await rendered.findAllByText('DatePickerComponent')).length,
|
||||
).toEqual(2);
|
||||
expect((await rendered.findAllByText('DatePicker')).length).toEqual(2);
|
||||
expect(await rendered.findByText('Status')).toBeInTheDocument();
|
||||
expect(await rendered.findByText('Project')).toBeInTheDocument();
|
||||
|
||||
userEvent.click(rendered.getByLabelText('hide filters'));
|
||||
expect(rendered.queryByText('DatePickerComponent')).toBeNull();
|
||||
expect(rendered.queryByText('DatePicker')).toBeNull();
|
||||
expect(rendered.queryByText('Status')).toBeNull();
|
||||
expect(rendered.queryByText('Project')).toBeNull();
|
||||
});
|
||||
+4
-4
@@ -22,7 +22,7 @@ import { BackstageTheme } from '@backstage/theme';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { useAsync } from 'react-use';
|
||||
import { BuildFilters, BuildStatus, xcmetricsApiRef } from '../../api';
|
||||
import { DatePickerComponent } from '../DatePickerComponent';
|
||||
import { DatePicker } from '../DatePicker';
|
||||
|
||||
const toSelectItems = (strings: string[]) => {
|
||||
return strings.map(str => ({ label: str, value: str }));
|
||||
@@ -41,7 +41,7 @@ interface FiltersProps {
|
||||
onFilterChange: (filters: BuildFilters) => void;
|
||||
}
|
||||
|
||||
export const BuildListFilterComponent = ({
|
||||
export const BuildListFilter = ({
|
||||
onFilterChange,
|
||||
initialValues,
|
||||
}: FiltersProps) => {
|
||||
@@ -93,14 +93,14 @@ export const BuildListFilterComponent = ({
|
||||
className={classes.filtersContent}
|
||||
>
|
||||
<Grid item sm={6} md={4} lg={2}>
|
||||
<DatePickerComponent
|
||||
<DatePicker
|
||||
label="From"
|
||||
value={values.from}
|
||||
onDateChange={date => setValues({ ...values, from: date })}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sm={6} md={4} lg={2}>
|
||||
<DatePickerComponent
|
||||
<DatePicker
|
||||
label="To"
|
||||
value={values.to}
|
||||
onDateChange={date => setValues({ ...values, to: date })}
|
||||
@@ -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 { BuildListFilter } from './BuildListFilter';
|
||||
@@ -19,7 +19,7 @@ import React from 'react';
|
||||
import { TableColumn } from '@backstage/core-components';
|
||||
import { Build } from '../api';
|
||||
import { formatTime, formatDuration } from '../utils';
|
||||
import { StatusIconComponent as StatusIcon } from './StatusIconComponent';
|
||||
import { StatusIcon } from './StatusIcon';
|
||||
|
||||
const baseColumns: TableColumn<Build>[] = [
|
||||
{
|
||||
|
||||
+4
-10
@@ -15,19 +15,15 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { BuildTimelineComponent } from './BuildTimelineComponent';
|
||||
import { BuildTimeline } from './BuildTimeline';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
describe('BuildTimelineComponent', () => {
|
||||
describe('BuildTimeline', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<BuildTimelineComponent
|
||||
targets={[client.mockTarget]}
|
||||
height={100}
|
||||
width={100}
|
||||
/>,
|
||||
<BuildTimeline targets={[client.mockTarget]} height={100} width={100} />,
|
||||
);
|
||||
expect(
|
||||
await rendered.findByText(client.mockTarget.name),
|
||||
@@ -35,9 +31,7 @@ describe('BuildTimelineComponent', () => {
|
||||
});
|
||||
|
||||
it('should render a message if no targets are provided', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<BuildTimelineComponent targets={[]} />,
|
||||
);
|
||||
const rendered = await renderInTestApp(<BuildTimeline targets={[]} />);
|
||||
expect(rendered.getByText('No Targets')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -85,7 +85,7 @@ export interface BuildTimelineProps {
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export const BuildTimelineComponent = ({
|
||||
export const BuildTimeline = ({
|
||||
targets,
|
||||
height,
|
||||
width,
|
||||
@@ -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 { BuildTimeline } from './BuildTimeline';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export { BuildTimelineComponent } from './BuildTimelineComponent';
|
||||
@@ -17,27 +17,27 @@ import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { BuildsPage } from './BuildsPage';
|
||||
|
||||
jest.mock('../BuildDetailsComponent', () => ({
|
||||
jest.mock('../BuildDetails', () => ({
|
||||
withRequest: (component: any) => component,
|
||||
BuildDetailsComponent: () => 'BuildDetailsComponent',
|
||||
BuildDetails: () => 'BuildDetails',
|
||||
}));
|
||||
|
||||
jest.mock('../BuildListComponent', () => ({
|
||||
BuildListComponent: () => 'BuildListComponent',
|
||||
jest.mock('../BuildList', () => ({
|
||||
BuildList: () => 'BuildList',
|
||||
}));
|
||||
|
||||
describe('BuildPageComponent', () => {
|
||||
it('should render BuildDetailsWithDataComponent if build id is provided in path', async () => {
|
||||
describe('BuildPage', () => {
|
||||
it('should render BuildDetails if build id is provided in path', async () => {
|
||||
const rendered = await renderInTestApp(<BuildsPage />, {
|
||||
routeEntries: [`/buildId`],
|
||||
});
|
||||
|
||||
expect(rendered.getByText('BuildDetailsComponent')).toBeInTheDocument();
|
||||
expect(rendered.getByText('BuildDetails')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render BuildListComponent if no build id is provided in path', async () => {
|
||||
it('should render BuildList if no build id is provided in path', async () => {
|
||||
const rendered = await renderInTestApp(<BuildsPage />);
|
||||
|
||||
expect(rendered.getByText('BuildListComponent')).toBeInTheDocument();
|
||||
expect(rendered.getByText('BuildList')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,22 +16,22 @@
|
||||
import React from 'react';
|
||||
import { useRouteRefParams } from '@backstage/core-plugin-api';
|
||||
import { buildsRouteRef } from '../../routes';
|
||||
import { BuildListComponent } from '../BuildListComponent';
|
||||
import { BuildDetailsComponent, withRequest } from '../BuildDetailsComponent';
|
||||
import { BuildList } from '../BuildList';
|
||||
import { BuildDetails, withRequest } from '../BuildDetails';
|
||||
import { InfoCard } from '@backstage/core-components';
|
||||
|
||||
export const BuildsPage = () => {
|
||||
const { '*': buildId } = useRouteRefParams(buildsRouteRef) ?? { '*': '' };
|
||||
|
||||
if (buildId) {
|
||||
const BuildDetails = withRequest(BuildDetailsComponent);
|
||||
const BuildDetailsWithRequest = withRequest(BuildDetails);
|
||||
|
||||
return (
|
||||
<InfoCard title="Build Details" subheader={buildId}>
|
||||
<BuildDetails buildId={buildId} showId={false} />
|
||||
<BuildDetailsWithRequest buildId={buildId} showId={false} />
|
||||
</InfoCard>
|
||||
);
|
||||
}
|
||||
|
||||
return <BuildListComponent />;
|
||||
return <BuildList />;
|
||||
};
|
||||
|
||||
+4
-6
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { DataValueComponent, DataValueGridItem } from './DataValueComponent';
|
||||
import { DataValue, DataValueGridItem } from './DataValue';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('DataValueComponent', () => {
|
||||
describe('DataValue', () => {
|
||||
it('should render', async () => {
|
||||
const field = 'Field';
|
||||
const value = 'Value';
|
||||
const rendered = await renderInTestApp(
|
||||
<DataValueComponent field={field} value={value} />,
|
||||
<DataValue field={field} value={value} />,
|
||||
);
|
||||
expect(rendered.getByText(field)).toBeInTheDocument();
|
||||
expect(rendered.getByText(value)).toBeInTheDocument();
|
||||
@@ -30,9 +30,7 @@ describe('DataValueComponent', () => {
|
||||
|
||||
it('should render placeholder text when no value is present', async () => {
|
||||
const field = 'Field';
|
||||
const rendered = await renderInTestApp(
|
||||
<DataValueComponent field={field} />,
|
||||
);
|
||||
const rendered = await renderInTestApp(<DataValue field={field} />);
|
||||
expect(rendered.getByText(field)).toBeInTheDocument();
|
||||
expect(rendered.getByText('--')).toBeInTheDocument();
|
||||
});
|
||||
+2
-2
@@ -21,7 +21,7 @@ interface DataValueProps {
|
||||
value?: string | number | null | undefined;
|
||||
}
|
||||
|
||||
export const DataValueComponent = ({ field, value }: DataValueProps) => {
|
||||
export const DataValue = ({ field, value }: DataValueProps) => {
|
||||
return (
|
||||
<div>
|
||||
<Typography variant="caption">{field}</Typography>
|
||||
@@ -38,6 +38,6 @@ interface GridProps {
|
||||
|
||||
export const DataValueGridItem = (props: DataValueProps & GridProps) => (
|
||||
<Grid item xs={props.xs ?? 6} md={props.md ?? 6} lg={props.lg ?? 4}>
|
||||
<DataValueComponent {...props} />
|
||||
<DataValue {...props} />
|
||||
</Grid>
|
||||
);
|
||||
@@ -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 { DataValue, DataValueGridItem } from './DataValue';
|
||||
+5
-7
@@ -15,15 +15,13 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { DatePickerComponent } from './DatePickerComponent';
|
||||
import { DatePicker } from './DatePicker';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('DatePickerComponent', () => {
|
||||
describe('DatePicker', () => {
|
||||
it('should render', async () => {
|
||||
const label = 'label';
|
||||
const rendered = await renderInTestApp(
|
||||
<DatePickerComponent label={label} />,
|
||||
);
|
||||
const rendered = await renderInTestApp(<DatePicker label={label} />);
|
||||
expect(rendered.getByText(label)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -31,7 +29,7 @@ describe('DatePickerComponent', () => {
|
||||
const label = 'label';
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderInTestApp(
|
||||
<DatePickerComponent label={label} onDateChange={callback} />,
|
||||
<DatePicker label={label} onDateChange={callback} />,
|
||||
);
|
||||
const input = rendered.getByLabelText(label);
|
||||
|
||||
@@ -43,7 +41,7 @@ describe('DatePickerComponent', () => {
|
||||
const label = 'label';
|
||||
const callback = jest.fn();
|
||||
const rendered = await renderInTestApp(
|
||||
<DatePickerComponent label={label} onDateChange={callback} />,
|
||||
<DatePicker label={label} onDateChange={callback} />,
|
||||
);
|
||||
const input = rendered.getByLabelText(label);
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ interface DatePickerProps {
|
||||
onDateChange?: (date: string) => void;
|
||||
}
|
||||
|
||||
export const DatePickerComponent = ({
|
||||
export const DatePicker = ({
|
||||
label,
|
||||
onDateChange,
|
||||
...inputProps
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './OverviewComponent';
|
||||
export { DatePicker } from './DatePicker';
|
||||
+9
-9
@@ -17,26 +17,26 @@ import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { OverviewComponent } from './OverviewComponent';
|
||||
import { Overview } from './Overview';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../OverviewTrendsComponent', () => ({
|
||||
OverviewTrendsComponent: () => 'OverviewTrendsComponent',
|
||||
jest.mock('../OverviewTrends', () => ({
|
||||
OverviewTrends: () => 'OverviewTrends',
|
||||
}));
|
||||
|
||||
jest.mock('../StatusMatrixComponent', () => ({
|
||||
StatusMatrixComponent: () => 'StatusMatrixComponent',
|
||||
jest.mock('../StatusMatrix', () => ({
|
||||
StatusMatrix: () => 'StatusMatrix',
|
||||
}));
|
||||
|
||||
describe('OverviewComponent', () => {
|
||||
describe('Overview', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<OverviewComponent />
|
||||
<Overview />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -50,7 +50,7 @@ describe('OverviewComponent', () => {
|
||||
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={ApiRegistry.with(xcmetricsApiRef, api)}>
|
||||
<OverviewComponent />
|
||||
<Overview />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('OverviewComponent', () => {
|
||||
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={ApiRegistry.with(xcmetricsApiRef, api)}>
|
||||
<OverviewComponent />
|
||||
<Overview />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
+5
-5
@@ -26,12 +26,12 @@ import { useApi } from '@backstage/core-plugin-api';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
import { useAsync } from 'react-use';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import { StatusMatrixComponent } from '../StatusMatrixComponent';
|
||||
import { StatusMatrix } from '../StatusMatrix';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import { OverviewTrendsComponent } from '../OverviewTrendsComponent';
|
||||
import { OverviewTrends } from '../OverviewTrends';
|
||||
import { overviewColumns } from '../BuildTableColumns';
|
||||
|
||||
export const OverviewComponent = () => {
|
||||
export const Overview = () => {
|
||||
const client = useApi(xcmetricsApiRef);
|
||||
const {
|
||||
value: builds,
|
||||
@@ -74,14 +74,14 @@ export const OverviewComponent = () => {
|
||||
title={
|
||||
<>
|
||||
Latest Builds
|
||||
<StatusMatrixComponent />
|
||||
<StatusMatrix />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4} lg={4} xl={3}>
|
||||
<InfoCard>
|
||||
<OverviewTrendsComponent />
|
||||
<OverviewTrends />
|
||||
</InfoCard>
|
||||
</Grid>
|
||||
</Grid>
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './DataValueComponent';
|
||||
export { Overview } from './Overview';
|
||||
+6
-6
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { OverviewTrendsComponent } from './OverviewTrendsComponent';
|
||||
import { OverviewTrends } from './OverviewTrends';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
@@ -23,13 +23,13 @@ import userEvent from '@testing-library/user-event';
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
describe('OverviewTrendsComponent', () => {
|
||||
describe('OverviewTrends', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<OverviewTrendsComponent />
|
||||
<OverviewTrends />
|
||||
</ApiProvider>,
|
||||
);
|
||||
expect(rendered.getByText('Trends for')).toBeInTheDocument();
|
||||
@@ -43,7 +43,7 @@ describe('OverviewTrendsComponent', () => {
|
||||
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={ApiRegistry.with(xcmetricsApiRef, api)}>
|
||||
<OverviewTrendsComponent />
|
||||
<OverviewTrends />
|
||||
</ApiProvider>,
|
||||
);
|
||||
expect(rendered.getByText('--')).toBeInTheDocument();
|
||||
@@ -54,7 +54,7 @@ describe('OverviewTrendsComponent', () => {
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<OverviewTrendsComponent />
|
||||
<OverviewTrends />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('OverviewTrendsComponent', () => {
|
||||
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={ApiRegistry.with(xcmetricsApiRef, api)}>
|
||||
<OverviewTrendsComponent />
|
||||
<OverviewTrends />
|
||||
</ApiProvider>,
|
||||
);
|
||||
expect(rendered.getByText(buildCountError)).toBeInTheDocument();
|
||||
+6
-6
@@ -16,12 +16,12 @@
|
||||
import { Grid, makeStyles, useTheme } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
import { Progress, Select } from '@backstage/core-components';
|
||||
import { TrendComponent } from '../TrendComponent';
|
||||
import { Trend } from '../Trend';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
import { useAsync } from 'react-use';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { DataValueGridItem } from '../DataValueComponent';
|
||||
import { DataValueGridItem } from '../DataValue';
|
||||
import {
|
||||
formatDuration,
|
||||
formatPercentage,
|
||||
@@ -49,7 +49,7 @@ const DAYS_SELECT_ITEMS = [
|
||||
{ label: '60 days', value: 60 },
|
||||
];
|
||||
|
||||
export const OverviewTrendsComponent = () => {
|
||||
export const OverviewTrends = () => {
|
||||
const [days, setDays] = useState(14);
|
||||
const theme = useTheme<BackstageTheme>();
|
||||
const classes = useStyles();
|
||||
@@ -103,17 +103,17 @@ export const OverviewTrendsComponent = () => {
|
||||
)}
|
||||
{(!buildCountsResult.error || !buildTimesResult.error) && (
|
||||
<div className={classes.spacingVertical}>
|
||||
<TrendComponent
|
||||
<Trend
|
||||
title="Build Time"
|
||||
color={theme.palette.secondary.main}
|
||||
data={getValues(e => e.durationP50, buildTimesResult.value)}
|
||||
/>
|
||||
<TrendComponent
|
||||
<Trend
|
||||
title="Error Rate"
|
||||
color={theme.palette.status.warning}
|
||||
data={getErrorRatios(buildCountsResult.value)}
|
||||
/>
|
||||
<TrendComponent
|
||||
<Trend
|
||||
title="Build Count"
|
||||
color={theme.palette.primary.main}
|
||||
data={getValues(e => e.builds, buildCountsResult.value)}
|
||||
@@ -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 { OverviewTrends } from './OverviewTrends';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export * from './OverviewTrendsComponent';
|
||||
+1
-1
@@ -65,7 +65,7 @@ interface NonExpandableProps extends PreformattedTextProps {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const PreformattedTextComponent = ({
|
||||
export const PreformattedText = ({
|
||||
text,
|
||||
maxChars,
|
||||
expandable,
|
||||
@@ -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 { PreformattedText } from './PreformattedText';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export { PreformattedTextComponent } from './PreformattedTextComponent';
|
||||
+3
-3
@@ -17,20 +17,20 @@ import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { StatusCellComponent } from './StatusCellComponent';
|
||||
import { StatusCell } from './StatusCell';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
import { formatDuration, formatStatus } from '../../utils';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
describe('StatusCellComponent', () => {
|
||||
describe('StatusCell', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<StatusCellComponent
|
||||
<StatusCell
|
||||
buildStatus={{
|
||||
id: client.mockBuild.id,
|
||||
buildStatus: client.mockBuild.buildStatus,
|
||||
+1
-1
@@ -102,7 +102,7 @@ const useStyles = makeStyles<BackstageTheme, StatusCellProps>(theme => ({
|
||||
} as StatusStyle),
|
||||
}));
|
||||
|
||||
export const StatusCellComponent = (props: StatusCellProps) => {
|
||||
export const StatusCell = (props: StatusCellProps) => {
|
||||
const classes = useStyles(props);
|
||||
const { buildStatus } = props;
|
||||
|
||||
@@ -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 { StatusCell } from './StatusCell';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export * from './StatusCellComponent';
|
||||
+5
-9
@@ -16,23 +16,19 @@
|
||||
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { StatusIconComponent } from './StatusIconComponent';
|
||||
import { StatusIcon } from './StatusIcon';
|
||||
|
||||
describe('StatusIconComponent', () => {
|
||||
describe('StatusIcon', () => {
|
||||
it('should render', async () => {
|
||||
let rendered = await renderInTestApp(
|
||||
<StatusIconComponent buildStatus="succeeded" />,
|
||||
<StatusIcon buildStatus="succeeded" />,
|
||||
);
|
||||
expect(rendered.getByLabelText('Status ok')).toBeInTheDocument();
|
||||
|
||||
rendered = await renderInTestApp(
|
||||
<StatusIconComponent buildStatus="failed" />,
|
||||
);
|
||||
rendered = await renderInTestApp(<StatusIcon buildStatus="failed" />);
|
||||
expect(rendered.getByLabelText('Status error')).toBeInTheDocument();
|
||||
|
||||
rendered = await renderInTestApp(
|
||||
<StatusIconComponent buildStatus="stopped" />,
|
||||
);
|
||||
rendered = await renderInTestApp(<StatusIcon buildStatus="stopped" />);
|
||||
expect(rendered.getByLabelText('Status warning')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -31,5 +31,5 @@ interface StatusIconProps {
|
||||
buildStatus: BuildStatus;
|
||||
}
|
||||
|
||||
export const StatusIconComponent = ({ buildStatus }: StatusIconProps) =>
|
||||
export const StatusIcon = ({ buildStatus }: StatusIconProps) =>
|
||||
STATUS_ICONS[buildStatus];
|
||||
@@ -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 { StatusIcon } from './StatusIcon';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export { StatusIconComponent } from './StatusIconComponent';
|
||||
+3
-3
@@ -16,19 +16,19 @@
|
||||
import React from 'react';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
|
||||
import { StatusMatrixComponent } from './StatusMatrixComponent';
|
||||
import { StatusMatrix } from './StatusMatrix';
|
||||
import { xcmetricsApiRef } from '../../api';
|
||||
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
describe('StatusMatrixComponent', () => {
|
||||
describe('StatusMatrix', () => {
|
||||
it('should render', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<StatusMatrixComponent />
|
||||
<StatusMatrix />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
+4
-8
@@ -21,7 +21,7 @@ import { useAsync, useMeasure } from 'react-use';
|
||||
import { cn } from '../../utils';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import { StatusCellComponent } from '../StatusCellComponent';
|
||||
import { StatusCell } from '../StatusCell';
|
||||
|
||||
const CELL_SIZE = 12;
|
||||
const CELL_MARGIN = 4;
|
||||
@@ -44,7 +44,7 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
},
|
||||
}));
|
||||
|
||||
export const StatusMatrixComponent = () => {
|
||||
export const StatusMatrix = () => {
|
||||
const classes = useStyles();
|
||||
const [measureRef, { width: rootWidth }] = useMeasure<HTMLDivElement>();
|
||||
const client = useApi(xcmetricsApiRef);
|
||||
@@ -68,11 +68,7 @@ export const StatusMatrixComponent = () => {
|
||||
{loading &&
|
||||
[...new Array(cols * MAX_ROWS)].map((_, index) => {
|
||||
return (
|
||||
<StatusCellComponent
|
||||
key={index}
|
||||
size={CELL_SIZE}
|
||||
spacing={CELL_MARGIN}
|
||||
/>
|
||||
<StatusCell key={index} size={CELL_SIZE} spacing={CELL_MARGIN} />
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -80,7 +76,7 @@ export const StatusMatrixComponent = () => {
|
||||
builds
|
||||
.slice(0, cols * MAX_ROWS)
|
||||
.map((buildStatus, index) => (
|
||||
<StatusCellComponent
|
||||
<StatusCell
|
||||
key={index}
|
||||
buildStatus={buildStatus}
|
||||
size={CELL_SIZE}
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './BuildListFilterComponent';
|
||||
export { StatusMatrix } from './StatusMatrix';
|
||||
@@ -1,16 +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.
|
||||
*/
|
||||
export * from './StatusMatrixComponent';
|
||||
+4
-4
@@ -14,15 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { TrendComponent } from './TrendComponent';
|
||||
import { Trend } from './Trend';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('TrendComponent', () => {
|
||||
describe('Trend', () => {
|
||||
it('should render', async () => {
|
||||
const data = [1, 2, 3, 4];
|
||||
const title = 'testTitle';
|
||||
const rendered = await renderInTestApp(
|
||||
<TrendComponent data={data} title={title} color="#000" />,
|
||||
<Trend data={data} title={title} color="#000" />,
|
||||
);
|
||||
expect(rendered.findAllByText('testTitle')).toBeTruthy();
|
||||
});
|
||||
@@ -30,7 +30,7 @@ describe('TrendComponent', () => {
|
||||
it('should render empty state', async () => {
|
||||
const title = 'testTitle';
|
||||
const rendered = await renderInTestApp(
|
||||
<TrendComponent title={title} color="#000" />,
|
||||
<Trend title={title} color="#000" />,
|
||||
);
|
||||
expect(rendered.findAllByText('testTitle')).toBeTruthy();
|
||||
});
|
||||
+1
-1
@@ -23,7 +23,7 @@ interface TrendProps {
|
||||
color: string;
|
||||
}
|
||||
|
||||
export const TrendComponent = ({ data, title, color }: TrendProps) => {
|
||||
export const Trend = ({ data, title, color }: TrendProps) => {
|
||||
const emptyData = [0, 0];
|
||||
const max = Math.max(...(data ?? emptyData));
|
||||
|
||||
+1
-1
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './TrendComponent';
|
||||
export { Trend } from './Trend';
|
||||
@@ -23,12 +23,12 @@ import userEvent from '@testing-library/user-event';
|
||||
jest.mock('../../api/XcmetricsClient');
|
||||
const client = require('../../api/XcmetricsClient');
|
||||
|
||||
jest.mock('../OverviewComponent', () => ({
|
||||
OverviewComponent: () => 'OverviewComponent',
|
||||
jest.mock('../Overview', () => ({
|
||||
Overview: () => 'OverviewComponent',
|
||||
}));
|
||||
|
||||
jest.mock('../BuildListComponent', () => ({
|
||||
BuildListComponent: () => 'BuildListComponent',
|
||||
jest.mock('../BuildList', () => ({
|
||||
BuildList: () => 'BuildList',
|
||||
}));
|
||||
|
||||
describe('XcmetricsLayout', () => {
|
||||
@@ -45,7 +45,18 @@ describe('XcmetricsLayout', () => {
|
||||
expect(rendered.getByText('Builds')).toBeInTheDocument();
|
||||
|
||||
expect(rendered.getByText('OverviewComponent')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show a list of builds when the Builds tab is selected', async () => {
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(xcmetricsApiRef, client.XcmetricsClient)}
|
||||
>
|
||||
<XcmetricsLayout />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
userEvent.click(rendered.getByText('Builds'));
|
||||
expect(await rendered.findByText('BuildListComponent')).toBeInTheDocument();
|
||||
expect(await rendered.findByText('BuildList')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
Page,
|
||||
TabbedLayout,
|
||||
} from '@backstage/core-components';
|
||||
import { OverviewComponent } from '../OverviewComponent';
|
||||
import { Overview } from '../Overview';
|
||||
import { buildsRouteRef, rootRouteRef } from '../../routes';
|
||||
import { RouteRef, SubRouteRef } from '@backstage/core-plugin-api';
|
||||
import { BuildsPage } from '../BuildsPage';
|
||||
@@ -36,7 +36,7 @@ const TABS: TabConfig[] = [
|
||||
{
|
||||
routeRef: rootRouteRef,
|
||||
title: 'Overview',
|
||||
component: <OverviewComponent />,
|
||||
component: <Overview />,
|
||||
},
|
||||
{
|
||||
routeRef: buildsRouteRef,
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './XcmetricsLayout';
|
||||
export { XcmetricsLayout } from './XcmetricsLayout';
|
||||
|
||||
Reference in New Issue
Block a user