diff --git a/plugins/xcmetrics/src/components/BuildTrendComponent/BuildTrendComponent.test.tsx b/plugins/xcmetrics/src/components/BuildTrendComponent/BuildTrendComponent.test.tsx
new file mode 100644
index 0000000000..2e96a0fb4e
--- /dev/null
+++ b/plugins/xcmetrics/src/components/BuildTrendComponent/BuildTrendComponent.test.tsx
@@ -0,0 +1,31 @@
+/*
+ * 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 { BuildTrendComponent } from './BuildTrendComponent';
+import { renderInTestApp } from '@backstage/test-utils';
+import { BuildCount } from '../../api';
+
+describe('BuildTrendComponent', () => {
+ it('should render', async () => {
+ const buildCounts: BuildCount[] = [
+ { day: '2021-01-01', errors: 10, builds: 100 },
+ ];
+ const rendered = await renderInTestApp(
+ ,
+ );
+ expect(rendered.findAllByText('Build Count')).toBeTruthy();
+ });
+});
diff --git a/plugins/xcmetrics/src/components/BuildTrendComponent/BuildTrendComponent.tsx b/plugins/xcmetrics/src/components/BuildTrendComponent/BuildTrendComponent.tsx
new file mode 100644
index 0000000000..7403ec1c43
--- /dev/null
+++ b/plugins/xcmetrics/src/components/BuildTrendComponent/BuildTrendComponent.tsx
@@ -0,0 +1,48 @@
+/*
+ * 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 { TrendLine } from '@backstage/core-components';
+import { BuildCount } from '../../api';
+import { Typography, useTheme } from '@material-ui/core';
+import { BackstageTheme } from '@backstage/theme';
+
+const TRENDLINE_TITLE = 'Build Count';
+
+interface BuildTrendProps {
+ buildCounts: BuildCount[];
+}
+
+export const BuildTrendComponent = ({ buildCounts }: BuildTrendProps) => {
+ const theme = useTheme();
+
+ let max = 0;
+ const builds = buildCounts.map(counts => {
+ max = Math.max(max, counts.builds);
+ return counts.builds;
+ });
+
+ return (
+ <>
+ {TRENDLINE_TITLE}
+
+ >
+ );
+};
diff --git a/plugins/xcmetrics/src/components/BuildTrendComponent/index.ts b/plugins/xcmetrics/src/components/BuildTrendComponent/index.ts
new file mode 100644
index 0000000000..4f4ef09aca
--- /dev/null
+++ b/plugins/xcmetrics/src/components/BuildTrendComponent/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 './BuildTrendComponent';
diff --git a/plugins/xcmetrics/src/components/DataValueComponent/DataValueComponent.test.tsx b/plugins/xcmetrics/src/components/DataValueComponent/DataValueComponent.test.tsx
new file mode 100644
index 0000000000..3681b7cf20
--- /dev/null
+++ b/plugins/xcmetrics/src/components/DataValueComponent/DataValueComponent.test.tsx
@@ -0,0 +1,40 @@
+/*
+ * 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 { DataValueComponent, DataValueGridItem } from './DataValueComponent';
+import { renderInTestApp } from '@backstage/test-utils';
+
+describe('DataValueComponent', () => {
+ it('should render', async () => {
+ const field = 'Field';
+ const value = 'Value';
+ const rendered = await renderInTestApp(
+ ,
+ );
+ expect(rendered.getByText(field)).toBeInTheDocument();
+ expect(rendered.getByText(value)).toBeInTheDocument();
+ });
+
+ it('grid item should render', async () => {
+ const field = 'Field';
+ const value = 'Value';
+ const rendered = await renderInTestApp(
+ ,
+ );
+ expect(rendered.getByText(field)).toBeInTheDocument();
+ expect(rendered.getByText(value)).toBeInTheDocument();
+ });
+});
diff --git a/plugins/xcmetrics/src/components/DataValueComponent/DataValueComponent.tsx b/plugins/xcmetrics/src/components/DataValueComponent/DataValueComponent.tsx
new file mode 100644
index 0000000000..52e80d3291
--- /dev/null
+++ b/plugins/xcmetrics/src/components/DataValueComponent/DataValueComponent.tsx
@@ -0,0 +1,42 @@
+/*
+ * 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 { Grid, GridSize, Typography } from '@material-ui/core';
+import React from 'react';
+
+interface DataValueProps {
+ field: string;
+ value: string | number | undefined;
+}
+
+export const DataValueComponent = ({ field, value }: DataValueProps) => {
+ return (
+
+ {field}
+ {value}
+
+ );
+};
+
+interface GridProps {
+ xs?: GridSize;
+ md?: GridSize;
+}
+
+export const DataValueGridItem = (props: DataValueProps & GridProps) => (
+
+
+
+);
diff --git a/plugins/xcmetrics/src/components/DataValueComponent/index.ts b/plugins/xcmetrics/src/components/DataValueComponent/index.ts
new file mode 100644
index 0000000000..cbf0ffe851
--- /dev/null
+++ b/plugins/xcmetrics/src/components/DataValueComponent/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 './DataValueComponent';
diff --git a/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.test.tsx b/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.test.tsx
new file mode 100644
index 0000000000..67b2b0ce90
--- /dev/null
+++ b/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.test.tsx
@@ -0,0 +1,31 @@
+/*
+ * 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 { ErrorTrendComponent } from './ErrorTrendComponent';
+import { renderInTestApp } from '@backstage/test-utils';
+import { BuildCount } from '../../api';
+
+describe('ErrorTrendComponent', () => {
+ it('should render', async () => {
+ const buildCounts: BuildCount[] = [
+ { day: '2021-01-01', errors: 10, builds: 100 },
+ ];
+ const rendered = await renderInTestApp(
+ ,
+ );
+ expect(rendered.findAllByText('Error Rate')).toBeTruthy();
+ });
+});
diff --git a/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.tsx b/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.tsx
index b8f358a903..d6bf789f5b 100644
--- a/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.tsx
+++ b/plugins/xcmetrics/src/components/ErrorTrendComponent/ErrorTrendComponent.tsx
@@ -14,32 +14,19 @@
* limitations under the License.
*/
import React from 'react';
-import { Progress, TrendLine } from '@backstage/core-components';
-import { useApi } from '@backstage/core-plugin-api';
-import { BuildCount, xcmetricsApiRef } from '../../api';
-import { useAsync } from 'react-use';
-import { Alert } from '@material-ui/lab';
+import { TrendLine } from '@backstage/core-components';
+import { BuildCount } from '../../api';
+import { Typography, useTheme } from '@material-ui/core';
+import { BackstageTheme } from '@backstage/theme';
const TRENDLINE_TITLE = 'Error Rate';
interface ErrorTrendProps {
- days: number;
+ buildCounts: BuildCount[];
}
-export const ErrorTrendComponent = ({ days }: ErrorTrendProps) => {
- const client = useApi(xcmetricsApiRef);
- const { value: buildCounts, loading, error } = useAsync(
- async (): Promise => client.getBuildCounts(days),
- [],
- );
-
- if (loading) {
- return ;
- } else if (error) {
- return {error.message};
- } else if (!buildCounts) {
- return ;
- }
+export const ErrorTrendComponent = ({ buildCounts }: ErrorTrendProps) => {
+ const theme = useTheme();
let max = 0;
const averageErrors = buildCounts.map(counts => {
@@ -49,5 +36,15 @@ export const ErrorTrendComponent = ({ days }: ErrorTrendProps) => {
return dayAverage;
});
- return ;
+ return (
+ <>
+ {TRENDLINE_TITLE}
+
+ >
+ );
};
diff --git a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx
index 545e9e8c1d..e5689869c1 100644
--- a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx
+++ b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx
@@ -14,47 +14,59 @@
* limitations under the License.
*/
import React from 'react';
-import { OverviewComponent } from './OverviewComponent';
import { renderInTestApp } from '@backstage/test-utils';
import { xcmetricsApiRef } from '../../api';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
-import { mockUserId, mockXcmetricsApi } from '../../test-utils';
+import { mockUserId, createMockXcmetricsApi } from '../../test-utils';
+import { OverviewComponent } from './OverviewComponent';
+
+jest.mock('../OverviewTrendsComponent', () => ({
+ OverviewTrendsComponent: () => 'OverviewTrendsComponent',
+}));
+
+jest.mock('../StatusMatrixComponent', () => ({
+ StatusMatrixComponent: () => 'StatusMatrixComponent',
+}));
describe('OverviewComponent', () => {
it('should render', async () => {
const rendered = await renderInTestApp(
-
+
,
);
+
expect(rendered.getByText('XCMetrics Dashboard')).toBeInTheDocument();
expect(rendered.getByText(mockUserId)).toBeInTheDocument();
- expect(rendered.queryByText('CI')).toBeNull();
});
it('should render an empty state when no builds exist', async () => {
- mockXcmetricsApi.getBuilds = jest.fn().mockResolvedValue([]);
+ const api = createMockXcmetricsApi();
+ api.getBuilds = jest.fn().mockResolvedValue([]);
const rendered = await renderInTestApp(
-
+
,
);
+
expect(rendered.getByText('No builds to show')).toBeInTheDocument();
});
it('should show an error when API not responding', async () => {
+ const api = createMockXcmetricsApi();
const errorMessage = 'MockErrorMessage';
- mockXcmetricsApi.getBuilds = jest
- .fn()
- .mockRejectedValue({ message: errorMessage });
+ api.getBuilds = jest.fn().mockRejectedValue({ message: errorMessage });
const rendered = await renderInTestApp(
-
+
,
);
+
expect(rendered.getByText(errorMessage)).toBeInTheDocument();
});
});
diff --git a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx
index b9bd048ac1..3cb8b69be0 100644
--- a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx
+++ b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.tsx
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { ReactChild } from 'react';
import {
ContentHeader,
SupportButton,
@@ -31,33 +31,21 @@ import { Build, BuildStatus, xcmetricsApiRef } from '../../api';
import { useAsync } from 'react-use';
import { Alert } from '@material-ui/lab';
import { StatusMatrixComponent } from '../StatusMatrixComponent';
-import { formatDuration, formatStatus } from '../../utils';
-import { Chip, Grid, Typography } from '@material-ui/core';
-import { ErrorTrendComponent } from '../ErrorTrendComponent';
+import { formatTime } from '../../utils';
+import { Chip, Grid } from '@material-ui/core';
+import { OverviewTrendsComponent } from '../OverviewTrendsComponent';
-const Status = ({
- status,
- warningCount,
-}: {
- status: BuildStatus;
- warningCount: number;
-}) => {
- const statusIcons = {
- succeeded: ,
- failed: ,
- stopped: ,
- };
-
- return (
- <>
- {statusIcons[status]} {formatStatus(status)}
- {warningCount > 0 && ` with ${warningCount} warning`}
- {warningCount > 1 && 's'}
- >
- );
+const STATUS_ICONS: { [key in BuildStatus]: ReactChild } = {
+ succeeded: ,
+ failed: ,
+ stopped: ,
};
const columns: TableColumn[] = [
+ {
+ field: 'buildStatus',
+ render: data => STATUS_ICONS[data.buildStatus],
+ },
{
title: 'Project',
field: 'projectName',
@@ -67,23 +55,15 @@ const columns: TableColumn[] = [
field: 'schema',
},
{
- title: 'Duration',
- field: 'duration',
- type: 'time',
+ title: 'Started',
+ field: 'startedAt',
searchable: false,
- render: data => formatDuration(data.duration),
+ render: data => formatTime(data.startTimestamp),
},
{
title: 'User',
field: 'userid',
},
- {
- title: 'Status',
- field: 'buildStatus',
- render: data => (
-
- ),
- },
{
field: 'isCI',
render: data => data.isCi && ,
@@ -121,7 +101,7 @@ export const OverviewComponent = () => {
Dashboard for XCMetrics
-
+
{
}
/>
-
+
- Error Rate
-
+
diff --git a/plugins/xcmetrics/src/components/OverviewTrendsComponent/OverviewTrendsComponent.test.tsx b/plugins/xcmetrics/src/components/OverviewTrendsComponent/OverviewTrendsComponent.test.tsx
new file mode 100644
index 0000000000..957602384d
--- /dev/null
+++ b/plugins/xcmetrics/src/components/OverviewTrendsComponent/OverviewTrendsComponent.test.tsx
@@ -0,0 +1,60 @@
+/*
+ * 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 { OverviewTrendsComponent } from './OverviewTrendsComponent';
+import { renderInTestApp } from '@backstage/test-utils';
+import { xcmetricsApiRef } from '../../api';
+import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
+import { createMockXcmetricsApi } from '../../test-utils';
+
+describe('OverviewTrendsComponent', () => {
+ it('should render', async () => {
+ const rendered = await renderInTestApp(
+
+
+ ,
+ );
+ expect(rendered.getByText('Last 14 Days')).toBeInTheDocument();
+ });
+
+ it('should render empty state', async () => {
+ const api = createMockXcmetricsApi();
+ api.getBuildCounts = jest.fn().mockResolvedValue([]);
+
+ const rendered = await renderInTestApp(
+
+
+ ,
+ );
+ expect(rendered.getByText('No Trends Available')).toBeInTheDocument();
+ });
+
+ it('should show an error when API not responding', async () => {
+ const api = createMockXcmetricsApi();
+ const errorMessage = 'MockErrorMessage';
+
+ api.getBuildCounts = jest.fn().mockRejectedValue({ message: errorMessage });
+
+ const rendered = await renderInTestApp(
+
+
+ ,
+ );
+ expect(rendered.getByText(errorMessage)).toBeInTheDocument();
+ });
+});
diff --git a/plugins/xcmetrics/src/components/OverviewTrendsComponent/OverviewTrendsComponent.tsx b/plugins/xcmetrics/src/components/OverviewTrendsComponent/OverviewTrendsComponent.tsx
new file mode 100644
index 0000000000..cbc64a902e
--- /dev/null
+++ b/plugins/xcmetrics/src/components/OverviewTrendsComponent/OverviewTrendsComponent.tsx
@@ -0,0 +1,85 @@
+/*
+ * 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 { Grid, makeStyles, Typography } from '@material-ui/core';
+import React from 'react';
+import { Progress, TrendLine } from '@backstage/core-components';
+import { ErrorTrendComponent } from '../ErrorTrendComponent';
+import { Alert } from '@material-ui/lab';
+import { BuildCount, xcmetricsApiRef } from '../../api';
+import { useAsync } from 'react-use';
+import { useApi } from '@backstage/core-plugin-api';
+import { BuildTrendComponent } from '../BuildTrendComponent';
+import { DataValueGridItem } from '../DataValueComponent';
+import { formatPercentage } from '../../utils';
+
+const useStyles = makeStyles({
+ spacingTop: {
+ marginTop: 8,
+ },
+});
+
+export const OverviewTrendsComponent = ({ days }: { days: number }) => {
+ const classes = useStyles();
+ const client = useApi(xcmetricsApiRef);
+ const { value: buildCounts, loading, error } = useAsync(
+ async (): Promise => client.getBuildCounts(days),
+ [],
+ );
+
+ if (loading) {
+ return ;
+ } else if (error) {
+ return {error.message};
+ } else if (!buildCounts || buildCounts.length === 0) {
+ return (
+ <>
+ No Trends Available
+
+ >
+ );
+ }
+
+ const sumCount = buildCounts.reduce(
+ (sum, current) => sum + current.builds,
+ 0,
+ );
+ const sumErrors = buildCounts.reduce(
+ (sum, current) => sum + current.errors,
+ 0,
+ );
+ const errorRate = sumCount > 0 ? sumErrors / sumCount : 0;
+
+ return (
+ <>
+ Last {days} Days
+
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/plugins/xcmetrics/src/components/OverviewTrendsComponent/index.ts b/plugins/xcmetrics/src/components/OverviewTrendsComponent/index.ts
new file mode 100644
index 0000000000..778a4bf503
--- /dev/null
+++ b/plugins/xcmetrics/src/components/OverviewTrendsComponent/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 './OverviewTrendsComponent';
diff --git a/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx b/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx
index 470f69fa8d..363486eb51 100644
--- a/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx
+++ b/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx
@@ -19,13 +19,19 @@ import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
import userEvent from '@testing-library/user-event';
import { StatusCellComponent } from './StatusCellComponent';
import { xcmetricsApiRef } from '../../api';
-import { mockBuildId, mockStatus, mockXcmetricsApi } from '../../test-utils';
+import {
+ mockBuildId,
+ mockStatus,
+ createMockXcmetricsApi,
+} from '../../test-utils';
import { formatStatus } from '../../utils';
describe('StatusCellComponent', () => {
it('should render', async () => {
const rendered = await renderInTestApp(
-
+
{
it('should render', async () => {
const rendered = await renderInTestApp(
-
+
,
);
diff --git a/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts b/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts
index 58419dfd48..b73b361926 100644
--- a/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts
+++ b/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts
@@ -19,7 +19,7 @@ export const mockUserId = 'user_id';
export const mockBuildId = 'build_id';
export const mockStatus = 'succeeded';
-export const mockXcmetricsApi: jest.Mocked = {
+export const createMockXcmetricsApi = (): jest.Mocked => ({
getBuildStatuses: jest
.fn()
.mockResolvedValue([{ id: mockBuildId, status: mockStatus }]),
@@ -40,5 +40,8 @@ export const mockXcmetricsApi: jest.Mocked = {
schema: 'AppSchema',
},
]),
- getBuildCounts: jest.fn(),
-};
+ getBuildCounts: jest.fn().mockResolvedValue([
+ { day: '2021-07-10', builds: 10, errors: 1 },
+ { day: '2021-07-09', builds: 11, errors: 2 },
+ ]),
+});
diff --git a/plugins/xcmetrics/src/utils/format.ts b/plugins/xcmetrics/src/utils/format.ts
index d8c08d9367..20d8cc68db 100644
--- a/plugins/xcmetrics/src/utils/format.ts
+++ b/plugins/xcmetrics/src/utils/format.ts
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Duration } from 'luxon';
+import { DateTime, Duration } from 'luxon';
import { BuildStatus } from '../api';
export const formatDuration = (seconds: number) =>
@@ -21,5 +21,15 @@ export const formatDuration = (seconds: number) =>
suppressMilliseconds: true,
});
+export const formatTime = (timestamp: string) => {
+ return DateTime.fromISO(timestamp).toLocaleString(
+ DateTime.DATETIME_SHORT_WITH_SECONDS,
+ );
+};
+
+export const formatPercentage = (number: number) => {
+ return `${Math.round(number * 100)} %`;
+};
+
export const formatStatus = (status: BuildStatus) =>
status[0].toUpperCase() + status.slice(1);