Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions src/_helpers/route.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import qs from "qs";
export const buildProjectPageUrl = (projectId: string) =>
`${routes.HOME}${projectId}`;

export const buildTestRunLocation = (buildId: string, testRunId?: string) => ({
search: testRunId
? `buildId=${buildId}&testId=${testRunId}`
: `buildId=${buildId}`,
export const buildTestRunLocation = (buildId?: string, testRunId?: string) => ({
search: buildId
? testRunId
? `buildId=${buildId}&testId=${testRunId}`
: `buildId=${buildId}`
: "",
});

export interface QueryParams {
Expand Down
2 changes: 2 additions & 0 deletions src/_test/stub.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const buildsServiceStub = {
const testRunServiceStub = {
getList: (testRuns: Array<TestRun>) =>
cy.stub(testRunService, "getList").resolves(testRuns),
getDetails: (testRun: TestRun) =>
cy.stub(testRunService, "getDetails").resolves(testRun),
};

const staticServiceStub = {
Expand Down
49 changes: 28 additions & 21 deletions src/components/BuildList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import {
useBuildState,
useBuildDispatch,
deleteBuild,
selectBuild,
getBuildList,
useProjectState,
} from "../../contexts";
import { BuildStatusChip } from "../BuildStatusChip";
Expand All @@ -34,6 +32,8 @@ import { Pagination } from "@material-ui/lab";
import { Build } from "../../types";
import { BaseModal } from "../BaseModal";
import { buildsService } from "../../services";
import { useHistory } from "react-router";
import { buildTestRunLocation } from "../../_helpers/route.helpers";

const useStyles = makeStyles((theme: Theme) =>
createStyles({
Expand All @@ -54,6 +54,7 @@ const useStyles = makeStyles((theme: Theme) =>

const BuildList: FunctionComponent = () => {
const classes = useStyles();
const history = useHistory();
const { buildList, selectedBuild, loading, total, take } = useBuildState();
const buildDispatch = useBuildDispatch();
const { enqueueSnackbar } = useSnackbar();
Expand Down Expand Up @@ -85,23 +86,28 @@ const BuildList: FunctionComponent = () => {
setEditDialogOpen(!editDialogOpen);
};

React.useEffect(() => {
if (!selectedBuild || selectedBuild.projectId !== selectedProjectId) {
const buildId = buildList.length > 0 ? buildList[0].id : null;
selectBuild(buildDispatch, buildId);
}
}, [buildDispatch, selectedBuild, buildList, selectedProjectId]);
const selectBuildCalback = React.useCallback(
(id?: string) => history.push(buildTestRunLocation(id)),
[history]
);

const getBuildListCalback: any = React.useCallback(
(page: number) =>
selectedProjectId &&
getBuildList(buildDispatch, selectedProjectId, page).catch(
(err: string) =>
enqueueSnackbar(err, {
variant: "error",
const getBuildListCalback = React.useCallback(
(page: number) => {
if (selectedProjectId) {
buildDispatch({ type: "request" });
buildsService
.getList(selectedProjectId, take, take * (page - 1))
.then((payload) => {
buildDispatch({ type: "get", payload });
})
),
[buildDispatch, enqueueSnackbar, selectedProjectId]
.catch((err: string) =>
enqueueSnackbar(err, {
variant: "error",
})
);
}
},
[buildDispatch, enqueueSnackbar, selectedProjectId, take]
);

React.useEffect(() => {
Expand All @@ -122,9 +128,7 @@ const BuildList: FunctionComponent = () => {
<ListItem
selected={selectedBuild?.id === build.id}
button
onClick={() => {
selectBuild(buildDispatch, build.id);
}}
onClick={() => selectBuildCalback(build.id)}
classes={{
container: classes.listItem,
}}
Expand Down Expand Up @@ -273,14 +277,17 @@ const BuildList: FunctionComponent = () => {
}
onSubmit={() => {
deleteBuild(buildDispatch, menuBuild.id)
.then((b) => {
.then((build) => {
toggleDeleteDialogOpen();
enqueueSnackbar(
`Build #${menuBuild.number || menuBuild.id} deleted`,
{
variant: "success",
}
);
if (menuBuild.id === selectedBuild?.id) {
selectBuildCalback();
}
})
.catch((err) =>
enqueueSnackbar(err, {
Expand Down
26 changes: 14 additions & 12 deletions src/components/TestDetailsDialog/TestDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ const TestDetailsModal: React.FunctionComponent<{
const [isDiffShown, setIsDiffShown] = useState(!!testRun.diffName);
const [selectedRectId, setSelectedRectId] = React.useState<string>();
const [ignoreAreas, setIgnoreAreas] = React.useState<IgnoreArea[]>([]);
const [applyIgnoreDialogOpen, setApplyIgnoreDialogOpen] = React.useState(false);
const [applyIgnoreDialogOpen, setApplyIgnoreDialogOpen] = React.useState(
false
);

const toggleApplyIgnoreDialogOpen = () => {
setApplyIgnoreDialogOpen(!applyIgnoreDialogOpen);
Expand All @@ -101,7 +103,8 @@ const TestDetailsModal: React.FunctionComponent<{
staticService.getImage(testRun.diffName)
);

const applyIgnoreAreaText = 'Apply selected ignore area to all images in this build.';
const applyIgnoreAreaText =
"Apply selected ignore area to all images in this build.";

React.useEffect(() => {
fitStageToScreen();
Expand Down Expand Up @@ -195,9 +198,9 @@ const TestDetailsModal: React.FunctionComponent<{
const fitStageToScreen = () => {
const scale = image
? Math.min(
stageWidth < image.width ? stageWidth / image.width : 1,
stageHeigth < image.height ? stageHeigth / image.height : 1
)
stageWidth < image.width ? stageWidth / image.width : 1,
stageHeigth < image.height ? stageHeigth / image.height : 1
)
: 1;
setStageScale(scale);
resetPositioin();
Expand Down Expand Up @@ -274,10 +277,10 @@ const TestDetailsModal: React.FunctionComponent<{
)}
{(testRun.status === TestStatus.unresolved ||
testRun.status === TestStatus.new) && (
<Grid item>
<ApproveRejectButtons testRun={testRun} />
</Grid>
)}
<Grid item>
<ApproveRejectButtons testRun={testRun} />
</Grid>
)}
<Grid item>
<IconButton color="inherit" onClick={handleClose}>
<Close />
Expand Down Expand Up @@ -492,7 +495,7 @@ const TestDetailsModal: React.FunctionComponent<{
<BaseModal
open={applyIgnoreDialogOpen}
title={applyIgnoreAreaText}
submitButtonText={'Yes'}
submitButtonText={"Yes"}
onCancel={toggleApplyIgnoreDialogOpen}
content={
<Typography>
Expand All @@ -502,8 +505,7 @@ const TestDetailsModal: React.FunctionComponent<{
onSubmit={() => {
toggleApplyIgnoreDialogOpen();
applyIgnoreArea();
}
}
}}
/>
</React.Fragment>
);
Expand Down
30 changes: 15 additions & 15 deletions src/components/TestDetailsDialog/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Dialog, makeStyles, Typography } from "@material-ui/core";
import React from "react";
import {
selectTestRun,
useTestRunDispatch,
useTestRunState,
} from "../../contexts";
import { useHistory } from "react-router";
import { useBuildState, useTestRunState } from "../../contexts";
import { buildTestRunLocation } from "../../_helpers/route.helpers";
import { BaseModal } from "../BaseModal";
import { ArrowButtons } from "./ArrowButtons";
import TestDetailsModal from "./TestDetailsModal";
Expand All @@ -18,14 +16,14 @@ const useStyles = makeStyles((theme) => ({
export const TestDetailsDialog: React.FunctionComponent = () => {
const classes = useStyles();
const {
testRun,
selectedTestRun,
touched,
testRuns: allTestRuns,
filteredTestRunIds,
sortedTestRunIds,
selectedTestRunId,
} = useTestRunState();
const testRunDispatch = useTestRunDispatch();
const { selectedBuild } = useBuildState();
const history = useHistory();
const [notSavedChangesModal, setNotSavedChangesModal] = React.useState(false);
const [navigationTargetId, setNavigationTargetId] = React.useState<string>();

Expand All @@ -46,8 +44,8 @@ export const TestDetailsDialog: React.FunctionComponent = () => {
}, [allTestRuns, filteredTestRunIds, sortedTestRunIds]);

const selectedTestRunIndex = React.useMemo(
() => testRuns.findIndex((t) => t.id === selectedTestRunId),
[testRuns, selectedTestRunId]
() => testRuns.findIndex((t) => t.id === selectedTestRun?.id),
[testRuns, selectedTestRun?.id]
);

const handleNavigation = React.useCallback(
Expand All @@ -56,20 +54,20 @@ export const TestDetailsDialog: React.FunctionComponent = () => {
setNavigationTargetId(id);
setNotSavedChangesModal(true);
} else {
selectTestRun(testRunDispatch, id);
history.push(buildTestRunLocation(selectedBuild?.id, id));
}
},
[testRunDispatch, touched]
[touched, history, selectedBuild?.id]
);

if (!testRun) {
if (!selectedTestRun) {
return null;
}

return (
<Dialog open={true} fullScreen className={classes.modal}>
<TestDetailsModal
testRun={testRun}
testRun={selectedTestRun}
touched={touched}
handleClose={() => handleNavigation()}
/>
Expand All @@ -87,7 +85,9 @@ export const TestDetailsDialog: React.FunctionComponent = () => {
<Typography>{`Are you sure you want to discard changes?`}</Typography>
}
onSubmit={() => {
selectTestRun(testRunDispatch, navigationTargetId);
history.push(
buildTestRunLocation(selectedBuild?.id, navigationTargetId)
);
setNotSavedChangesModal(false);
}}
/>
Expand Down
51 changes: 31 additions & 20 deletions src/components/TestRunList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React from "react";
import { Chip } from "@material-ui/core";
import { Chip, Typography } from "@material-ui/core";
import TestStatusChip from "../TestStatusChip";
import {
useTestRunState,
useTestRunDispatch,
getTestRunList,
useBuildState,
selectTestRun,
} from "../../contexts";
import { useSnackbar } from "notistack";
import {
Expand All @@ -26,6 +24,9 @@ import { DataGridCustomToolbar } from "./DataGridCustomToolbar";
import { StatusFilterOperators } from "./StatusFilterOperators";
import { TagFilterOperators } from "./TagFilterOperators";
import { TestStatus } from "../../types";
import { testRunService } from "../../services";
import { useHistory } from "react-router";
import { buildTestRunLocation } from "../../_helpers/route.helpers";

const columnsDef: GridColDef[] = [
{ field: "id", hide: true, filterable: false },
Expand Down Expand Up @@ -97,8 +98,9 @@ const columnsDef: GridColDef[] = [

const TestRunList: React.FunctionComponent = () => {
const { enqueueSnackbar } = useSnackbar();
const { testRun, testRuns, loading } = useTestRunState();
const { selectedBuildId } = useBuildState();
const history = useHistory();
const { selectedTestRun, testRuns, loading } = useTestRunState();
const { selectedBuild } = useBuildState();
const testRunDispatch = useTestRunDispatch();

const [sortModel, setSortModel] = React.useState<GridSortModel>([
Expand All @@ -108,24 +110,29 @@ const TestRunList: React.FunctionComponent = () => {
},
]);

const getTestRunListCallback = React.useCallback(
() =>
selectedBuildId &&
getTestRunList(testRunDispatch, selectedBuildId).catch((err: string) =>
enqueueSnackbar(err, {
variant: "error",
})
),
[testRunDispatch, enqueueSnackbar, selectedBuildId]
);
const getTestRunListCallback = React.useCallback(() => {
testRunDispatch({ type: "request" });
if (selectedBuild?.id) {
testRunService
.getList(selectedBuild.id)
.then((payload) => testRunDispatch({ type: "get", payload }))
.catch((err: string) =>
enqueueSnackbar(err, {
variant: "error",
})
);
} else {
testRunDispatch({ type: "get", payload: [] });
}
}, [testRunDispatch, enqueueSnackbar, selectedBuild?.id]);

React.useEffect(() => {
getTestRunListCallback();
}, [getTestRunListCallback]);

return (
<React.Fragment>
{selectedBuildId && (
{selectedBuild ? (
<DataGrid
rows={testRuns}
columns={columnsDef}
Expand All @@ -142,13 +149,15 @@ const TestRunList: React.FunctionComponent = () => {
sortModel={sortModel}
onSortModelChange={(model) => setSortModel(model)}
onRowClick={(param: GridRowParams) => {
selectTestRun(
testRunDispatch,
param.getValue(param.id, "id")?.toString()
history.push(
buildTestRunLocation(
selectedBuild.id,
param.getValue(param.id, "id")?.toString()
)
);
}}
onStateChange={(props: GridStateChangeParams) => {
if (!testRun) {
if (!selectedTestRun) {
// only if testRun modal is not shown
testRunDispatch({
type: "filter",
Expand All @@ -161,6 +170,8 @@ const TestRunList: React.FunctionComponent = () => {
}
}}
/>
) : (
<Typography variant="h5">Select build from list</Typography>
)}
</React.Fragment>
);
Expand Down
Loading