diff --git a/src/components/IOC/IOCManage/IOCManage.js b/src/components/IOC/IOCManage/IOCManage.js index 5001a0e26123888fc075015efcf90261258307b4..e2f767cff5624f0154e9e58a2253c495112cc27c 100644 --- a/src/components/IOC/IOCManage/IOCManage.js +++ b/src/components/IOC/IOCManage/IOCManage.js @@ -28,8 +28,8 @@ export function IOCManage({ operationsLoading, getOperations, setButtonDisabled, - jobLazyParams, - setJobLazyParams + pagination, + onPage }) { const { user } = useContext(userContext); const [state, setState] = useUrlState( @@ -44,8 +44,6 @@ export function IOCManage({ const [deploymentJob, getDeploymentJobById] = useJobById(); const [operationList, setOperationList] = useState(operations.operationsList); - const rowsPerPage = [5, 20]; - useEffect(() => { if (ioc.activeDeployment?.awxJobId) { getDeploymentJobById(ioc.activeDeployment?.awxJobId); @@ -114,7 +112,7 @@ export function IOCManage({ getOperations, buttonDisabled, setButtonDisabled, - jobLazyParams + jobLazyParams: pagination }} /> ) : ( @@ -126,7 +124,7 @@ export function IOCManage({ }, [ buttonDisabled, - jobLazyParams, + pagination, currentCommand, deploymentJob, getOperations, @@ -225,12 +223,9 @@ export function IOCManage({ <JobAsyncList jobs={operationList} setJobs={setOperationList} + pagination={pagination} + onPage={onPage} loading={operationsLoading} - totalCount={operations.totalCount} - lazyParams={jobLazyParams} - setLazyParams={setJobLazyParams} - rowsPerPage={rowsPerPage} - deploymentId={ioc?.activeDeployment?.id} /> </SimpleAccordion> <SimpleModal diff --git a/src/components/Job/JobAsyncList.js b/src/components/Job/JobAsyncList.js index ea48e862223140adc47718e22a5ef2eab8d213b6..33a4743ba7840e43260b845ba22d04111537067a 100644 --- a/src/components/Job/JobAsyncList.js +++ b/src/components/Job/JobAsyncList.js @@ -6,13 +6,9 @@ export function JobAsyncList({ jobs, setJobs, rowType, - totalCount, - lazyParams, - setLazyParams, - rowsPerPage, - loading, - paginator, - deploymentId + pagination, + onPage, + loading }) { const jobDetailFetchers = jobs?.map((job, index) => ( <JobDetailFetcher @@ -27,12 +23,9 @@ export function JobAsyncList({ <JobTable jobs={jobs} rowType={rowType} + pagination={pagination} + onPage={onPage} loading={loading} - totalCount={totalCount} - lazyParams={lazyParams} - setLazyParams={setLazyParams} - rowsPerPage={rowsPerPage} - deploymentId={deploymentId} /> {jobDetailFetchers} </> diff --git a/src/components/Job/JobTable.js b/src/components/Job/JobTable.js index 02dddc2c3576a0651df6a5220b86dac8cc02bb0e..70193c8001109e224a7c6a669ceeaa96248bfa5e 100644 --- a/src/components/Job/JobTable.js +++ b/src/components/Job/JobTable.js @@ -1,5 +1,5 @@ -import React, { useCallback } from "react"; -import { CustomTable } from "../common/table/CustomTable"; +import React from "react"; +import { Table } from "@ess-ics/ce-ui-common"; import { Grid, Tooltip } from "@mui/material"; import { noWrapText } from "../common/Helper"; import { useRedirect } from "../../hooks/Redirect"; @@ -7,16 +7,23 @@ import { JobStatusIcon, JobTypeIcon } from "./JobIcons"; import { formatDate } from "../common/Helper"; const jobLogColumns = [ - { id: "type", label: "Type", width: "8ch", textAlign: "center" }, - { id: "ioc", label: "IOC name", width: "15ch", sortable: false }, - { id: "version", label: "Revision", width: "10ch", sortable: false }, - { id: "host", label: "Host", width: "15ch", sortable: false }, - { id: "user", label: "User", width: "10ch", sortable: false }, { - id: "start", - label: "Time", + field: "type", + headerName: "Type", + flex: 0, + headerAlign: "center", + align: "center" + }, + { field: "ioc", headerName: "IOC name", width: "15ch", sortable: false }, + { field: "version", headerName: "Revision", width: "10ch", sortable: false }, + { field: "host", headerName: "Host", width: "15ch", sortable: false }, + { field: "user", headerName: "User", width: "10ch", sortable: false }, + { + field: "start", + headerName: "Time", width: "15ch", sortable: false, + headerAlign: "right", textAlign: "right" } ]; @@ -33,7 +40,7 @@ function createGitVersionField(version, shortVersion) { ); } -function createTableRow(job, deploymentId, colorStyle) { +function createTableRow(job, colorStyle) { return { id: job.id, type: ( @@ -72,19 +79,16 @@ function createTableRow(job, deploymentId, colorStyle) { }; } -function createTableRowJobLog(job, deploymentId) { - return createTableRow(job, deploymentId, "black"); +function createTableRowJobLog(job) { + return createTableRow(job, "black"); } export function JobTable({ jobs, rowType = "jobLog", - totalCount, - lazyParams, - setLazyParams, - rowsPerPage, - loading, - deploymentId + pagination, + onPage, + loading }) { const tableTypeSpecifics = { jobLog: [jobLogColumns, createTableRowJobLog] @@ -93,29 +97,22 @@ export function JobTable({ const redirect = useRedirect(); const [columns, createRow] = tableTypeSpecifics[rowType]; - const itemLink = useCallback((item) => { - if (["DEPLOY", "UNDEPLOY", "START", "STOP"].includes(item.jobType)) { - return `/jobs/${item.id}`; + const onRowClick = (params) => { + const job = params.row; + if (["DEPLOY", "UNDEPLOY", "START", "STOP"].includes(job?.jobType)) { + redirect(`/jobs/${job?.id}`); } - }, []); - const onRowClicked = useCallback( - (id, item) => { - redirect(itemLink(item)); - }, - [itemLink, redirect] - ); + }; return ( - <CustomTable + <Table columns={columns} - rows={jobs?.map((job) => createRow(job, deploymentId))} - handleRowClick={onRowClicked} - itemLink={itemLink} - totalCount={totalCount} - lazyParams={lazyParams} - setLazyParams={setLazyParams} - rowsPerPage={rowsPerPage} + rows={jobs?.map((job) => createRow(job))} + onRowClick={onRowClick} + pagination={pagination} + onPage={onPage} loading={loading} + autoHeight /> ); } diff --git a/src/components/common/User/UserOperationList.js b/src/components/common/User/UserOperationList.js index d98be2cb5df1b0fc946b28a32e5f0d5113499da1..371401793ed9ae95e5b406b35e909fa81ad0ec8a 100644 --- a/src/components/common/User/UserOperationList.js +++ b/src/components/common/User/UserOperationList.js @@ -4,31 +4,39 @@ import { initRequestParams } from "../Helper"; import { useEffect, useState } from "react"; import { useOperationsSearch } from "../../../api/SwaggerApi"; import { JobAsyncList } from "../../Job/JobAsyncList"; +import { usePagination } from "../../../hooks/pagination"; export function UserOperationList({ userName }) { const [operations, getOperations, , loading] = useOperationsSearch(); - - const [lazyParams, setLazyParams] = useState({ - first: 0, - rows: 20, - page: 0 - }); + const [jobList, setJobList] = useState([]); + useEffect(() => { + setJobList(operations.operationsList); + }, [operations, setJobList]); const rowsPerPage = [20, 50]; + const { pagination, setPagination } = usePagination({ + rowsPerPageOptions: rowsPerPage, + initLimit: rowsPerPage[0], + initPage: 0 + }); - const [jobList, setJobList] = useState([]); + // update pagination whenever search result total pages change + useEffect(() => { + setPagination({ totalCount: operations.totalCount ?? 0 }); + }, [setPagination, operations.totalCount]); useEffect(() => { - let requestParams = initRequestParams(lazyParams); + let requestParams = initRequestParams(pagination); requestParams.user = userName; getOperations(requestParams); - }, [getOperations, lazyParams, userName]); + }, [getOperations, pagination, userName]); - useEffect(() => { - setJobList(operations.operationsList); - }, [operations, setJobList]); + // Invoked by Table on change to pagination + const onPage = (params) => { + setPagination(params); + }; return ( <Card> @@ -43,10 +51,8 @@ export function UserOperationList({ userName }) { jobs={jobList} setJobs={setJobList} loading={loading} - totalCount={operations.totalCount} - lazyParams={lazyParams} - setLazyParams={setLazyParams} - rowsPerPage={rowsPerPage} + pagination={pagination} + onPage={onPage} /> </Card> ); diff --git a/src/mocks/mockAPI.js b/src/mocks/mockAPI.js index 51a700cd6ddb066690faea67efcc0f644600dfbf..d9ed82ec00d754844679f171ae91f0a9c5d11fcb 100644 --- a/src/mocks/mockAPI.js +++ b/src/mocks/mockAPI.js @@ -8,6 +8,26 @@ function getParameters(req, pattern) { return match?.params; } +function withMockPagination({ req, data, key }) { + const params = new URL(req.url).searchParams; + const page = Number(params.get("page")) || 0; + const limit = Number(params.get("limit")) || 20; + + const startIndex = page * limit; + const pagedData = data[key].slice(startIndex, startIndex + limit); + + const results = { + limit, + listSize: pagedData.length, + pageNumber: page, + totalCount: data[key].length, + [key]: pagedData, + DEVELOPER_NOTE: "THIS IS MOCKED PAGING!" + }; + + return results; +} + function spec(req) { const data = require("./fixtures/ccce-api.json"); return { @@ -121,6 +141,12 @@ function getDeploymentJobLog(req) { return { body, status }; } +function listOperations(req) { + const data = require("./fixtures/OperationList.json"); + const body = withMockPagination({ req, data, key: "operations" }); + return { body }; +} + function getCommandList(req) { const body = require("./fixtures/PagedCommandResponse.json"); return { body }; @@ -176,7 +202,8 @@ const mockAPI = { getDeployment, getDeploymentJob, getDeploymentJobLog, - getCommandList + getCommandList, + listOperations }, hosts: { getCSEntryHostWithStatus @@ -243,6 +270,11 @@ export const apiHandlers = [ ), // deployments + makeHandler( + "GET", + qRegExp(".*/operations"), + mockAPI.deployments.listOperations + ), makeHandler( "GET", qRegExp(".*/deployments/[0-9]+"), diff --git a/src/stories/views/UserPage/UserPageView.stories.js b/src/stories/views/UserPage/UserPageView.stories.js new file mode 100644 index 0000000000000000000000000000000000000000..3e248aa889bb550b124b9ce2c819a171565ab4c9 --- /dev/null +++ b/src/stories/views/UserPage/UserPageView.stories.js @@ -0,0 +1,13 @@ +import React from "react"; +import { UserPageView } from "../../../views/UserPage"; +import { AppHarness } from "../../../mocks/AppHarness"; + +export default { + title: "Views/UserPage/UserPageView" +}; + +export const Default = () => ( + <AppHarness> + <UserPageView /> + </AppHarness> +); diff --git a/src/views/IOC/IOCDetailsView.js b/src/views/IOC/IOCDetailsView.js index ecb584cbd305fd1c0ec6796211dd4f0cb8c4eb8a..018dd0bf8337295292481a435bbdba30279e8c7d 100644 --- a/src/views/IOC/IOCDetailsView.js +++ b/src/views/IOC/IOCDetailsView.js @@ -1,6 +1,12 @@ import { Grid, Paper, Tab, Tabs, Typography, IconButton } from "@mui/material"; import ArrowBackIcon from "@mui/icons-material/ArrowBack"; -import React, { useCallback, useContext, useEffect, useState } from "react"; +import React, { + useCallback, + useContext, + useEffect, + useMemo, + useState +} from "react"; import { useOngoingCommand, useOperationsSearch } from "../../api/SwaggerApi"; import { IOCLiveStatus } from "../../components/IOC/IOCLiveStatus"; import { IOCManage } from "../../components/IOC/IOCManage"; @@ -18,10 +24,11 @@ import { serialize, deserialize } from "../../components/common/URLState/URLState"; +import { usePagination } from "../../hooks/pagination"; const IOC_POLL_INTERVAL = 10000; export function IOCDetailsView({ ioc, getIOC, loading }) { - const [state, setState] = useUrlState( + const [urlState, setUrlState] = useUrlState( { tab: "Status", jobs_rows: "5", @@ -41,23 +48,53 @@ export function IOCDetailsView({ ioc, getIOC, loading }) { /* reset*/ ongoingCommandLoading ] = useOngoingCommand(ioc.id); - const jobLazyParams = useCallback(() => { + const jobUrlPagination = useMemo(() => { return { - rows: deserialize(state.jobs_rows), - page: deserialize(state.jobs_page) + rows: deserialize(urlState.jobs_rows), + page: deserialize(urlState.jobs_page) }; - }, [state]); + }, [urlState.jobs_rows, urlState.jobs_page]); - const setJobLazyParams = useCallback( + const setJobUrlPagination = useCallback( (params) => { - setState({ + setUrlState({ jobs_rows: serialize(params.rows), jobs_page: serialize(params.page) }); }, - [setState] + [setUrlState] ); + const rowsPerPage = [5, 20]; + + const { pagination: jobPagination, setPagination: setJobPagination } = + usePagination({ + rowsPerPageOptions: rowsPerPage, + initLimit: jobUrlPagination.rows ?? rowsPerPage[0], + initPage: jobUrlPagination.page ?? 0 + }); + + // update pagination whenever search result total pages change + useEffect(() => { + setJobPagination({ totalCount: operations.totalCount ?? 0 }); + }, [setJobPagination, operations.totalCount]); + + // whenever url state changes, update pagination + useEffect(() => { + setJobPagination({ ...jobUrlPagination }); + }, [setJobPagination, jobUrlPagination]); + + // whenever table pagination internally changes (user clicks next page etc) + // update the row params + useEffect(() => { + setJobUrlPagination(jobPagination); + }, [jobPagination, setJobUrlPagination]); + + // Invoked by Table on change to pagination + const onPage = (params) => { + setJobPagination(params); + }; + useSafePolling(getIOC, loading, IOC_POLL_INTERVAL); useSafePolling(getOngoingCommand, ongoingCommandLoading, IOC_POLL_INTERVAL); @@ -66,14 +103,15 @@ export function IOCDetailsView({ ioc, getIOC, loading }) { }, [ioc?.operationInProgress]); const handleTabChange = (event, tab) => { - setState({ tab: serialize(tab) }); + setUrlState({ tab: serialize(tab) }); }; + // Submit new search whenever pagination or ioc changes useEffect(() => { - let requestParams = initRequestParams(jobLazyParams()); + let requestParams = initRequestParams(jobPagination); requestParams.ioc_id = ioc.id; getOperations(requestParams); - }, [getOperations, jobLazyParams, ioc]); + }, [getOperations, jobPagination, ioc]); const handleClick = () => { navigate(-1); @@ -81,11 +119,11 @@ export function IOCDetailsView({ ioc, getIOC, loading }) { const resetTab = useCallback(() => { if (ioc?.activeDeployment) { - setState({ tab: "Status" }); + setUrlState({ tab: "Status" }); } else { - setState({ tab: "Management" }); + setUrlState({ tab: "Management" }); } - }, [ioc?.activeDeployment, setState]); + }, [ioc?.activeDeployment, setUrlState]); const setButtonDisabledAndUpdate = useCallback( (isDisabled) => { @@ -127,7 +165,7 @@ export function IOCDetailsView({ ioc, getIOC, loading }) { const CustomTabs = ({ children }) => { return ( <Tabs - value={deserialize(state.tab)} + value={deserialize(urlState.tab)} onChange={handleTabChange} > {children} @@ -188,8 +226,10 @@ export function IOCDetailsView({ ioc, getIOC, loading }) { xs={12} style={{ paddingBottom: 0 }} > - {deserialize(state.tab) === "Status" && <IOCLiveStatus ioc={ioc} />} - {deserialize(state.tab) === "Management" && ( + {deserialize(urlState.tab) === "Status" && ( + <IOCLiveStatus ioc={ioc} /> + )} + {deserialize(urlState.tab) === "Management" && ( <IOCManage ioc={ioc} getIOC={getIOC} @@ -199,11 +239,11 @@ export function IOCDetailsView({ ioc, getIOC, loading }) { operationsLoading={operationsLoading} getOperations={getOperations} setButtonDisabled={setButtonDisabledAndUpdate} - jobLazyParams={jobLazyParams()} - setJobLazyParams={setJobLazyParams} + pagination={jobPagination} + onPage={onPage} /> )} - {deserialize(state.tab) === "Admin" && ( + {deserialize(urlState.tab) === "Admin" && ( <IOCAdmin ioc={ioc} getIOC={getIOC} diff --git a/src/views/host/HostListView.js b/src/views/host/HostListView.js index 9a1cc77c12f09199c9115af1efc4fbb5705fd5c3..27145fa8b938e5a57e2d3665850b31e1e4b8b177 100644 --- a/src/views/host/HostListView.js +++ b/src/views/host/HostListView.js @@ -5,21 +5,18 @@ import React, { useContext, useMemo } from "react"; -import { styled } from "@mui/material/styles"; import { Container, - Paper, Grid, Tabs, Tab, Typography, useMediaQuery } from "@mui/material"; -import { RootContainer } from "../../components/common/Container/RootContainer"; import { HostList } from "../../components/host/HostList"; import { HostTable } from "../../components/host/HostTable"; import { useCSEntrySearch } from "../../api/SwaggerApi"; -import { GlobalAppBarContext } from "@ess-ics/ce-ui-common"; +import { GlobalAppBarContext, RootPaper } from "@ess-ics/ce-ui-common"; import { applicationTitle, initRequestParams, @@ -33,18 +30,6 @@ import { } from "../../components/common/URLState/URLState"; import { usePagination } from "../../hooks/pagination"; -const PREFIX = "HostListView"; - -const classes = { - root: `${PREFIX}-root` -}; - -const StyledRootContainer = styled(RootContainer)(({ theme }) => ({ - [`& .${classes.root}`]: { - marginBottom: theme.spacing(2) - } -})); - export function HostListView() { const { setTitle } = useContext(GlobalAppBarContext); useEffect(() => setTitle(applicationTitle("IOC hosts")), [setTitle]); @@ -177,50 +162,46 @@ export function HostListView() { ); return ( - <StyledRootContainer> - <Paper className={classes.root}> + <RootPaper> + <Grid + container + spacing={1} + > <Grid container spacing={1} + component={Container} + justifyContent="space-between" + alignItems="center" + style={{ display: "flex" }} > - <Grid - container - spacing={1} - component={Container} - justifyContent="space-between" - alignItems="center" - style={{ display: "flex" }} - > - <Grid item> - <Tabs - value={deserialize(urlState.tab)} - onChange={handleTabChange} - > - <Tab label={<Typography variant="h5">All</Typography>} /> - <Tab - label={ - <Typography variant="h5">Only hosts with IOCs</Typography> - } - /> - <Tab - label={ - <Typography variant="h5"> - Only hosts without IOCs - </Typography> - } - /> - </Tabs> - </Grid> - </Grid> - <Grid - item - xs={12} - md={12} - > - {content} + <Grid item> + <Tabs + value={deserialize(urlState.tab)} + onChange={handleTabChange} + > + <Tab label={<Typography variant="h5">All</Typography>} /> + <Tab + label={ + <Typography variant="h5">Only hosts with IOCs</Typography> + } + /> + <Tab + label={ + <Typography variant="h5">Only hosts without IOCs</Typography> + } + /> + </Tabs> </Grid> </Grid> - </Paper> - </StyledRootContainer> + <Grid + item + xs={12} + md={12} + > + {content} + </Grid> + </Grid> + </RootPaper> ); } diff --git a/src/views/jobs/JobListView.js b/src/views/jobs/JobListView.js index ab49c9a9faa03442c285be0fe671ea6ae5c0580f..79331f48e586dd0f8d31fbed47b28c689a3439b8 100644 --- a/src/views/jobs/JobListView.js +++ b/src/views/jobs/JobListView.js @@ -1,7 +1,5 @@ -import React, { useContext, useState, useCallback } from "react"; -import { styled } from "@mui/material/styles"; +import React, { useContext, useState, useCallback, useMemo } from "react"; import { - Paper, Grid, FormControlLabel, Switch, @@ -13,7 +11,7 @@ import { import Tabs from "@mui/material/Tabs"; import Tab from "@mui/material/Tab"; import { useOperationsSearch } from "../../api/SwaggerApi"; -import { userContext } from "@ess-ics/ce-ui-common"; +import { userContext, RootPaper } from "@ess-ics/ce-ui-common"; import { initRequestParams } from "../../components/common/Helper"; import { useEffect } from "react"; import { SearchBar } from "../../components/common/SearchBar/SearchBar"; @@ -24,34 +22,18 @@ import { serialize, deserialize } from "../../components/common/URLState/URLState"; - -const PREFIX = "JobListView"; - -const classes = { - root: `${PREFIX}-root`, - paper: `${PREFIX}-paper`, - formControl: `${PREFIX}-formControl` -}; - -const StyledPaper = styled(Paper)(({ theme }) => ({ - [`& .${classes.root}`]: { - width: "100%" - }, - - [`&.${classes.paper}`]: { - marginBottom: theme.spacing(2) - }, - - [`& .${classes.formControl}`]: { - marginLeft: "5px", - marginRight: "5px" - } -})); +import { usePagination } from "../../hooks/pagination"; export function JobListView() { const [operations, getOperations /* reset*/, , loading] = useOperationsSearch(); - const [state, setState] = useUrlState( + const [jobList, setJobList] = useState([]); + // Sync results with mutatable list + useEffect(() => { + setJobList(operations.operationsList); + }, [operations, setJobList]); + + const [urlState, setUrlState] = useUrlState( { tab: "0", own: "false", @@ -65,10 +47,9 @@ export function JobListView() { const { user } = useContext(userContext); const [deploymentStatus, setDeploymentStatus] = useState(null); - const [jobList, setJobList] = useState([]); const handleTabChange = (event, tab) => { - setState((s) => + setUrlState((s) => serialize(s.tab) === serialize(tab) ? { tab: serialize(tab) } : { tab: serialize(tab), page: "0" } @@ -88,37 +69,63 @@ export function JobListView() { }; useEffect(() => { - state.tab && changeTab(deserialize(state.tab)); - }, [state]); + urlState.tab && changeTab(deserialize(urlState.tab)); + }, [urlState]); const handleChangeOwn = (event) => { const own = event.target.checked; - setState({ own: serialize(own), page: "0" }); + setUrlState({ own: serialize(own), page: "0" }); }; - const lazyParams = useCallback(() => { + const urlPagination = useMemo(() => { return { - rows: deserialize(state.rows), - page: deserialize(state.page) + rows: deserialize(urlState.rows), + page: deserialize(urlState.page) }; - }, [state]); + }, [urlState.rows, urlState.page]); - const setLazyParams = useCallback( - (params) => { - setState({ rows: serialize(params.rows), page: serialize(params.page) }); + const setUrlPagination = useCallback( + ({ rows, page }) => { + setUrlState({ + rows: serialize(rows), + page: serialize(page) + }); }, - [setState] + [setUrlState] ); const rowsPerPage = [20, 50]; + const { pagination, setPagination } = usePagination({ + rowsPerPageOptions: rowsPerPage, + initLimit: urlPagination.rows ?? rowsPerPage[0], + initPage: urlPagination.page ?? 0 + }); + + // update pagination whenever search result total pages change + useEffect(() => { + setPagination({ totalCount: operations.totalCount ?? 0 }); + }, [setPagination, operations.totalCount]); + + // whenever url state changes, update pagination + useEffect(() => { + setPagination({ ...urlPagination }); + }, [setPagination, urlPagination]); + + // whenever table pagination internally changes (user clicks next page etc) + // update the row params + useEffect(() => { + setUrlPagination(pagination); + }, [pagination, setUrlPagination]); + + // Request new search results whenever search or pagination changes useEffect(() => { let requestParams = initRequestParams( - lazyParams(), - deserialize(state.query) + urlPagination, + deserialize(urlState.query) ); - if (deserialize(state.own)) { + if (deserialize(urlState.own)) { requestParams.user = user?.loginName; } @@ -126,39 +133,46 @@ export function JobListView() { requestParams.status = deploymentStatus; } - if (state.job_type) { - requestParams.type = deserialize(state.job_type); + if (urlState.job_type) { + requestParams.type = deserialize(urlState.job_type); } getOperations(requestParams); - }, [getOperations, lazyParams, state, user, deploymentStatus]); - - useEffect(() => { - setJobList(operations.operationsList); - }, [operations, setJobList]); + }, [ + getOperations, + urlPagination, + urlState.query, + urlState.own, + urlState.job_type, + user, + deploymentStatus + ]); const setSearch = useCallback( (query) => { - setState({ query: serialize(query) }); + setUrlState({ query: serialize(query) }); }, - [setState] + [setUrlState] ); + // Invoked by Table on change to pagination + const onPage = (params) => { + setPagination(params); + }; + const content = ( <SearchBar search={setSearch} - query={deserialize(state.query)} + query={deserialize(urlState.query)} loading={loading} placeholder="Search in IOC name, user or git reference" > <JobAsyncList jobs={jobList} setJobs={setJobList} + pagination={pagination} + onPage={onPage} loading={loading} - totalCount={operations.totalCount} - lazyParams={lazyParams()} - setLazyParams={setLazyParams} - rowsPerPage={rowsPerPage} /> </SearchBar> ); @@ -170,7 +184,7 @@ export function JobListView() { ]; return ( - <StyledPaper className={classes.paper}> + <RootPaper> <Grid container spacing={1} @@ -185,7 +199,7 @@ export function JobListView() { > <Grid item> <Tabs - value={deserialize(state.tab)} + value={deserialize(urlState.tab)} onChange={handleTabChange} > <Tab label={<Typography variant="h5">All</Typography>} /> @@ -203,8 +217,10 @@ export function JobListView() { id="combo-box-demo" options={jobTypeOptions} defaultValue={ - state.job_type - ? jobTypeOptions.find((o) => o.filter === state.job_type) || { + urlState.job_type + ? jobTypeOptions.find( + (o) => o.filter === urlState.job_type + ) || { label: "Show all" } : { label: "Show all" } @@ -222,7 +238,7 @@ export function JobListView() { /> )} onChange={(event, value, reason) => - setState({ job_type: value?.filter }) + setUrlState({ job_type: value?.filter }) } autoSelect /> @@ -233,10 +249,9 @@ export function JobListView() { renderNoAccess={() => <></>} > <FormControlLabel - className={classes.formControl} control={ <Switch - checked={deserialize(state.own)} + checked={deserialize(urlState.own)} onChange={handleChangeOwn} /> } @@ -253,6 +268,6 @@ export function JobListView() { {content} </Grid> </Grid> - </StyledPaper> + </RootPaper> ); }