Skip to content

Commit 4136b59

Browse files
authored
188 datagrid (#141)
* TestRun list add BULK operations Visual-Regression-Tracker/Visual-Regression-Tracker#188
1 parent b9376a8 commit 4136b59

File tree

15 files changed

+437
-386
lines changed

15 files changed

+437
-386
lines changed

package-lock.json

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"private": true,
55
"dependencies": {
66
"@material-ui/core": "^4.11.2",
7+
"@material-ui/data-grid": "^4.0.0-alpha.19",
78
"@material-ui/icons": "^4.11.2",
89
"@material-ui/lab": "^4.0.0-alpha.57",
910
"@testing-library/jest-dom": "^5.11.1",

src/_helpers/route.helpers.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
import { TestRun, TestVariation } from "../types";
22
import { routes } from "../constants";
3+
import qs from "qs";
34

45
export const buildTestRunUrl = (
56
testVariation: TestVariation,
67
testRun: TestRun
78
) =>
89
`${routes.HOME}${testVariation.projectId}?buildId=${testRun.buildId}&testId=${testRun.id}`;
910

10-
export const buildTestRunLocation = (testRun: TestRun) => ({
11-
search: `buildId=${testRun.buildId}&testId=${testRun.id}`,
11+
export const buildTestRunLocation = (buildId: string, testRunId: string) => ({
12+
search: `buildId=${buildId}&testId=${testRunId}`,
1213
});
1314

1415
export const buildBuildPageUrl = (projectId: string, buildId: string) =>
1516
`${routes.HOME}${projectId}?buildId=${buildId}`;
17+
18+
export interface QueryParams {
19+
buildId?: string;
20+
testId?: string;
21+
}
22+
23+
export const getQueryParams = (guery: string): QueryParams => {
24+
const queryParams = qs.parse(guery, { ignoreQueryPrefix: true });
25+
return {
26+
buildId: queryParams.buildId as string,
27+
testId: queryParams.testId as string,
28+
};
29+
};

src/components/ArrowButtons.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const ArrowButtons: React.FunctionComponent<{
3333
const navigateNext = () => {
3434
if (selectedTestRunIndex + 1 < testRuns.length) {
3535
const next = testRuns[selectedTestRunIndex + 1];
36-
history.push(buildTestRunLocation(next));
36+
history.push(buildTestRunLocation(next.buildId, next.id));
3737
selectTestRun(testRunDispatch, next.id);
3838
}
3939
};
@@ -42,7 +42,7 @@ export const ArrowButtons: React.FunctionComponent<{
4242
const navigateBefore = () => {
4343
if (selectedTestRunIndex > 0) {
4444
const prev = testRuns[selectedTestRunIndex - 1];
45-
history.push(buildTestRunLocation(prev));
45+
history.push(buildTestRunLocation(prev.buildId, prev.id));
4646
selectTestRun(testRunDispatch, prev.id);
4747
}
4848
};

src/components/BuildDetails.tsx

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,67 +7,72 @@ import {
77
Button,
88
LinearProgress,
99
} from "@material-ui/core";
10-
import { Build } from "../types";
1110
import { BuildStatusChip } from "./BuildStatusChip";
1211
import { useSnackbar } from "notistack";
1312
import { buildsService } from "../services";
1413
import { formatDateTime } from "../_helpers/format.helper";
14+
import { useBuildState } from "../contexts";
1515

16-
interface IProps {
17-
build: Build;
18-
}
19-
20-
const BuildDetails: React.FunctionComponent<IProps> = ({ build }) => {
16+
const BuildDetails: React.FunctionComponent = () => {
2117
const { enqueueSnackbar } = useSnackbar();
18+
const { selectedBuild } = useBuildState();
19+
20+
if (!selectedBuild) {
21+
return null;
22+
}
23+
24+
const approveAllButton = selectedBuild.unresolvedCount > 0 && (
25+
<Grid item>
26+
<Button
27+
variant="contained"
28+
color="primary"
29+
size="small"
30+
onClick={async () => {
31+
enqueueSnackbar(
32+
"Wait for the confirmation message until approval is completed.",
33+
{
34+
variant: "info",
35+
}
36+
);
37+
38+
buildsService
39+
.approve(selectedBuild.id, selectedBuild.merge)
40+
.then(() =>
41+
enqueueSnackbar("All approved.", {
42+
variant: "success",
43+
})
44+
)
45+
.catch((err) =>
46+
enqueueSnackbar(err, {
47+
variant: "error",
48+
})
49+
);
50+
}}
51+
>
52+
Approve All
53+
</Button>
54+
</Grid>
55+
);
56+
57+
const loadingAnimation = selectedBuild.isRunning && <LinearProgress />;
2258

2359
return (
2460
<Grid container direction="column">
2561
<Grid item>
2662
<Box m={0.5}>
2763
<Grid container spacing={1} alignItems="center">
2864
<Grid item>
29-
<Typography variant="subtitle2">{`#${build.number} ${
30-
build.ciBuildId || ""
65+
<Typography variant="subtitle2">{`#${selectedBuild.number} ${
66+
selectedBuild.ciBuildId || ""
3167
}`}</Typography>
3268
</Grid>
3369
<Grid item>
34-
<Chip size="small" label={build.branchName} />
70+
<Chip size="small" label={selectedBuild.branchName} />
3571
</Grid>
3672
<Grid item>
37-
<BuildStatusChip status={build.status} />
73+
<BuildStatusChip status={selectedBuild.status} />
3874
</Grid>
39-
{build.unresolvedCount > 0 && (
40-
<Grid item>
41-
<Button
42-
variant="contained"
43-
color="primary"
44-
size="small"
45-
onClick={async () => {
46-
enqueueSnackbar(
47-
"Wait for the confirmation message until approval is completed.",
48-
{
49-
variant: "info",
50-
}
51-
);
52-
53-
buildsService
54-
.approve(build.id, build.merge)
55-
.then(() =>
56-
enqueueSnackbar("All approved.", {
57-
variant: "success",
58-
})
59-
)
60-
.catch((err) =>
61-
enqueueSnackbar(err, {
62-
variant: "error",
63-
})
64-
);
65-
}}
66-
>
67-
Approve All
68-
</Button>
69-
</Grid>
70-
)}
75+
{approveAllButton}
7176
</Grid>
7277
</Box>
7378
</Grid>
@@ -76,7 +81,7 @@ const BuildDetails: React.FunctionComponent<IProps> = ({ build }) => {
7681
<Grid container spacing={1}>
7782
<Grid item>
7883
<Typography variant="caption">
79-
{formatDateTime(build.createdAt)}
84+
{formatDateTime(selectedBuild.createdAt)}
8085
</Typography>
8186
</Grid>
8287
</Grid>
@@ -87,22 +92,24 @@ const BuildDetails: React.FunctionComponent<IProps> = ({ build }) => {
8792
<Grid container spacing={1}>
8893
<Grid item>
8994
<Typography variant="caption">{`${
90-
build.unresolvedCount + build.failedCount + build.passedCount
95+
selectedBuild.unresolvedCount +
96+
selectedBuild.failedCount +
97+
selectedBuild.passedCount
9198
} total`}</Typography>
9299
</Grid>
93100
<Grid item>
94-
<Typography variant="caption">{`${build.unresolvedCount} unresolved`}</Typography>
101+
<Typography variant="caption">{`${selectedBuild.unresolvedCount} unresolved`}</Typography>
95102
</Grid>
96103
<Grid item>
97-
<Typography variant="caption">{`${build.failedCount} failed`}</Typography>
104+
<Typography variant="caption">{`${selectedBuild.failedCount} failed`}</Typography>
98105
</Grid>
99106
<Grid item>
100-
<Typography variant="caption">{`${build.passedCount} passed`}</Typography>
107+
<Typography variant="caption">{`${selectedBuild.passedCount} passed`}</Typography>
101108
</Grid>
102109
</Grid>
103110
</Box>
104111
</Grid>
105-
{build.isRunning && <LinearProgress />}
112+
{loadingAnimation}
106113
</Grid>
107114
);
108115
};

src/components/BuildList.tsx renamed to src/components/BuildList/index.tsx

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@ import {
2424
deleteBuild,
2525
selectBuild,
2626
stopBuild,
27-
} from "../contexts";
28-
import { BuildStatusChip } from "./BuildStatusChip";
29-
import { SkeletonList } from "./SkeletonList";
30-
import { formatDateTime } from "../_helpers/format.helper";
27+
getBuildList,
28+
useProjectState,
29+
} from "../../contexts";
30+
import { BuildStatusChip } from "../BuildStatusChip";
31+
import { SkeletonList } from "../SkeletonList";
32+
import { formatDateTime } from "../../_helpers/format.helper";
3133
import { useSnackbar } from "notistack";
32-
import { Build } from "../types";
33-
import { BaseModal } from "./BaseModal";
34+
import { Build } from "../../types";
35+
import { BaseModal } from "../BaseModal";
36+
import { Pagination } from "@material-ui/lab";
3437

3538
const useStyles = makeStyles((theme: Theme) =>
3639
createStyles({
@@ -52,10 +55,10 @@ const useStyles = makeStyles((theme: Theme) =>
5255
const BuildList: FunctionComponent = () => {
5356
const classes = useStyles();
5457
const history = useHistory();
55-
const { buildList, selectedBuild, loading } = useBuildState();
58+
const { buildList, selectedBuild, loading, total, take } = useBuildState();
5659
const buildDispatch = useBuildDispatch();
5760
const { enqueueSnackbar } = useSnackbar();
58-
61+
const { selectedProjectId } = useProjectState();
5962
const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
6063
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
6164
const [menuBuild, setMenuBuild] = React.useState<Build | null>();
@@ -83,9 +86,25 @@ const BuildList: FunctionComponent = () => {
8386
}
8487
}, [buildDispatch, selectedBuild, buildList]);
8588

89+
const getBuildListCalback: any = React.useCallback(
90+
(page: number) =>
91+
selectedProjectId &&
92+
getBuildList(buildDispatch, selectedProjectId, page).catch(
93+
(err: string) =>
94+
enqueueSnackbar(err, {
95+
variant: "error",
96+
})
97+
),
98+
[buildDispatch, enqueueSnackbar, selectedProjectId]
99+
);
100+
101+
React.useEffect(() => {
102+
getBuildListCalback(1);
103+
}, [getBuildListCalback]);
104+
86105
return (
87106
<React.Fragment>
88-
<Box height={1} overflow="auto">
107+
<Box height="91%" overflow="auto">
89108
<List>
90109
{loading ? (
91110
<SkeletonList />
@@ -150,6 +169,19 @@ const BuildList: FunctionComponent = () => {
150169
)}
151170
</List>
152171
</Box>
172+
<Box height="9%">
173+
<Grid container justify="center">
174+
<Grid item>
175+
<Pagination
176+
size="small"
177+
defaultPage={1}
178+
count={Math.ceil(total / take)}
179+
onChange={(event, page) => getBuildListCalback(page)}
180+
/>
181+
</Grid>
182+
</Grid>
183+
</Box>
184+
153185
{menuBuild && (
154186
<Menu anchorEl={anchorEl} open={!!menuBuild} onClose={handleMenuClose}>
155187
{menuBuild.isRunning && (
@@ -187,16 +219,23 @@ const BuildList: FunctionComponent = () => {
187219
}?`}</Typography>
188220
}
189221
onSubmit={() => {
190-
let indexOfBuildDeleted = buildList.findIndex((e) => e.id === menuBuild.id);
191-
let indexOfSelectedBuild = buildList.findIndex((e) => e.id === selectedBuild?.id);
222+
let indexOfBuildDeleted = buildList.findIndex(
223+
(e) => e.id === menuBuild.id
224+
);
225+
let indexOfSelectedBuild = buildList.findIndex(
226+
(e) => e.id === selectedBuild?.id
227+
);
192228
deleteBuild(buildDispatch, menuBuild.id)
193229
.then((b) => {
194230
if (indexOfBuildDeleted === indexOfSelectedBuild) {
195231
if (buildList.length > 1) {
196232
if (indexOfBuildDeleted === 0) {
197233
selectBuild(buildDispatch, buildList[1].id);
198234
} else {
199-
selectBuild(buildDispatch, buildList[indexOfBuildDeleted - 1].id);
235+
selectBuild(
236+
buildDispatch,
237+
buildList[indexOfBuildDeleted - 1].id
238+
);
200239
}
201240
} else {
202241
selectBuild(buildDispatch, null);

0 commit comments

Comments
 (0)