diff --git a/package-lock.json b/package-lock.json index 7063ee43f9..b1c40d5907 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,6 @@ "downshift": "^9.0.8", "fast-deep-equal": "^3.1.3", "fast-xml-parser": "^4.4.1", - "history": "^4.10.1", "hoist-non-react-statics": "^3.3.2", "i18next": "^23.14.0", "i18next-http-backend": "^2.6.1", @@ -36,8 +35,6 @@ "moment": "^2.30.1", "moment-timezone": "^0.5.45", "prop-types": "^15.8.1", - "qhistory": "^1.1.0", - "qs": "^6.13.0", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-datepicker": "^6.0.0", @@ -5098,6 +5095,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -5802,6 +5800,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -6023,6 +6022,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -6034,6 +6034,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -6996,6 +6997,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -7149,6 +7151,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -7184,6 +7187,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -7195,6 +7199,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -7206,6 +7211,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -7239,19 +7245,6 @@ "node": ">= 0.4" } }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -7618,14 +7611,6 @@ "node": ">=12" } }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -8979,6 +8964,7 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9522,31 +9508,6 @@ "node": ">=6" } }, - "node_modules/qhistory": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/qhistory/-/qhistory-1.1.0.tgz", - "integrity": "sha512-mb5x+kKmEVSnUAX/loL20Y0kr1l4RZf7Al0Z1aNlwRL7nZo/QE46lRzLDro6CTNKcSUjiTOSQuFGRk4sU+FRUQ==", - "dependencies": { - "invariant": "^2.2.2" - }, - "peerDependencies": { - "history": ">=4.0.0" - } - }, - "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -9987,11 +9948,6 @@ "node": ">=4" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, "node_modules/restore-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", @@ -10230,6 +10186,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -10287,6 +10244,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -10837,11 +10795,6 @@ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -11212,11 +11165,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, "node_modules/vite": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.3.tgz", diff --git a/package.json b/package.json index 54e870d2ed..d2ab577c31 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "type": "git", "url": "https://github.com/greenbone/gsa/" }, - "author": "Bj\u00f6rn Ricks ", + "author": "Björn Ricks ", "license": "AGPL-3.0+", "type": "module", "scripts": { @@ -50,7 +50,6 @@ "downshift": "^9.0.8", "fast-deep-equal": "^3.1.3", "fast-xml-parser": "^4.4.1", - "history": "^4.10.1", "hoist-non-react-statics": "^3.3.2", "i18next": "^23.14.0", "i18next-http-backend": "^2.6.1", @@ -59,8 +58,6 @@ "moment": "^2.30.1", "moment-timezone": "^0.5.45", "prop-types": "^15.8.1", - "qhistory": "^1.1.0", - "qs": "^6.13.0", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-datepicker": "^6.0.0", @@ -118,4 +115,4 @@ "prettier --write" ] } -} \ No newline at end of file +} diff --git a/src/web/authorized.jsx b/src/web/authorized.jsx index 687ac32046..adacf84657 100644 --- a/src/web/authorized.jsx +++ b/src/web/authorized.jsx @@ -3,108 +3,65 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import React from 'react'; - -import {connect} from 'react-redux'; - -import {withRouter} from 'react-router-dom'; - -import {isDefined} from 'gmp/utils/identity'; - +import {useEffect, useCallback} from 'react'; import {setIsLoggedIn} from './store/usersettings/actions'; -import {isLoggedIn} from 'web/store/usersettings/selectors'; - -import compose from 'web/utils/compose'; +import {isLoggedIn as selectIsLoggedIn} from 'web/store/usersettings/selectors'; import PropTypes from 'web/utils/proptypes'; -import withGmp from 'web/utils/withGmp'; - -class Authorized extends React.Component { - constructor(...args) { - super(...args); - - this.responseError = this.responseError.bind(this); - } - - componentDidMount() { - const {gmp} = this.props; - - this.responseError = this.responseError.bind(this); - - this.unsubscribe = gmp.addHttpErrorHandler(this.responseError); - - this.checkIsLoggedIn(); - } - - componentWillUnmount() { - if (isDefined(this.unsubscribe)) { - this.unsubscribe(); - } - } - - componentDidUpdate() { - this.checkIsLoggedIn(); - } - - responseError(xhr) { - const {logout} = this.props; - - if (xhr.status === 401) { - logout(); - return Promise.resolve(xhr); - } - return Promise.reject(xhr); - } - - checkIsLoggedIn() { - if (!this.props.isLoggedIn) { - this.toLoginPage(); +import useGmp from 'web/hooks/useGmp'; +import {useDispatch, useSelector} from 'react-redux'; +import {useNavigate, useLocation} from 'react-router-dom'; + +const Authorized = ({children}) => { + const gmp = useGmp(); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const location = useLocation(); + const isLoggedIn = useSelector(selectIsLoggedIn); + + const logout = useCallback(() => { + gmp.logout(); + dispatch(setIsLoggedIn(false)); + }, [dispatch, gmp]); + + const responseError = useCallback( + xhr => { + if (xhr.status === 401) { + logout(); + return Promise.resolve(xhr); + } + return Promise.reject(new Error(xhr)); + }, + [logout], + ); + + const checkIsLoggedIn = useCallback(() => { + if (!isLoggedIn) { + navigate('/login', { + state: {next: location.pathname}, + }); } - } + }, [isLoggedIn, location.pathname, navigate]); - toLoginPage() { - const {history, location} = this.props; + useEffect(() => { + const unsubscribe = gmp.addHttpErrorHandler(responseError); + checkIsLoggedIn(); - if (location.pathname === '/login') { - // already at login page - return; - } + return () => { + if (unsubscribe) { + unsubscribe(); + } + }; + }, [gmp, responseError, checkIsLoggedIn]); - history.replace('/login', { - next: this.props.location.pathname, - }); - } + useEffect(() => { + checkIsLoggedIn(); + }, [isLoggedIn, checkIsLoggedIn]); - render() { - return this.props.isLoggedIn ? this.props.children : null; - } -} + return isLoggedIn ? children : null; +}; Authorized.propTypes = { - gmp: PropTypes.gmp.isRequired, - history: PropTypes.object.isRequired, - isLoggedIn: PropTypes.bool.isRequired, - location: PropTypes.object.isRequired, - logout: PropTypes.func.isRequired, + children: PropTypes.node.isRequired, }; -const mapStateToProps = rootState => ({ - isLoggedIn: isLoggedIn(rootState), -}); - -const mapDispatchToProps = (dispatch, {gmp}) => ({ - logout: () => { - gmp.logout(); - dispatch(setIsLoggedIn(false)); - }, -}); - -export default compose( - withGmp, - withRouter, - connect( - mapStateToProps, - mapDispatchToProps, - ), -)(Authorized); - -// vim: set ts=2 sw=2 tw=80: +export default Authorized; diff --git a/src/web/components/bar/menubar.jsx b/src/web/components/bar/menubar.jsx index 9d1315365b..388586c6b0 100644 --- a/src/web/components/bar/menubar.jsx +++ b/src/web/components/bar/menubar.jsx @@ -54,9 +54,8 @@ const MenuBarPlaceholder = styled.div` // eslint-disable-next-line no-shadow const MenuBar = ({isLoggedIn}) => { - const caps = useCapabilities(); - + if (!isLoggedIn || !isDefined(caps)) { return null; } @@ -115,7 +114,7 @@ const MenuBar = ({isLoggedIn}) => {
    - + {may_op_scans && ( {caps.mayAccess('tasks') && ( @@ -170,13 +169,13 @@ const MenuBar = ({isLoggedIn}) => { {caps.mayAccess('audits') && ( )} - {caps.featureEnabled('COMPLIANCE_REPORTS') && - caps.mayAccess('audits') && ( - - )} + {caps.featureEnabled('COMPLIANCE_REPORTS') && + caps.mayAccess('audits') && ( + + )} )} @@ -294,8 +293,6 @@ const mapStateToProps = rootState => ({ isLoggedIn: isLoggedIn(rootState), }); -export default compose( - connect(mapStateToProps), -)(MenuBar); +export default compose(connect(mapStateToProps))(MenuBar); // vim: set ts=2 sw=2 tw=80: diff --git a/src/web/components/conditionalRoute/ConditionalRoute.jsx b/src/web/components/conditionalRoute/ConditionalRoute.jsx index 97323b30fc..6e9cecb75b 100644 --- a/src/web/components/conditionalRoute/ConditionalRoute.jsx +++ b/src/web/components/conditionalRoute/ConditionalRoute.jsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; -import {Route, Redirect} from 'react-router-dom'; +import {Navigate} from 'react-router-dom'; import useCapabilities from 'web/hooks/useCapabilities'; const ConditionalRoute = ({component: Component, feature, ...rest}) => { @@ -13,12 +13,7 @@ const ConditionalRoute = ({component: Component, feature, ...rest}) => { const isEnabled = capabilities.featureEnabled(feature); return ( - - isEnabled ? : - } - {...rest} - /> + <>{isEnabled ? : } ); }; diff --git a/src/web/components/conditionalRoute/__tests__/ConditionalRoute.jsx b/src/web/components/conditionalRoute/__tests__/ConditionalRoute.jsx index a88608e852..f2ae3ba811 100644 --- a/src/web/components/conditionalRoute/__tests__/ConditionalRoute.jsx +++ b/src/web/components/conditionalRoute/__tests__/ConditionalRoute.jsx @@ -5,7 +5,7 @@ import {describe, test, expect} from '@gsa/testing'; import {screen, rendererWith} from 'web/utils/testing'; -import {Route, MemoryRouter} from 'react-router-dom'; +import {Route, Routes} from 'react-router-dom'; import ConditionalRoute from 'web/components/conditionalRoute/ConditionalRoute'; import Capabilities from 'gmp/capabilities/capabilities'; @@ -36,10 +36,15 @@ describe('ConditionalRoute', () => { }, ])('$description', ({feature, expectedText}) => { render( - - -
    Not Found
    } /> -
    , + + + } + /> + Not Found} /> + , ); expect(screen.getByText(expectedText)).toBeVisible(); diff --git a/src/web/components/dialog/__tests__/__snapshots__/multistepfooter.jsx.snap b/src/web/components/dialog/__tests__/__snapshots__/multistepfooter.jsx.snap index 5bd2debaff..430912e5f7 100644 --- a/src/web/components/dialog/__tests__/__snapshots__/multistepfooter.jsx.snap +++ b/src/web/components/dialog/__tests__/__snapshots__/multistepfooter.jsx.snap @@ -40,28 +40,6 @@ exports[`MultiStepFooter tests > should render 1`] = ` align-items: center; } -.c8 { - margin-left: -5px; -} - -.c8>* { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c8>* { - margin-left: 5px; -} - -.c7 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c3 { display: inline-block; padding: 0 15px; @@ -161,6 +139,28 @@ exports[`MultiStepFooter tests > should render 1`] = ` background: #11ab51; } +.c8 { + margin-left: -5px; +} + +.c8>* { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c8>* { + margin-left: 5px; +} + +.c7 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + .c2 { -webkit-box-pack: justify; -webkit-justify-content: space-between; @@ -249,28 +249,6 @@ exports[`MultiStepFooter tests > should render loading and disable cancel button align-items: center; } -.c8 { - margin-left: -5px; -} - -.c8>* { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c8>* { - margin-left: 5px; -} - -.c7 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c3 { display: inline-block; padding: 0 15px; @@ -381,6 +359,28 @@ exports[`MultiStepFooter tests > should render loading and disable cancel button background: #11ab51; } +.c8 { + margin-left: -5px; +} + +.c8>* { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c8>* { + margin-left: 5px; +} + +.c7 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + .c2 { -webkit-box-pack: justify; -webkit-justify-content: space-between; diff --git a/src/web/components/link/__tests__/certlink.jsx b/src/web/components/link/__tests__/certlink.jsx index 65dc8d5ff2..61b5fd5c13 100644 --- a/src/web/components/link/__tests__/certlink.jsx +++ b/src/web/components/link/__tests__/certlink.jsx @@ -8,8 +8,12 @@ import {describe, test, expect} from '@gsa/testing'; import {fireEvent, rendererWith} from 'web/utils/testing'; import CertLink from '../certlink'; +import {beforeEach} from 'vitest'; describe('CertLink tests', () => { + beforeEach(() => { + window.history.pushState({}, 'Test page', '/'); + }); test('should render CertLink', () => { const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); @@ -30,48 +34,47 @@ describe('CertLink tests', () => { }); test('should route to certbund details', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/certbund/foo'); + expect(window.location.pathname).toEqual('/certbund/foo'); }); test('should route to dfncert details', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - - expect(history.location.pathname).toEqual('/dfncert/foo'); + expect(window.location.pathname).toEqual('/dfncert/foo'); }); test('should not route to unknown type', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); }); test('should not route in text mode', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render( , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); }); }); diff --git a/src/web/components/link/__tests__/cvelink.jsx b/src/web/components/link/__tests__/cvelink.jsx index 6b74d62342..90323079a9 100644 --- a/src/web/components/link/__tests__/cvelink.jsx +++ b/src/web/components/link/__tests__/cvelink.jsx @@ -10,6 +10,9 @@ import {fireEvent, rendererWith} from 'web/utils/testing'; import CveLink from '../cvelink'; describe('CveLink tests', () => { + beforeEach(() => { + window.history.pushState({}, 'Test page', '/'); + }); test('should render CveLink', () => { const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); @@ -29,25 +32,25 @@ describe('CveLink tests', () => { }); test('should route to details', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/cve/foo'); + expect(window.location.pathname).toEqual('/cve/foo'); }); test('should not route to details in text mode', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render(); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); }); }); diff --git a/src/web/components/link/__tests__/detailslink.jsx b/src/web/components/link/__tests__/detailslink.jsx index fd78aced37..2d211019d7 100644 --- a/src/web/components/link/__tests__/detailslink.jsx +++ b/src/web/components/link/__tests__/detailslink.jsx @@ -12,6 +12,9 @@ import {fireEvent, rendererWith} from 'web/utils/testing'; import DetailsLink from '../detailslink'; describe('DetailsLink tests', () => { + beforeEach(() => { + window.history.pushState({}, 'Test page', '/'); + }); test('should render DetailsLink', () => { const {render} = rendererWith({capabilities: true, router: true}); const {element} = render( @@ -25,7 +28,7 @@ describe('DetailsLink tests', () => { }); test('should route to url', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render( @@ -33,15 +36,15 @@ describe('DetailsLink tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/foo/1'); + expect(window.location.pathname).toEqual('/foo/1'); }); test('should url encode id', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render( @@ -49,17 +52,17 @@ describe('DetailsLink tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual( + expect(window.location.pathname).toEqual( '/foo/cpe%3A%2Fa%3Ajenkins%3Ajenkins%3A2.141', ); }); test('should not route to url in text mode', () => { - const {render, history} = rendererWith({capabilities: true, router: true}); + const {render} = rendererWith({capabilities: true, router: true}); const {element} = render( @@ -67,16 +70,16 @@ describe('DetailsLink tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); }); test('should not route to url without capabilities', () => { const capabilities = new Capabilities(); - const {render, history} = rendererWith({capabilities, router: true}); + const {render} = rendererWith({capabilities, router: true}); const {element} = render( @@ -84,11 +87,11 @@ describe('DetailsLink tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); }); }); diff --git a/src/web/components/link/__tests__/link.jsx b/src/web/components/link/__tests__/link.jsx index 2282d3b976..437d8face0 100644 --- a/src/web/components/link/__tests__/link.jsx +++ b/src/web/components/link/__tests__/link.jsx @@ -11,6 +11,9 @@ import Link from '../link'; import Filter from 'gmp/models/filter'; describe('Link tests', () => { + beforeEach(() => { + window.history.pushState({}, 'Test page', '/'); + }); test('render Link', () => { const {render} = rendererWith({router: true}); @@ -20,32 +23,32 @@ describe('Link tests', () => { }); test('should route to url on click', () => { - const {render, history} = rendererWith({router: true}); + const {render} = rendererWith({router: true}); const {element} = render(Foo); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/foo'); + expect(window.location.pathname).toEqual('/foo'); }); test('should route to absolute url on click', () => { - const {render, history} = rendererWith({router: true}); + const {render} = rendererWith({router: true}); const {element} = render(Foo); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/foo'); + expect(window.location.pathname).toEqual('/foo'); }); test('should route to url with filter on click', () => { const filter = Filter.fromString('foo=bar'); - const {render, history} = rendererWith({router: true}); + const {render} = rendererWith({router: true}); const {element} = render( @@ -53,16 +56,18 @@ describe('Link tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/foo'); - expect(history.location.query).toEqual({filter: 'foo=bar'}); + expect(window.location.pathname).toEqual('/foo'); + + const searchParams = new URLSearchParams(window.location.search); + expect(searchParams.get('filter')).toEqual('foo=bar'); }); test('should route to url with query on click', () => { - const {render, history} = rendererWith({router: true}); + const {render} = rendererWith({router: true}); const query = {foo: 'bar'}; const {element} = render( @@ -71,16 +76,18 @@ describe('Link tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/foo'); - expect(history.location.query).toEqual(query); + expect(window.location.pathname).toEqual('/foo'); + + const searchParams = new URLSearchParams(window.location.search); + expect(searchParams.get('foo')).toEqual('bar'); }); test('should route to url with anchor on click', () => { - const {render, history} = rendererWith({router: true}); + const {render} = rendererWith({router: true}); const {element} = render( @@ -88,16 +95,16 @@ describe('Link tests', () => { , ); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); fireEvent.click(element); - expect(history.location.pathname).toEqual('/foo'); - expect(history.location.hash).toEqual('#bar'); + expect(window.location.pathname).toEqual('/foo'); + expect(window.location.hash).toEqual('#bar'); }); test('should not route to url in text mode', () => { - const {render, history} = rendererWith({router: true}); + const {render} = rendererWith({router: true}); const {element} = render( @@ -107,7 +114,7 @@ describe('Link tests', () => { fireEvent.click(element); - expect(history.location.pathname).toEqual('/'); + expect(window.location.pathname).toEqual('/'); }); test('should render styles', () => { diff --git a/src/web/components/link/link.jsx b/src/web/components/link/link.jsx index 9c8c7964fd..c628d96bf8 100644 --- a/src/web/components/link/link.jsx +++ b/src/web/components/link/link.jsx @@ -3,15 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; - import styled from 'styled-components'; - import {Link as RLink} from 'react-router-dom'; - import {isDefined, isString} from 'gmp/utils/identity'; - import PropTypes from 'web/utils/proptypes'; RLink.displayName = 'RouterLink'; @@ -45,7 +40,7 @@ export const withTextOnly = Component => { return TextOnly; }; -let Link = ({anchor, to = '', filter, query, ...other}) => { +const LinkComponent = ({anchor, to = '', filter, query, ...other}) => { let pathname = ''; if (to.startsWith('/')) { @@ -54,29 +49,32 @@ let Link = ({anchor, to = '', filter, query, ...other}) => { pathname += '/' + to; } - const location = { + const searchParams = new URLSearchParams(isDefined(query) ? query : {}); + if (isDefined(filter)) { + searchParams.set( + 'filter', + isString(filter) ? filter : filter.toFilterString(), + ); + } + + const fullPath = { pathname, - query: isDefined(query) ? {...query} : {}, - hash: isDefined(anchor) ? '#' + anchor : undefined, + search: searchParams.toString().replace(/\+/g, '%20'), + hash: isDefined(anchor) ? '#' + anchor : '', }; - if (isDefined(filter)) { - location.query.filter = isString(filter) ? filter : filter.toFilterString(); - } - return ; + return ; }; -Link.propTypes = { +LinkComponent.propTypes = { anchor: PropTypes.string, filter: PropTypes.oneOfType([PropTypes.filter, PropTypes.string]), query: PropTypes.object, to: PropTypes.string.isRequired, }; -Link = styled(withTextOnly(Link))` +const Link = styled(withTextOnly(LinkComponent))` display: inline-flex; `; export default Link; - -// vim: set ts=2 sw=2 tw=80: diff --git a/src/web/components/menu/__tests__/__snapshots__/usermenu.jsx.snap b/src/web/components/menu/__tests__/__snapshots__/usermenu.jsx.snap index ff58c4ba57..75be74124b 100644 --- a/src/web/components/menu/__tests__/__snapshots__/usermenu.jsx.snap +++ b/src/web/components/menu/__tests__/__snapshots__/usermenu.jsx.snap @@ -1,6 +1,40 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`UserMenu component tests > should render UserMenu 1`] = ` +.c2 { + width: 24px; + height: 24px; + line-height: 24px; +} + +.c2 * { + height: inherit; + width: inherit; +} + +.c10 { + width: 16px; + height: 16px; + line-height: 16px; +} + +.c10 * { + height: inherit; + width: inherit; +} + +.c11 { + cursor: pointer; + width: 16px; + height: 16px; + line-height: 16px; +} + +.c11 * { + height: inherit; + width: inherit; +} + .c7 { display: -webkit-box; display: -webkit-flex; @@ -19,13 +53,6 @@ exports[`UserMenu component tests > should render UserMenu 1`] = ` align-items: center; } -.c12 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c9 { margin-left: -5px; } @@ -48,38 +75,11 @@ exports[`UserMenu component tests > should render UserMenu 1`] = ` display: inline-flex; } -.c2 { - width: 24px; - height: 24px; - line-height: 24px; -} - -.c2 * { - height: inherit; - width: inherit; -} - -.c10 { - width: 16px; - height: 16px; - line-height: 16px; -} - -.c10 * { - height: inherit; - width: inherit; -} - -.c11 { - cursor: pointer; - width: 16px; - height: 16px; - line-height: 16px; -} - -.c11 * { - height: inherit; - width: inherit; +.c12 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; } .c1 { diff --git a/src/web/components/menu/__tests__/usermenu.jsx b/src/web/components/menu/__tests__/usermenu.jsx index bf444b67c2..9f4dfa0497 100644 --- a/src/web/components/menu/__tests__/usermenu.jsx +++ b/src/web/components/menu/__tests__/usermenu.jsx @@ -37,7 +37,7 @@ describe('UserMenu component tests', () => { }); test('should route to usersettings on click', () => { - const {render, history} = rendererWith({ + const {render} = rendererWith({ gmp: {}, store: true, router: true, @@ -48,7 +48,7 @@ describe('UserMenu component tests', () => { fireEvent.click(userSettingsElement); - expect(history.location.pathname).toMatch('usersettings'); + expect(window.location.pathname).toMatch('usersettings'); }); test('should logout user on click', async () => { diff --git a/src/web/components/menu/usermenu.jsx b/src/web/components/menu/usermenu.jsx index 9aef15e649..d4b6623c52 100644 --- a/src/web/components/menu/usermenu.jsx +++ b/src/web/components/menu/usermenu.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import {useHistory} from 'react-router-dom'; +import {useNavigate} from 'react-router-dom'; import styled, {keyframes} from 'styled-components'; @@ -121,13 +121,13 @@ const UserMenuContainer = () => { const [userTimezone] = useUserTimezone(); const [userName] = useUserName(); const gmp = useGmp(); - const history = useHistory(); + const navigate = useNavigate(); const handleLogout = event => { event.preventDefault(); gmp.doLogout().then(() => { - history.push('/login?type=logout'); + navigate('/login?type=logout'); }); }; diff --git a/src/web/components/observer/locationobserver.jsx b/src/web/components/observer/locationobserver.jsx index c43c990d96..53d5baa4c9 100644 --- a/src/web/components/observer/locationobserver.jsx +++ b/src/web/components/observer/locationobserver.jsx @@ -7,7 +7,7 @@ import React from 'react'; import {connect} from 'react-redux'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import Logger from 'gmp/log'; @@ -71,12 +71,9 @@ LocationObserver.propTypes = { export default compose( withGmp, withRouter, - connect( - undefined, - (dispatch, {gmp}) => ({ - renewSessionTimeout: () => dispatch(renewSessionTimeout(gmp)()), - }), - ), + connect(undefined, (dispatch, {gmp}) => ({ + renewSessionTimeout: () => dispatch(renewSessionTimeout(gmp)()), + })), )(LocationObserver); // vim: set ts=2 sw=2 tw=80: diff --git a/src/web/components/powerfilter/__tests__/__snapshots__/booleanfiltergroup.jsx.snap b/src/web/components/powerfilter/__tests__/__snapshots__/booleanfiltergroup.jsx.snap index 7bc3e91f64..d0443b1317 100644 --- a/src/web/components/powerfilter/__tests__/__snapshots__/booleanfiltergroup.jsx.snap +++ b/src/web/components/powerfilter/__tests__/__snapshots__/booleanfiltergroup.jsx.snap @@ -19,28 +19,6 @@ exports[`BooleanFilterGroup tests > should render 1`] = ` align-items: center; } -.c5 { - margin-left: -5px; -} - -.c5>* { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c5>* { - margin-left: 5px; -} - -.c4 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c0 { display: -webkit-box; display: -webkit-flex; @@ -74,6 +52,28 @@ exports[`BooleanFilterGroup tests > should render 1`] = ` padding-right: 10px; } +.c5 { + margin-left: -5px; +} + +.c5>* { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c5>* { + margin-left: 5px; +} + +.c4 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + .c6 { display: -webkit-inline-box; display: -webkit-inline-flex; diff --git a/src/web/components/powerfilter/__tests__/__snapshots__/createnamedfiltergroup.jsx.snap b/src/web/components/powerfilter/__tests__/__snapshots__/createnamedfiltergroup.jsx.snap index 05cde3acdd..d2579e75cd 100644 --- a/src/web/components/powerfilter/__tests__/__snapshots__/createnamedfiltergroup.jsx.snap +++ b/src/web/components/powerfilter/__tests__/__snapshots__/createnamedfiltergroup.jsx.snap @@ -41,54 +41,6 @@ exports[`CreateNamedFilterGroup tests > should render 1`] = ` display: inline-flex; } -.c10 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - -.c8 { - font-family: inherit; - font-size: inherit; - line-height: inherit; - display: block; - height: 22px; - color: #4C4C4C; - background-color: #fff; - background-image: none; - border: 1px solid #bfbfbf; - border-radius: 2px; - padding: 1px 8px; - cursor: not-allowed; - background-color: #f3f3f3; - opacity: 0.65; -} - -.c8:-webkit-autofill { - box-shadow: 0 0 0 1000px white inset; -} - -.c9 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-pack: start; - -ms-flex-pack: start; - -webkit-justify-content: start; - justify-content: start; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - .c4 { display: -webkit-inline-box; display: -webkit-inline-flex; @@ -138,6 +90,54 @@ exports[`CreateNamedFilterGroup tests > should render 1`] = ` align-items: center; } +.c8 { + font-family: inherit; + font-size: inherit; + line-height: inherit; + display: block; + height: 22px; + color: #4C4C4C; + background-color: #fff; + background-image: none; + border: 1px solid #bfbfbf; + border-radius: 2px; + padding: 1px 8px; + cursor: not-allowed; + background-color: #f3f3f3; + opacity: 0.65; +} + +.c8:-webkit-autofill { + box-shadow: 0 0 0 1000px white inset; +} + +.c9 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: start; + justify-content: start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c10 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; +} + .c1 { margin-top: 15px; } diff --git a/src/web/components/powerfilter/__tests__/__snapshots__/filtersearchgroup.jsx.snap b/src/web/components/powerfilter/__tests__/__snapshots__/filtersearchgroup.jsx.snap index 2432bfab64..03e1f8f9a6 100644 --- a/src/web/components/powerfilter/__tests__/__snapshots__/filtersearchgroup.jsx.snap +++ b/src/web/components/powerfilter/__tests__/__snapshots__/filtersearchgroup.jsx.snap @@ -35,15 +35,6 @@ exports[`FilterSearchGroup tests > should render 1`] = ` padding-bottom: 10px; } -.c4 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - .c2 { font-family: inherit; font-size: inherit; @@ -80,6 +71,15 @@ exports[`FilterSearchGroup tests > should render 1`] = ` align-items: center; } +.c4 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; +} +
    diff --git a/src/web/components/powerfilter/__tests__/__snapshots__/filterstringgroup.jsx.snap b/src/web/components/powerfilter/__tests__/__snapshots__/filterstringgroup.jsx.snap index d0fec2f880..f762240cdd 100644 --- a/src/web/components/powerfilter/__tests__/__snapshots__/filterstringgroup.jsx.snap +++ b/src/web/components/powerfilter/__tests__/__snapshots__/filterstringgroup.jsx.snap @@ -52,15 +52,6 @@ exports[`FilterStringGroup tests > should render 1`] = ` padding-right: 10px; } -.c6 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - .c4 { font-family: inherit; font-size: inherit; @@ -101,6 +92,15 @@ exports[`FilterStringGroup tests > should render 1`] = ` align-items: center; } +.c6 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; +} +
    diff --git a/src/web/components/powerfilter/__tests__/__snapshots__/minqodgroup.jsx.snap b/src/web/components/powerfilter/__tests__/__snapshots__/minqodgroup.jsx.snap index 4639acb333..f76e5c38f7 100644 --- a/src/web/components/powerfilter/__tests__/__snapshots__/minqodgroup.jsx.snap +++ b/src/web/components/powerfilter/__tests__/__snapshots__/minqodgroup.jsx.snap @@ -19,28 +19,6 @@ exports[`MinQodGroup tests > should render 1`] = ` align-items: center; } -.c5 { - margin-left: -5px; -} - -.c5>* { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c5>* { - margin-left: 5px; -} - -.c4 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c0 { display: -webkit-box; display: -webkit-flex; @@ -148,6 +126,28 @@ exports[`MinQodGroup tests > should render 1`] = ` bottom: 0; } +.c5 { + margin-left: -5px; +} + +.c5>* { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c5>* { + margin-left: 5px; +} + +.c4 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} +
    diff --git a/src/web/components/table/__tests__/__snapshots__/detailstable.jsx.snap b/src/web/components/table/__tests__/__snapshots__/detailstable.jsx.snap index 47a12aef28..ee9f45906c 100644 --- a/src/web/components/table/__tests__/__snapshots__/detailstable.jsx.snap +++ b/src/web/components/table/__tests__/__snapshots__/detailstable.jsx.snap @@ -19,6 +19,14 @@ exports[`DetailsTable tests > should render 1`] = ` align-items: stretch; } +.c2 { + width: 10%; +} + +.c3 { + width: 90%; +} + .c0 { border: 0; border-spacing: 0px; @@ -36,14 +44,6 @@ exports[`DetailsTable tests > should render 1`] = ` padding-right: 5px; } -.c2 { - width: 10%; -} - -.c3 { - width: 90%; -} - @media print { .c0 { border-collapse: collapse; diff --git a/src/web/entities/container.jsx b/src/web/entities/container.jsx index a29c90f3a2..b05c809a84 100644 --- a/src/web/entities/container.jsx +++ b/src/web/entities/container.jsx @@ -3,10 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import {connect} from 'react-redux'; @@ -322,13 +321,13 @@ class EntitiesContainer extends React.Component { } handleFilterReset() { - const {history, location} = this.props; + const {navigate, location} = this.props; const query = {...location.query}; // remove filter param from url delete query.filter; - history.push({pathname: location.pathname, query}); + navigate({pathname: location.pathname, query}); this.changeFilter(); } @@ -585,7 +584,7 @@ EntitiesContainer.propTypes = { filter: PropTypes.filter, gmp: PropTypes.gmp.isRequired, gmpname: PropTypes.string.isRequired, - history: PropTypes.object.isRequired, + navigate: PropTypes.object.isRequired, isLoading: PropTypes.bool.isRequired, listExportFileName: PropTypes.string, loadSettings: PropTypes.func.isRequired, @@ -604,9 +603,8 @@ EntitiesContainer.propTypes = { const mapStateToProps = rootState => { const userDefaultsSelector = getUserSettingsDefaults(rootState); const username = getUsername(rootState); - const listExportFileName = userDefaultsSelector.getValueByName( - 'listexportfilename', - ); + const listExportFileName = + userDefaultsSelector.getValueByName('listexportfilename'); return { listExportFileName, username, diff --git a/src/web/entity/component.jsx b/src/web/entity/component.jsx index 662e4ac833..0f22134ec3 100644 --- a/src/web/entity/component.jsx +++ b/src/web/entity/component.jsx @@ -23,14 +23,16 @@ import {generateFilename} from 'web/utils/render'; import withGmp from 'web/utils/withGmp'; -export const goto_details = (type, props) => ({data}) => { - const {history} = props; - return history.push('/' + type + '/' + data.id); -}; +export const goto_details = + (type, props) => + ({data}) => { + const {navigate} = props; + return navigate('/' + type + '/' + data.id); + }; export const goto_list = (type, props) => () => { - const {history} = props; - return history.push('/' + type); + const {navigate} = props; + return navigate('/' + type); }; class EntityComponent extends React.Component { @@ -173,10 +175,7 @@ const mapDispatchToProps = (dispatch, {name, gmp}) => { export default compose( withGmp, - connect( - mapStateToProps, - mapDispatchToProps, - ), + connect(mapStateToProps, mapDispatchToProps), )(EntityComponent); // vim: set ts=2 sw=2 tw=80: diff --git a/src/web/entity/withEntityContainer.jsx b/src/web/entity/withEntityContainer.jsx index e0b1ebbf1e..c0a48bd7dd 100644 --- a/src/web/entity/withEntityContainer.jsx +++ b/src/web/entity/withEntityContainer.jsx @@ -7,7 +7,7 @@ import React from 'react'; import {connect} from 'react-redux'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import Filter from 'gmp/models/filter'; @@ -45,71 +45,70 @@ export const permissionsSubjectFilter = id => id, ).all(); -const withEntityContainer = ( - entityType, - { - load, - entitySelector, - mapStateToProps: componentMapStateToProps, - reloadInterval = defaultEntityReloadIntervalFunc, - }, -) => Component => { - const EntityContainerWrapper = props => ( - reloadInterval(props)} - reload={(id = props.id) => props.load(id)} - name={entityType} - > - {({reload}) => ( - - {cprops => } - - )} - - ); - - EntityContainerWrapper.propTypes = { - id: PropTypes.id.isRequired, - load: PropTypes.func.isRequired, - }; +const withEntityContainer = + ( + entityType, + { + load, + entitySelector, + mapStateToProps: componentMapStateToProps, + reloadInterval = defaultEntityReloadIntervalFunc, + }, + ) => + Component => { + const EntityContainerWrapper = props => ( + reloadInterval(props)} + reload={(id = props.id) => props.load(id)} + name={entityType} + > + {({reload}) => ( + + {cprops => } + + )} + + ); + + EntityContainerWrapper.propTypes = { + id: PropTypes.id.isRequired, + load: PropTypes.func.isRequired, + }; - const mapDispatchToProps = (dispatch, {gmp}) => ({ - onInteraction: () => dispatch(renewSessionTimeout(gmp)()), - load: id => dispatch(load(gmp)(id)), - }); - - const mapStateToProps = (rootState, {gmp, id, match, ...props}) => { - if (!isDefined(id)) { - id = decodeURIComponent(match.params.id); // decodeURIComponent needs to be done for CPE IDs - } - const entitySel = entitySelector(rootState); - const otherProps = isDefined(componentMapStateToProps) - ? componentMapStateToProps(rootState, { - gmp, - id, - ...props, - }) - : undefined; - return { - isLoading: entitySel.isLoadingEntity(id), - ...otherProps, - id, - entity: entitySel.getEntity(id), - entityError: entitySel.getEntityError(id), + const mapDispatchToProps = (dispatch, {gmp}) => ({ + onInteraction: () => dispatch(renewSessionTimeout(gmp)()), + load: id => dispatch(load(gmp)(id)), + }); + + const mapStateToProps = (rootState, {gmp, id, params, ...props}) => { + if (!isDefined(id)) { + id = decodeURIComponent(params.id); // decodeURIComponent needs to be done for CPE IDs + } + const entitySel = entitySelector(rootState); + const otherProps = isDefined(componentMapStateToProps) + ? componentMapStateToProps(rootState, { + gmp, + id, + ...props, + }) + : undefined; + return { + isLoading: entitySel.isLoadingEntity(id), + ...otherProps, + id, + entity: entitySel.getEntity(id), + entityError: entitySel.getEntityError(id), + }; }; - }; - return compose( - withGmp, - withRouter, - withDialogNotification, - withDownload, - connect( - mapStateToProps, - mapDispatchToProps, - ), - )(EntityContainerWrapper); -}; + return compose( + withGmp, + withRouter, + withDialogNotification, + withDownload, + connect(mapStateToProps, mapDispatchToProps), + )(EntityContainerWrapper); + }; export default withEntityContainer; diff --git a/src/web/hooks/__tests__/usePageFilter.jsx b/src/web/hooks/__tests__/usePageFilter.jsx index 7d4d008b57..e6d868a545 100644 --- a/src/web/hooks/__tests__/usePageFilter.jsx +++ b/src/web/hooks/__tests__/usePageFilter.jsx @@ -18,14 +18,14 @@ import usePageFilter from '../usePageFilter'; import {pageFilter} from 'web/store/pages/actions'; import {vi} from 'vitest'; -const mockUseHistory = testing.fn(); +const mockUseNavigate = testing.fn(); vi.mock('react-router-dom', async () => { const actual = await vi.importActual('react-router-dom'); return { ...actual, useLocation: () => ({pathname: '/'}), - useHistory: () => mockUseHistory(), + useNavigate: () => mockUseNavigate(), }; }); @@ -42,14 +42,12 @@ describe('usePageFilter tests', () => { }, }; - const {renderHook, store, history} = rendererWith({ + const {renderHook, store} = rendererWith({ gmp, store: true, router: true, }); - history.push({query: locationQuery}); - store.dispatch(loadingActions.success({rowsperpage: {value: '42'}})); store.dispatch( defaultFilterLoadingActions.success('somePage', defaultSettingFilter), diff --git a/src/web/hooks/usePageFilter.js b/src/web/hooks/usePageFilter.js index e7b9f472b1..16f2f225cc 100644 --- a/src/web/hooks/usePageFilter.js +++ b/src/web/hooks/usePageFilter.js @@ -5,7 +5,7 @@ import {useCallback, useEffect, useState} from 'react'; -import {useLocation, useHistory} from 'react-router-dom'; +import {useLocation, useNavigate} from 'react-router-dom'; import {useDispatch} from 'react-redux'; @@ -63,7 +63,7 @@ const usePageFilter = ( const gmp = useGmp(); const dispatch = useDispatch(); const location = useLocation(); - const history = useHistory(); + const navigate = useNavigate(); const [defaultSettingFilter, defaultSettingsFilterError] = useDefaultFilter(gmpName); @@ -168,10 +168,10 @@ const usePageFilter = ( // remove filter param from url delete query.filter; - history.push({pathname: location.pathname, query}); + navigate({pathname: location.pathname, query}); changeFilter(); - }, [changeFilter, history, location]); + }, [changeFilter, navigate, location]); return [ returnedFilter, diff --git a/src/web/pages/audits/__tests__/__snapshots__/details.jsx.snap b/src/web/pages/audits/__tests__/__snapshots__/details.jsx.snap index 7c56606273..8c732ad812 100644 --- a/src/web/pages/audits/__tests__/__snapshots__/details.jsx.snap +++ b/src/web/pages/audits/__tests__/__snapshots__/details.jsx.snap @@ -59,35 +59,48 @@ exports[`Audit Details tests > should render full audit details 1`] = ` align-items: center; } -.c2 { +.c5 { + margin-left: -5px; +} + +.c5>* { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } -.c5 { - margin-left: -5px; +.c5>* { + margin-left: 5px; } -.c5>* { +.c4 { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } -.c5>* { +.c6>*:not(:last-child)::after { + content: '•'; margin-left: 5px; } -.c4 { +.c2 { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } +.c9 { + width: 10%; +} + +.c10 { + width: 90%; +} + .c7 { border: 0; border-spacing: 0px; @@ -97,11 +110,6 @@ exports[`Audit Details tests > should render full audit details 1`] = ` width: 100%; } -.c6>*:not(:last-child)::after { - content: '•'; - margin-left: 5px; -} - .c8 td { padding: 4px 4px 4px 0; } @@ -110,14 +118,6 @@ exports[`Audit Details tests > should render full audit details 1`] = ` padding-right: 5px; } -.c9 { - width: 10%; -} - -.c10 { - width: 90%; -} - @media print { .c7 { border-collapse: collapse; diff --git a/src/web/pages/audits/component.jsx b/src/web/pages/audits/component.jsx index a3deda1916..810a831ec6 100644 --- a/src/web/pages/audits/component.jsx +++ b/src/web/pages/audits/component.jsx @@ -19,7 +19,7 @@ import {isDefined} from 'gmp/utils/identity'; import {hasId} from 'gmp/utils/id'; import withDownload from 'web/components/form/withDownload'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import { OPENVAS_DEFAULT_SCANNER_ID, @@ -588,7 +588,7 @@ AuditComponent.propTypes = { onStopped: PropTypes.func, }; -const mapStateToProps = (rootState, {match}) => { +const mapStateToProps = rootState => { const alertSel = alertSelector(rootState); const userDefaults = getUserSettingsDefaults(rootState); const policiesSel = policiesSelector(rootState); diff --git a/src/web/pages/hosts/dashboard/topologydisplay.jsx b/src/web/pages/hosts/dashboard/topologydisplay.jsx index f2c0e3dad1..f1835673da 100644 --- a/src/web/pages/hosts/dashboard/topologydisplay.jsx +++ b/src/web/pages/hosts/dashboard/topologydisplay.jsx @@ -3,10 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import {_, _l} from 'gmp/locale/lang'; @@ -115,9 +114,9 @@ export class HostsTopologyDisplay extends React.Component { } handleDataClick(data) { - const {history} = this.props; + const {navigate} = this.props; - history.push(`/host/${data.id}`); + navigate(`/host/${data.id}`); } render() { @@ -151,7 +150,7 @@ export class HostsTopologyDisplay extends React.Component { HostsTopologyDisplay.propTypes = { filter: PropTypes.filter, - history: PropTypes.object.isRequired, + navigate: PropTypes.object.isRequired, }; const DISPLAY_ID = 'host-by-topology'; diff --git a/src/web/pages/hosts/dashboard/vulnscoredisplay.jsx b/src/web/pages/hosts/dashboard/vulnscoredisplay.jsx index 370944562c..ebe54913b9 100644 --- a/src/web/pages/hosts/dashboard/vulnscoredisplay.jsx +++ b/src/web/pages/hosts/dashboard/vulnscoredisplay.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import styled from 'styled-components'; @@ -86,9 +86,9 @@ export class HostsVulnScoreDisplay extends React.Component { } handleDataClick(data) { - const {history} = this.props; + const {navigate} = this.props; - history.push(`/host/${data.id}`); + navigate(`/host/${data.id}`); } render() { @@ -125,7 +125,7 @@ export class HostsVulnScoreDisplay extends React.Component { HostsVulnScoreDisplay.propTypes = { filter: PropTypes.filter, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, }; HostsVulnScoreDisplay = compose( diff --git a/src/web/pages/login/__tests__/loginpage.jsx b/src/web/pages/login/__tests__/loginpage.jsx index 757563f632..6871cdfbe0 100644 --- a/src/web/pages/login/__tests__/loginpage.jsx +++ b/src/web/pages/login/__tests__/loginpage.jsx @@ -155,10 +155,10 @@ describe('LoginPage tests', () => { clearToken, settings: {}, }; - const {render, history} = rendererWith({gmp, router: true, store: true}); + const {render} = rendererWith({gmp, router: true, store: true}); render(); - expect(history.location.pathname).toMatch(/^\/$/); + expect(window.location.pathname).toMatch(/^\/dashboard$/); }); }); diff --git a/src/web/pages/login/loginpage.jsx b/src/web/pages/login/loginpage.jsx index 1745152e28..67a6bb77ec 100644 --- a/src/web/pages/login/loginpage.jsx +++ b/src/web/pages/login/loginpage.jsx @@ -3,12 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; import {connect} from 'react-redux'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import styled from 'styled-components'; @@ -102,7 +101,7 @@ class LoginPage extends React.Component { data => { const {locale, timezone, sessionTimeout} = data; - const {location, history} = this.props; + const {location, navigate} = this.props; this.props.setTimezone(timezone); this.props.setLocale(locale); @@ -117,9 +116,9 @@ class LoginPage extends React.Component { location.state.next && location.state.next !== location.pathname ) { - history.replace(location.state.next); + navigate(location.state.next, {replace: true}); } else { - history.replace('/'); + navigate('/dashboard', {replace: true}); } }, rej => { @@ -130,11 +129,11 @@ class LoginPage extends React.Component { } componentDidMount() { - const {history, isLoggedIn = false} = this.props; // eslint-disable-line no-shadow + const {navigate, isLoggedIn = false} = this.props; // eslint-disable-line no-shadow // redirect user to main page if he is already logged in if (isLoggedIn) { - history.replace('/'); + navigate('/dashboard', {replace: true}); } } @@ -182,7 +181,7 @@ class LoginPage extends React.Component { LoginPage.propTypes = { gmp: PropTypes.gmp.isRequired, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, isLoggedIn: PropTypes.bool, location: PropTypes.object.isRequired, setIsLoggedIn: PropTypes.func.isRequired, diff --git a/src/web/pages/omp.jsx b/src/web/pages/omp.jsx index 485264a5bf..7dfe296a74 100644 --- a/src/web/pages/omp.jsx +++ b/src/web/pages/omp.jsx @@ -3,10 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import PropTypes from 'web/utils/proptypes'; @@ -19,11 +18,11 @@ import PropTypes from 'web/utils/proptypes'; */ class LegacyOmpPage extends React.Component { componentDidMount() { - const {location, history} = this.props; + const {location, navigate} = this.props; const {cmd, info_type, info_id = ''} = location.query; if (cmd !== 'get_info') { - history.replace('/notfound'); + navigate('/notfound', {replace: true}); return; } @@ -31,22 +30,22 @@ class LegacyOmpPage extends React.Component { switch (info_type) { case 'nvt': - history.replace('/nvt/' + id); + navigate('/nvt/' + id, {replace: true}); break; case 'cve': - history.replace('/cve/' + id); + navigate('/cve/' + id, {replace: true}); break; case 'cpe': - history.replace('/cpe/' + id); + navigate('/cpe/' + id, {replace: true}); break; case 'cert_bund_adv': - history.replace('/certbund/' + id); + navigate('/certbund/' + id, {replace: true}); break; case 'dfn_cert_adv': - history.replace('/dfncert/' + id); + navigate('/dfncert/' + id, {replace: true}); break; default: - history.replace('/notfound'); + navigate('/notfound', {replace: true}); break; } } @@ -57,7 +56,7 @@ class LegacyOmpPage extends React.Component { } LegacyOmpPage.propTypes = { - history: PropTypes.object.isRequired, + navigate: PropTypes.object.isRequired, }; export default withRouter(LegacyOmpPage); diff --git a/src/web/pages/operatingsystems/dashboard/vulnscoredisplay.jsx b/src/web/pages/operatingsystems/dashboard/vulnscoredisplay.jsx index 729a3e8a54..96c4409643 100644 --- a/src/web/pages/operatingsystems/dashboard/vulnscoredisplay.jsx +++ b/src/web/pages/operatingsystems/dashboard/vulnscoredisplay.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import styled from 'styled-components'; @@ -88,9 +88,9 @@ export class OsVulnScoreDisplay extends React.Component { } handleDataClick(data) { - const {history} = this.props; + const {navigate} = this.props; - history.push(`/operatingsystem/${data.id}`); + navigate(`/operatingsystem/${data.id}`); } render() { @@ -127,7 +127,7 @@ export class OsVulnScoreDisplay extends React.Component { OsVulnScoreDisplay.propTypes = { filter: PropTypes.filter, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, }; OsVulnScoreDisplay.displayId = 'os-by-most-vulnerable'; diff --git a/src/web/pages/page.jsx b/src/web/pages/page.jsx index db27412f0e..d9a15ba645 100644 --- a/src/web/pages/page.jsx +++ b/src/web/pages/page.jsx @@ -3,10 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import styled from 'styled-components'; diff --git a/src/web/pages/policies/__tests__/__snapshots__/details.jsx.snap b/src/web/pages/policies/__tests__/__snapshots__/details.jsx.snap index 5b8077164c..384eef093c 100644 --- a/src/web/pages/policies/__tests__/__snapshots__/details.jsx.snap +++ b/src/web/pages/policies/__tests__/__snapshots__/details.jsx.snap @@ -81,13 +81,6 @@ exports[`Policy Details tests > should render full Details 1`] = ` align-items: center; } -.c10 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c9 { margin-left: -5px; } @@ -110,6 +103,13 @@ exports[`Policy Details tests > should render full Details 1`] = ` display: inline-flex; } +.c10 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + .c1 { border: 0; border-spacing: 0px; diff --git a/src/web/pages/reportconfigs/__tests__/__snapshots__/component.jsx.snap b/src/web/pages/reportconfigs/__tests__/__snapshots__/component.jsx.snap index 46cc076154..8652502d54 100644 --- a/src/web/pages/reportconfigs/__tests__/__snapshots__/component.jsx.snap +++ b/src/web/pages/reportconfigs/__tests__/__snapshots__/component.jsx.snap @@ -382,6 +382,55 @@ exports[`Report Config Component tests > should open create dialog and call GMP padding-right: 10px; } +.c14 { + font-family: inherit; + font-size: inherit; + line-height: inherit; + display: block; + height: 22px; + color: #4C4C4C; + background-color: #fff; + background-image: none; + border: 1px solid #bfbfbf; + border-radius: 2px; + padding: 1px 8px; +} + +.c14:-webkit-autofill { + box-shadow: 0 0 0 1000px white inset; +} + +.c15 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: start; + justify-content: start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c16 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; +} + .c23 { background-color: transparent; border: none; @@ -470,15 +519,6 @@ exports[`Report Config Component tests > should open create dialog and call GMP cursor: pointer; } -.c16 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - .c21 { cursor: default; } @@ -490,46 +530,6 @@ exports[`Report Config Component tests > should open create dialog and call GMP display: flex; } -.c14 { - font-family: inherit; - font-size: inherit; - line-height: inherit; - display: block; - height: 22px; - color: #4C4C4C; - background-color: #fff; - background-image: none; - border: 1px solid #bfbfbf; - border-radius: 2px; - padding: 1px 8px; -} - -.c14:-webkit-autofill { - box-shadow: 0 0 0 1000px white inset; -} - -.c15 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; - -webkit-box-pack: start; - -ms-flex-pack: start; - -webkit-justify-content: start; - justify-content: start; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} -
    should render full Details 1`] = ` table-layout: auto; } -.c7 { - vertical-align: top; -} - .c2 td { padding: 4px 4px 4px 0; } @@ -86,6 +82,10 @@ exports[`Report Config Details tests > should render full Details 1`] = ` padding-right: 5px; } +.c7 { + vertical-align: top; +} + .c3 { width: 10%; } @@ -402,10 +402,6 @@ exports[`Report Config Details tests > should render orphaned config details 1`] table-layout: auto; } -.c6 { - vertical-align: top; -} - .c2 td { padding: 4px 4px 4px 0; } @@ -414,6 +410,10 @@ exports[`Report Config Details tests > should render orphaned config details 1`] padding-right: 5px; } +.c6 { + vertical-align: top; +} + .c3 { width: 10%; } diff --git a/src/web/pages/reports/auditdeltadetailspage.jsx b/src/web/pages/reports/auditdeltadetailspage.jsx index 2a65928c1f..09ead8258d 100644 --- a/src/web/pages/reports/auditdeltadetailspage.jsx +++ b/src/web/pages/reports/auditdeltadetailspage.jsx @@ -3,12 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React, {useEffect, useState} from 'react'; import {useDispatch, useSelector, shallowEqual} from 'react-redux'; -import {useRouteMatch} from 'react-router-dom'; +import {useParams} from 'react-router-dom'; import useTranslation from 'web/hooks/useTranslation'; @@ -17,7 +16,7 @@ import logger from 'gmp/log'; import Filter, { ALL_FILTER, RESET_FILTER, - RESULTS_FILTER_FILTER + RESULTS_FILTER_FILTER, } from 'gmp/models/filter'; import {isActive} from 'gmp/models/task'; @@ -114,12 +113,12 @@ const DeltaAuditReportDetails = props => { sortReverse: false, }, }); - + const [_] = useTranslation(); const gmp = useGmp(); const dispatch = useDispatch(); - const match = useRouteMatch(); - const {id: reportId, deltaid: deltaReportId} = match.params; + const params = useParams(); + const {id: reportId, deltaid: deltaReportId} = params; const reportFormatsSel = useSelector(reportFormatsSelector); const reportConfigsSel = useSelector(reportConfigsSelector); @@ -513,9 +512,9 @@ const load = const DeltaAuditReportDetailsWrapper = ({defaultFilter, ...props}) => { const gmp = useGmp(); const dispatch = useDispatch(); - const match = useRouteMatch(); + const params = useParams('/auditreport/delta/:id/:deltaid'); - const {id: reportId, deltaid: deltaReportId} = match.params; + const {id: reportId, deltaid: deltaReportId} = params; const deltaSel = useSelector(deltaAuditReportSelector, shallowEqual); const entity = deltaSel.getEntity(reportId, deltaReportId); const reportFilter = entity?.report?.filter; @@ -562,4 +561,4 @@ DeltaAuditReportDetailsWrapper.propTypes = { export default compose( withDialogNotification, withDownload, -)(DeltaAuditReportDetailsWrapper); \ No newline at end of file +)(DeltaAuditReportDetailsWrapper); diff --git a/src/web/pages/reports/auditdetailspage.jsx b/src/web/pages/reports/auditdetailspage.jsx index b0585d6ffa..73ff234257 100644 --- a/src/web/pages/reports/auditdetailspage.jsx +++ b/src/web/pages/reports/auditdetailspage.jsx @@ -3,12 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React, {useEffect, useState} from 'react'; import {useDispatch, useSelector, shallowEqual} from 'react-redux'; -import {useRouteMatch} from 'react-router-dom'; +import {useParams} from 'react-router-dom'; import useTranslation from 'web/hooks/useTranslation'; @@ -17,7 +16,7 @@ import logger from 'gmp/log'; import Filter, { ALL_FILTER, RESET_FILTER, - RESULTS_FILTER_FILTER + RESULTS_FILTER_FILTER, } from 'gmp/models/filter'; import {isActive} from 'gmp/models/task'; @@ -149,8 +148,8 @@ const ReportDetails = props => { const [_] = useTranslation(); const gmp = useGmp(); const dispatch = useDispatch(); - const match = useRouteMatch(); - const {id: reportId} = match.params; + const params = useParams('/audit/:id'); + const {id: reportId} = params; const pSelector = useSelector(getPage, shallowEqual); const pageFilter = pSelector?.getFilter(getReportPageName(reportId)); @@ -613,7 +612,7 @@ const load = // eslint-disable-next-line no-shadow dispatch, gmp, - match, + params, pageFilter, reportFilter, }) => @@ -637,16 +636,16 @@ const load = // use fallback filter filter = DEFAULT_FILTER; } - dispatch(setPageFilter(getReportPageName(match.params.id), filter)); + dispatch(setPageFilter(getReportPageName(params.id), filter)); return dispatch(loadAuditReportWithThreshold(gmp)(reportId, {filter})); }; const ReportDetailsWrapper = props => { const dispatch = useDispatch(); const gmp = useGmp(); - const match = useRouteMatch(); + const params = useParams(); - const {id: reportId} = match.params; + const {id: reportId} = params; const reportSel = useSelector(auditReportSelector, shallowEqual); const pSelector = useSelector(getPage, shallowEqual); @@ -667,7 +666,7 @@ const ReportDetailsWrapper = props => { ...props, dispatch, gmp, - match, + params, defaultFilter: filter, reportFilter, reportId, @@ -677,7 +676,7 @@ const ReportDetailsWrapper = props => { ...props, dispatch, gmp, - match, + params, defaultFilter: filter, reportFilter, reportId, @@ -702,4 +701,4 @@ const ReportDetailsWrapper = props => { export default compose( withDialogNotification, withDownload, -)(ReportDetailsWrapper); \ No newline at end of file +)(ReportDetailsWrapper); diff --git a/src/web/pages/reports/auditreportslistpage.jsx b/src/web/pages/reports/auditreportslistpage.jsx index b12d3739a0..57949e3490 100644 --- a/src/web/pages/reports/auditreportslistpage.jsx +++ b/src/web/pages/reports/auditreportslistpage.jsx @@ -3,10 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React, {useEffect, useState} from 'react'; -import {useHistory} from 'react-router-dom'; +import {useNavigate} from 'react-router-dom'; import useTranslation from 'web/hooks/useTranslation'; @@ -49,14 +48,14 @@ import AuditReportsDashboard, { const ToolBarIcons = () => { const [_] = useTranslation(); return ( - - - - ) + + + + ); }; const AuditReportsPage = ({ @@ -68,7 +67,7 @@ const AuditReportsPage = ({ }) => { const [selectedDeltaReport, setSelectedDeltaReport] = useState(); const [beforeSelectFilter, setBeforeSelectFilter] = useState(); - const history = useHistory(); + const navigate = useNavigate(); const [_] = useTranslation(); useEffect(() => { @@ -88,7 +87,7 @@ const AuditReportsPage = ({ if (isDefined(selectedDeltaReport)) { onFilterChanged(beforeSelectFilter); - history.push( + navigate( '/auditreport/delta/' + selectedDeltaReport.id + '/' + report.id, ); } else { @@ -144,7 +143,7 @@ const AuditReportsPage = ({ AuditReportsPage.propTypes = { filter: PropTypes.filter, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, onChanged: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, onError: PropTypes.func.isRequired, @@ -162,8 +161,8 @@ const FALLBACK_AUDIT_REPORT_LIST_FILTER = Filter.fromString( ); export default withEntitiesContainer('auditreport', { - fallbackFilter: FALLBACK_AUDIT_REPORT_LIST_FILTER, - entitiesSelector, - loadEntities, - reloadInterval: reportsReloadInterval, - })(AuditReportsPage); \ No newline at end of file + fallbackFilter: FALLBACK_AUDIT_REPORT_LIST_FILTER, + entitiesSelector, + loadEntities, + reloadInterval: reportsReloadInterval, +})(AuditReportsPage); diff --git a/src/web/pages/reports/deltadetailspage.jsx b/src/web/pages/reports/deltadetailspage.jsx index 6a854d3d34..4683940529 100644 --- a/src/web/pages/reports/deltadetailspage.jsx +++ b/src/web/pages/reports/deltadetailspage.jsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; import {connect} from 'react-redux'; @@ -15,7 +14,8 @@ import logger from 'gmp/log'; import Filter, { ALL_FILTER, RESET_FILTER, - RESULTS_FILTER_FILTER} from 'gmp/models/filter'; + RESULTS_FILTER_FILTER, +} from 'gmp/models/filter'; import {isActive} from 'gmp/models/task'; import {first} from 'gmp/utils/array'; @@ -76,6 +76,7 @@ import TargetComponent from '../targets/component'; import Page from './deltadetailscontent'; import FilterDialog from './detailsfilterdialog'; +import {withRouter} from 'web/utils/withRouter'; const log = logger.getLogger('web.pages.report.deltadetailspage'); @@ -99,7 +100,6 @@ const getFilter = (entity = {}) => { class DeltaReportDetails extends React.Component { constructor(...args) { super(...args); - this.state = { activeTab: 0, showFilterDialog: false, @@ -318,7 +318,7 @@ class DeltaReportDetails extends React.Component { includeOverrides, reportConfigId, reportFormatId, - storeAsDefault + storeAsDefault, } = state; const newFilter = reportFilter.copy(); @@ -564,7 +564,6 @@ DeltaReportDetails.propTypes = { loadSettings: PropTypes.func.isRequired, loadTarget: PropTypes.func.isRequired, location: PropTypes.object.isRequired, - match: PropTypes.object.isRequired, reload: PropTypes.func.isRequired, reportComposerDefaults: PropTypes.object, reportExportFileName: PropTypes.string, @@ -605,8 +604,9 @@ const mapDispatchToProps = (dispatch, {gmp}) => { }; }; -const mapStateToProps = (rootState, {match}) => { - const {id, deltaid} = match.params; +const mapStateToProps = (rootState, {params}) => { + const {id, deltaid} = params; + const filterSel = filterSelector(rootState); const deltaSel = deltaReportSelector(rootState); const reportFormatsSel = reportFormatsSelector(rootState); @@ -708,6 +708,7 @@ export default compose( withGmp, withDialogNotification, withDownload, + withRouter, connect(mapStateToProps, mapDispatchToProps), )(DeltaReportDetailsWrapper); diff --git a/src/web/pages/reports/details/toolbaricons.jsx b/src/web/pages/reports/details/toolbaricons.jsx index 7a61def7f5..76554d924c 100644 --- a/src/web/pages/reports/details/toolbaricons.jsx +++ b/src/web/pages/reports/details/toolbaricons.jsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; import _ from 'gmp/locale'; @@ -120,7 +119,7 @@ const ToolBarIcons = ({ end: isDefined(report.scan_end) ? report.scan_end.toISOString() : undefined, - scanner: isDefined(report.slave) ? report.slave.id : undefined, + ...(isDefined(report.slave) && {scanner: report.slave.id}), }} > diff --git a/src/web/pages/reports/detailspage.jsx b/src/web/pages/reports/detailspage.jsx index 63a76527f3..9f56cea385 100644 --- a/src/web/pages/reports/detailspage.jsx +++ b/src/web/pages/reports/detailspage.jsx @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; import {connect} from 'react-redux'; +import {withRouter} from 'web/utils/withRouter'; import _ from 'gmp/locale'; @@ -685,7 +685,6 @@ ReportDetails.propTypes = { loadSettings: PropTypes.func.isRequired, loadTarget: PropTypes.func.isRequired, location: PropTypes.object.isRequired, - match: PropTypes.object.isRequired, pageFilter: PropTypes.filter, reload: PropTypes.func.isRequired, reportComposerDefaults: PropTypes.object, @@ -781,7 +780,7 @@ ReportDetailsWrapper.propTypes = { const getReportPageName = id => `report-${id}`; -const mapDispatchToProps = (dispatch, {gmp, match}) => ({ +const mapDispatchToProps = (dispatch, {gmp, params}) => ({ onInteraction: () => dispatch(renewSessionTimeout(gmp)()), loadFilters: () => dispatch(loadFilters(gmp)(RESULTS_FILTER_FILTER)), loadSettings: () => dispatch(loadUserSettingDefaults(gmp)()), @@ -794,12 +793,11 @@ const mapDispatchToProps = (dispatch, {gmp, match}) => ({ loadReportComposerDefaults: () => dispatch(loadReportComposerDefaults(gmp)()), saveReportComposerDefaults: reportComposerDefaults => dispatch(saveReportComposerDefaults(gmp)(reportComposerDefaults)), - updateFilter: f => - dispatch(setPageFilter(getReportPageName(match.params.id), f)), + updateFilter: f => dispatch(setPageFilter(getReportPageName(params.id), f)), }); -const mapStateToProps = (rootState, {match}) => { - const {id} = match.params; +const mapStateToProps = (rootState, {params}) => { + const {id} = params; const filterSel = filterSelector(rootState); const reportSel = reportSelector(rootState); const reportConfigsSel = reportConfigsSelector(rootState); @@ -847,6 +845,7 @@ export default compose( withGmp, withDialogNotification, withDownload, + withRouter, connect(mapStateToProps, mapDispatchToProps), )(ReportDetailsWrapper); diff --git a/src/web/pages/reports/listpage.jsx b/src/web/pages/reports/listpage.jsx index 946f2a0966..24ef66be9a 100644 --- a/src/web/pages/reports/listpage.jsx +++ b/src/web/pages/reports/listpage.jsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; import {connect} from 'react-redux'; @@ -159,11 +158,13 @@ class Page extends React.Component { const {selectedDeltaReport, beforeSelectFilter} = this.state; if (isDefined(selectedDeltaReport)) { - const {history} = this.props; + const {navigate} = this.props; onFilterChanged(beforeSelectFilter); - history.push('/report/delta/' + selectedDeltaReport.id + '/' + report.id); + navigate('/report/delta/' + selectedDeltaReport.id + '/' + report.id, { + replace: true, + }); } else { const {filter = new Filter()} = this.props; @@ -192,11 +193,8 @@ class Page extends React.Component { render() { const {filter, onFilterChanged, onInteraction, tasks} = this.props; - const { - containerTaskDialogVisible, - importDialogVisible, - task_id, - } = this.state; + const {containerTaskDialogVisible, importDialogVisible, task_id} = + this.state; return ( @@ -252,7 +250,7 @@ class Page extends React.Component { Page.propTypes = { filter: PropTypes.filter, gmp: PropTypes.gmp.isRequired, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, loadTasks: PropTypes.func.isRequired, tasks: PropTypes.arrayOf(PropTypes.model), onChanged: PropTypes.func.isRequired, @@ -284,10 +282,7 @@ const FALLBACK_REPORT_LIST_FILTER = Filter.fromString( export default compose( withGmp, - connect( - mapStateToProps, - mapDispatchToProps, - ), + connect(mapStateToProps, mapDispatchToProps), withEntitiesContainer('report', { fallbackFilter: FALLBACK_REPORT_LIST_FILTER, entitiesSelector, diff --git a/src/web/pages/scanconfigs/__tests__/__snapshots__/details.jsx.snap b/src/web/pages/scanconfigs/__tests__/__snapshots__/details.jsx.snap index 0960b0fddc..339788e5fc 100644 --- a/src/web/pages/scanconfigs/__tests__/__snapshots__/details.jsx.snap +++ b/src/web/pages/scanconfigs/__tests__/__snapshots__/details.jsx.snap @@ -81,13 +81,6 @@ exports[`Scan Config Details tests > should render full Details 1`] = ` align-items: center; } -.c10 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c9 { margin-left: -5px; } @@ -110,6 +103,13 @@ exports[`Scan Config Details tests > should render full Details 1`] = ` display: inline-flex; } +.c10 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + .c1 { border: 0; border-spacing: 0px; diff --git a/src/web/pages/scanconfigs/__tests__/__snapshots__/editdialog.jsx.snap b/src/web/pages/scanconfigs/__tests__/__snapshots__/editdialog.jsx.snap index fa5712f392..f8ce81efb6 100644 --- a/src/web/pages/scanconfigs/__tests__/__snapshots__/editdialog.jsx.snap +++ b/src/web/pages/scanconfigs/__tests__/__snapshots__/editdialog.jsx.snap @@ -281,59 +281,6 @@ exports[`EditScanConfigDialog component tests > should render dialog 1`] = ` width: inherit; } -.c25 { - overflow: hidden; - -webkit-transition: 0.4s; - transition: 0.4s; -} - -.c44 { - overflow: hidden; - -webkit-transition: 0.4s; - transition: 0.4s; - display: none; - height: 0; -} - -.c18 { - margin: 10px 0px; - padding-bottom: 1px; - border-bottom: 2px solid #e5e5e5; - position: relative; -} - -.c19 { - margin: 0 0 1px 0; -} - -.c20 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-pack: start; - -ms-flex-pack: start; - -webkit-justify-content: flex-start; - justify-content: flex-start; - -webkit-align-items: stretch; - -webkit-box-align: stretch; - -ms-flex-align: stretch; - align-items: stretch; -} - -.c22 { - word-break: break-all; - min-width: 100px; -} - -.c23 { - margin-left: 3px; - margin-top: -2px; -} - .c1 { position: relative; display: -webkit-box; @@ -601,90 +548,6 @@ exports[`EditScanConfigDialog component tests > should render dialog 1`] = ` padding-right: 10px; } -.c16 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - -.c27 { - border: 0; - border-spacing: 0px; - font-size: 12px; - text-align: left; - table-layout: auto; - width: 100%; -} - -.c46 { - border: 0; - border-spacing: 0px; - font-size: 12px; - text-align: left; - table-layout: fixed; - width: 100%; -} - -.c28 th, -.c28 td { - padding: 4px 10px; - border-bottom: 1px solid #e5e5e5; -} - -.c28 tfoot tr { - background: #fff; -} - -.c28 tfoot tr td { - border-bottom: 1px solid #e5e5e5; -} - -.c29 a { - -webkit-text-decoration: none; - text-decoration: none; - color: #000; -} - -.c29 a:hover { - -webkit-text-decoration: underline; - text-decoration: underline; - color: #000; -} - -.c30 { - background-color: #fff; - color: #000; - border-top: 1px solid #e5e5e5; - font-weight: bold; -} - -.c31 { - background-color: #fff; - color: #000; - border-top: 1px solid #e5e5e5; - font-weight: bold; - width: 9em; -} - -.c47 { - background-color: #fff; - color: #000; - border-top: 1px solid #e5e5e5; - font-weight: bold; - width: 30%; -} - -.c48 { - background-color: #fff; - color: #000; - border-top: 1px solid #e5e5e5; - font-weight: bold; - width: 10%; -} - .c14 { font-family: inherit; font-size: inherit; @@ -743,6 +606,15 @@ exports[`EditScanConfigDialog component tests > should render dialog 1`] = ` align-items: center; } +.c16 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; +} + .c37 { display: -webkit-inline-box; display: -webkit-inline-flex; @@ -806,6 +678,134 @@ exports[`EditScanConfigDialog component tests > should render dialog 1`] = ` align-items: center; } +.c25 { + overflow: hidden; + -webkit-transition: 0.4s; + transition: 0.4s; +} + +.c44 { + overflow: hidden; + -webkit-transition: 0.4s; + transition: 0.4s; + display: none; + height: 0; +} + +.c18 { + margin: 10px 0px; + padding-bottom: 1px; + border-bottom: 2px solid #e5e5e5; + position: relative; +} + +.c19 { + margin: 0 0 1px 0; +} + +.c20 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + -webkit-align-items: stretch; + -webkit-box-align: stretch; + -ms-flex-align: stretch; + align-items: stretch; +} + +.c22 { + word-break: break-all; + min-width: 100px; +} + +.c23 { + margin-left: 3px; + margin-top: -2px; +} + +.c27 { + border: 0; + border-spacing: 0px; + font-size: 12px; + text-align: left; + table-layout: auto; + width: 100%; +} + +.c46 { + border: 0; + border-spacing: 0px; + font-size: 12px; + text-align: left; + table-layout: fixed; + width: 100%; +} + +.c28 th, +.c28 td { + padding: 4px 10px; + border-bottom: 1px solid #e5e5e5; +} + +.c28 tfoot tr { + background: #fff; +} + +.c28 tfoot tr td { + border-bottom: 1px solid #e5e5e5; +} + +.c29 a { + -webkit-text-decoration: none; + text-decoration: none; + color: #000; +} + +.c29 a:hover { + -webkit-text-decoration: underline; + text-decoration: underline; + color: #000; +} + +.c30 { + background-color: #fff; + color: #000; + border-top: 1px solid #e5e5e5; + font-weight: bold; +} + +.c31 { + background-color: #fff; + color: #000; + border-top: 1px solid #e5e5e5; + font-weight: bold; + width: 9em; +} + +.c47 { + background-color: #fff; + color: #000; + border-top: 1px solid #e5e5e5; + font-weight: bold; + width: 30%; +} + +.c48 { + background-color: #fff; + color: #000; + border-top: 1px solid #e5e5e5; + font-weight: bold; + width: 10%; +} + .c49 { overflow-wrap: break-word; } @@ -2609,6 +2609,19 @@ exports[`EditScanConfigDialog component tests > should render dialog for config height: 100%; } +.c17 { + font-size: 14px; + margin-bottom: 0px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; +} + .c10 { display: -webkit-box; display: -webkit-flex; @@ -2642,15 +2655,6 @@ exports[`EditScanConfigDialog component tests > should render dialog for config padding-right: 10px; } -.c16 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - .c14 { font-family: inherit; font-size: inherit; @@ -2691,17 +2695,13 @@ exports[`EditScanConfigDialog component tests > should render dialog for config align-items: center; } -.c17 { - font-size: 14px; - margin-bottom: 0px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -ms-flex-pack: center; - -webkit-justify-content: center; - justify-content: center; +.c16 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; } @@ -3177,6 +3177,19 @@ exports[`EditScanConfigDialog component tests > should render dialog inline noti height: 100%; } +.c17 { + font-size: 14px; + margin-bottom: 0px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; +} + .c10 { display: -webkit-box; display: -webkit-flex; @@ -3210,15 +3223,6 @@ exports[`EditScanConfigDialog component tests > should render dialog inline noti padding-right: 10px; } -.c16 { - color: #c12c30; - font-weight: bold; - font-size: 19px; - padding-bottom: 1px; - padding-left: 4px; - display: none; -} - .c14 { font-family: inherit; font-size: inherit; @@ -3259,17 +3263,13 @@ exports[`EditScanConfigDialog component tests > should render dialog inline noti align-items: center; } -.c17 { - font-size: 14px; - margin-bottom: 0px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: center; - -ms-flex-pack: center; - -webkit-justify-content: center; - justify-content: center; +.c16 { + color: #c12c30; + font-weight: bold; + font-size: 19px; + padding-bottom: 1px; + padding-left: 4px; + display: none; } diff --git a/src/web/pages/tasks/__tests__/__snapshots__/autodeletereportsgroup.jsx.snap b/src/web/pages/tasks/__tests__/__snapshots__/autodeletereportsgroup.jsx.snap index 12fe4743ae..d828689415 100644 --- a/src/web/pages/tasks/__tests__/__snapshots__/autodeletereportsgroup.jsx.snap +++ b/src/web/pages/tasks/__tests__/__snapshots__/autodeletereportsgroup.jsx.snap @@ -37,28 +37,6 @@ exports[`AutoDeleteReportsGroup tests > should render dialog group 1`] = ` align-items: center; } -.c7 { - margin-left: -5px; -} - -.c7>* { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - -.c7>* { - margin-left: 5px; -} - -.c6 { - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; -} - .c0 { display: -webkit-box; display: -webkit-flex; @@ -92,6 +70,28 @@ exports[`AutoDeleteReportsGroup tests > should render dialog group 1`] = ` padding-right: 10px; } +.c7 { + margin-left: -5px; +} + +.c7>* { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c7>* { + margin-left: 5px; +} + +.c6 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + .c4 { display: -webkit-inline-box; display: -webkit-inline-flex; diff --git a/src/web/pages/tasks/__tests__/__snapshots__/details.jsx.snap b/src/web/pages/tasks/__tests__/__snapshots__/details.jsx.snap index e743288e07..d88ca107ed 100644 --- a/src/web/pages/tasks/__tests__/__snapshots__/details.jsx.snap +++ b/src/web/pages/tasks/__tests__/__snapshots__/details.jsx.snap @@ -59,35 +59,48 @@ exports[`Task Details tests > should render full task details 1`] = ` align-items: center; } -.c2 { +.c5 { + margin-left: -5px; +} + +.c5>* { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } -.c5 { - margin-left: -5px; +.c5>* { + margin-left: 5px; } -.c5>* { +.c4 { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } -.c5>* { +.c6>*:not(:last-child)::after { + content: '•'; margin-left: 5px; } -.c4 { +.c2 { display: -webkit-inline-box; display: -webkit-inline-flex; display: -ms-inline-flexbox; display: inline-flex; } +.c9 { + width: 10%; +} + +.c10 { + width: 90%; +} + .c7 { border: 0; border-spacing: 0px; @@ -97,11 +110,6 @@ exports[`Task Details tests > should render full task details 1`] = ` width: 100%; } -.c6>*:not(:last-child)::after { - content: '•'; - margin-left: 5px; -} - .c8 td { padding: 4px 4px 4px 0; } @@ -110,14 +118,6 @@ exports[`Task Details tests > should render full task details 1`] = ` padding-right: 5px; } -.c9 { - width: 10%; -} - -.c10 { - width: 90%; -} - @media print { .c7 { border-collapse: collapse; diff --git a/src/web/pages/tasks/dashboard/highresults.jsx b/src/web/pages/tasks/dashboard/highresults.jsx index 34a43c8b2a..9190c8009b 100644 --- a/src/web/pages/tasks/dashboard/highresults.jsx +++ b/src/web/pages/tasks/dashboard/highresults.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import {format as d3format} from 'd3-format'; @@ -73,9 +73,9 @@ export class TasksHighResultsDisplay extends React.Component { } handleDataClick(data) { - const {history} = this.props; + const {navigate} = this.props; - history.push(`/task/${data.id}`); + navigate(`/task/${data.id}`); } render() { @@ -109,7 +109,7 @@ export class TasksHighResultsDisplay extends React.Component { TasksHighResultsDisplay.propTypes = { filter: PropTypes.filter, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, }; TasksHighResultsDisplay = compose( diff --git a/src/web/pages/tasks/dashboard/mosthighresults.jsx b/src/web/pages/tasks/dashboard/mosthighresults.jsx index 2fbe5bf242..3e827ed1bf 100644 --- a/src/web/pages/tasks/dashboard/mosthighresults.jsx +++ b/src/web/pages/tasks/dashboard/mosthighresults.jsx @@ -5,7 +5,7 @@ import React from 'react'; -import {withRouter} from 'react-router-dom'; +import {withRouter} from 'web/utils/withRouter'; import {format as d3format} from 'd3-format'; @@ -66,9 +66,9 @@ export class TasksMostHighResultsDisplay extends React.Component { } handleDataClick(data) { - const {history} = this.props; + const {navigate} = this.props; - history.push(`/task/${data.id}`); + navigate(`/task/${data.id}`); } render() { @@ -107,7 +107,7 @@ export class TasksMostHighResultsDisplay extends React.Component { TasksMostHighResultsDisplay.propTypes = { filter: PropTypes.filter, - history: PropTypes.object.isRequired, + navigate: PropTypes.func.isRequired, }; TasksMostHighResultsDisplay = compose( diff --git a/src/web/pages/tasks/detailspage.jsx b/src/web/pages/tasks/detailspage.jsx index 4cf49ebf50..b44518cbb4 100644 --- a/src/web/pages/tasks/detailspage.jsx +++ b/src/web/pages/tasks/detailspage.jsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ - import React from 'react'; import _ from 'gmp/locale'; @@ -182,18 +181,19 @@ export const ToolBarIcons = ({ )} - {!isDefined(entity.current_report) && isDefined(entity.last_report) && ( - - - - )} + {!isDefined(entity.current_report) && + isDefined(entity.last_report) && ( + + + + )} - qhistory(history, stringify, parse); +const LoggedOutRoutes = () => ( + + } /> + } /> + } /> + +); -const HISTORY = createQueryHistory(); +const LoggedInRoutes = () => { + return ( + + + + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + } /> + } /> + } /> + } + /> + } /> + } + /> + } + /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } + /> + } /> -const Routes = () => ( - - - - - - - - - - + } /> + + } + /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + } + /> + + } + /> + } /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + } /> + + + + + ); +}; - - - - - - - - -); +const AppRoutes = () => { + const isLoggedIn = useSelector(selectIsLoggedIn); -Routes.propTypes = { - gmp: PropTypes.gmp.isRequired, + return ( + {isLoggedIn ? : } + ); }; -export default withGmp(Routes); - -// vim: set ts=2 sw=2 tw=80: +export default AppRoutes; diff --git a/src/web/utils/testing.jsx b/src/web/utils/testing.jsx index 626b33b3dc..788f70f2d8 100644 --- a/src/web/utils/testing.jsx +++ b/src/web/utils/testing.jsx @@ -22,14 +22,13 @@ import { within, renderHook as rtlRenderHook, } from '@testing-library/react/pure'; + import userEvent from '@testing-library/user-event'; -import {Router} from 'react-router-dom'; +import {BrowserRouter} from 'react-router-dom'; import {Provider} from 'react-redux'; -import {createMemoryHistory} from 'history'; - import EverythingCapabilities from 'gmp/capabilities/everything'; import {hasValue, isDefined} from 'gmp/utils/identity'; @@ -38,7 +37,6 @@ import GmpContext from 'web/components/provider/gmpprovider'; import CapabilitiesContext from 'web/components/provider/capabilitiesprovider'; import LicenseProvider from 'web/components/provider/licenseprovider'; -import {createQueryHistory} from 'web/routes'; import configureStore from 'web/store'; import {StyleSheetManager} from 'styled-components'; @@ -116,7 +114,6 @@ const withProvider = const TestingGmpProvider = withProvider('gmp', 'value')(GmpContext.Provider); const TestingStoreProvider = withProvider('store')(Provider); -const TestingRouter = withProvider('history')(Router); const TestingCapabilitiesProvider = withProvider( 'capabilities', 'value', @@ -136,11 +133,6 @@ export const rendererWith = ( store = configureStore({testing: true}); } - let history; - if (router === true) { - history = createQueryHistory(createMemoryHistory({initialEntries: ['/']})); - } - if (capabilities === true) { capabilities = new EverythingCapabilities(); } @@ -150,7 +142,11 @@ export const rendererWith = ( - {children} + {router ? ( + {children} + ) : ( + children + )} @@ -163,7 +159,6 @@ export const rendererWith = ( render: ui => render({ui}), gmp, store, - history, renderHook: hook => rtlRenderHook(hook, {wrapper}), }; }; diff --git a/src/web/utils/withRouter.jsx b/src/web/utils/withRouter.jsx new file mode 100644 index 0000000000..b97f0c0679 --- /dev/null +++ b/src/web/utils/withRouter.jsx @@ -0,0 +1,25 @@ +/* SPDX-FileCopyrightText: 2024 Greenbone AG + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import {useLocation, useNavigate, useParams} from 'react-router-dom'; + +export const withRouter = Component => { + function ComponentWithRouterProp(props) { + let location = useLocation(); + let navigate = useNavigate(); + let params = useParams(); + + return ( + + ); + } + + return ComponentWithRouterProp; +};