diff --git a/package-lock.json b/package-lock.json index ea919b97f96aa3a2acdd3f36ab9c00ebf3f5c0f5..4a1bd3308f2a7c038cc84ecd9287171fba36c54c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "name": "ce-deploy-ui", "version": "0.1.0", "dependencies": { - "@ahooksjs/use-url-state": "^3.5.0", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@ess-ics/ce-ui-common": "7.5.0", @@ -73,20 +72,6 @@ "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", "dev": true }, - "node_modules/@ahooksjs/use-url-state": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@ahooksjs/use-url-state/-/use-url-state-3.5.1.tgz", - "integrity": "sha512-XTrOLZKOAXahDD1Evg+aSN6qNzoh/FuvRKbUtB/0RhYvz57tyXRPbED0KXK4h2C3ZyHUKBJcVCSDcd6EsTyMyQ==", - "dependencies": { - "ahooks": "^3.4.1", - "query-string": "^6.9.0", - "tslib": "^2.4.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-router": "^5.0.0 || ^6.0.0" - } - }, "node_modules/@ai-sdk/anthropic": { "version": "0.0.27", "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-0.0.27.tgz", @@ -4690,28 +4675,6 @@ "node": ">=8" } }, - "node_modules/ahooks": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/ahooks/-/ahooks-3.8.1.tgz", - "integrity": "sha512-JoP9+/RWO7MnI/uSKdvQ8WB10Y3oo1PjLv+4Sv4Vpm19Z86VUMdXh+RhWvMGxZZs06sq2p0xVtFk8Oh5ZObsoA==", - "dependencies": { - "@babel/runtime": "^7.21.0", - "dayjs": "^1.9.1", - "intersection-observer": "^0.12.0", - "js-cookie": "^3.0.5", - "lodash": "^4.17.21", - "react-fast-compare": "^3.2.2", - "resize-observer-polyfill": "^1.5.1", - "screenfull": "^5.0.0", - "tslib": "^2.4.1" - }, - "engines": { - "node": ">=8.0.0" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/ai": { "version": "3.2.16", "resolved": "https://registry.npmjs.org/ai/-/ai-3.2.16.tgz", @@ -6250,7 +6213,8 @@ "node_modules/dayjs": { "version": "1.11.13", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "dev": true }, "node_modules/debug": { "version": "4.3.7", @@ -6268,14 +6232,6 @@ } } }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -7757,14 +7713,6 @@ "node": ">=8" } }, - "node_modules/filter-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", - "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -8470,11 +8418,6 @@ "node": ">= 0.4" } }, - "node_modules/intersection-observer": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.12.2.tgz", - "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==" - }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -9010,14 +8953,6 @@ "node": ">= 0.4" } }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "engines": { - "node": ">=14" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -10874,23 +10809,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/query-string": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", - "integrity": "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw==", - "dependencies": { - "decode-uri-component": "^0.2.0", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", @@ -11111,11 +11029,6 @@ "react": ">=16.13.1" } }, - "node_modules/react-fast-compare": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" - }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -11355,11 +11268,6 @@ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" }, - "node_modules/resize-observer-polyfill": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", - "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" - }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -11586,17 +11494,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/screenfull": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz", - "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==", - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", @@ -11860,14 +11757,6 @@ "node": ">=0.10.0" } }, - "node_modules/split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "engines": { - "node": ">=6" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -11974,14 +11863,6 @@ "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", "dev": true }, - "node_modules/strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -12600,7 +12481,8 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true }, "node_modules/tty-browserify": { "version": "0.0.1", diff --git a/package.json b/package.json index dce84fd3c6c5fd2162baad4d9128367ec80f246d..b55e51837c1d9f3a7e745a01e095a500ed405909 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "0.1.0", "private": true, "dependencies": { - "@ahooksjs/use-url-state": "^3.5.0", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@ess-ics/ce-ui-common": "7.5.0", diff --git a/src/components/IOC/IOCLiveStatus/IOCLiveStatus.jsx b/src/components/IOC/IOCLiveStatus/IOCLiveStatus.jsx index 6bd7994eb79a521bbb5d6e5462d49d9ce7d30fec..b8a0c051c8ff69b9a613e58f9ab66bf457116fbc 100644 --- a/src/components/IOC/IOCLiveStatus/IOCLiveStatus.jsx +++ b/src/components/IOC/IOCLiveStatus/IOCLiveStatus.jsx @@ -1,4 +1,4 @@ -import { useCallback } from "react"; +import { useCallback, useState } from "react"; import { Typography } from "@mui/material"; import { SimpleAccordion, @@ -10,18 +10,14 @@ import { LokiPanel } from "../../common/Loki/LokiPanel"; import { RecordSearch } from "../../records/RecordSearch"; import { GitRefLink } from "../../common/Git/GitRefLink"; import AccessControl from "../../auth/AccessControl"; -import useUrlState from "@ahooksjs/use-url-state"; -import { serialize, deserialize } from "../../common/URLState/URLState"; +import { useSearchParams } from "react-router-dom"; export function IOCLiveStatus({ ioc }) { - const [state, setState] = useUrlState( - { - procserv_log_open: "true", - records_open: "false", - log_stream_open: "false" - }, - { navigateMode: "replace" } - ); + const [searchParams] = useSearchParams(); + const [accordionState, setAccordionState] = useState({ + logStreamOpen: false, + recordsOpen: !!searchParams.get("query") + }); const hostName = ioc.activeDeployment?.host?.hostName; const externalIdValid = ioc.activeDeployment?.host?.externalIdValid; @@ -81,9 +77,9 @@ export function IOCLiveStatus({ ioc }) { IOC log stream </Typography> } - expanded={deserialize(state.log_stream_open)} + expanded={accordionState.logStreamOpen} onChange={(_, expanded) => - setState({ log_stream_open: serialize(expanded) }) + setAccordionState({ ...accordionState, logStreamOpen: expanded }) } > {hostName && ( @@ -103,9 +99,9 @@ export function IOCLiveStatus({ ioc }) { Records </Typography> } - expanded={deserialize(state.records_open)} + expanded={accordionState.recordsOpen} onChange={(_, expanded) => - setState({ records_open: serialize(expanded) }) + setAccordionState({ ...accordionState, recordsOpen: expanded }) } > <RecordSearch diff --git a/src/components/IOC/IOCTable/IOCTable.jsx b/src/components/IOC/IOCTable/IOCTable.jsx index d2ab4837843a2d8458191bd1857dce24227ec062..5084d98b81da3c6a8fbb52bfbec92c9f2bcefa4f 100644 --- a/src/components/IOC/IOCTable/IOCTable.jsx +++ b/src/components/IOC/IOCTable/IOCTable.jsx @@ -135,7 +135,7 @@ function createTableRowForExploreIocs(ioc) { } export function IOCTable({ - iocs = [], + iocs, rowType = "explore", loading, pagination, diff --git a/src/components/common/URLState/URLState.js b/src/components/common/URLState/URLState.js deleted file mode 100644 index e291eedac26f907d5605095075c195761311cc75..0000000000000000000000000000000000000000 --- a/src/components/common/URLState/URLState.js +++ /dev/null @@ -1,25 +0,0 @@ -export function serialize(value) { - if (typeof value === "boolean") { - return value ? "true" : "false"; - } - if (typeof value === "number") { - return value.toString(); - } - if (typeof value === "object") { - return JSON.stringify(value); - } - return value; -} - -export function deserialize(value) { - if (value === "true") { - return true; - } - if (value === "false") { - return false; - } - if (Number(value).toString() === value && !isNaN(Number(value))) { - return Number(value); - } - return value; -} diff --git a/src/components/common/URLState/index.js b/src/components/common/URLState/index.js deleted file mode 100644 index 778ede8aba4f359f6cdf41a85cff241958d0ff9d..0000000000000000000000000000000000000000 --- a/src/components/common/URLState/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import { serialize, deserialize } from "./URLState"; - -export { serialize, deserialize }; diff --git a/src/components/common/User/UserOperationList.jsx b/src/components/common/User/UserOperationList.jsx index 52345558afae0eb9a9167cd1bb27e5d862839520..ad5eaf38c0f118dae97d93a305ae418fa4c16a16 100644 --- a/src/components/common/User/UserOperationList.jsx +++ b/src/components/common/User/UserOperationList.jsx @@ -4,6 +4,7 @@ import { initRequestParams } from "../Helper"; import { JobTable } from "../../Job"; import { apiContext } from "../../../api/DeployApi"; import { useAPIMethod, usePagination, usePolling } from "@ess-ics/ce-ui-common"; +import { ROWS_PER_PAGE } from "../../../constants"; export function UserOperationList({ userName }) { const client = useContext(apiContext); @@ -19,10 +20,9 @@ export function UserOperationList({ userName }) { call: false }); - const rowsPerPage = [20, 50]; const { pagination, setPagination } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: rowsPerPage[0], + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], initPage: 0 }); diff --git a/src/components/records/RecordSearch.jsx b/src/components/records/RecordSearch.jsx index ff07e9aad34178fc08e9f7ed0966107a8fe55e85..0a38e118115a410304aae2e2bb9b417082574f4a 100644 --- a/src/components/records/RecordSearch.jsx +++ b/src/components/records/RecordSearch.jsx @@ -1,11 +1,11 @@ -import { useEffect, useCallback, useState, useContext, useMemo } from "react"; +import { useEffect, useCallback, useState, useContext } from "react"; import { initRequestParams } from "../common/Helper"; import { RecordTable } from "./RecordTable"; -import useUrlState from "@ahooksjs/use-url-state"; -import { serialize, deserialize } from "../common/URLState/URLState"; +import { useSearchParams } from "react-router-dom"; import { Grid, Tabs, Tab } from "@mui/material"; import { useAPIMethod, usePagination, SearchBar } from "@ess-ics/ce-ui-common"; import { apiContext } from "../../api/DeployApi"; +import { ROWS_PER_PAGE } from "../../constants"; export function RecordSearch({ iocName, rowType }) { const client = useContext(apiContext); @@ -21,37 +21,11 @@ export function RecordSearch({ iocName, rowType }) { call: false }); - const [urlState, setUrlState] = useUrlState( - { - record_tab: "0", - rows: "20", - page: "0", - query: "" - }, - { navigateMode: "replace" } - ); + const [searchParams, setSearchParams] = useSearchParams({ query: "" }); const [recordFilter, setRecordFilter] = useState(); + const [tabIndex, setTabIndex] = useState(0); - const handleTabChange = useCallback( - (event, tab) => { - setUrlState((s) => - serialize(s.record_tab) === serialize(tab) - ? { record_tab: serialize(tab) } - : { record_tab: serialize(tab), page: "0" } - ); - - changeTab(tab); - }, - [setUrlState] - ); - - useEffect(() => { - if (urlState.record_tab) { - changeTab(deserialize(urlState.record_tab)); - } - }, [urlState]); - - const changeTab = (tab) => { + const handleTabChange = (tab) => { if (tab === 0) { setRecordFilter(null); } else if (tab === 1) { @@ -59,28 +33,13 @@ export function RecordSearch({ iocName, rowType }) { } else if (tab === 2) { setRecordFilter("INACTIVE"); } + setTabIndex(tab); }; - const urlPagination = useMemo(() => { - return { - rows: deserialize(urlState.rows), - page: deserialize(urlState.page) - }; - }, [urlState.rows, urlState.page]); - - const setUrlPagination = useCallback( - ({ rows, page }) => { - setUrlState({ rows: serialize(rows), page: serialize(page) }); - }, - [setUrlState] - ); - - const rowsPerPage = [20, 50]; - const { pagination, setPagination, setTotalCount } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: urlPagination.rows ?? rowsPerPage[0], - initPage: urlPagination.page ?? 0 + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); // update pagination whenever search result total pages change @@ -88,36 +47,25 @@ export function RecordSearch({ iocName, rowType }) { setTotalCount(records?.totalCount ?? 0); }, [records?.totalCount, setTotalCount]); - // 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(pagination); requestParams.pv_status = recordFilter; - requestParams.text = deserialize(urlState.query); + requestParams.text = searchParams.get("query"); requestParams.ioc_name = iocName; getRecords(requestParams); return () => { abort(); }; - }, [getRecords, recordFilter, urlState.query, pagination, abort, iocName]); + }, [getRecords, recordFilter, searchParams, pagination, abort, iocName]); // Callback for searchbar, called whenever user updates search const setSearch = useCallback( (query) => { - setUrlState({ query: serialize(query) }); + setSearchParams({ query }); }, - [setUrlState] + [setSearchParams] ); // Invoked by Table on change to pagination @@ -134,8 +82,8 @@ export function RecordSearch({ iocName, rowType }) { > <Grid item> <Tabs - value={deserialize(urlState.record_tab)} - onChange={handleTabChange} + value={tabIndex} + onChange={(_, tab) => handleTabChange(tab)} > <Tab label="All" /> <Tab label="Only active" /> @@ -145,7 +93,7 @@ export function RecordSearch({ iocName, rowType }) { <Grid item> <SearchBar search={setSearch} - query={deserialize(urlState.query)} + query={searchParams.get("query")} loading={loading || !dataReady} > <RecordTable diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8de6913d72fe11b847a3b8302e83aed3017b2a46 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1 @@ +export const ROWS_PER_PAGE = [20, 50]; diff --git a/src/views/IOC/IOCDetailsContainer.jsx b/src/views/IOC/IOCDetailsContainer.jsx index f89a4ac4514b5e89e14a7f9d429380df205a5df2..b8e38f54673d1278b2aebf980e89419252fc6f76 100644 --- a/src/views/IOC/IOCDetailsContainer.jsx +++ b/src/views/IOC/IOCDetailsContainer.jsx @@ -3,13 +3,10 @@ import { IOCDetailsView } from "./IOCDetailsView"; import { LinearProgress } from "@mui/material"; import NotFoundView from "../../components/navigation/NotFoundView/NotFoundView"; import { onFetchEntityError } from "../../components/common/Helper"; -import { userContext, useAPIMethod } from "@ess-ics/ce-ui-common"; -import useUrlState from "@ahooksjs/use-url-state"; +import { useAPIMethod } from "@ess-ics/ce-ui-common"; import { apiContext } from "../../api/DeployApi"; export function IOCDetailsContainer({ id }) { - const { user } = useContext(userContext); - const [urlState] = useUrlState(); const [error, setError] = useState(null); const client = useContext(apiContext); @@ -38,16 +35,6 @@ export function IOCDetailsContainer({ id }) { } }, [fetchError]); - useEffect(() => { - // user logs in => clear error message, and try to re-request userInfo - if (user) { - setError(null); - } else if (!user && urlState?.tab) { - // user is not logged in => show a message - setError({ message: "Unauthorized", status: "401" }); - } - }, [urlState, user]); - if (error) { return ( <NotFoundView diff --git a/src/views/IOC/IOCDetailsView.jsx b/src/views/IOC/IOCDetailsView.jsx index 699b3268b85f71c5cf89f56560e698329946db18..8de62919c324f45c3506088cc63e570f720a77b9 100644 --- a/src/views/IOC/IOCDetailsView.jsx +++ b/src/views/IOC/IOCDetailsView.jsx @@ -17,12 +17,8 @@ import { usePagination, usePolling } from "@ess-ics/ce-ui-common"; -import useUrlState from "@ahooksjs/use-url-state"; -import { - serialize, - deserialize -} from "../../components/common/URLState/URLState"; import { apiContext } from "../../api/DeployApi"; +import { ROWS_PER_PAGE } from "../../constants"; const IOC_POLL_INTERVAL = 10000; export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { @@ -33,15 +29,6 @@ export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { } }, [ioc, setTitle]); - const [urlState, setUrlState] = useUrlState( - { - tab: "Status", - jobs_rows: "20", - jobs_page: "0" - }, - { navigateMode: "replace" } - ); - const [buttonDisabled, setButtonDisabled] = useState(false); const navigate = useNavigate(); @@ -78,48 +65,19 @@ export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { call: false }); - const jobUrlPagination = useMemo(() => { - return { - rows: deserialize(urlState.jobs_rows), - page: deserialize(urlState.jobs_page) - }; - }, [urlState.jobs_rows, urlState.jobs_page]); - - const setJobUrlPagination = useCallback( - (params) => { - setUrlState({ - jobs_rows: serialize(params.rows), - jobs_page: serialize(params.page) - }); - }, - [setUrlState] - ); - - const rowsPerPage = [20, 50]; - const { pagination: jobPagination, setPagination: setJobPagination } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: jobUrlPagination.rows ?? rowsPerPage[0], - initPage: jobUrlPagination.page ?? 0 + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); + const [tabIndex, setTabIndex] = useState(0); // update pagination whenever search result total pages change useEffect(() => { setJobPagination({ totalCount: jobs?.totalCount ?? 0 }); }, [setJobPagination, jobs?.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 = useCallback( (params) => { @@ -141,10 +99,6 @@ export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { setButtonDisabled(Boolean(ioc?.operationInProgress)); }, [ioc?.operationInProgress]); - const onTabChange = (index, label) => { - setUrlState({ tab: serialize(label) }); - }; - const callGetJobs = useCallback(() => { let requestParams = initRequestParams(jobPagination); requestParams.ioc_id = ioc.id; @@ -166,14 +120,6 @@ export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { navigate(-1); }; - const resetTab = useCallback(() => { - if (ioc?.activeDeployment) { - setUrlState({ tab: "Status" }); - } else { - setUrlState({ tab: "Management" }); - } - }, [ioc?.activeDeployment, setUrlState]); - const setButtonDisabledAndUpdate = useCallback( (isDisabled) => { setButtonDisabled(isDisabled); @@ -225,14 +171,13 @@ export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { <IOCAdmin ioc={ioc} getIOC={getIOC} - resetTab={resetTab} + resetTab={() => setTabIndex(0)} buttonDisabled={buttonDisabled} setButtonDisabled={setButtonDisabled} /> ) }); } - const initialIndex = tabs.map((it) => it.label).indexOf(urlState?.tab); return ( <Grid @@ -246,8 +191,8 @@ export function IOCDetailsView({ ioc, getIOC, abortGetIOC, loading }) { > <TabPanel tabs={tabs} - initialIndex={initialIndex} - onTabChange={onTabChange} + initialIndex={tabIndex} + onTabChange={(_, tab) => setTabIndex(tab)} TabsProps={{ centered: true, sx: { flex: 1 } }} renderTabs={(tabs) => ( <Stack diff --git a/src/views/IOC/IOCListView.tsx b/src/views/IOC/IOCListView.tsx index 8c750824e54f823f39c902daf62c4414fc942869..3a5e700c398bd9c16e8b8dd72349cad41c333173 100644 --- a/src/views/IOC/IOCListView.tsx +++ b/src/views/IOC/IOCListView.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, useMemo } from "react"; +import { useState, useEffect, useCallback } from "react"; import { useLazyListIocsQuery, ListIocsApiArg } from "../../store/deployApi"; import { useGlobalAppBarContext, @@ -10,46 +10,22 @@ import { applicationTitle, initRequestParams } from "../../components/common/Helper"; -import useUrlState from "@ahooksjs/use-url-state"; -import { - serialize, - deserialize -} from "../../components/common/URLState/URLState"; +import { useSearchParams } from "react-router-dom"; import { GlobalAppBarContext, OnPageParams } from "../../types/common"; import { ApiAlertError } from "../../components/common/Alerts/ApiAlertError"; import { Container, Grid, Tabs, Tab } from "@mui/material"; import IOCTable from "../../components/IOC/IOCTable"; - -const ROWS_PER_PAGE = [20, 50]; +import { ROWS_PER_PAGE } from "../../constants"; export const IOCListView = () => { const [deploymentStatus, setDeploymentStatus] = useState<ListIocsApiArg["deploymentStatus"]>("ALL"); + const [tabIndex, setTabIndex] = useState(0); const [listIocs, { data: iocs, isFetching, error }] = useLazyListIocsQuery(); - const [urlState, setUrlState] = useUrlState( - { - tab: "0", - rows: "20", - page: "0", - query: "" - }, - { navigateMode: "replace" } - ); + const [searchParams, setSearchParams] = useSearchParams({ query: "" }); const { setTitle }: GlobalAppBarContext = useGlobalAppBarContext(); - const handleTabChange = useCallback( - (tab: number) => { - setUrlState((s) => - serialize(s.tab) === serialize(tab) - ? { tab: serialize(tab) } - : { tab: serialize(tab), page: "0" } - ); - changeTab(tab); - }, - [setUrlState] - ); - - const changeTab = (tab: number) => { + const handleTabChange = (tab: number) => { if (tab === 0) { setDeploymentStatus("ALL"); } else if (tab === 1) { @@ -57,29 +33,13 @@ export const IOCListView = () => { } else if (tab === 2) { setDeploymentStatus("NOT_DEPLOYED"); } + setTabIndex(tab); }; - const setUrlPagination = useCallback( - ({ rows, page }: OnPageParams) => { - setUrlState({ - rows: serialize(rows), - page: serialize(page) - }); - }, - [setUrlState] - ); - - const urlPagination = useMemo(() => { - return { - rows: deserialize(urlState.rows), - page: deserialize(urlState.page) - }; - }, [urlState.rows, urlState.page]); - const { pagination, setPagination } = usePagination({ rowsPerPageOptions: ROWS_PER_PAGE, - initLimit: urlPagination.rows ?? ROWS_PER_PAGE[0], - initPage: urlPagination.page ?? 0 + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); // Invoked by Table on change to pagination @@ -90,44 +50,27 @@ export const IOCListView = () => { // Callback for searchbar, called whenever user updates search const setSearch = useCallback( (query: string) => { - setUrlState({ query: serialize(query) }); + setSearchParams({ query }); }, - [setUrlState] + [setSearchParams] ); useEffect(() => setTitle(applicationTitle("IOCs")), [setTitle]); - useEffect(() => { - if (urlState.tab) { - changeTab(deserialize(urlState.tab)); - } - }, [urlState.tab]); - // update pagination whenever search result total pages change useEffect(() => { setPagination({ totalCount: iocs?.totalCount ?? 0 }); }, [setPagination, iocs?.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]); - useEffect(() => { const requestParams = Object.assign( {}, - initRequestParams(pagination, deserialize(urlState.query)), + initRequestParams(pagination, searchParams.get("query")), { deploymentStatus: deploymentStatus } ); listIocs(requestParams); - }, [listIocs, urlPagination, deploymentStatus, urlState.query, pagination]); + }, [listIocs, deploymentStatus, searchParams, pagination]); return ( <RootPaper> @@ -145,7 +88,7 @@ export const IOCListView = () => { > <Grid item> <Tabs - value={deserialize(urlState.tab)} + value={tabIndex} onChange={(_, tab) => handleTabChange(tab)} > <Tab label="All" /> @@ -161,14 +104,14 @@ export const IOCListView = () => { > <SearchBar search={setSearch} - query={deserialize(urlState.query)} + query={searchParams.get("query")} loading={isFetching || !iocs} > {error ? ( <ApiAlertError error={error} /> ) : ( <IOCTable - iocs={iocs?.iocList} + iocs={iocs?.iocList || []} loading={isFetching || !iocs} rowType="explore" pagination={pagination} diff --git a/src/views/host/HostListView.jsx b/src/views/host/HostListView.jsx index e2beda242b48fd1ce02f2b48574faf0dba06ddf6..1ec9c3a3d8c80afb20c9dca12851b242b5bb7a3f 100644 --- a/src/views/host/HostListView.jsx +++ b/src/views/host/HostListView.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, useContext, useMemo } from "react"; +import { useState, useEffect, useCallback, useContext } from "react"; import { Container, Grid, Tabs, Tab } from "@mui/material"; import { HostTable } from "../../components/host/HostTable"; import { @@ -12,12 +12,9 @@ import { applicationTitle, initRequestParams } from "../../components/common/Helper"; -import useUrlState from "@ahooksjs/use-url-state"; -import { - serialize, - deserialize -} from "../../components/common/URLState/URLState"; +import { useSearchParams } from "react-router-dom"; import { apiContext } from "../../api/DeployApi"; +import { ROWS_PER_PAGE } from "../../constants"; export function HostListView() { const { setTitle } = useContext(GlobalAppBarContext); @@ -35,49 +32,11 @@ export function HostListView() { call: false }); - const [urlState, setUrlState] = useUrlState( - { - tab: "0", - rows: "20", - page: "0", - query: "" - }, - { navigateMode: "replace" } - ); + const [searchParams, setSearchParams] = useSearchParams({ query: "" }); + const [tabIndex, setTabIndex] = useState(0); const [hostFilter, setHostFilter] = useState("ALL"); - const urlPagination = useMemo( - () => ({ - rows: deserialize(urlState.rows), - page: deserialize(urlState.page) - }), - [urlState.rows, urlState.page] - ); - - const setUrlPagination = useCallback( - ({ rows, page }) => { - setUrlState({ - rows: serialize(rows), - page: serialize(page) - }); - }, - [setUrlState] - ); - - const handleTabChange = useCallback( - (event, tab) => { - setUrlState((s) => - serialize(s.tab) === serialize(tab) - ? { tab: serialize(tab) } - : { tab: serialize(tab), page: "0" } - ); - - changeTab(tab); - }, - [setUrlState] - ); - - const changeTab = (tab) => { + const handleTabChange = (tab) => { if (tab === 0) { setHostFilter("ALL"); } else if (tab === 1) { @@ -85,20 +44,13 @@ export function HostListView() { } else if (tab === 2) { setHostFilter("NO_IOCS"); } + setTabIndex(tab); }; - useEffect(() => { - if (urlState.tab) { - changeTab(deserialize(urlState.tab)); - } - }, [urlState]); - - const rowsPerPage = [20, 50]; - const { pagination, setPagination } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: urlPagination.rows ?? rowsPerPage[0], - initPage: urlPagination.page ?? 0 + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); // update pagination whenever search result total pages change @@ -106,35 +58,24 @@ export function HostListView() { setPagination({ totalCount: hosts?.totalCount ?? 0 }); }, [setPagination, hosts?.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(pagination); requestParams.filter = hostFilter; - requestParams.text = deserialize(urlState.query); + requestParams.text = searchParams.get("query"); getHosts(requestParams); return () => { abort(); }; - }, [getHosts, hostFilter, urlState.query, pagination, abort]); + }, [getHosts, hostFilter, searchParams, pagination, abort]); // Callback for searchbar, called whenever user updates search const setSearch = useCallback( (query) => { - setUrlState({ query: serialize(query) }); + setSearchParams({ query }); }, - [setUrlState] + [setSearchParams] ); // Invoked by Table on change to pagination @@ -146,7 +87,7 @@ export function HostListView() { const content = ( <SearchBar search={setSearch} - query={deserialize(urlState.query)} + query={searchParams.get("query")} loading={loading} > <HostTable @@ -174,8 +115,8 @@ export function HostListView() { > <Grid item> <Tabs - value={deserialize(urlState.tab)} - onChange={handleTabChange} + value={tabIndex} + onChange={(_, tab) => handleTabChange(tab)} > <Tab label="All" /> <Tab label="Only hosts with IOCs" /> diff --git a/src/views/host/details/HostDetailsView.jsx b/src/views/host/details/HostDetailsView.jsx index 40f707ca2b89d4ad56062dcbaf5b2dfd31fe8e4f..e10f69904f2f56544078077f7262aa8c18c5d1e9 100644 --- a/src/views/host/details/HostDetailsView.jsx +++ b/src/views/host/details/HostDetailsView.jsx @@ -1,5 +1,4 @@ -import { useEffect, useContext } from "react"; -import useUrlState from "@ahooksjs/use-url-state"; +import { useEffect, useContext, useState } from "react"; import { Box, IconButton, Typography, Stack } from "@mui/material"; import ArrowBackIcon from "@mui/icons-material/ArrowBack"; import { @@ -13,10 +12,6 @@ import { LokiPanel } from "../../../components/common/Loki/LokiPanel"; import { useNavigate } from "react-router-dom"; import { applicationTitle } from "../../../components/common/Helper"; import AccessControl from "../../../components/auth/AccessControl"; -import { - serialize, - deserialize -} from "../../../components/common/URLState/URLState"; import { HostDetailsTable } from "./HostDetailsTable"; import { HostStatus } from "../../../components/host/HostStatus"; import { HostJobsSection } from "./HostJobsSection"; @@ -25,6 +20,10 @@ import env from "../../../config/env"; export function HostDetailsView({ hostId, host, alert }) { const { setTitle } = useContext(GlobalAppBarContext); + const [accordionState, setAccordionState] = useState({ + detailsOpen: false, + logStreamOpen: false + }); useEffect(() => { if (host && host.name) { @@ -32,18 +31,6 @@ export function HostDetailsView({ hostId, host, alert }) { } }, [host, setTitle]); - const [urlState, setUrlState] = useUrlState( - { - iocs_rows: 20, - iocs_page: 0, - details_open: false, - log_stream_open: false, - job_log_open: false, - job_log_rows: 20, - job_log_page: 0 - }, - { navigateMode: "replace" } - ); const navigate = useNavigate(); return ( @@ -95,20 +82,9 @@ export function HostDetailsView({ hostId, host, alert }) { </Box> </Stack> <Stack gap={2}> - <HostIocSection - hostId={hostId} - rows={deserialize(urlState.iocs_rows)} - page={deserialize(urlState.iocs_page)} - onUrlStateChange={(params) => setUrlState(params)} - /> + <HostIocSection hostId={hostId} /> </Stack> - <HostJobsSection - hostId={hostId} - rows={deserialize(urlState.job_log_rows)} - page={deserialize(urlState.job_log_page)} - expanded={deserialize(urlState.job_log_open)} - onUrlStateChange={(params) => setUrlState(params)} - /> + <HostJobsSection hostId={hostId} /> <AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]} @@ -123,9 +99,9 @@ export function HostDetailsView({ hostId, host, alert }) { Host details </Typography> } - expanded={deserialize(urlState.details_open)} + expanded={accordionState.detailsOpen} onChange={(_, expanded) => - setUrlState({ details_open: serialize(expanded) }) + setAccordionState({ detailsOpen: expanded }) } > <HostDetailsTable host={host} /> @@ -140,9 +116,9 @@ export function HostDetailsView({ hostId, host, alert }) { Host log stream </Typography> } - expanded={deserialize(urlState.log_stream_open)} + expanded={accordionState.logStreamOpen} onChange={(_, expanded) => - setUrlState({ log_stream_open: serialize(expanded) }) + setAccordionState({ logStreamOpen: expanded }) } > <LokiPanel diff --git a/src/views/host/details/HostIocSection.jsx b/src/views/host/details/HostIocSection.jsx index fa81ed1dec3f1b01a3d2e3d28bc6956e1c5da311..c3ed876004ff863608d57e8a885b083360d4c672 100644 --- a/src/views/host/details/HostIocSection.jsx +++ b/src/views/host/details/HostIocSection.jsx @@ -1,24 +1,22 @@ import { useEffect, useContext, useCallback } from "react"; import IOCTable from "../../../components/IOC/IOCTable"; -import { string, number, func } from "prop-types"; +import { string } from "prop-types"; import { apiContext } from "../../../api/DeployApi"; import { Typography } from "@mui/material"; import { useAPIMethod, usePagination } from "@ess-ics/ce-ui-common"; import { initRequestParams } from "../../../components/common/Helper"; -import { serialize } from "../../../components/common/URLState/URLState"; +import { ROWS_PER_PAGE } from "../../../constants"; const propTypes = { - hostId: string, - row: number, - page: number, - onUrlStateChange: func + hostId: string }; -export const HostIocSection = ({ hostId, rows, page, onUrlStateChange }) => { +export const HostIocSection = ({ hostId }) => { const client = useContext(apiContext); + const { pagination, setPagination, setTotalCount } = usePagination({ - initLimit: rows, - initPage: page + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); const { @@ -36,19 +34,15 @@ export const HostIocSection = ({ hostId, rows, page, onUrlStateChange }) => { (params) => { setPagination(params); abortGetIocs(); - onUrlStateChange({ - iocs_rows: serialize(params.limit), - iocs_page: serialize(params.page) - }); }, - [setPagination, abortGetIocs, onUrlStateChange] + [setPagination, abortGetIocs] ); const getIocs = useCallback(() => { - let requestParams = initRequestParams({ page, rows }, null); + let requestParams = initRequestParams(pagination, null); requestParams.host_id = hostId; callgetIocs(requestParams); - }, [callgetIocs, hostId, page, rows]); + }, [callgetIocs, hostId, pagination]); // update pagination whenever search result total pages change useEffect(() => { @@ -61,7 +55,7 @@ export const HostIocSection = ({ hostId, rows, page, onUrlStateChange }) => { return () => { abortGetIocs(); }; - }, [rows, page, abortGetIocs, getIocs]); + }, [abortGetIocs, getIocs]); return ( <> diff --git a/src/views/host/details/HostJobsSection.jsx b/src/views/host/details/HostJobsSection.jsx index 15edecf3819dc7a068ce2fd9f8696d10ac3be795..8430a3eac11dc210b1dddf20b86eb29bdcd561dd 100644 --- a/src/views/host/details/HostJobsSection.jsx +++ b/src/views/host/details/HostJobsSection.jsx @@ -1,6 +1,5 @@ -import { useContext, useEffect, useMemo, useCallback } from "react"; -import { string, number, boolean, func } from "prop-types"; -import { serialize } from "../../../components/common/URLState/URLState"; +import { useContext, useEffect, useMemo, useCallback, useState } from "react"; +import { string } from "prop-types"; import { getErrorMessage } from "../../../components/common/Helper"; import { apiContext } from "../../../api/DeployApi"; import { @@ -10,31 +9,21 @@ import { } from "@ess-ics/ce-ui-common"; import { JobTable } from "../../../components/Job"; import { Alert, Typography } from "@mui/material"; +import { ROWS_PER_PAGE } from "../../../constants"; const propTypes = { - hostId: string.isRequired, - rows: number, - page: number, - expanded: boolean, - onUrlStateChange: func + hostId: string.isRequired }; -const rowsPerPage = [20, 50]; - -export const HostJobsSection = ({ - hostId, - rows, - page, - expanded, - onUrlStateChange -}) => { +export const HostJobsSection = ({ hostId }) => { const client = useContext(apiContext); const { pagination, setPagination } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: rows, - initPage: page + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); + const [expanded, setExpanded] = useState(false); const { value: hostLog, @@ -56,12 +45,8 @@ export const HostJobsSection = ({ (params) => { setPagination(params); abortGetHostLog(); - onUrlStateChange({ - job_log_rows: serialize(params.limit), - job_log_page: serialize(params.page) - }); }, - [setPagination, abortGetHostLog, onUrlStateChange] + [setPagination, abortGetHostLog] ); useEffect(() => { @@ -82,6 +67,7 @@ export const HostJobsSection = ({ return ( <SimpleAccordion + expanded={expanded} summary={ <Typography variant="h3" @@ -90,9 +76,7 @@ export const HostJobsSection = ({ Job log </Typography> } - onChange={(_, isExpanded) => - onUrlStateChange({ job_log_open: serialize(isExpanded) }) - } + onChange={(_, expanded) => setExpanded(expanded)} > {error ? <Alert severity="error">{getErrorMessage(error)}</Alert> : null} {hostLog ? ( diff --git a/src/views/jobs/JobListView.jsx b/src/views/jobs/JobListView.jsx index 9449ba16236be7433047ed0e8f03391e4461c5f0..3f5e5fef22ceaf6bd8f7a72f1722eef4a955b7f0 100644 --- a/src/views/jobs/JobListView.jsx +++ b/src/views/jobs/JobListView.jsx @@ -1,4 +1,4 @@ -import { useContext, useCallback, useMemo, useEffect } from "react"; +import { useContext, useCallback, useEffect } from "react"; import { Box } from "@mui/material"; import { RootPaper, @@ -7,13 +7,9 @@ import { usePolling } from "@ess-ics/ce-ui-common"; import { initRequestParams } from "../../components/common/Helper"; -import useUrlState from "@ahooksjs/use-url-state"; -import { - serialize, - deserialize -} from "../../components/common/URLState/URLState"; import { JobTable } from "../../components/Job/JobTable"; import { apiContext } from "../../api/DeployApi"; +import { ROWS_PER_PAGE } from "../../constants"; export function JobListView() { const client = useContext(apiContext); @@ -29,38 +25,10 @@ export function JobListView() { call: false }); - const [urlState, setUrlState] = useUrlState( - { - rows: "20", - page: "0", - query: "" - }, - { navigateMode: "replace" } - ); - - const urlPagination = useMemo(() => { - return { - rows: deserialize(urlState.rows), - page: deserialize(urlState.page) - }; - }, [urlState.rows, urlState.page]); - - const setUrlPagination = useCallback( - ({ rows, page }) => { - setUrlState({ - rows: serialize(rows), - page: serialize(page) - }); - }, - [setUrlState] - ); - - const rowsPerPage = [20, 50]; - const { pagination, setPagination } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: urlPagination.rows ?? rowsPerPage[0], - initPage: urlPagination.page ?? 0 + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); // update pagination whenever search result total pages change @@ -68,25 +36,10 @@ export function JobListView() { setPagination({ totalCount: jobs?.totalCount ?? 0 }); }, [setPagination, jobs?.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]); - const callGetOperations = useCallback(() => { - let requestParams = initRequestParams( - urlPagination, - deserialize(urlState.query) - ); - + let requestParams = initRequestParams(pagination); getJobs(requestParams); - }, [getJobs, urlPagination, urlState.query]); + }, [getJobs, pagination]); // Request new search results whenever search or pagination changes useEffect(() => { @@ -95,7 +48,7 @@ export function JobListView() { return () => { abort(); }; - }, [callGetOperations, abort]); + }, [abort, callGetOperations, pagination]); usePolling(callGetOperations, loading, 30000, abort, false); diff --git a/src/views/records/RecordListView.jsx b/src/views/records/RecordListView.jsx index b4c6bc2dccdffa572313fae15c6972152edb6fb6..05ed3a623fd66a95d66a8adca0600e8ee1435cf1 100644 --- a/src/views/records/RecordListView.jsx +++ b/src/views/records/RecordListView.jsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useCallback, useContext, useEffect } from "react"; +import { useState, useCallback, useContext, useEffect } from "react"; import { Container, Grid, Tabs, Tab } from "@mui/material"; import { GlobalAppBarContext, @@ -11,13 +11,10 @@ import { applicationTitle, initRequestParams } from "../../components/common/Helper"; -import useUrlState from "@ahooksjs/use-url-state"; -import { - serialize, - deserialize -} from "../../components/common/URLState/URLState"; +import { useSearchParams } from "react-router-dom"; import { RecordTable } from "../../components/records/RecordTable"; import { apiContext } from "../../api/DeployApi"; +import { ROWS_PER_PAGE } from "../../constants"; export function RecordListView() { const { setTitle } = useContext(GlobalAppBarContext); @@ -36,32 +33,12 @@ export function RecordListView() { call: false }); - const [urlState, setUrlState] = useUrlState( - { - tab: "0", - rows: "20", - page: "0", - query: "" - }, - { navigateMode: "replace" } - ); + const [searchParams, setSearchParams] = useSearchParams({ query: "" }); + const [tabIndex, setTabIndex] = useState(0); const [recordFilter, setRecordFilter] = useState(null); // used to request record list again when tab is switched, but request it only once! (totalRecord is a random number that is generated by ChannelFinder) - const handleTabChange = useCallback( - (event, tab) => { - setUrlState((s) => - serialize(s.tab) === serialize(tab) - ? { tab: serialize(tab) } - : { tab: serialize(tab), page: "0" } - ); - - changeTab(tab); - }, - [setUrlState] - ); - - const changeTab = (tab) => { + const handleTabChange = (tab) => { if (tab === 0) { setRecordFilter(null); } else if (tab === 1) { @@ -69,37 +46,13 @@ export function RecordListView() { } else if (tab === 2) { setRecordFilter("INACTIVE"); } + setTabIndex(tab); }; - useEffect(() => { - if (urlState.tab) { - changeTab(deserialize(urlState.tab)); - } - }, [urlState]); - - const urlPagination = useMemo(() => { - return { - rows: deserialize(urlState.rows), - page: deserialize(urlState.page) - }; - }, [urlState.rows, urlState.page]); - - const setUrlPagination = useCallback( - ({ rows, page }) => { - setUrlState({ - rows: serialize(rows), - page: serialize(page) - }); - }, - [setUrlState] - ); - - const rowsPerPage = [20, 50]; - const { pagination, setPagination, setTotalCount } = usePagination({ - rowsPerPageOptions: rowsPerPage, - initLimit: urlPagination.rows ?? rowsPerPage[0], - initPage: urlPagination.page ?? 0 + rowsPerPageOptions: ROWS_PER_PAGE, + initLimit: ROWS_PER_PAGE[0], + initPage: 0 }); // update pagination whenever search result total pages change @@ -107,35 +60,24 @@ export function RecordListView() { setTotalCount(records?.totalCount ?? 0); }, [records?.totalCount, setTotalCount]); - // 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(pagination); requestParams.pv_status = recordFilter; - requestParams.text = deserialize(urlState.query); + requestParams.text = searchParams.get("query"); getRecords(requestParams); return () => { abort(); }; - }, [getRecords, recordFilter, urlState.query, pagination, abort]); + }, [getRecords, recordFilter, pagination, abort, searchParams]); // Callback for searchbar, called whenever user updates search const setSearch = useCallback( (query) => { - setUrlState({ query: serialize(query) }); + setSearchParams({ query }); }, - [setUrlState] + [setSearchParams] ); // Invoked by Table on change to pagination @@ -147,7 +89,7 @@ export function RecordListView() { let content = ( <SearchBar search={setSearch} - query={deserialize(urlState.query)} + query={searchParams.get("query")} loading={loading || !dataReady} > <RecordTable @@ -175,8 +117,8 @@ export function RecordListView() { > <Grid item> <Tabs - value={deserialize(urlState.tab)} - onChange={handleTabChange} + value={tabIndex} + onChange={(_, tab) => handleTabChange(tab)} > <Tab label="All" /> <Tab label="Only active" />