Replacing SortableTable and a few MUI tables with new Table component (#722)
* Befind work of replacing tables with new Table component * Removed test plugins and fixed test * Fixed lint issue * Removed toolbar from lighthouse audit page * Moved column out of auditstables render function, no no interation with useInterval
This commit is contained in:
committed by
GitHub
parent
5b0e808204
commit
425cf93c08
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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, { FC } from 'react';
|
||||
import { Link, TableCell, TableRow } from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { TrendLine } from '@backstage/core';
|
||||
import { Website } from '../../api';
|
||||
import {
|
||||
formatTime,
|
||||
CATEGORIES,
|
||||
CATEGORY_LABELS,
|
||||
SparklinesDataByCategory,
|
||||
} from '../../utils';
|
||||
import AuditStatusIcon from '../AuditStatusIcon';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
table: {
|
||||
minWidth: 650,
|
||||
},
|
||||
status: {
|
||||
textTransform: 'capitalize',
|
||||
},
|
||||
link: {
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2),
|
||||
display: 'inline-block',
|
||||
},
|
||||
statusCell: { whiteSpace: 'nowrap' },
|
||||
sparklinesCell: { minWidth: 120 },
|
||||
}));
|
||||
|
||||
export const AuditRow: FC<{
|
||||
website: Website;
|
||||
categorySparkline: SparklinesDataByCategory;
|
||||
}> = ({ website, categorySparkline }) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<TableRow key={website.url}>
|
||||
<TableCell>
|
||||
<Link
|
||||
className={classes.link}
|
||||
href={`/lighthouse/audit/${website.lastAudit.id}`}
|
||||
>
|
||||
{website.url}
|
||||
</Link>
|
||||
</TableCell>
|
||||
{CATEGORIES.map(category => (
|
||||
<TableCell
|
||||
key={`${website.url}|${category}`}
|
||||
className={classes.sparklinesCell}
|
||||
>
|
||||
<TrendLine
|
||||
title={`trendline for ${CATEGORY_LABELS[category]} category of ${website.url}`}
|
||||
data={categorySparkline[category] || []}
|
||||
/>
|
||||
</TableCell>
|
||||
))}
|
||||
<TableCell className={classes.statusCell}>
|
||||
<AuditStatusIcon audit={website.lastAudit} />{' '}
|
||||
<span className={classes.status}>
|
||||
{website.lastAudit.status.toLowerCase()}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>{formatTime(website.lastAudit.timeCreated)}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuditRow;
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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, { FC, useState } from 'react';
|
||||
import { useInterval } from 'react-use';
|
||||
import { Website, lighthouseApiRef } from '../../api';
|
||||
import { useApi } from '@backstage/core';
|
||||
import {
|
||||
SparklinesDataByCategory,
|
||||
buildSparklinesDataForItem,
|
||||
} from '../../utils';
|
||||
import { AuditRow } from './AuditRow';
|
||||
export const LIMIT = 10;
|
||||
|
||||
export const Audit: FC<{
|
||||
website: Website;
|
||||
categorySparkline: SparklinesDataByCategory;
|
||||
}> = ({ website, categorySparkline }) => {
|
||||
const lighthouseApi = useApi(lighthouseApiRef);
|
||||
const [websiteState, setWebsiteState] = useState(website);
|
||||
const [sparklineState, setSparklineState] = useState(categorySparkline);
|
||||
|
||||
const runRefresh = async () => {
|
||||
const response = await lighthouseApi.getWebsiteForAuditId(
|
||||
websiteState.lastAudit.id,
|
||||
);
|
||||
const auditStatus = response.lastAudit.status;
|
||||
if (auditStatus === 'COMPLETED' || auditStatus === 'FAILED') {
|
||||
setSparklineState(buildSparklinesDataForItem(response));
|
||||
setWebsiteState(response);
|
||||
}
|
||||
};
|
||||
|
||||
useInterval(
|
||||
runRefresh,
|
||||
websiteState?.lastAudit.status === 'RUNNING' ? 5000 : null,
|
||||
);
|
||||
|
||||
return <AuditRow website={websiteState} categorySparkline={sparklineState} />;
|
||||
};
|
||||
|
||||
export default Audit;
|
||||
@@ -55,7 +55,7 @@ describe('AuditListTable', () => {
|
||||
);
|
||||
const link = rendered.queryByText('https://anchor.fm');
|
||||
const website = websiteListResponse.items.find(
|
||||
w => w.url === 'https://anchor.fm',
|
||||
(w) => w.url === 'https://anchor.fm',
|
||||
);
|
||||
if (!website)
|
||||
throw new Error('https://anchor.fm must be present in fixture');
|
||||
@@ -71,7 +71,7 @@ describe('AuditListTable', () => {
|
||||
wrapInThemedTestApp(auditList(websiteListResponse)),
|
||||
);
|
||||
const website = websiteListResponse.items.find(
|
||||
w => w.url === 'https://anchor.fm',
|
||||
(w) => w.url === 'https://anchor.fm',
|
||||
);
|
||||
if (!website)
|
||||
throw new Error('https://anchor.fm must be present in fixture');
|
||||
@@ -85,21 +85,22 @@ describe('AuditListTable', () => {
|
||||
wrapInThemedTestApp(auditList(websiteListResponse)),
|
||||
);
|
||||
|
||||
const completed = await rendered.findAllByText('completed');
|
||||
const completed = await rendered.findAllByText('COMPLETED');
|
||||
expect(completed).toHaveLength(
|
||||
websiteListResponse.items.filter(w => w.lastAudit.status === 'COMPLETED')
|
||||
.length,
|
||||
websiteListResponse.items.filter(
|
||||
(w) => w.lastAudit.status === 'COMPLETED',
|
||||
).length,
|
||||
);
|
||||
|
||||
const failed = await rendered.findAllByText('failed');
|
||||
const failed = await rendered.findAllByText('FAILED');
|
||||
expect(failed).toHaveLength(
|
||||
websiteListResponse.items.filter(w => w.lastAudit.status === 'FAILED')
|
||||
websiteListResponse.items.filter((w) => w.lastAudit.status === 'FAILED')
|
||||
.length,
|
||||
);
|
||||
|
||||
const running = await rendered.findAllByText('failed');
|
||||
const running = await rendered.findAllByText('FAILED');
|
||||
expect(running).toHaveLength(
|
||||
websiteListResponse.items.filter(w => w.lastAudit.status === 'RUNNING')
|
||||
websiteListResponse.items.filter((w) => w.lastAudit.status === 'RUNNING')
|
||||
.length,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -13,81 +13,111 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
} from '@material-ui/core';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Website } from '../../api';
|
||||
import React, { FC, useState } from 'react';
|
||||
import { Table, TableColumn, TrendLine, useApi } from '@backstage/core';
|
||||
import { Website, lighthouseApiRef } from '../../api';
|
||||
import { useInterval } from 'react-use';
|
||||
import {
|
||||
formatTime,
|
||||
CATEGORIES,
|
||||
CATEGORY_LABELS,
|
||||
SparklinesDataByCategory,
|
||||
buildSparklinesDataForItem,
|
||||
} from '../../utils';
|
||||
import Audit from '../Audit';
|
||||
import { Link } from '@material-ui/core';
|
||||
import AuditStatusIcon from '../AuditStatusIcon';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
table: {
|
||||
minWidth: 650,
|
||||
const columns: TableColumn[] = [
|
||||
{
|
||||
title: 'Website URL',
|
||||
field: 'websiteUrl',
|
||||
},
|
||||
status: {
|
||||
textTransform: 'capitalize',
|
||||
...CATEGORIES.map((category) => ({
|
||||
title: CATEGORY_LABELS[category],
|
||||
field: category,
|
||||
})),
|
||||
{
|
||||
title: 'Last Report',
|
||||
field: 'lastReport',
|
||||
cellStyle: {
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
},
|
||||
link: {
|
||||
paddingTop: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(2),
|
||||
display: 'inline-block',
|
||||
{
|
||||
title: 'Last Audit Triggered',
|
||||
field: 'lastAuditTriggered',
|
||||
cellStyle: {
|
||||
minWidth: 120,
|
||||
},
|
||||
},
|
||||
statusCell: { whiteSpace: 'nowrap' },
|
||||
sparklinesCell: { minWidth: 120 },
|
||||
}));
|
||||
];
|
||||
|
||||
export const AuditListTable: FC<{ items: Website[] }> = ({ items }) => {
|
||||
const classes = useStyles();
|
||||
const categorySparklines: Record<string, SparklinesDataByCategory> = useMemo(
|
||||
() =>
|
||||
items.reduce(
|
||||
(res, item) => ({
|
||||
...res,
|
||||
[item.url]: buildSparklinesDataForItem(item),
|
||||
}),
|
||||
{},
|
||||
),
|
||||
[items],
|
||||
const [websiteState, setWebsiteState] = useState(items);
|
||||
const lighthouseApi = useApi(lighthouseApiRef);
|
||||
|
||||
const runRefresh = (websites: Website[]) => {
|
||||
websites.forEach(async (website) => {
|
||||
const response = await lighthouseApi.getWebsiteForAuditId(
|
||||
website.lastAudit.id,
|
||||
);
|
||||
const auditStatus = response.lastAudit.status;
|
||||
if (auditStatus === 'COMPLETED' || auditStatus === 'FAILED') {
|
||||
const newWebsiteData = websiteState.slice(0);
|
||||
newWebsiteData[
|
||||
newWebsiteData.findIndex((w) => w.url === response.url)
|
||||
] = response;
|
||||
setWebsiteState(newWebsiteData);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const runningWebsiteAudits = websiteState
|
||||
? websiteState.filter((website) => website.lastAudit.status === 'RUNNING')
|
||||
: [];
|
||||
|
||||
useInterval(
|
||||
() => runRefresh(runningWebsiteAudits),
|
||||
runningWebsiteAudits.length > 0 ? 5000 : null,
|
||||
);
|
||||
|
||||
const data = websiteState.map((website) => {
|
||||
const trendlineData = buildSparklinesDataForItem(website);
|
||||
const trendlines: any = {};
|
||||
CATEGORIES.forEach((category) => {
|
||||
trendlines[category] = (
|
||||
<TrendLine
|
||||
title={`trendline for ${CATEGORY_LABELS[category]} category of ${website.url}`}
|
||||
data={trendlineData[category] || []}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
websiteUrl: (
|
||||
<Link href={`/lighthouse/audit/${website.lastAudit.id}`}>
|
||||
{website.url}
|
||||
</Link>
|
||||
),
|
||||
...trendlines,
|
||||
lastReport: (
|
||||
<>
|
||||
<AuditStatusIcon audit={website.lastAudit} />{' '}
|
||||
<span>{website.lastAudit.status.toUpperCase()}</span>
|
||||
</>
|
||||
),
|
||||
lastAuditTriggered: formatTime(website.lastAudit.timeCreated),
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table className={classes.table} size="small" aria-label="a dense table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Website URL</TableCell>
|
||||
{CATEGORIES.map(category => (
|
||||
<TableCell key={`${category}-label`}>
|
||||
{CATEGORY_LABELS[category]}
|
||||
</TableCell>
|
||||
))}
|
||||
<TableCell>Last Report</TableCell>
|
||||
<TableCell>Last Audit Triggered</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{items.map(website => (
|
||||
<Audit
|
||||
key={website.url}
|
||||
website={website}
|
||||
categorySparkline={categorySparklines[website.url]}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Table
|
||||
options={{
|
||||
paging: false,
|
||||
toolbar: false,
|
||||
}}
|
||||
columns={columns}
|
||||
data={data}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user