diff --git a/package-lock.json b/package-lock.json index d1db5011..633ae1e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2433,6 +2433,30 @@ } } }, + "@material-ui/data-grid": { + "version": "4.0.0-alpha.19", + "resolved": "https://registry.npmjs.org/@material-ui/data-grid/-/data-grid-4.0.0-alpha.19.tgz", + "integrity": "sha512-DqBbRZPAREti4XM/AbaUy8hLaNMAvZLUbwQ82UWGkwkv5zF6fhtSEl51W/q+bkvpLwok6SuJyJvoUE5zrlmaUw==", + "requires": { + "@material-ui/utils": "^5.0.0-alpha.14", + "prop-types": "^15.7.2", + "reselect": "^4.0.0" + }, + "dependencies": { + "@material-ui/utils": { + "version": "5.0.0-alpha.24", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-5.0.0-alpha.24.tgz", + "integrity": "sha512-di0zaQKHiRi6NwPAt/4mRNfUYTa5aWVTqfzTYN/OdnQTGtOLPPFo9Om+uYgkunZIOa3lsahveo6ieH/YgFnJfQ==", + "requires": { + "@babel/runtime": "^7.4.4", + "@types/prop-types": "^15.7.3", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + } + } + }, "@material-ui/icons": { "version": "4.11.2", "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", @@ -2971,6 +2995,14 @@ "@types/react": "*" } }, + "@types/react-is": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.0.tgz", + "integrity": "sha512-A0DQ1YWZ0RG2+PV7neAotNCIh8gZ3z7tQnDJyS2xRPDNtAtSPcJ9YyfMP8be36Ha0kQRzbZCrrTMznA4blqO5g==", + "requires": { + "@types/react": "*" + } + }, "@types/react-material-ui-form-validator": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/react-material-ui-form-validator/-/react-material-ui-form-validator-2.1.0.tgz", @@ -17180,6 +17212,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "reselect": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", + "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + }, "resolve": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", diff --git a/package.json b/package.json index c02ca802..848b3926 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@material-ui/core": "^4.11.2", + "@material-ui/data-grid": "^4.0.0-alpha.19", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.57", "@testing-library/jest-dom": "^5.11.1", diff --git a/src/_helpers/route.helpers.ts b/src/_helpers/route.helpers.ts index 620e45a5..01baa579 100644 --- a/src/_helpers/route.helpers.ts +++ b/src/_helpers/route.helpers.ts @@ -1,5 +1,6 @@ import { TestRun, TestVariation } from "../types"; import { routes } from "../constants"; +import qs from "qs"; export const buildTestRunUrl = ( testVariation: TestVariation, @@ -7,9 +8,22 @@ export const buildTestRunUrl = ( ) => `${routes.HOME}${testVariation.projectId}?buildId=${testRun.buildId}&testId=${testRun.id}`; -export const buildTestRunLocation = (testRun: TestRun) => ({ - search: `buildId=${testRun.buildId}&testId=${testRun.id}`, +export const buildTestRunLocation = (buildId: string, testRunId: string) => ({ + search: `buildId=${buildId}&testId=${testRunId}`, }); export const buildBuildPageUrl = (projectId: string, buildId: string) => `${routes.HOME}${projectId}?buildId=${buildId}`; + +export interface QueryParams { + buildId?: string; + testId?: string; +} + +export const getQueryParams = (guery: string): QueryParams => { + const queryParams = qs.parse(guery, { ignoreQueryPrefix: true }); + return { + buildId: queryParams.buildId as string, + testId: queryParams.testId as string, + }; +}; diff --git a/src/components/ArrowButtons.tsx b/src/components/ArrowButtons.tsx index 2e59ae3a..baeb3c8c 100644 --- a/src/components/ArrowButtons.tsx +++ b/src/components/ArrowButtons.tsx @@ -33,7 +33,7 @@ export const ArrowButtons: React.FunctionComponent<{ const navigateNext = () => { if (selectedTestRunIndex + 1 < testRuns.length) { const next = testRuns[selectedTestRunIndex + 1]; - history.push(buildTestRunLocation(next)); + history.push(buildTestRunLocation(next.buildId, next.id)); selectTestRun(testRunDispatch, next.id); } }; @@ -42,7 +42,7 @@ export const ArrowButtons: React.FunctionComponent<{ const navigateBefore = () => { if (selectedTestRunIndex > 0) { const prev = testRuns[selectedTestRunIndex - 1]; - history.push(buildTestRunLocation(prev)); + history.push(buildTestRunLocation(prev.buildId, prev.id)); selectTestRun(testRunDispatch, prev.id); } }; diff --git a/src/components/BuildDetails.tsx b/src/components/BuildDetails.tsx index 523e1d04..54a99d53 100644 --- a/src/components/BuildDetails.tsx +++ b/src/components/BuildDetails.tsx @@ -7,18 +7,54 @@ import { Button, LinearProgress, } from "@material-ui/core"; -import { Build } from "../types"; import { BuildStatusChip } from "./BuildStatusChip"; import { useSnackbar } from "notistack"; import { buildsService } from "../services"; import { formatDateTime } from "../_helpers/format.helper"; +import { useBuildState } from "../contexts"; -interface IProps { - build: Build; -} - -const BuildDetails: React.FunctionComponent = ({ build }) => { +const BuildDetails: React.FunctionComponent = () => { const { enqueueSnackbar } = useSnackbar(); + const { selectedBuild } = useBuildState(); + + if (!selectedBuild) { + return null; + } + + const approveAllButton = selectedBuild.unresolvedCount > 0 && ( + + + + ); + + const loadingAnimation = selectedBuild.isRunning && ; return ( @@ -26,48 +62,17 @@ const BuildDetails: React.FunctionComponent = ({ build }) => { - {`#${build.number} ${ - build.ciBuildId || "" + {`#${selectedBuild.number} ${ + selectedBuild.ciBuildId || "" }`} - + - + - {build.unresolvedCount > 0 && ( - - - - )} + {approveAllButton} @@ -76,7 +81,7 @@ const BuildDetails: React.FunctionComponent = ({ build }) => { - {formatDateTime(build.createdAt)} + {formatDateTime(selectedBuild.createdAt)} @@ -87,22 +92,24 @@ const BuildDetails: React.FunctionComponent = ({ build }) => { {`${ - build.unresolvedCount + build.failedCount + build.passedCount + selectedBuild.unresolvedCount + + selectedBuild.failedCount + + selectedBuild.passedCount } total`} - {`${build.unresolvedCount} unresolved`} + {`${selectedBuild.unresolvedCount} unresolved`} - {`${build.failedCount} failed`} + {`${selectedBuild.failedCount} failed`} - {`${build.passedCount} passed`} + {`${selectedBuild.passedCount} passed`} - {build.isRunning && } + {loadingAnimation} ); }; diff --git a/src/components/BuildList.tsx b/src/components/BuildList/index.tsx similarity index 79% rename from src/components/BuildList.tsx rename to src/components/BuildList/index.tsx index 39181a7c..4c6e8627 100644 --- a/src/components/BuildList.tsx +++ b/src/components/BuildList/index.tsx @@ -24,13 +24,16 @@ import { deleteBuild, selectBuild, stopBuild, -} from "../contexts"; -import { BuildStatusChip } from "./BuildStatusChip"; -import { SkeletonList } from "./SkeletonList"; -import { formatDateTime } from "../_helpers/format.helper"; + getBuildList, + useProjectState, +} from "../../contexts"; +import { BuildStatusChip } from "../BuildStatusChip"; +import { SkeletonList } from "../SkeletonList"; +import { formatDateTime } from "../../_helpers/format.helper"; import { useSnackbar } from "notistack"; -import { Build } from "../types"; -import { BaseModal } from "./BaseModal"; +import { Build } from "../../types"; +import { BaseModal } from "../BaseModal"; +import { Pagination } from "@material-ui/lab"; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -52,10 +55,10 @@ const useStyles = makeStyles((theme: Theme) => const BuildList: FunctionComponent = () => { const classes = useStyles(); const history = useHistory(); - const { buildList, selectedBuild, loading } = useBuildState(); + const { buildList, selectedBuild, loading, total, take } = useBuildState(); const buildDispatch = useBuildDispatch(); const { enqueueSnackbar } = useSnackbar(); - + const { selectedProjectId } = useProjectState(); const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); const [anchorEl, setAnchorEl] = React.useState(null); const [menuBuild, setMenuBuild] = React.useState(); @@ -83,9 +86,25 @@ const BuildList: FunctionComponent = () => { } }, [buildDispatch, selectedBuild, buildList]); + const getBuildListCalback: any = React.useCallback( + (page: number) => + selectedProjectId && + getBuildList(buildDispatch, selectedProjectId, page).catch( + (err: string) => + enqueueSnackbar(err, { + variant: "error", + }) + ), + [buildDispatch, enqueueSnackbar, selectedProjectId] + ); + + React.useEffect(() => { + getBuildListCalback(1); + }, [getBuildListCalback]); + return ( - + {loading ? ( @@ -150,6 +169,19 @@ const BuildList: FunctionComponent = () => { )} + + + + getBuildListCalback(page)} + /> + + + + {menuBuild && ( {menuBuild.isRunning && ( @@ -187,8 +219,12 @@ const BuildList: FunctionComponent = () => { }?`} } onSubmit={() => { - let indexOfBuildDeleted = buildList.findIndex((e) => e.id === menuBuild.id); - let indexOfSelectedBuild = buildList.findIndex((e) => e.id === selectedBuild?.id); + let indexOfBuildDeleted = buildList.findIndex( + (e) => e.id === menuBuild.id + ); + let indexOfSelectedBuild = buildList.findIndex( + (e) => e.id === selectedBuild?.id + ); deleteBuild(buildDispatch, menuBuild.id) .then((b) => { if (indexOfBuildDeleted === indexOfSelectedBuild) { @@ -196,7 +232,10 @@ const BuildList: FunctionComponent = () => { if (indexOfBuildDeleted === 0) { selectBuild(buildDispatch, buildList[1].id); } else { - selectBuild(buildDispatch, buildList[indexOfBuildDeleted - 1].id); + selectBuild( + buildDispatch, + buildList[indexOfBuildDeleted - 1].id + ); } } else { selectBuild(buildDispatch, null); diff --git a/src/components/ProjectSelect.tsx b/src/components/ProjectSelect.tsx index 370e23ef..af0e28df 100644 --- a/src/components/ProjectSelect.tsx +++ b/src/components/ProjectSelect.tsx @@ -8,7 +8,11 @@ import { Select, Theme, } from "@material-ui/core"; -import { useProjectState } from "../contexts"; +import { + useProjectState, + useProjectDispatch, + selectProject, +} from "../contexts"; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -22,10 +26,18 @@ const useStyles = makeStyles((theme: Theme) => ); const ProjectSelect: FunctionComponent<{ + projectId?: string; onProjectSelect: (id: string) => void; -}> = ({ onProjectSelect }) => { +}> = ({ projectId, onProjectSelect }) => { const classes = useStyles(); const { projectList, selectedProjectId } = useProjectState(); + const projectDispatch = useProjectDispatch(); + + React.useEffect(() => { + if (projectId && projectId !== selectedProjectId) { + selectProject(projectDispatch, projectId); + } + }, [projectId, selectedProjectId, projectDispatch]); return ( diff --git a/src/components/TestDetailsDialog/index.tsx b/src/components/TestDetailsDialog/index.tsx new file mode 100644 index 00000000..e18f017a --- /dev/null +++ b/src/components/TestDetailsDialog/index.tsx @@ -0,0 +1,49 @@ +import { Dialog, makeStyles } from "@material-ui/core"; +import React from "react"; +import { useLocation } from "react-router-dom"; +import { + selectTestRun, + useTestRunDispatch, + useTestRunState, +} from "../../contexts"; +import { QueryParams, getQueryParams } from "../../_helpers/route.helpers"; +import { ArrowButtons } from "../ArrowButtons"; +import TestDetailsModal from "../TestDetailsModal"; + +const useStyles = makeStyles((theme) => ({ + modal: { + margin: 40, + }, +})); + +export const TestDetailsDialog: React.FunctionComponent = () => { + const classes = useStyles(); + const location = useLocation(); + const { testRuns, selectedTestRunIndex } = useTestRunState(); + const testRunDispatch = useTestRunDispatch(); + + const queryParams: QueryParams = React.useMemo( + () => getQueryParams(location.search), + [location.search] + ); + + React.useEffect(() => { + if (queryParams.testId) { + selectTestRun(testRunDispatch, queryParams.testId); + } + }, [queryParams.testId, testRunDispatch]); + + if (selectedTestRunIndex === undefined || !testRuns[selectedTestRunIndex]) { + return null; + } + + return ( + + + + + ); +}; diff --git a/src/components/TestRunList.tsx b/src/components/TestRunList.tsx deleted file mode 100644 index 1f80e344..00000000 --- a/src/components/TestRunList.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import React from "react"; -import { - Typography, - TableContainer, - TableHead, - TableCell, - Table, - TableRow, - TableBody, - IconButton, - Menu, - MenuItem, - makeStyles, -} from "@material-ui/core"; -import { MoreVert } from "@material-ui/icons"; -import { useHistory } from "react-router-dom"; -import { TestRun } from "../types"; -import TestStatusChip from "./TestStatusChip"; -import { buildTestRunLocation } from "../_helpers/route.helpers"; -import { - useTestRunState, - useTestRunDispatch, - deleteTestRun, - selectTestRun, -} from "../contexts"; -import { SkeletonList } from "./SkeletonList"; -import { useSnackbar } from "notistack"; -import { BaseModal } from "./BaseModal"; - -const useStyles = makeStyles((theme) => ({ - root: { - height: "100%", - }, -})); - -const TestRunList: React.FunctionComponent<{ - items: TestRun[]; -}> = ({ items }) => { - const classes = useStyles(); - const { enqueueSnackbar } = useSnackbar(); - const { selectedTestRunId, loading } = useTestRunState(); - const testRunDispatch = useTestRunDispatch(); - const history = useHistory(); - const [anchorEl, setAnchorEl] = React.useState(null); - const [selectedTestRun, setSelectedTestRun] = React.useState< - TestRun | undefined - >(undefined); - const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); - - const handleClick = ( - event: React.MouseEvent, - testRun: TestRun - ) => { - event.stopPropagation(); - setAnchorEl(event.currentTarget); - setSelectedTestRun(testRun); - }; - - const handleClose = () => { - setSelectedTestRun(undefined); - }; - - const toggleDeleteDialogOpen = () => { - setDeleteDialogOpen(!deleteDialogOpen); - }; - - return ( - - {loading ? ( - - ) : items.length === 0 ? ( - No test runs - ) : ( - - - - - - Name - OS - Device - Browser - Viewport - Status - - - - - {items.map((test) => ( - - { - history.push(buildTestRunLocation(test)); - selectTestRun(testRunDispatch, test.id); - }} - > - {test.name} - - - {test.os} - - - {test.device} - - - {test.browser} - - - {test.viewport} - - - - - - handleClick(event, test)}> - - - - - ))} - -
-
- - {selectedTestRun && ( - - { - history.push(buildTestRunLocation(selectedTestRun)); - handleClose(); - }} - > - Details - - Delete - - )} - - {selectedTestRun && ( - {`Are you sure you want to delete: ${selectedTestRun.name}?`} - } - onSubmit={() => { - deleteTestRun(testRunDispatch, selectedTestRun.id) - .then((testRun) => { - enqueueSnackbar(`${selectedTestRun.name} deleted`, { - variant: "success", - }); - }) - .catch((err) => - enqueueSnackbar(err, { - variant: "error", - }) - ); - handleClose(); - }} - /> - )} -
- )} -
- ); -}; - -export default TestRunList; diff --git a/src/components/TestRunList/BulkDeleteButton.tsx b/src/components/TestRunList/BulkDeleteButton.tsx new file mode 100644 index 00000000..84c916bc --- /dev/null +++ b/src/components/TestRunList/BulkDeleteButton.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import { Typography, IconButton } from "@material-ui/core"; +import { BaseComponentProps } from "@material-ui/data-grid"; +import { deleteTestRun, useTestRunDispatch } from "../../contexts"; +import { BaseModal } from "../BaseModal"; +import { useSnackbar } from "notistack"; +import { Delete } from "@material-ui/icons"; + +export const BulkDeleteButton: React.FunctionComponent = ( + props: BaseComponentProps +) => { + const { enqueueSnackbar } = useSnackbar(); + const testRunDispatch = useTestRunDispatch(); + const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); + const rows: Record = props.state.selection; + const count = Object.keys(rows).length; + + const toggleDeleteDialogOpen = () => { + setDeleteDialogOpen(!deleteDialogOpen); + }; + return ( + <> + + + + + {`Are you sure you want to delete ${count} items?`} + } + onSubmit={() => { + Promise.all( + Object.keys(rows).map((id: string) => + deleteTestRun(testRunDispatch, id) + ) + ) + .then(() => { + toggleDeleteDialogOpen(); + enqueueSnackbar(`${count} items deleted`, { + variant: "success", + }); + }) + .catch((err) => + enqueueSnackbar(err, { + variant: "error", + }) + ); + }} + /> + + ); +}; diff --git a/src/components/TestRunList/DataGridCustomToolbar.tsx b/src/components/TestRunList/DataGridCustomToolbar.tsx new file mode 100644 index 00000000..8cfac800 --- /dev/null +++ b/src/components/TestRunList/DataGridCustomToolbar.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { Toolbar, Box } from "@material-ui/core"; +import { BaseComponentProps, DensitySelector } from "@material-ui/data-grid"; +import { BulkDeleteButton } from "./BulkDeleteButton"; + +export const DataGridCustomToolbar: React.FunctionComponent = ( + props: BaseComponentProps +) => { + return ( + <> + + + + + + + + ); +}; diff --git a/src/components/TestRunList/index.tsx b/src/components/TestRunList/index.tsx new file mode 100644 index 00000000..aec84995 --- /dev/null +++ b/src/components/TestRunList/index.tsx @@ -0,0 +1,110 @@ +import React from "react"; +import { Chip } from "@material-ui/core"; +import { useHistory } from "react-router-dom"; +import TestStatusChip from "../TestStatusChip"; +import { buildTestRunLocation } from "../../_helpers/route.helpers"; +import { + useTestRunState, + useTestRunDispatch, + getTestRunList, + useBuildState, +} from "../../contexts"; +import { useSnackbar } from "notistack"; +import { + DataGrid, + ColDef, + RowParams, + CellParams, + PageChangeParams, +} from "@material-ui/data-grid"; +import { DataGridCustomToolbar } from "./DataGridCustomToolbar"; + +const columns: ColDef[] = [ + { field: "id", hide: true }, + { field: "name", headerName: "Name", flex: 1 }, + { + field: "tags", + headerName: "Tags", + flex: 1, + renderCell: (params: CellParams) => { + const tags = [ + params.row["os"], + params.row["device"], + params.row["browser"], + params.row["viewport"], + ]; + return ( + <> + {tags.map( + (tag) => tag && + )} + + ); + }, + }, + { + field: "status", + headerName: "Status", + renderCell: (params: CellParams) => { + return ; + }, + }, +]; + +const TestRunList: React.FunctionComponent = () => { + const { enqueueSnackbar } = useSnackbar(); + const { testRuns, loading, total, take } = useTestRunState(); + const { selectedBuildId } = useBuildState(); + const testRunDispatch = useTestRunDispatch(); + const history = useHistory(); + + const getTestRunListCalback = React.useCallback( + (page: number) => + selectedBuildId && + getTestRunList(testRunDispatch, selectedBuildId, page).catch( + (err: string) => + enqueueSnackbar(err, { + variant: "error", + }) + ), + [testRunDispatch, enqueueSnackbar, selectedBuildId] + ); + + React.useEffect(() => { + getTestRunListCalback(1); + }, [getTestRunListCalback]); + + return ( + + { + history.push( + buildTestRunLocation( + param.getValue("buildId")?.toString() || "", + param.getValue("id")?.toString() || "" + ) + ); + }} + onPageChange={(param: PageChangeParams) => + getTestRunListCalback(param.page) + } + /> + + ); +}; + +export default TestRunList; diff --git a/src/components/TestStatusChip.tsx b/src/components/TestStatusChip.tsx index 2a75e059..b108666b 100644 --- a/src/components/TestStatusChip.tsx +++ b/src/components/TestStatusChip.tsx @@ -2,9 +2,9 @@ import React from "react"; import { Chip } from "@material-ui/core"; import { TestStatus } from "../types/testStatus"; -const TestStatusChip: React.FunctionComponent<{ status: TestStatus }> = ({ - status, -}) => { +const TestStatusChip: React.FunctionComponent<{ + status: string | undefined; +}> = ({ status }) => { let color: "inherit" | "primary" | "secondary" | "default" | undefined; switch (status) { case TestStatus.new: diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx index cccf749f..3c36b4b6 100644 --- a/src/pages/ProjectPage.tsx +++ b/src/pages/ProjectPage.tsx @@ -1,51 +1,18 @@ import React, { useEffect } from "react"; -import { Grid, Dialog, Box, makeStyles } from "@material-ui/core"; +import { Grid, Box, makeStyles } from "@material-ui/core"; import { useParams, useLocation, useHistory } from "react-router-dom"; -import { TestRun } from "../types"; import BuildList from "../components/BuildList"; import ProjectSelect from "../components/ProjectSelect"; -import qs from "qs"; import TestRunList from "../components/TestRunList"; -import TestDetailsModal from "../components/TestDetailsModal"; -import Filters from "../components/Filters"; -import { - useProjectState, - useBuildState, - useBuildDispatch, - selectBuild, - useTestRunState, - useTestRunDispatch, - selectTestRun, - getTestRunList, - useProjectDispatch, - selectProject, - getBuildList, -} from "../contexts"; -import { useSnackbar } from "notistack"; -import { ArrowButtons } from "../components/ArrowButtons"; +import { useBuildDispatch, selectBuild } from "../contexts"; import BuildDetails from "../components/BuildDetails"; -import { Pagination } from "@material-ui/lab"; - -interface QueryParams { - buildId?: string; - testId?: string; -} - -const getQueryParams = (guery: string): QueryParams => { - const queryParams = qs.parse(guery, { ignoreQueryPrefix: true }); - return { - buildId: queryParams.buildId as string, - testId: queryParams.testId as string, - }; -}; +import { TestDetailsDialog } from "../components/TestDetailsDialog"; +import { getQueryParams, QueryParams } from "../_helpers/route.helpers"; const useStyles = makeStyles((theme) => ({ root: { height: "100%", }, - modal: { - margin: 40, - }, })); const ProjectPage = () => { @@ -53,29 +20,11 @@ const ProjectPage = () => { const { projectId } = useParams<{ projectId: string }>(); const location = useLocation(); const history = useHistory(); - const { enqueueSnackbar } = useSnackbar(); - const { selectedBuild, selectedBuildId, total, take } = useBuildState(); const buildDispatch = useBuildDispatch(); - const { selectedProjectId } = useProjectState(); - const projectDispatch = useProjectDispatch(); - const { - testRuns, - selectedTestRunIndex, - total: testRunTotal, - take: testRunTake, - } = useTestRunState(); - const testRunDispatch = useTestRunDispatch(); - - const queryParams: QueryParams = React.useMemo( - () => getQueryParams(location.search), - [location.search] - ); - useEffect(() => { - if (projectId) { - selectProject(projectDispatch, projectId); - } - }, [projectId, projectDispatch]); + const queryParams: QueryParams = React.useMemo(() => { + return getQueryParams(location.search); + }, [location.search]); useEffect(() => { if (queryParams.buildId) { @@ -83,89 +32,30 @@ const ProjectPage = () => { } }, [buildDispatch, queryParams.buildId]); - useEffect(() => { - if (queryParams.testId) { - selectTestRun(testRunDispatch, queryParams.testId); - } - }, [queryParams.testId, testRunDispatch]); - - const getTestRunListCalback: any = React.useCallback( - (page: number) => - selectedBuildId && - getTestRunList(testRunDispatch, selectedBuildId, page).catch( - (err: string) => - enqueueSnackbar(err, { - variant: "error", - }) - ), - [testRunDispatch, enqueueSnackbar, selectedBuildId] - ); - - const getBuildListCalback: any = React.useCallback( - (page: number) => - selectedProjectId && - getBuildList(buildDispatch, selectedProjectId, page).catch( - (err: string) => - enqueueSnackbar(err, { - variant: "error", - }) - ), - [buildDispatch, enqueueSnackbar, selectedProjectId] - ); - - React.useEffect(() => { - getTestRunListCalback(1); - }, [getTestRunListCalback]); - - React.useEffect(() => { - getBuildListCalback(1); - }, [getBuildListCalback]); - return ( - history.push(id)} /> - + + history.push(id)} + /> + + - - - getBuildListCalback(page)} - /> - - - {selectedBuild && } - - + + + + + - - - getTestRunListCalback(page)} - /> - - - {selectedTestRunIndex !== undefined && testRuns[selectedTestRunIndex] && ( - - - - - )} + ); }; diff --git a/src/pages/TestVariationListPage.tsx b/src/pages/TestVariationListPage.tsx index 43077029..c7633139 100644 --- a/src/pages/TestVariationListPage.tsx +++ b/src/pages/TestVariationListPage.tsx @@ -8,12 +8,10 @@ import ProjectSelect from "../components/ProjectSelect"; import Filters from "../components/Filters"; import { TestVariationMergeForm } from "../components/TestVariationMergeForm"; import { useSnackbar } from "notistack"; -import { selectProject, useProjectDispatch } from "../contexts"; const TestVariationListPage: React.FunctionComponent = () => { const history = useHistory(); const { enqueueSnackbar } = useSnackbar(); - const projectDispatch = useProjectDispatch(); const { projectId = "" } = useParams<{ projectId: string }>(); const [testVariations, setTestVariations] = React.useState( [] @@ -28,12 +26,6 @@ const TestVariationListPage: React.FunctionComponent = () => { const [branchName, setBranchName] = React.useState(""); const [filteredItems, setFilteredItems] = React.useState([]); - React.useEffect(() => { - if (projectId) { - selectProject(projectDispatch, projectId); - } - }, [projectId, projectDispatch]); - React.useEffect(() => { if (projectId) { testVariationService @@ -84,7 +76,10 @@ const TestVariationListPage: React.FunctionComponent = () => { - history.push(id)} /> + history.push(id)} + />