diff --git a/jsx/package-lock.json b/jsx/package-lock.json index 0227a069..cd0ce79b 100644 --- a/jsx/package-lock.json +++ b/jsx/package-lock.json @@ -19,7 +19,7 @@ "react-icons": "^5.3.0", "react-multi-select-component": "^4.3.4", "react-redux": "^9.1.2", - "react-router-dom": "^6.27.0", + "react-router": "^7.0.1", "recompose": "npm:react-recompose@^0.33.0", "redux": "^5.0.1", "regenerator-runtime": "^0.14.1" @@ -2463,14 +2463,6 @@ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/@remix-run/router": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", - "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@restart/hooks": { "version": "0.4.16", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", @@ -2767,6 +2759,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -8986,33 +8984,36 @@ } }, "node_modules/react-router": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", - "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.0.1.tgz", + "integrity": "sha512-WVAhv9oWCNsja5AkK6KLpXJDSJCQizOIyOd4vvB/+eHGbYx5vkhcmcmwWjQ9yqkRClogi+xjEg9fNEOd5EX/tw==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.20.0" + "@types/cookie": "^0.6.0", + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "react": ">=16.8" + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, - "node_modules/react-router-dom": { - "version": "6.27.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", - "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", - "dependencies": { - "@remix-run/router": "1.20.0", - "react-router": "6.27.0" - }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" + "node": ">=18" } }, "node_modules/react-transition-group": { @@ -9564,6 +9565,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -10268,6 +10275,12 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/jsx/package.json b/jsx/package.json index dae2eec2..e464968f 100644 --- a/jsx/package.json +++ b/jsx/package.json @@ -29,6 +29,9 @@ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", "\\.(css|less)$": "identity-obj-proxy" }, + "setupFiles": [ + "./testing/setup.jest.js" + ], "testEnvironment": "jsdom" }, "dependencies": { @@ -42,7 +45,7 @@ "react-icons": "^5.3.0", "react-multi-select-component": "^4.3.4", "react-redux": "^9.1.2", - "react-router-dom": "^6.27.0", + "react-router": "^7.0.1", "recompose": "npm:react-recompose@^0.33.0", "redux": "^5.0.1", "regenerator-runtime": "^0.14.1" diff --git a/jsx/src/App.jsx b/jsx/src/App.jsx index ba48d224..49886fa1 100644 --- a/jsx/src/App.jsx +++ b/jsx/src/App.jsx @@ -5,7 +5,7 @@ import { createStore } from "redux"; import { compose } from "recompose"; import { initialState, reducers } from "./Store"; import withAPI from "./util/withAPI"; -import { HashRouter, Routes, Route } from "react-router-dom"; +import { HashRouter, Routes, Route } from "react-router"; import ServerDashboard from "./components/ServerDashboard/ServerDashboard"; import Groups from "./components/Groups/Groups"; diff --git a/jsx/src/components/AddUser/AddUser.jsx b/jsx/src/components/AddUser/AddUser.jsx index 2310a284..872dba91 100644 --- a/jsx/src/components/AddUser/AddUser.jsx +++ b/jsx/src/components/AddUser/AddUser.jsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router"; import { Button, Col } from "react-bootstrap"; import PropTypes from "prop-types"; import ErrorAlert from "../../util/error"; diff --git a/jsx/src/components/AddUser/AddUser.test.js b/jsx/src/components/AddUser/AddUser.test.js index dbe0d0ac..217508ac 100644 --- a/jsx/src/components/AddUser/AddUser.test.js +++ b/jsx/src/components/AddUser/AddUser.test.js @@ -4,7 +4,7 @@ import { render, screen, fireEvent } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider, useDispatch, useSelector } from "react-redux"; import { createStore } from "redux"; -import { HashRouter } from "react-router-dom"; +import { HashRouter } from "react-router"; // eslint-disable-next-line import regeneratorRuntime from "regenerator-runtime"; diff --git a/jsx/src/components/CreateGroup/CreateGroup.jsx b/jsx/src/components/CreateGroup/CreateGroup.jsx index 6c6ed89b..4a0b1659 100644 --- a/jsx/src/components/CreateGroup/CreateGroup.jsx +++ b/jsx/src/components/CreateGroup/CreateGroup.jsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router"; import { Button, Card } from "react-bootstrap"; import PropTypes from "prop-types"; import { MainContainer } from "../../util/layout"; diff --git a/jsx/src/components/CreateGroup/CreateGroup.test.js b/jsx/src/components/CreateGroup/CreateGroup.test.js index 83b01212..98fcbdc1 100644 --- a/jsx/src/components/CreateGroup/CreateGroup.test.js +++ b/jsx/src/components/CreateGroup/CreateGroup.test.js @@ -4,7 +4,7 @@ import { render, screen, fireEvent } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider, useDispatch, useSelector } from "react-redux"; import { createStore } from "redux"; -import { HashRouter } from "react-router-dom"; +import { HashRouter } from "react-router"; // eslint-disable-next-line import regeneratorRuntime from "regenerator-runtime"; import CreateGroup from "./CreateGroup"; diff --git a/jsx/src/components/EditUser/EditUser.jsx b/jsx/src/components/EditUser/EditUser.jsx index 10c9f06f..d49c7aa2 100644 --- a/jsx/src/components/EditUser/EditUser.jsx +++ b/jsx/src/components/EditUser/EditUser.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import PropTypes from "prop-types"; -import { Link, useLocation, useNavigate } from "react-router-dom"; +import { Link, useLocation, useNavigate } from "react-router"; import { Button, Card } from "react-bootstrap"; import { MainContainer } from "../../util/layout"; diff --git a/jsx/src/components/EditUser/EditUser.test.js b/jsx/src/components/EditUser/EditUser.test.js index 9070f4a5..e36b3f14 100644 --- a/jsx/src/components/EditUser/EditUser.test.js +++ b/jsx/src/components/EditUser/EditUser.test.js @@ -3,7 +3,7 @@ import "@testing-library/jest-dom"; import { render, screen, fireEvent } from "@testing-library/react"; import { Provider, useDispatch, useSelector } from "react-redux"; import { createStore } from "redux"; -import { HashRouter } from "react-router-dom"; +import { HashRouter } from "react-router"; // eslint-disable-next-line import regeneratorRuntime from "regenerator-runtime"; @@ -15,8 +15,8 @@ jest.mock("react-redux", () => ({ useSelector: jest.fn(), })); -jest.mock("react-router-dom", () => ({ - ...jest.requireActual("react-router-dom"), +jest.mock("react-router", () => ({ + ...jest.requireActual("react-router"), useLocation: jest.fn().mockImplementation(() => { return { state: { username: "foo", has_admin: false } }; }), diff --git a/jsx/src/components/GroupEdit/GroupEdit.jsx b/jsx/src/components/GroupEdit/GroupEdit.jsx index b856cb89..8111b2c0 100644 --- a/jsx/src/components/GroupEdit/GroupEdit.jsx +++ b/jsx/src/components/GroupEdit/GroupEdit.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { useSelector, useDispatch } from "react-redux"; -import { Link, useNavigate, useLocation } from "react-router-dom"; +import { Link, useNavigate, useLocation } from "react-router"; import PropTypes from "prop-types"; import { Button, Card } from "react-bootstrap"; import GroupSelect from "../GroupSelect/GroupSelect"; diff --git a/jsx/src/components/GroupEdit/GroupEdit.test.jsx b/jsx/src/components/GroupEdit/GroupEdit.test.jsx index d8fb7b87..bcf282f6 100644 --- a/jsx/src/components/GroupEdit/GroupEdit.test.jsx +++ b/jsx/src/components/GroupEdit/GroupEdit.test.jsx @@ -4,7 +4,7 @@ import { render, screen, fireEvent } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Provider, useSelector } from "react-redux"; import { createStore } from "redux"; -import { HashRouter } from "react-router-dom"; +import { HashRouter } from "react-router"; // eslint-disable-next-line import regeneratorRuntime from "regenerator-runtime"; @@ -15,8 +15,8 @@ jest.mock("react-redux", () => ({ useSelector: jest.fn(), })); -jest.mock("react-router-dom", () => ({ - ...jest.requireActual("react-router-dom"), +jest.mock("react-router", () => ({ + ...jest.requireActual("react-router"), useLocation: jest.fn().mockImplementation(() => { return { state: { group_data: { users: ["foo"], name: "group" } } }; }), diff --git a/jsx/src/components/Groups/Groups.jsx b/jsx/src/components/Groups/Groups.jsx index 3771ea24..48de0d9c 100644 --- a/jsx/src/components/Groups/Groups.jsx +++ b/jsx/src/components/Groups/Groups.jsx @@ -3,7 +3,7 @@ import { useSelector, useDispatch } from "react-redux"; import PropTypes from "prop-types"; import { Button, Card } from "react-bootstrap"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router"; import { usePaginationParams } from "../../util/paginationParams"; import PaginationFooter from "../PaginationFooter/PaginationFooter"; import { MainContainer } from "../../util/layout"; diff --git a/jsx/src/components/Groups/Groups.test.js b/jsx/src/components/Groups/Groups.test.js index 2aa09442..c9749004 100644 --- a/jsx/src/components/Groups/Groups.test.js +++ b/jsx/src/components/Groups/Groups.test.js @@ -3,7 +3,7 @@ import "@testing-library/jest-dom"; import { render, screen, fireEvent } from "@testing-library/react"; import { Provider, useSelector } from "react-redux"; import { createStore } from "redux"; -import { HashRouter, useSearchParams } from "react-router-dom"; +import { HashRouter, useSearchParams } from "react-router"; // eslint-disable-next-line import regeneratorRuntime from "regenerator-runtime"; @@ -15,8 +15,8 @@ jest.mock("react-redux", () => ({ useSelector: jest.fn(), })); -jest.mock("react-router-dom", () => ({ - ...jest.requireActual("react-router-dom"), +jest.mock("react-router", () => ({ + ...jest.requireActual("react-router"), useSearchParams: jest.fn(), })); diff --git a/jsx/src/components/ServerDashboard/ServerDashboard.jsx b/jsx/src/components/ServerDashboard/ServerDashboard.jsx index 622a168c..cca39e0a 100644 --- a/jsx/src/components/ServerDashboard/ServerDashboard.jsx +++ b/jsx/src/components/ServerDashboard/ServerDashboard.jsx @@ -16,7 +16,7 @@ import { } from "react-bootstrap"; import ReactObjectTableViewer from "../ReactObjectTableViewer/ReactObjectTableViewer"; -import { Link, useSearchParams, useNavigate } from "react-router-dom"; +import { Link, useSearchParams, useNavigate } from "react-router"; import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa"; import "./server-dashboard.css"; diff --git a/jsx/src/components/ServerDashboard/ServerDashboard.test.js b/jsx/src/components/ServerDashboard/ServerDashboard.test.js index 5eff136c..c7a87839 100644 --- a/jsx/src/components/ServerDashboard/ServerDashboard.test.js +++ b/jsx/src/components/ServerDashboard/ServerDashboard.test.js @@ -9,8 +9,7 @@ import { getByText, getAllByRole, } from "@testing-library/react"; -import { HashRouter, Routes, Route, useSearchParams } from "react-router-dom"; -// import { CompatRouter, } from "react-router-dom-v5-compat"; +import { HashRouter, Routes, Route, useSearchParams } from "react-router"; import { Provider, useSelector } from "react-redux"; import { createStore } from "redux"; // eslint-disable-next-line @@ -23,8 +22,8 @@ jest.mock("react-redux", () => ({ ...jest.requireActual("react-redux"), useSelector: jest.fn(), })); -jest.mock("react-router-dom", () => ({ - ...jest.requireActual("react-router-dom"), +jest.mock("react-router", () => ({ + ...jest.requireActual("react-router"), useSearchParams: jest.fn(), })); diff --git a/jsx/src/util/paginationParams.js b/jsx/src/util/paginationParams.js index d1da95dd..080eb44e 100644 --- a/jsx/src/util/paginationParams.js +++ b/jsx/src/util/paginationParams.js @@ -1,5 +1,5 @@ import { debounce } from "lodash"; -import { useSearchParams } from "react-router-dom"; +import { useSearchParams } from "react-router"; export const usePaginationParams = () => { // get offset, limit, name filter from URL diff --git a/jsx/testing/setup.jest.js b/jsx/testing/setup.jest.js new file mode 100644 index 00000000..d782b1d1 --- /dev/null +++ b/jsx/testing/setup.jest.js @@ -0,0 +1,5 @@ +// Workaround "ReferenceError: TextEncoder is not defined" +// https://stackoverflow.com/questions/68468203/why-am-i-getting-textencoder-is-not-defined-in-jest/68468204#68468204 +// https://jestjs.io/docs/configuration#setupfiles-array +import { TextEncoder, TextDecoder } from 'util'; +Object.assign(global, { TextDecoder, TextEncoder });