Skip to content

Commit 7c6e4d3

Browse files
Merge pull request #33 from OpenSpace/feature/quality-of-life
Feature/quality of life
2 parents 2bb0133 + a0e36ff commit 7c6e4d3

7 files changed

Lines changed: 266 additions & 157 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Box, Text } from '@mantine/core';
2+
3+
export function PixelDiffNumber({ value }: { value: number }) {
4+
const style = diffStyle(value);
5+
6+
function diffDisplay(diff: number): string {
7+
return `${Math.round(diff * 100000) / 1000}%`;
8+
}
9+
10+
function diffStyle(diff: number): { backgroundColor: string; color: string } {
11+
if (diff === 0.0) return { backgroundColor: '#eeeeee', color: '#111111' };
12+
else if (diff < 0.001) return { backgroundColor: '#4ce600', color: '#111111' };
13+
else if (diff < 0.01) return { backgroundColor: '#55cc00', color: '#111111' };
14+
else if (diff < 0.05) return { backgroundColor: '#66cc00', color: '#111111' };
15+
else if (diff < 0.1) return { backgroundColor: '#ede621', color: '#111111' };
16+
else if (diff < 0.25) return { backgroundColor: '#edc421', color: '#111111' };
17+
else if (diff < 0.5) return { backgroundColor: '#cc5000', color: '#ffffff' };
18+
else if (diff < 0.75) return { backgroundColor: '#cc4400', color: '#ffffff' };
19+
else if (diff < 1.0) return { backgroundColor: '#cc2200', color: '#ffffff' };
20+
else return { backgroundColor: '#cc0000', color: '#ffffff' };
21+
}
22+
23+
return (
24+
<Box px={4} py={2} style={{ borderRadius: 4, display: 'inline-block', ...style }}>
25+
<Text size={'sm'}>{diffDisplay(value)}</Text>
26+
</Box>
27+
);
28+
}
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { Table } from '@mantine/core';
1+
import { Stack, Table, UnstyledButton } from '@mantine/core';
22

33
import { SortColumn, SortDirection } from '../types';
44

55
interface Props {
66
sortKey: SortColumn;
77
label: string;
88
onSort: (col: SortColumn) => void;
9+
filter?: React.ReactNode;
910
activeColumn?: SortColumn;
1011
direction?: SortDirection;
1112
}
@@ -14,18 +15,24 @@ export function SortableHeader({
1415
sortKey,
1516
label,
1617
onSort,
18+
filter,
1719
activeColumn,
1820
direction
1921
}: Props) {
2022
const isActive = activeColumn === sortKey;
2123
const indicator = isActive ? (direction === 'asc' ? ' ↑' : ' ↓') : '';
2224
return (
23-
<Table.Th
24-
style={{ cursor: 'pointer', whiteSpace: 'nowrap' }}
25-
onClick={() => onSort(sortKey)}
26-
>
27-
{label}
28-
{indicator}
25+
<Table.Th>
26+
<Stack gap={0}>
27+
<UnstyledButton
28+
style={{ cursor: 'pointer', whiteSpace: 'nowrap' }}
29+
onClick={() => onSort(sortKey)}
30+
>
31+
{label}
32+
{indicator}
33+
</UnstyledButton>
34+
{filter}
35+
</Stack>
2936
</Table.Th>
3037
);
3138
}
Lines changed: 172 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,192 @@
1-
import { Anchor, Box, Button, Table, Text } from '@mantine/core';
1+
import { Anchor, Box, Button, Group, Modal, Stack, Table, Text } from '@mantine/core';
22

33
import { TestData, TestRecord } from '../types';
4-
import { diffDisplay, diffStyle, timingDisplay } from '../utils';
4+
import { timingDisplay } from '../utils';
55

66
import { ImageThumbnail } from './ImageThumbnail';
7+
import { useState } from 'react';
8+
import { useDisclosure } from '@mantine/hooks';
9+
import { PixelDiffNumber } from './PixelDiffNumber';
710

811
interface Props {
912
record: TestRecord;
1013
onUpdateReference: (record: TestRecord) => void;
1114
}
1215

1316
export function TestHistory({ record, onUpdateReference }: Props) {
17+
const [wasUpdated, setWasUpdated] = useState(false);
18+
const [confirmOpened, { open, close }] = useDisclosure(false);
19+
1420
const testData = [...record.data].reverse();
1521

1622
const ImageWidth = 250;
1723

1824
return (
19-
<Box p={'md'} bg={'dark.8'}>
20-
<Table
21-
horizontalSpacing={'xs'}
22-
verticalSpacing={4}
23-
withTableBorder
24-
withColumnBorders
25+
<>
26+
<Modal
27+
opened={confirmOpened}
28+
onClose={close}
29+
title="Are you sure?"
30+
size="lg"
31+
withCloseButton
32+
centered
2533
>
26-
<Table.Thead>
27-
<Table.Tr>
28-
<Table.Th>Timestamp</Table.Th>
29-
<Table.Th>Error</Table.Th>
30-
<Table.Th>Commit</Table.Th>
31-
<Table.Th>Timing</Table.Th>
32-
<Table.Th>Log</Table.Th>
33-
<Table.Th>Candidate</Table.Th>
34-
<Table.Th>Reference</Table.Th>
35-
<Table.Th>Difference</Table.Th>
36-
<Table.Th />
37-
</Table.Tr>
38-
</Table.Thead>
39-
<Table.Tbody>
40-
{testData.map((d: TestData, i: number) => (
41-
<Table.Tr key={d.timeStamp}>
42-
<Table.Td>
43-
<Text size={'sm'} c={'dimmed'}>
44-
{new Date(d.timeStamp).toISOString().split('T')[0]}
45-
<br />
46-
{new Date(d.timeStamp).toISOString().split('T')[1]?.replace('Z', '')}
47-
</Text>
48-
</Table.Td>
49-
<Table.Td>
50-
<Box
51-
px={4}
52-
style={{
53-
borderRadius: 4,
54-
display: 'inline-block',
55-
width: 70,
56-
textAlign: 'center',
57-
...diffStyle(d.pixelError)
58-
}}
59-
>
60-
<Text>{diffDisplay(d.pixelError)}</Text>
61-
</Box>
62-
</Table.Td>
63-
<Table.Td>
64-
<Anchor
65-
href={`https://github.com/OpenSpace/OpenSpace/commit/${d.commitHash}`}
66-
target={'_blank'}
67-
>
68-
{d.commitHash.substring(0, 8)}
69-
</Anchor>
70-
</Table.Td>
71-
<Table.Td>
72-
<Text>{timingDisplay(d.timing)}</Text>
73-
</Table.Td>
74-
<Table.Td>
75-
<Anchor
76-
href={`/api/result/log/${record.group}/${record.name}/${record.hardware}/${d.timeStamp}`}
77-
target={'_blank'}
78-
>
79-
Log ({d.nErrors} errors)
80-
</Anchor>
81-
</Table.Td>
82-
<Table.Td>
83-
<ImageThumbnail
84-
type={'candidate'}
85-
group={record.group}
86-
name={record.name}
87-
hardware={record.hardware}
88-
timestamp={d.timeStamp}
89-
width={ImageWidth}
90-
/>
91-
</Table.Td>
92-
<Table.Td>
93-
<ImageThumbnail
94-
type={'reference'}
95-
group={record.group}
96-
name={record.name}
97-
hardware={record.hardware}
98-
timestamp={d.timeStamp}
99-
width={ImageWidth}
100-
/>
101-
</Table.Td>
102-
<Table.Td>
103-
<ImageThumbnail
104-
type={'difference'}
105-
group={record.group}
106-
name={record.name}
107-
hardware={record.hardware}
108-
timestamp={d.timeStamp}
109-
width={ImageWidth}
110-
/>
111-
</Table.Td>
112-
<Table.Td>
113-
{i === 0 && (
114-
<Button variant={'default'} onClick={() => onUpdateReference(record)}>
115-
Upgrade Candidate to Reference
116-
</Button>
117-
)}
118-
</Table.Td>
34+
<Stack align="center">
35+
<Text px={'md'}>
36+
Are you sure you want to update the reference image to the candidate for the
37+
test: {record.name}?{' '}
38+
<Text span fw={'bold'}>
39+
This action cannot be undone.
40+
</Text>
41+
</Text>
42+
43+
<Group align={'center'} my={'sm'} wrap="nowrap">
44+
<Stack align={'center'} gap={'xs'}>
45+
<Text>Candidate</Text>
46+
<ImageThumbnail
47+
type={'candidate'}
48+
group={record.group}
49+
name={record.name}
50+
hardware={record.hardware}
51+
timestamp={testData[0].timeStamp}
52+
width={ImageWidth}
53+
/>
54+
</Stack>
55+
<Text></Text>
56+
<Stack align={'center'} gap={'xs'}>
57+
<Text>Reference</Text>
58+
<ImageThumbnail
59+
type={'reference'}
60+
group={record.group}
61+
name={record.name}
62+
hardware={record.hardware}
63+
timestamp={testData[0].timeStamp}
64+
width={ImageWidth}
65+
/>
66+
</Stack>
67+
</Group>
68+
<Text>
69+
Error: <PixelDiffNumber value={testData[0].pixelError} />
70+
</Text>
71+
72+
<Text c={'dimmed'} size={'sm'} px={'md'}>
73+
After updating, you may have to wait a few seconds and refresh the page to see
74+
the updated reference.
75+
</Text>
76+
<Group>
77+
<Button
78+
onClick={() => {
79+
onUpdateReference(record);
80+
setWasUpdated(true);
81+
close();
82+
}}
83+
color="red"
84+
>
85+
Yes, update reference
86+
</Button>
87+
<Button onClick={close} variant="default" autoFocus>
88+
Cancel
89+
</Button>
90+
</Group>
91+
</Stack>
92+
</Modal>
93+
94+
<Box p={'md'} bg={'dark.8'}>
95+
<Table
96+
horizontalSpacing={'xs'}
97+
verticalSpacing={4}
98+
withTableBorder
99+
withColumnBorders
100+
>
101+
<Table.Thead>
102+
<Table.Tr>
103+
<Table.Th>Timestamp</Table.Th>
104+
<Table.Th>Error</Table.Th>
105+
<Table.Th>Commit</Table.Th>
106+
<Table.Th>Timing</Table.Th>
107+
<Table.Th>Log</Table.Th>
108+
<Table.Th>Candidate</Table.Th>
109+
<Table.Th>Reference</Table.Th>
110+
<Table.Th>Difference</Table.Th>
111+
<Table.Th />
119112
</Table.Tr>
120-
))}
121-
</Table.Tbody>
122-
</Table>
123-
</Box>
113+
</Table.Thead>
114+
<Table.Tbody>
115+
{testData.map((d: TestData, i: number) => (
116+
<Table.Tr key={d.timeStamp}>
117+
<Table.Td>
118+
<Text size={'sm'} c={'dimmed'}>
119+
{new Date(d.timeStamp).toISOString().split('T')[0]}
120+
<br />
121+
{new Date(d.timeStamp).toISOString().split('T')[1]?.replace('Z', '')}
122+
</Text>
123+
</Table.Td>
124+
<Table.Td>
125+
<PixelDiffNumber value={d.pixelError} />
126+
</Table.Td>
127+
<Table.Td>
128+
<Anchor
129+
href={`https://github.com/OpenSpace/OpenSpace/commit/${d.commitHash}`}
130+
target={'_blank'}
131+
>
132+
{d.commitHash.substring(0, 8)}
133+
</Anchor>
134+
</Table.Td>
135+
<Table.Td>
136+
<Text>{timingDisplay(d.timing)}</Text>
137+
</Table.Td>
138+
<Table.Td>
139+
<Anchor
140+
href={`/api/result/log/${record.group}/${record.name}/${record.hardware}/${d.timeStamp}`}
141+
target={'_blank'}
142+
>
143+
Log ({d.nErrors} errors)
144+
</Anchor>
145+
</Table.Td>
146+
<Table.Td>
147+
<ImageThumbnail
148+
type={'candidate'}
149+
group={record.group}
150+
name={record.name}
151+
hardware={record.hardware}
152+
timestamp={d.timeStamp}
153+
width={ImageWidth}
154+
/>
155+
</Table.Td>
156+
<Table.Td>
157+
<ImageThumbnail
158+
type={'reference'}
159+
group={record.group}
160+
name={record.name}
161+
hardware={record.hardware}
162+
timestamp={d.timeStamp}
163+
width={ImageWidth}
164+
/>
165+
</Table.Td>
166+
<Table.Td>
167+
<ImageThumbnail
168+
type={'difference'}
169+
group={record.group}
170+
name={record.name}
171+
hardware={record.hardware}
172+
timestamp={d.timeStamp}
173+
width={ImageWidth}
174+
/>
175+
</Table.Td>
176+
<Table.Td>
177+
{i === 0 && (
178+
<>
179+
<Button variant={'default'} onClick={open} disabled={wasUpdated}>
180+
Upgrade Candidate to Reference
181+
</Button>
182+
</>
183+
)}
184+
</Table.Td>
185+
</Table.Tr>
186+
))}
187+
</Table.Tbody>
188+
</Table>
189+
</Box>
190+
</>
124191
);
125192
}

0 commit comments

Comments
 (0)