diff --git a/.storybook/Container.js b/.storybook/Container.js
index 102d2a20c..f9de34b11 100644
--- a/.storybook/Container.js
+++ b/.storybook/Container.js
@@ -14,7 +14,8 @@ limitations under the License.
import React from 'react';
import { IntlProvider } from 'react-intl';
import { createMemoryHistory } from 'history';
-import { Router, Route } from 'react-router-dom';
+import { Router, Switch } from 'react-router-dom';
+import { CompatRoute, CompatRouter } from 'react-router-dom-v5-compat';
import messages from '../src/nls/messages_en.json';
@@ -31,11 +32,15 @@ export default function Container({
{notes &&
{notes}
}
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 3b17dc057..686f52415 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,6 +35,7 @@
"react-hot-loader": "^4.13.0",
"react-intl": "^6.2.1",
"react-router-dom": "^5.3.4",
+ "react-router-dom-v5-compat": "^6.4.2",
"reconnecting-websocket": "^4.4.0"
},
"devDependencies": {
@@ -4379,6 +4380,14 @@
"node": ">= 8"
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz",
+ "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.24.38",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.38.tgz",
@@ -20174,7 +20183,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
- "dev": true,
"dependencies": {
"@babel/runtime": "^7.7.6"
}
@@ -28795,6 +28803,37 @@
"react": ">=15"
}
},
+ "node_modules/react-router-dom-v5-compat": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom-v5-compat/-/react-router-dom-v5-compat-6.4.2.tgz",
+ "integrity": "sha512-tsod/xR3XOuOM3ncIzaiGHfaO0lf4W5ZIwRX+c9n6x2pJiiZHm2SkTfivD913G1ZobaAW7WDQgIw5ZCIxeMIyA==",
+ "dependencies": {
+ "history": "^5.3.0",
+ "react-router": "6.4.2"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8",
+ "react-router-dom": "4 || 5"
+ }
+ },
+ "node_modules/react-router-dom-v5-compat/node_modules/react-router": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz",
+ "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==",
+ "dependencies": {
+ "@remix-run/router": "1.0.2"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
"node_modules/react-router-dom/node_modules/history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
@@ -37244,6 +37283,11 @@
}
}
},
+ "@remix-run/router": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.2.tgz",
+ "integrity": "sha512-GRSOFhJzjGN+d4sKHTMSvNeUPoZiDHWmRnXfzaxrqe7dE/Nzlc8BiMSJdLDESZlndM7jIUrZ/F4yWqVYlI0rwQ=="
+ },
"@sinclair/typebox": {
"version": "0.24.38",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.38.tgz",
@@ -49477,7 +49521,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
- "dev": true,
"requires": {
"@babel/runtime": "^7.7.6"
}
@@ -56134,6 +56177,25 @@
}
}
},
+ "react-router-dom-v5-compat": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/react-router-dom-v5-compat/-/react-router-dom-v5-compat-6.4.2.tgz",
+ "integrity": "sha512-tsod/xR3XOuOM3ncIzaiGHfaO0lf4W5ZIwRX+c9n6x2pJiiZHm2SkTfivD913G1ZobaAW7WDQgIw5ZCIxeMIyA==",
+ "requires": {
+ "history": "^5.3.0",
+ "react-router": "6.4.2"
+ },
+ "dependencies": {
+ "react-router": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.2.tgz",
+ "integrity": "sha512-Rb0BAX9KHhVzT1OKhMvCDMw776aTYM0DtkxqUBP8dNBom3mPXlfNs76JNGK8wKJ1IZEY1+WGj+cvZxHVk/GiKw==",
+ "requires": {
+ "@remix-run/router": "1.0.2"
+ }
+ }
+ }
+ },
"react-syntax-highlighter": {
"version": "15.5.0",
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
diff --git a/package.json b/package.json
index 8cd1c005c..15875b6f8 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"react-hot-loader": "^4.13.0",
"react-intl": "^6.2.1",
"react-router-dom": "^5.3.4",
+ "react-router-dom-v5-compat": "^6.4.2",
"reconnecting-websocket": "^4.4.0"
},
"devDependencies": {
diff --git a/packages/components/src/components/PageErrorBoundary/PageErrorBoundary.js b/packages/components/src/components/PageErrorBoundary/PageErrorBoundary.js
index e040d1bd0..f7e2faf4b 100644
--- a/packages/components/src/components/PageErrorBoundary/PageErrorBoundary.js
+++ b/packages/components/src/components/PageErrorBoundary/PageErrorBoundary.js
@@ -13,7 +13,7 @@ limitations under the License.
import React from 'react';
import { useIntl } from 'react-intl';
-import { useLocation } from 'react-router-dom';
+import { useLocation } from 'react-router-dom-v5-compat';
import { ErrorBoundary } from '..';
diff --git a/packages/components/src/utils/test.js b/packages/components/src/utils/test.js
index d5608d0f8..81af48550 100644
--- a/packages/components/src/utils/test.js
+++ b/packages/components/src/utils/test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -12,18 +12,23 @@ limitations under the License.
*/
/* istanbul ignore file */
import React from 'react';
-import { BrowserRouter, Route } from 'react-router-dom';
+import { BrowserRouter, Switch } from 'react-router-dom';
+import { CompatRoute, CompatRouter } from 'react-router-dom-v5-compat';
import { render as baseRender } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
function RouterWrapper({ children, path }) {
return (
-
-
- {children}
-
-
+
+
+
+
+ {children}
+
+
+
+
);
}
diff --git a/packages/utils/src/utils/index.js b/packages/utils/src/utils/index.js
index 9b8315e28..267ef60e1 100644
--- a/packages/utils/src/utils/index.js
+++ b/packages/utils/src/utils/index.js
@@ -243,16 +243,16 @@ export function getFilters({ search }) {
return filters;
}
-export function getAddFilterHandler({ history, location }) {
+export function getAddFilterHandler({ location, navigate }) {
return function handleAddFilter(labelFilters) {
const queryParams = new URLSearchParams(location.search);
queryParams.set('labelSelector', labelFilters);
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
};
}
-export function getDeleteFilterHandler({ history, location }) {
+export function getDeleteFilterHandler({ location, navigate }) {
return function handleDeleteFilter(filter) {
const queryParams = new URLSearchParams(location.search);
const labelFilters = queryParams.getAll('labelSelector');
@@ -269,16 +269,16 @@ export function getDeleteFilterHandler({ history, location }) {
const browserURL = location.pathname.concat(
queryString ? `?${queryString}` : ''
);
- history.push(browserURL);
+ navigate(browserURL);
};
}
-export function getClearFiltersHandler({ history, location }) {
+export function getClearFiltersHandler({ location, navigate }) {
return function handleClearFilters() {
const queryParams = new URLSearchParams(location.search);
queryParams.delete('labelSelector');
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
};
}
@@ -299,7 +299,7 @@ export function getStatusFilter({ search }) {
return status;
}
-export function getStatusFilterHandler({ history, location }) {
+export function getStatusFilterHandler({ location, navigate }) {
return function setStatusFilter(statusFilter) {
const queryParams = new URLSearchParams(location.search);
if (!statusFilter) {
@@ -308,7 +308,7 @@ export function getStatusFilterHandler({ history, location }) {
queryParams.set('status', statusFilter);
}
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
};
}
diff --git a/packages/utils/src/utils/index.test.js b/packages/utils/src/utils/index.test.js
index 301bca142..207a71f1f 100644
--- a/packages/utils/src/utils/index.test.js
+++ b/packages/utils/src/utils/index.test.js
@@ -218,12 +218,12 @@ it('getFilters', () => {
it('getAddFilterHandler', () => {
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search: '?nonFilterQueryParam=someValue' };
- const handleAddFilter = getAddFilterHandler({ history, location });
+ const handleAddFilter = getAddFilterHandler({ location, navigate });
const labelFilters = ['foo1=bar1', 'foo2=bar2'];
handleAddFilter(labelFilters);
- expect(history.push).toHaveBeenCalledWith(
+ expect(navigate).toHaveBeenCalledWith(
`${url}?nonFilterQueryParam=someValue&labelSelector=${encodeURIComponent(
'foo1=bar1,foo2=bar2'
)}`
@@ -234,14 +234,14 @@ describe('getDeleteFilterHandler', () => {
it('should redirect to unfiltered URL if no filters remain', () => {
const search = `?labelSelector=${encodeURIComponent('foo=bar')}`;
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search };
const handleDeleteFilter = getDeleteFilterHandler({
- history,
- location
+ location,
+ navigate
});
handleDeleteFilter('foo=bar');
- expect(history.push).toHaveBeenCalledWith(url);
+ expect(navigate).toHaveBeenCalledWith(url);
});
it('should correctly remove a filter from the URL', () => {
@@ -249,14 +249,14 @@ describe('getDeleteFilterHandler', () => {
'foo1=bar1,foo2=bar2'
)}`;
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search };
const handleDeleteFilter = getDeleteFilterHandler({
- history,
- location
+ location,
+ navigate
});
handleDeleteFilter('foo1=bar1');
- expect(history.push).toHaveBeenCalledWith(
+ expect(navigate).toHaveBeenCalledWith(
`${url}?labelSelector=${encodeURIComponent('foo2=bar2')}`
);
});
@@ -490,14 +490,14 @@ describe('getStatusFilter', () => {
'foo1=bar1,foo2=bar2'
)}`;
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search };
const handleDeleteFilter = getDeleteFilterHandler({
- history,
- location
+ location,
+ navigate
});
handleDeleteFilter('foo1=bar1');
- expect(history.push).toHaveBeenCalledWith(
+ expect(navigate).toHaveBeenCalledWith(
`${url}?labelSelector=${encodeURIComponent('foo2=bar2')}`
);
});
@@ -507,47 +507,47 @@ describe('getStatusFilterHandler', () => {
it('should redirect to unfiltered URL if no status specified', () => {
const search = '?nonFilterQueryParam=someValue&status=cancelled';
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search };
const setStatusFilter = getStatusFilterHandler({
- history,
- location
+ location,
+ navigate
});
setStatusFilter('');
- expect(history.push).toHaveBeenCalledWith(
+ expect(navigate).toHaveBeenCalledWith(
`${url}?nonFilterQueryParam=someValue`
);
});
it('should set a valid status filter in the URL', () => {
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = {
pathname: url,
search: '?nonFilterQueryParam=someValue'
};
const setStatusFilter = getStatusFilterHandler({
- history,
- location
+ location,
+ navigate
});
const statusFilter = 'cancelled';
setStatusFilter(statusFilter);
- expect(history.push).toHaveBeenCalledWith(
+ expect(navigate).toHaveBeenCalledWith(
`${url}?nonFilterQueryParam=someValue&status=${statusFilter}`
);
});
it('should update the status filter in the URL', () => {
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search: '?status=cancelled' };
const setStatusFilter = getStatusFilterHandler({
- history,
- location
+ location,
+ navigate
});
const statusFilter = 'completed';
setStatusFilter(statusFilter);
- expect(history.push).toHaveBeenCalledWith(`${url}?status=${statusFilter}`);
+ expect(navigate).toHaveBeenCalledWith(`${url}?status=${statusFilter}`);
});
});
diff --git a/packages/utils/src/utils/router.js b/packages/utils/src/utils/router.js
index 0d42a87c6..988536158 100644
--- a/packages/utils/src/utils/router.js
+++ b/packages/utils/src/utils/router.js
@@ -10,7 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-import { generatePath } from 'react-router-dom';
+import { generatePath } from 'react-router-dom-v5-compat';
function byNamespace({ path = '' } = {}) {
return `/namespaces/:namespace${path}`;
diff --git a/packages/utils/src/utils/router.test.js b/packages/utils/src/utils/router.test.js
index 69d3d0f84..5d2a943e6 100644
--- a/packages/utils/src/utils/router.test.js
+++ b/packages/utils/src/utils/router.test.js
@@ -10,7 +10,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-import { generatePath } from 'react-router-dom';
+import { generatePath } from 'react-router-dom-v5-compat';
import { paths, urls } from './router';
const clusterInterceptorName = 'fake_clusterInterceptorName';
diff --git a/src/containers/App/App.js b/src/containers/App/App.js
index bc4e62eaa..fd5c18d0e 100644
--- a/src/containers/App/App.js
+++ b/src/containers/App/App.js
@@ -14,14 +14,13 @@ limitations under the License.
import React, { useEffect, useMemo, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { hot } from 'react-hot-loader/root';
+import { Link, Redirect, HashRouter as Router, Switch } from 'react-router-dom';
import {
- Link,
- Redirect,
+ CompatRoute,
+ CompatRouter,
Route,
- HashRouter as Router,
- Switch
-} from 'react-router-dom';
-
+ Routes
+} from 'react-router-dom-v5-compat';
import { IntlProvider, useIntl } from 'react-intl';
import { Content, InlineNotification } from 'carbon-components-react';
@@ -210,6 +209,20 @@ export function App({ lang }) {
[namespacedMatch, selectedNamespace]
);
+ const header = (
+ {
+ setIsSideNavExpanded(prevIsSideNavExpanded => !prevIsSideNavExpanded);
+ }}
+ >
+
+
+ );
+
return (
}
{!showLoadingState && (
- <>
-
- {() => (
- <>
- {
- setIsSideNavExpanded(
- prevIsSideNavExpanded => !prevIsSideNavExpanded
- );
- }}
- >
-
-
-
- >
- )}
-
-
-
-
-
- }
- />
- (
+
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
- (
+
+
- )}
- />
-
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
-
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
-
-
-
-
-
-
-
-
-
-
-
-
- (
+
+
+
+
+
+
+
+
+
+
+
- )}
- />
-
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
-
-
-
-
-
-
- (
-
+
+
+
+
+
+
+
+
+
- )}
- />
- (
+
+
- )}
- />
- (
+
+
- )}
- />
-
-
-
-
-
-
- {extensions
- .filter(extension => !extension.type)
- .map(({ displayName, name, source }) => (
-
-
-
- ))}
-
- (
-
+
+
+
+
+
+
+
+ {extensions
+ .filter(extension => !extension.type)
+ .map(({ displayName, name, source }) => (
+
+
+
+ ))}
+
+
- )}
- />
-
-
-
- (
+
+
+
+
+
- )}
- />
- (
+
+
- )}
- />
- (
-
+
+
+
- )}
- />
-
-
-
-
-
-
-
-
- >
+
+
+
+
+
+
+
+
+ >
+
)}
diff --git a/src/containers/ClusterInterceptors/ClusterInterceptors.js b/src/containers/ClusterInterceptors/ClusterInterceptors.js
index 913ed893a..42ed82525 100644
--- a/src/containers/ClusterInterceptors/ClusterInterceptors.js
+++ b/src/containers/ClusterInterceptors/ClusterInterceptors.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { Link, useLocation } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
diff --git a/src/containers/ClusterInterceptors/ClusterInterceptors.test.js b/src/containers/ClusterInterceptors/ClusterInterceptors.test.js
index 6781d78e6..e8d707acf 100644
--- a/src/containers/ClusterInterceptors/ClusterInterceptors.test.js
+++ b/src/containers/ClusterInterceptors/ClusterInterceptors.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2021 The Tekton Authors
+Copyright 2021-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -12,7 +12,7 @@ limitations under the License.
*/
import React from 'react';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import { renderWithRouter } from '../../utils/test';
import * as API from '../../api/clusterInterceptors';
@@ -34,6 +34,7 @@ describe('ClusterInterceptors', () => {
.spyOn(API, 'useClusterInterceptors')
.mockImplementation(() => ({ isLoading: true }));
const { queryByText } = renderWithRouter(, {
+ path: paths.clusterInterceptors.all(),
route: urls.clusterInterceptors.all()
});
expect(queryByText('ClusterInterceptors')).toBeTruthy();
@@ -44,6 +45,7 @@ describe('ClusterInterceptors', () => {
.spyOn(API, 'useClusterInterceptors')
.mockImplementation(() => ({ data: [clusterInterceptor] }));
const { queryByText } = renderWithRouter(, {
+ path: paths.clusterInterceptors.all(),
route: urls.clusterInterceptors.all()
});
@@ -56,6 +58,7 @@ describe('ClusterInterceptors', () => {
.spyOn(API, 'useClusterInterceptors')
.mockImplementation(() => ({ error }));
const { queryByText } = renderWithRouter(, {
+ path: paths.clusterInterceptors.all(),
route: urls.clusterInterceptors.all()
});
diff --git a/src/containers/ClusterTasks/ClusterTasks.js b/src/containers/ClusterTasks/ClusterTasks.js
index e9274b9a4..1661bef03 100644
--- a/src/containers/ClusterTasks/ClusterTasks.js
+++ b/src/containers/ClusterTasks/ClusterTasks.js
@@ -13,7 +13,8 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { Link, useLocation } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import keyBy from 'lodash.keyby';
import {
diff --git a/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.js b/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.js
index eb826e079..86a602e8e 100644
--- a/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.js
+++ b/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.js
@@ -13,7 +13,11 @@ limitations under the License.
/* istanbul ignore file */
import React from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { ResourceDetails, Table } from '@tektoncd/dashboard-components';
import { useTitleSync } from '@tektoncd/dashboard-utils';
@@ -22,8 +26,8 @@ import { getViewChangeHandler } from '../../utils';
export function ClusterTriggerBindingContainer() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { clusterTriggerBindingName } = params;
@@ -74,7 +78,7 @@ export function ClusterTriggerBindingContainer() {
diff --git a/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.test.js b/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.test.js
index aaf783c54..5f442c39c 100644
--- a/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.test.js
+++ b/src/containers/ClusterTriggerBinding/ClusterTriggerBinding.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2020-2021 The Tekton Authors
+Copyright 2020-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -14,7 +14,7 @@ limitations under the License.
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { createIntl } from 'react-intl';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import * as API from '../../api/clusterTriggerBindings';
import { renderWithRouter } from '../../utils/test';
@@ -101,6 +101,7 @@ it('ClusterTriggerBindingContainer renders YAML', async () => {
const { getByText } = renderWithRouter(
,
{
+ path: paths.clusterTriggerBindings.byName(),
route: urls.clusterTriggerBindings.byName({
clusterTriggerBindingName
})
diff --git a/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.js b/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.js
index b556987d5..45d8d6af2 100644
--- a/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.js
+++ b/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { Link, useLocation } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
diff --git a/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.test.js b/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.test.js
index 05de020e6..f752a7dfa 100644
--- a/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.test.js
+++ b/src/containers/ClusterTriggerBindings/ClusterTriggerBindings.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2020-2021 The Tekton Authors
+Copyright 2020-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -35,6 +35,7 @@ it('ClusterTriggerBindings renders with no bindings', () => {
}));
const { getByText } = renderWithRouter(, {
+ path: '/clustertriggerbindings',
route: '/clustertriggerbindings'
});
@@ -48,6 +49,7 @@ it('ClusterTriggerBindings renders with one binding', () => {
.mockImplementation(() => ({ data: [clusterTriggerBinding] }));
const { queryByText } = renderWithRouter(, {
+ path: '/clustertriggerbindings',
route: '/clustertriggerbindings'
});
@@ -65,6 +67,7 @@ it('ClusterTriggerBindings can be filtered on a single label filter', async () =
const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
,
{
+ path: '/clustertriggerbindings',
route: '/clustertriggerbindings'
}
);
@@ -84,6 +87,7 @@ it('ClusterTriggerBindings renders in loading state', () => {
.mockImplementation(() => ({ isLoading: true }));
const { queryByText } = renderWithRouter(, {
+ path: '/clustertriggerbindings',
route: '/clustertriggerbindings'
});
@@ -99,6 +103,7 @@ it('ClusterTriggerBindings renders in error state', () => {
.mockImplementation(() => ({ error }));
const { queryByText } = renderWithRouter(, {
+ path: '/clustertriggerbindings',
route: '/clustertriggerbindings'
});
diff --git a/src/containers/CreatePipelineResource/CreatePipelineResource.js b/src/containers/CreatePipelineResource/CreatePipelineResource.js
index f988a89c9..b72561189 100644
--- a/src/containers/CreatePipelineResource/CreatePipelineResource.js
+++ b/src/containers/CreatePipelineResource/CreatePipelineResource.js
@@ -12,7 +12,7 @@ limitations under the License.
*/
import React, { useState } from 'react';
-import { useHistory } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { Button, InlineNotification } from 'carbon-components-react';
import {
@@ -53,7 +53,7 @@ function validateInputs(value, id) {
export /* istanbul ignore next */ function CreatePipelineResource() {
const intl = useIntl();
- const history = useHistory();
+ const navigate = useNavigate();
const { selectedNamespace: defaultNamespace } = useSelectedNamespace();
const [creating, setCreating] = useState(false);
const [gitSource, setGitSource] = useState(true);
@@ -75,7 +75,7 @@ export /* istanbul ignore next */ function CreatePipelineResource() {
});
function handleClose() {
- history.push(urls.pipelineResources.all());
+ navigate(urls.pipelineResources.all());
}
function resetError() {
@@ -166,7 +166,7 @@ export /* istanbul ignore next */ function CreatePipelineResource() {
createPipelineResource({ namespace, resource })
.then(() => {
- history.push(urls.pipelineResources.byNamespace({ namespace }));
+ navigate(urls.pipelineResources.byNamespace({ namespace }));
})
.catch(error => {
error.response.text().then(text => {
diff --git a/src/containers/CreatePipelineResource/CreatePipelineResource.test.js b/src/containers/CreatePipelineResource/CreatePipelineResource.test.js
index 32a669954..c74981cee 100644
--- a/src/containers/CreatePipelineResource/CreatePipelineResource.test.js
+++ b/src/containers/CreatePipelineResource/CreatePipelineResource.test.js
@@ -13,9 +13,9 @@ limitations under the License.
import React from 'react';
import { fireEvent } from '@testing-library/react';
-import { ALL_NAMESPACES, urls } from '@tektoncd/dashboard-utils';
+import { ALL_NAMESPACES, paths, urls } from '@tektoncd/dashboard-utils';
-import { render, renderWithRouter } from '../../utils/test';
+import { renderWithRouter } from '../../utils/test';
import CreatePipelineResource from '.';
import * as API from '../../api';
import * as APIUtils from '../../api/utils';
@@ -31,7 +31,7 @@ describe('CreatePipelineResource', () => {
});
it('renders blank', () => {
- const { queryByText } = render();
+ const { queryByText } = renderWithRouter();
expect(queryByText('Create PipelineResource')).toBeTruthy();
expect(queryByText('Cancel')).toBeTruthy();
expect(queryByText('Create')).toBeTruthy();
@@ -42,6 +42,7 @@ describe('CreatePipelineResource', () => {
jest.spyOn(window.history, 'pushState');
const { queryByText } = renderWithRouter(, {
+ path: paths.pipelineResources.create(),
route: urls.pipelineResources.create()
});
fireEvent.click(queryByText(/cancel/i));
@@ -59,7 +60,7 @@ describe('CreatePipelineResource', () => {
const revisionValidationErrorRegExp = /Revision required/i;
it('validates all empty inputs', () => {
- const { queryByText } = render();
+ const { queryByText } = renderWithRouter();
fireEvent.click(queryByText('Create'));
expect(queryByText(nameValidationErrorMsgRegExp)).toBeTruthy();
expect(queryByText(namespaceValidationErrorRegExp)).toBeTruthy();
@@ -68,7 +69,7 @@ describe('CreatePipelineResource', () => {
});
it('errors when name starts with a "-"', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -82,7 +83,7 @@ describe('CreatePipelineResource', () => {
});
it('errors when name ends with a "-"', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -96,7 +97,7 @@ describe('CreatePipelineResource', () => {
});
it('errors when name ends with a "."', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -110,7 +111,7 @@ describe('CreatePipelineResource', () => {
});
it('errors when name contains spaces', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -124,7 +125,7 @@ describe('CreatePipelineResource', () => {
});
it('errors when name contains capital letters', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -138,7 +139,7 @@ describe('CreatePipelineResource', () => {
});
it('doesn\'t error when contains "-" or "." in the middle of the name', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -152,7 +153,7 @@ describe('CreatePipelineResource', () => {
});
it("doesn't error when name contains number", () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -166,7 +167,7 @@ describe('CreatePipelineResource', () => {
});
it('errors when name contains 64 characters', () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -183,7 +184,7 @@ describe('CreatePipelineResource', () => {
});
it("doesn't error when name contains 63 characters", () => {
- const { queryByText, getByPlaceholderText } = render(
+ const { queryByText, getByPlaceholderText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -199,7 +200,7 @@ describe('CreatePipelineResource', () => {
});
it("doesn't error when contains a valid namespace", () => {
- const { queryByText, getByPlaceholderText, getByText } = render(
+ const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -215,7 +216,7 @@ describe('CreatePipelineResource', () => {
});
it("doesn't error when a url is entered", () => {
- const { queryByText, getByPlaceholderText, getByText } = render(
+ const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -236,7 +237,7 @@ describe('CreatePipelineResource', () => {
});
it("doesn't error when a revision is entered", () => {
- const { queryByText, getByPlaceholderText, getByText } = render(
+ const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
@@ -257,7 +258,7 @@ describe('CreatePipelineResource', () => {
});
it('handles type change', () => {
- const { queryByText, getByPlaceholderText, getByText } = render(
+ const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
);
fireEvent.change(getByPlaceholderText(/pipeline-resource-name/i), {
diff --git a/src/containers/CreatePipelineResource/CreatePipelineResourceErrorNotification.test.js b/src/containers/CreatePipelineResource/CreatePipelineResourceErrorNotification.test.js
index 331c28345..95791cd8a 100644
--- a/src/containers/CreatePipelineResource/CreatePipelineResourceErrorNotification.test.js
+++ b/src/containers/CreatePipelineResource/CreatePipelineResourceErrorNotification.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2020-2021 The Tekton Authors
+Copyright 2020-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -12,7 +12,7 @@ limitations under the License.
*/
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
-import { render } from '../../utils/test';
+import { renderWithRouter } from '../../utils/test';
import CreatePipelineResource from '.';
import * as API from '../../api';
@@ -29,7 +29,7 @@ it('CreatePipelineResource error notification appears', async () => {
.spyOn(PipelineResourcesAPI, 'createPipelineResource')
.mockImplementation(() => Promise.reject(errorResponseMock));
- const { getByPlaceholderText, getByText, queryByText } = render(
+ const { getByPlaceholderText, getByText, queryByText } = renderWithRouter(
);
diff --git a/src/containers/CreatePipelineRun/CreatePipelineRun.js b/src/containers/CreatePipelineRun/CreatePipelineRun.js
index fdb2b25d8..b864934dd 100644
--- a/src/containers/CreatePipelineRun/CreatePipelineRun.js
+++ b/src/containers/CreatePipelineRun/CreatePipelineRun.js
@@ -13,7 +13,7 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { useHistory, useLocation } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom-v5-compat';
import keyBy from 'lodash.keyby';
import {
Button,
@@ -92,8 +92,8 @@ const initialResourcesState = resourceSpecs => {
function CreatePipelineRun() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const { selectedNamespace: defaultNamespace } = useSelectedNamespace();
function getPipelineName() {
@@ -269,7 +269,7 @@ function CreatePipelineRun() {
} else if (namespace && namespace !== ALL_NAMESPACES) {
url = urls.pipelineRuns.byNamespace({ namespace });
}
- history.push(url);
+ navigate(url);
}
function handleAddLabel(prop) {
@@ -342,7 +342,7 @@ function CreatePipelineRun() {
}
queryParams.delete('pipelineName');
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
}
}
@@ -366,7 +366,7 @@ function CreatePipelineRun() {
queryParams.delete('pipelineName');
}
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
if (text && text !== pipelineRef) {
setState(state => {
@@ -434,7 +434,7 @@ function CreatePipelineRun() {
: null
})
.then(() => {
- history.push(urls.pipelineRuns.byNamespace({ namespace }));
+ navigate(urls.pipelineRuns.byNamespace({ namespace }));
})
.catch(error => {
error.response.text().then(text => {
diff --git a/src/containers/CreatePipelineRun/CreatePipelineRun.test.js b/src/containers/CreatePipelineRun/CreatePipelineRun.test.js
index 29e577d1b..04f0a1098 100644
--- a/src/containers/CreatePipelineRun/CreatePipelineRun.test.js
+++ b/src/containers/CreatePipelineRun/CreatePipelineRun.test.js
@@ -82,8 +82,6 @@ const pipelineResource2 = {
spec: { type: 'type-2' }
};
-const history = { push: () => {} };
-
describe('CreatePipelineRun', () => {
beforeEach(() => {
jest
@@ -109,8 +107,6 @@ describe('CreatePipelineRun', () => {
jest
.spyOn(APIUtils, 'useSelectedNamespace')
.mockImplementation(() => ({ selectedNamespace: 'namespace-1' }));
-
- jest.spyOn(history, 'push');
});
it('renders labels', () => {
diff --git a/src/containers/CreateTaskRun/CreateTaskRun.js b/src/containers/CreateTaskRun/CreateTaskRun.js
index 42976d126..c93c55a56 100644
--- a/src/containers/CreateTaskRun/CreateTaskRun.js
+++ b/src/containers/CreateTaskRun/CreateTaskRun.js
@@ -13,7 +13,7 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { useHistory, useLocation } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom-v5-compat';
import keyBy from 'lodash.keyby';
import {
Button,
@@ -105,8 +105,8 @@ const itemToString = ({ text }) => text;
function CreateTaskRun() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const { selectedNamespace: defaultNamespace } = useSelectedNamespace();
function getTaskDetails() {
@@ -276,7 +276,7 @@ function CreateTaskRun() {
} else if (namespace && namespace !== ALL_NAMESPACES) {
url = urls.taskRuns.byNamespace({ namespace });
}
- history.push(url);
+ navigate(url);
}
function handleAddLabel(prop) {
@@ -349,7 +349,7 @@ function CreateTaskRun() {
}
queryParams.delete('taskName');
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
}
}
@@ -367,7 +367,7 @@ function CreateTaskRun() {
queryParams.delete('namespace');
queryParams.delete('taskName');
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
}
}
@@ -391,7 +391,7 @@ function CreateTaskRun() {
queryParams.delete('taskName');
}
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
if (text && text !== taskRef) {
setState(state => {
@@ -454,7 +454,7 @@ function CreateTaskRun() {
timeout: timeoutInMins
})
.then(() => {
- history.push(urls.taskRuns.byNamespace({ namespace }));
+ navigate(urls.taskRuns.byNamespace({ namespace }));
})
.catch(error => {
error.response.text().then(text => {
diff --git a/src/containers/CreateTaskRun/CreateTaskRun.test.js b/src/containers/CreateTaskRun/CreateTaskRun.test.js
index 1d45144eb..963237a01 100644
--- a/src/containers/CreateTaskRun/CreateTaskRun.test.js
+++ b/src/containers/CreateTaskRun/CreateTaskRun.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -155,6 +155,7 @@ describe('CreateTaskRun', () => {
queryAllByText,
queryByPlaceholderText
} = renderWithRouter(, {
+ path: '/taskruns/create',
route: '/taskruns/create?kind=Task'
});
expect(queryByText(/create taskrun/i)).toBeTruthy();
@@ -250,6 +251,7 @@ describe('CreateTaskRun', () => {
const { getByPlaceholderText, queryByText } = renderWithRouter(
,
{
+ path: '/taskruns/create',
route: `/taskruns/create?taskName=${badTaskRef}`
}
);
diff --git a/src/containers/CustomResourceDefinition/CustomResourceDefinition.js b/src/containers/CustomResourceDefinition/CustomResourceDefinition.js
index c4331055d..6b209343d 100644
--- a/src/containers/CustomResourceDefinition/CustomResourceDefinition.js
+++ b/src/containers/CustomResourceDefinition/CustomResourceDefinition.js
@@ -13,7 +13,11 @@ limitations under the License.
/* istanbul ignore file */
import React from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useTitleSync } from '@tektoncd/dashboard-utils';
import { ResourceDetails } from '@tektoncd/dashboard-components';
@@ -42,8 +46,8 @@ function useResource({ group, name, namespace, type, version }) {
}
function CustomResourceDefinition() {
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { group, name, namespace, type, version } = params;
@@ -67,7 +71,7 @@ function CustomResourceDefinition() {
diff --git a/src/containers/EventListener/EventListener.js b/src/containers/EventListener/EventListener.js
index 83c4ae4cc..ea24dbd58 100644
--- a/src/containers/EventListener/EventListener.js
+++ b/src/containers/EventListener/EventListener.js
@@ -13,7 +13,12 @@ limitations under the License.
/* istanbul ignore file */
import React from 'react';
-import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
@@ -27,7 +32,7 @@ import { getViewChangeHandler } from '../../utils';
export function EventListenerContainer() {
const intl = useIntl();
- const history = useHistory();
+ const navigate = useNavigate();
const location = useLocation();
const params = useParams();
const { eventListenerName, namespace } = params;
@@ -137,7 +142,7 @@ export function EventListenerContainer() {
additionalMetadata={getAdditionalMetadata()}
error={error}
loading={isFetching}
- onViewChange={getViewChangeHandler({ history, location })}
+ onViewChange={getViewChangeHandler({ location, navigate })}
resource={eventListener}
view={view}
>
diff --git a/src/containers/EventListeners/EventListeners.js b/src/containers/EventListeners/EventListeners.js
index eaa062b33..54682baf3 100644
--- a/src/containers/EventListeners/EventListeners.js
+++ b/src/containers/EventListeners/EventListeners.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
diff --git a/src/containers/EventListeners/EventListeners.test.js b/src/containers/EventListeners/EventListeners.test.js
index cfa63a965..94eaac54f 100644
--- a/src/containers/EventListeners/EventListeners.test.js
+++ b/src/containers/EventListeners/EventListeners.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -41,12 +41,14 @@ describe('EventListeners', () => {
.spyOn(APIUtils, 'useSelectedNamespace')
.mockImplementation(() => ({ selectedNamespace: ALL_NAMESPACES }));
});
+
it('renders with no bindings', () => {
jest
.spyOn(EventListenersAPI, 'useEventListeners')
.mockImplementation(() => ({ data: [] }));
const { getByText } = renderWithRouter(, {
+ path: '/eventlisteners',
route: '/eventlisteners'
});
@@ -60,6 +62,7 @@ describe('EventListeners', () => {
.mockImplementation(() => ({ data: [eventListener] }));
const { queryByText, queryByTitle } = renderWithRouter(, {
+ path: '/eventlisteners',
route: '/eventlisteners'
});
@@ -78,7 +81,7 @@ describe('EventListeners', () => {
const { getByPlaceholderText, getByText, queryByText } = renderWithRouter(
,
- { route: '/eventlisteners' }
+ { path: '/eventlisteners', route: '/eventlisteners' }
);
const filterValue = 'baz:bam';
@@ -96,6 +99,7 @@ describe('EventListeners', () => {
.mockImplementation(() => ({ isLoading: true }));
const { queryByText } = renderWithRouter(, {
+ path: '/eventlisteners',
route: '/eventlisteners'
});
@@ -111,6 +115,7 @@ describe('EventListeners', () => {
.mockImplementation(() => ({ error }));
const { queryByText } = renderWithRouter(, {
+ path: '/eventlisteners',
route: '/eventlisteners'
});
diff --git a/src/containers/HeaderBarContent/HeaderBarContent.js b/src/containers/HeaderBarContent/HeaderBarContent.js
index 8b7d3c821..fbd1f565c 100644
--- a/src/containers/HeaderBarContent/HeaderBarContent.js
+++ b/src/containers/HeaderBarContent/HeaderBarContent.js
@@ -13,19 +13,20 @@ limitations under the License.
import React, { useEffect } from 'react';
import {
generatePath,
- useHistory,
useLocation,
+ useNavigate,
useParams
-} from 'react-router-dom';
-import { ALL_NAMESPACES, paths } from '@tektoncd/dashboard-utils';
+} from 'react-router-dom-v5-compat';
+import { ALL_NAMESPACES, paths, urls } from '@tektoncd/dashboard-utils';
import { NamespacesDropdown } from '..';
import { useSelectedNamespace, useTenantNamespace } from '../../api';
export default function HeaderBarContent({ logoutButton }) {
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
+
const {
namespacedMatch,
selectedNamespace: namespace,
@@ -40,7 +41,7 @@ export default function HeaderBarContent({ logoutButton }) {
}, [params.namespace]);
function setPath(path, { dropQueryParams } = {}) {
- history.push(`${path}${dropQueryParams ? '' : location.search}`);
+ navigate(`${path}${dropQueryParams ? '' : location.search}`);
}
function handleNamespaceSelected(event) {
@@ -52,11 +53,13 @@ export default function HeaderBarContent({ logoutButton }) {
}
if (newNamespace === ALL_NAMESPACES) {
- if (namespacedMatch.allNamespacesPath) {
+ if (namespacedMatch.isResourceDetails) {
setPath(
- generatePath(namespacedMatch.allNamespacesPath, {
- ...namespacedMatch.params
- }),
+ location.pathname
+ .replace(urls.byNamespace({ namespace }), '')
+ .split('/')
+ .slice(0, -1) // drop resource name
+ .join('/'),
{
dropQueryParams: true
}
diff --git a/src/containers/ListPageLayout/ListPageLayout.js b/src/containers/ListPageLayout/ListPageLayout.js
index e4bae0f39..5de21a639 100644
--- a/src/containers/ListPageLayout/ListPageLayout.js
+++ b/src/containers/ListPageLayout/ListPageLayout.js
@@ -13,7 +13,7 @@ limitations under the License.
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
-import { useHistory, useLocation } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { InlineNotification, Pagination } from 'carbon-components-react';
import { getErrorMessage } from '@tektoncd/dashboard-utils';
@@ -28,8 +28,8 @@ export const ListPageLayout = ({
title
}) => {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const [pageSize, setPageSize] = useState(100);
const [page, setPage] = useState(1); // pagination component counts from 1
@@ -56,7 +56,11 @@ export const ListPageLayout = ({
{title}
{filters && (
-
+
)}
{error && (
{
- const match = useRouteMatch();
+/*
+ There is no equivalent of the v5 `useRouteMatch` in v6 so we have to provide
+ our own to get the currently matched route. A future release may provide something
+ we can use but for now we rely on an internal API that's provided as an escape
+ hatch for exactly this reason. We'll have to be careful with future updates to
+ ensure this continues to work or switch to an alternative if needed.
+*/
+function useCurrentPath() {
+ const routeContext = useContext(UNSAFE_RouteContext);
+ const match = routeContext.matches.at(-1); // we always want the last match
+
+ let { path } = match.route;
+ path = path.replace(/\/\*/, ''); // remove any trailing splat
+
+ return path;
+}
+
+const NamespacedRoute = ({ children, isResourceDetails }) => {
+ const params = useParams();
+ const path = useCurrentPath();
const { setNamespacedMatch } = useSelectedNamespace();
useEffect(() => {
setNamespacedMatch({
- allNamespacesPath,
- params: match.params,
- path: match.path
+ isResourceDetails,
+ params,
+ path
});
return () => {
diff --git a/src/containers/PipelineResource/PipelineResource.js b/src/containers/PipelineResource/PipelineResource.js
index 5c7e72dd6..d11426dbf 100644
--- a/src/containers/PipelineResource/PipelineResource.js
+++ b/src/containers/PipelineResource/PipelineResource.js
@@ -12,7 +12,11 @@ limitations under the License.
*/
import React from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { DataTable } from 'carbon-components-react';
import { ResourceDetails } from '@tektoncd/dashboard-components';
@@ -34,8 +38,8 @@ const {
/* istanbul ignore next */
function PipelineResource() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const { namespace, pipelineResourceName: resourceName } = useParams();
const queryParams = new URLSearchParams(location.search);
@@ -72,7 +76,7 @@ function PipelineResource() {
}
error={error}
loading={isFetching}
- onViewChange={getViewChangeHandler({ history, location })}
+ onViewChange={getViewChangeHandler({ location, navigate })}
resource={pipelineResource}
view={view}
>
diff --git a/src/containers/PipelineResources/PipelineResources.js b/src/containers/PipelineResources/PipelineResources.js
index 13ce3c758..bf86e4f81 100644
--- a/src/containers/PipelineResources/PipelineResources.js
+++ b/src/containers/PipelineResources/PipelineResources.js
@@ -13,7 +13,11 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import keyBy from 'lodash.keyby';
import {
@@ -38,8 +42,8 @@ import {
export function PipelineResources() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const filters = getFilters(location);
@@ -125,7 +129,7 @@ export function PipelineResources() {
? []
: [
{
- onClick: () => history.push(urls.pipelineResources.create()),
+ onClick: () => navigate(urls.pipelineResources.create()),
text: intl.formatMessage({
id: 'dashboard.actions.createButton',
defaultMessage: 'Create'
diff --git a/src/containers/PipelineRun/PipelineRun.js b/src/containers/PipelineRun/PipelineRun.js
index d3e60c2ad..239253bab 100644
--- a/src/containers/PipelineRun/PipelineRun.js
+++ b/src/containers/PipelineRun/PipelineRun.js
@@ -29,7 +29,12 @@ import {
RadioTile,
TileGroup
} from 'carbon-components-react';
-import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import {
@@ -59,8 +64,8 @@ const { PIPELINE_TASK, RETRY, STEP, VIEW } = queryParamConstants;
export /* istanbul ignore next */ function PipelineRunContainer() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { namespace, pipelineRunName } = params;
@@ -223,10 +228,10 @@ export /* istanbul ignore next */ function PipelineRunContainer() {
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
if (currentPipelineTaskName) {
- history.push(browserURL);
+ navigate(browserURL);
} else {
// auto-selecting task & step on first load
- history.replace(browserURL);
+ navigate(browserURL, { replace: true });
}
}
@@ -256,7 +261,7 @@ export /* istanbul ignore next */ function PipelineRunContainer() {
const { name, namespace: resourceNamespace } = pipelineRun.metadata;
deletePipelineRun({ name, namespace: resourceNamespace })
.then(() => {
- history.push(urls.pipelineRuns.byNamespace({ namespace }));
+ navigate(urls.pipelineRuns.byNamespace({ namespace }));
})
.catch(err => {
err.response.text().then(text => {
@@ -547,7 +552,7 @@ export /* istanbul ignore next */ function PipelineRunContainer() {
})
}
maximizedLogsContainer={maximizedLogsContainer.current}
- onViewChange={getViewChangeHandler({ history, location })}
+ onViewChange={getViewChangeHandler({ location, navigate })}
pipelineRun={pipelineRun}
pod={podDetails}
runActions={
diff --git a/src/containers/PipelineRuns/PipelineRuns.js b/src/containers/PipelineRuns/PipelineRuns.js
index 5a561a3e6..ef4ed82ec 100644
--- a/src/containers/PipelineRuns/PipelineRuns.js
+++ b/src/containers/PipelineRuns/PipelineRuns.js
@@ -13,7 +13,11 @@ limitations under the License.
/* istanbul ignore file */
import React, { useEffect, useState } from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import keyBy from 'lodash.keyby';
import { RadioTile, TileGroup } from 'carbon-components-react';
@@ -53,8 +57,8 @@ import {
export function PipelineRuns() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { selectedNamespace } = useSelectedNamespace();
@@ -62,7 +66,7 @@ export function PipelineRuns() {
const filters = getFilters(location);
const statusFilter = getStatusFilter(location);
- const setStatusFilter = getStatusFilterHandler({ history, location });
+ const setStatusFilter = getStatusFilterHandler({ location, navigate });
const pipelineFilter =
filters.find(filter => filter.indexOf(`${labels.PIPELINE}=`) !== -1) || '';
@@ -345,7 +349,7 @@ export function PipelineRuns() {
...(pipelineName && { pipelineName })
}).toString();
}
- history.push(
+ navigate(
urls.pipelineRuns.create() +
(queryString ? `?${queryString}` : '')
);
diff --git a/src/containers/PipelineRuns/PipelineRuns.test.js b/src/containers/PipelineRuns/PipelineRuns.test.js
index 02e2eef2a..3398f2827 100644
--- a/src/containers/PipelineRuns/PipelineRuns.test.js
+++ b/src/containers/PipelineRuns/PipelineRuns.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -13,7 +13,7 @@ limitations under the License.
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import { renderWithRouter } from '../../utils/test';
import * as API from '../../api';
@@ -118,7 +118,7 @@ describe('PipelineRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: '/pipelineruns' }
+ { path: '/pipelineruns', route: '/pipelineruns' }
);
const filterValue = 'baz:bam';
@@ -140,7 +140,7 @@ describe('PipelineRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: '/pipelineruns' }
+ { path: '/pipelineruns', route: '/pipelineruns' }
);
const filterValue = 'baz=bam';
@@ -164,7 +164,7 @@ describe('PipelineRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: '/pipelineruns' }
+ { path: '/pipelineruns', route: '/pipelineruns' }
);
// Let the page finish rendering so we know if we're in read-only mode or not
@@ -183,7 +183,7 @@ describe('PipelineRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: '/pipelineruns' }
+ { path: '/pipelineruns', route: '/pipelineruns' }
);
// Let the page finish rendering so we know if we're in read-only mode or not
await waitFor(() => getByText('pipelineRunWithTwoLabels'));
@@ -203,6 +203,7 @@ describe('PipelineRuns container', () => {
const { getAllByTitle, getByText } = renderWithRouter(
,
{
+ path: paths.pipelineRuns.all(),
route: urls.pipelineRuns.all()
}
);
@@ -227,6 +228,7 @@ describe('PipelineRuns container', () => {
const { getAllByTitle, getByText } = renderWithRouter(
,
{
+ path: paths.pipelineRuns.all(),
route: urls.pipelineRuns.all()
}
);
diff --git a/src/containers/Pipelines/Pipelines.js b/src/containers/Pipelines/Pipelines.js
index 24e17f95d..da084e35a 100644
--- a/src/containers/Pipelines/Pipelines.js
+++ b/src/containers/Pipelines/Pipelines.js
@@ -13,7 +13,8 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import {
TrashCan16 as DeleteIcon,
PlayOutline16 as RunIcon,
diff --git a/src/containers/ResourceList/ResourceList.js b/src/containers/ResourceList/ResourceList.js
index 461141f9e..944ddd7a2 100644
--- a/src/containers/ResourceList/ResourceList.js
+++ b/src/containers/ResourceList/ResourceList.js
@@ -13,7 +13,8 @@ limitations under the License.
/* istanbul ignore file */
import React from 'react';
import { useIntl } from 'react-intl';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
Link as CustomLink,
diff --git a/src/containers/Run/Run.js b/src/containers/Run/Run.js
index 605834001..d54651a31 100644
--- a/src/containers/Run/Run.js
+++ b/src/containers/Run/Run.js
@@ -13,7 +13,12 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { UndefinedFilled20 as UndefinedIcon } from '@carbon/icons-react';
import {
@@ -85,8 +90,8 @@ function getRunStatusTooltip(run) {
function Run() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const { namespace, runName: resourceName } = useParams();
const queryParams = new URLSearchParams(location.search);
@@ -142,7 +147,7 @@ function Run() {
namespace: run.metadata.namespace
})
.then(() => {
- history.push(urls.runs.byNamespace({ namespace }));
+ navigate(urls.runs.byNamespace({ namespace }));
})
.catch(err => {
err.response.text().then(text => {
@@ -314,7 +319,7 @@ function Run() {
}
error={error}
loading={isFetching}
- onViewChange={getViewChangeHandler({ history, location })}
+ onViewChange={getViewChangeHandler({ location, navigate })}
resource={run}
view={view}
>
diff --git a/src/containers/Runs/Runs.js b/src/containers/Runs/Runs.js
index 6ac0c463f..6ca4562a5 100644
--- a/src/containers/Runs/Runs.js
+++ b/src/containers/Runs/Runs.js
@@ -13,7 +13,8 @@ limitations under the License.
/* istanbul ignore file */
import React, { useEffect, useState } from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import keyBy from 'lodash.keyby';
import {
diff --git a/src/containers/SideNav/SideNav.js b/src/containers/SideNav/SideNav.js
index e092ced7f..3cc6fbbd1 100644
--- a/src/containers/SideNav/SideNav.js
+++ b/src/containers/SideNav/SideNav.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { matchPath, NavLink, useLocation } from 'react-router-dom';
+import { matchPath } from 'react-router-dom';
+import { NavLink, useLocation } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import {
SideNav as CarbonSideNav,
diff --git a/src/containers/TaskRun/TaskRun.js b/src/containers/TaskRun/TaskRun.js
index f170f0ea9..f7b0e56b6 100644
--- a/src/containers/TaskRun/TaskRun.js
+++ b/src/containers/TaskRun/TaskRun.js
@@ -14,7 +14,12 @@ limitations under the License.
import React, { useRef, useState } from 'react';
import { useIntl } from 'react-intl';
-import { Link, useHistory, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { InlineNotification, SkeletonText } from 'carbon-components-react';
import {
Actions,
@@ -59,8 +64,8 @@ const { STEP, TASK_RUN_DETAILS, VIEW } = queryParamConstants;
export function TaskRunContainer() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { namespace: namespaceParam, taskRunName } = params;
@@ -181,10 +186,10 @@ export function TaskRunContainer() {
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
if (showTaskRunDetails || selectedStepId) {
- history.push(browserURL);
+ navigate(browserURL);
} else {
// auto-selecting step on first load
- history.replace(browserURL);
+ navigate(browserURL, { replace: true });
}
}
@@ -201,7 +206,7 @@ export function TaskRunContainer() {
namespace: taskRun.metadata.namespace
})
.then(() => {
- history.push(urls.taskRuns.byNamespace({ namespace }));
+ navigate(urls.taskRuns.byNamespace({ namespace }));
})
.catch(err => {
err.response.text().then(text => {
@@ -373,7 +378,7 @@ export function TaskRunContainer() {
taskRun
});
- const onViewChange = getViewChangeHandler({ history, location });
+ const onViewChange = getViewChangeHandler({ location, navigate });
const runActions = taskRunActions();
diff --git a/src/containers/TaskRuns/TaskRuns.js b/src/containers/TaskRuns/TaskRuns.js
index af1e4beec..c9c4ed078 100644
--- a/src/containers/TaskRuns/TaskRuns.js
+++ b/src/containers/TaskRuns/TaskRuns.js
@@ -12,7 +12,11 @@ limitations under the License.
*/
import React, { useEffect, useState } from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import keyBy from 'lodash.keyby';
import {
@@ -51,8 +55,8 @@ const { CLUSTER_TASK, TASK } = labels;
/* istanbul ignore next */
function TaskRuns() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { namespace: namespaceParam } = params;
@@ -79,7 +83,7 @@ function TaskRuns() {
? clusterTaskFilter.replace(`${CLUSTER_TASK}=`, '')
: taskFilter.replace(`${TASK}=`, '');
- const setStatusFilter = getStatusFilterHandler({ history, location });
+ const setStatusFilter = getStatusFilterHandler({ location, navigate });
useTitleSync({ page: 'TaskRuns' });
@@ -258,7 +262,7 @@ function TaskRuns() {
...(taskName && { taskName })
}).toString();
}
- history.push(
+ navigate(
urls.taskRuns.create() + (queryString ? `?${queryString}` : '')
);
},
diff --git a/src/containers/TaskRuns/TaskRuns.test.js b/src/containers/TaskRuns/TaskRuns.test.js
index f0ceabda9..423948dc2 100644
--- a/src/containers/TaskRuns/TaskRuns.test.js
+++ b/src/containers/TaskRuns/TaskRuns.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -13,7 +13,7 @@ limitations under the License.
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import { renderWithRouter } from '../../utils/test';
import * as API from '../../api';
@@ -74,7 +74,7 @@ describe('TaskRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: urls.taskRuns.all() }
+ { path: paths.taskRuns.all(), route: urls.taskRuns.all() }
);
const filterValue = 'baz:bam';
@@ -96,7 +96,7 @@ describe('TaskRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: urls.taskRuns.all() }
+ { path: paths.taskRuns.all(), route: urls.taskRuns.all() }
);
const filterValue = 'baz=bam';
@@ -120,7 +120,7 @@ describe('TaskRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: urls.taskRuns.all() }
+ { path: paths.taskRuns.all(), route: urls.taskRuns.all() }
);
await waitFor(() => getByText('taskRunWithTwoLabels'));
@@ -137,7 +137,7 @@ describe('TaskRuns container', () => {
loading={false}
namespace="namespace-1"
/>,
- { route: urls.taskRuns.all() }
+ { path: paths.taskRuns.all(), route: urls.taskRuns.all() }
);
await waitFor(() => getByText('taskRunWithTwoLabels'));
@@ -150,7 +150,7 @@ describe('TaskRuns container', () => {
jest.spyOn(taskRunsAPI, 'rerunTaskRun').mockImplementation(() => []);
const { getAllByTitle, getByText } = renderWithRouter(
,
- { route: urls.taskRuns.all() }
+ { path: paths.taskRuns.all(), route: urls.taskRuns.all() }
);
await waitFor(() => getByText(/taskRunWithTwoLabels/i));
fireEvent.click(await waitFor(() => getAllByTitle('Actions')[0]));
diff --git a/src/containers/Tasks/Tasks.js b/src/containers/Tasks/Tasks.js
index 2c94d638d..14536dc3e 100644
--- a/src/containers/Tasks/Tasks.js
+++ b/src/containers/Tasks/Tasks.js
@@ -13,7 +13,8 @@ limitations under the License.
/* istanbul ignore file */
import React, { useState } from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import keyBy from 'lodash.keyby';
import { Button } from 'carbon-components-react';
diff --git a/src/containers/Trigger/Trigger.js b/src/containers/Trigger/Trigger.js
index 39bfb909c..53f4731a2 100644
--- a/src/containers/Trigger/Trigger.js
+++ b/src/containers/Trigger/Trigger.js
@@ -12,7 +12,11 @@ limitations under the License.
*/
import React from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useTitleSync } from '@tektoncd/dashboard-utils';
import { ResourceDetails, Trigger } from '@tektoncd/dashboard-components';
@@ -20,8 +24,8 @@ import { useTrigger } from '../../api';
import { getViewChangeHandler } from '../../utils';
export function TriggerContainer() {
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { triggerName, namespace } = params;
@@ -46,7 +50,7 @@ export function TriggerContainer() {
diff --git a/src/containers/TriggerBinding/TriggerBinding.js b/src/containers/TriggerBinding/TriggerBinding.js
index a51ebbeb2..f6b4c52ba 100644
--- a/src/containers/TriggerBinding/TriggerBinding.js
+++ b/src/containers/TriggerBinding/TriggerBinding.js
@@ -12,7 +12,11 @@ limitations under the License.
*/
import React from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { ResourceDetails, Table } from '@tektoncd/dashboard-components';
import { useTitleSync } from '@tektoncd/dashboard-utils';
@@ -22,8 +26,8 @@ import { getViewChangeHandler } from '../../utils';
export function TriggerBindingContainer() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const params = useParams();
const { namespace, triggerBindingName: resourceName } = params;
@@ -80,7 +84,7 @@ export function TriggerBindingContainer() {
diff --git a/src/containers/TriggerBinding/TriggerBinding.test.js b/src/containers/TriggerBinding/TriggerBinding.test.js
index 9317d35e7..239438577 100644
--- a/src/containers/TriggerBinding/TriggerBinding.test.js
+++ b/src/containers/TriggerBinding/TriggerBinding.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -14,7 +14,7 @@ limitations under the License.
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { createIntl } from 'react-intl';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import * as API from '../../api/triggerBindings';
import { renderWithRouter } from '../../utils/test';
@@ -103,6 +103,7 @@ it('TriggerBindingContainer renders YAML', async () => {
const { getByText } = renderWithRouter(
,
{
+ path: paths.triggerBindings.byName(),
route: urls.triggerBindings.byName({
namespace,
triggerBindingName
diff --git a/src/containers/TriggerBindings/TriggerBindings.js b/src/containers/TriggerBindings/TriggerBindings.js
index 313d8b82d..496553449 100644
--- a/src/containers/TriggerBindings/TriggerBindings.js
+++ b/src/containers/TriggerBindings/TriggerBindings.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
diff --git a/src/containers/TriggerBindings/TriggerBindings.test.js b/src/containers/TriggerBindings/TriggerBindings.test.js
index c87a82c89..0327011b8 100644
--- a/src/containers/TriggerBindings/TriggerBindings.test.js
+++ b/src/containers/TriggerBindings/TriggerBindings.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -48,6 +48,7 @@ describe('TriggerBindings', () => {
.mockImplementation(() => ({ data: [] }));
const { getByText } = renderWithRouter(, {
+ path: '/triggerbindings',
route: '/triggerbindings'
});
@@ -61,6 +62,7 @@ describe('TriggerBindings', () => {
.mockImplementation(() => ({ data: [triggerBinding] }));
const { queryByText } = renderWithRouter(, {
+ path: '/triggerbindings',
route: '/triggerbindings'
});
@@ -78,7 +80,7 @@ describe('TriggerBindings', () => {
const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
,
- { route: '/triggerbindings' }
+ { path: '/triggerbindings', route: '/triggerbindings' }
);
const filterValue = 'baz:bam';
@@ -96,6 +98,7 @@ describe('TriggerBindings', () => {
.mockImplementation(() => ({ isLoading: true }));
const { queryByText } = renderWithRouter(, {
+ path: '/triggerbindings',
route: '/triggerbindings'
});
@@ -111,6 +114,7 @@ describe('TriggerBindings', () => {
.mockImplementation(() => ({ error }));
const { queryByText } = renderWithRouter(, {
+ path: '/triggerbindings',
route: '/triggerbindings'
});
diff --git a/src/containers/TriggerTemplate/TriggerTemplate.js b/src/containers/TriggerTemplate/TriggerTemplate.js
index 4124cf0db..d6dbd1d8f 100644
--- a/src/containers/TriggerTemplate/TriggerTemplate.js
+++ b/src/containers/TriggerTemplate/TriggerTemplate.js
@@ -12,7 +12,11 @@ limitations under the License.
*/
import React from 'react';
-import { useHistory, useLocation, useParams } from 'react-router-dom';
+import {
+ useLocation,
+ useNavigate,
+ useParams
+} from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { DataTable } from 'carbon-components-react';
import {
@@ -40,8 +44,8 @@ const {
export /* istanbul ignore next */ function TriggerTemplateContainer() {
const intl = useIntl();
- const history = useHistory();
const location = useLocation();
+ const navigate = useNavigate();
const { namespace, triggerTemplateName: resourceName } = useParams();
const queryParams = new URLSearchParams(location.search);
@@ -211,7 +215,7 @@ export /* istanbul ignore next */ function TriggerTemplateContainer() {
diff --git a/src/containers/TriggerTemplate/TriggerTemplate.test.js b/src/containers/TriggerTemplate/TriggerTemplate.test.js
index 546569dea..42a43c814 100644
--- a/src/containers/TriggerTemplate/TriggerTemplate.test.js
+++ b/src/containers/TriggerTemplate/TriggerTemplate.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -14,7 +14,7 @@ limitations under the License.
import React from 'react';
import { fireEvent, waitFor } from '@testing-library/react';
import { createIntl } from 'react-intl';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import * as API from '../../api/triggerTemplates';
import { renderWithRouter } from '../../utils/test';
@@ -241,6 +241,7 @@ it('TriggerTemplateContainer contains YAML tab with accurate information', async
const { getByText } = renderWithRouter(
,
{
+ path: paths.triggerTemplates.byName(),
route: urls.triggerTemplates.byName({
namespace,
triggerTemplateName: 'pipeline-template'
diff --git a/src/containers/TriggerTemplates/TriggerTemplates.js b/src/containers/TriggerTemplates/TriggerTemplates.js
index 9e6ae97cb..cce2d525f 100644
--- a/src/containers/TriggerTemplates/TriggerTemplates.js
+++ b/src/containers/TriggerTemplates/TriggerTemplates.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
diff --git a/src/containers/TriggerTemplates/TriggerTemplates.test.js b/src/containers/TriggerTemplates/TriggerTemplates.test.js
index fa0c1e1e6..d9f46ad0f 100644
--- a/src/containers/TriggerTemplates/TriggerTemplates.test.js
+++ b/src/containers/TriggerTemplates/TriggerTemplates.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -45,7 +45,8 @@ it('TriggerTemplates renders with no templates', () => {
.mockImplementation(() => ({ selectedNamespace: ALL_NAMESPACES }));
const { queryByText } = renderWithRouter(, {
- route: '/triggerTemplates'
+ path: '/triggertemplates',
+ route: '/triggertemplates'
});
expect(queryByText('TriggerTemplates')).toBeTruthy();
@@ -58,7 +59,8 @@ it('TriggerTemplates renders with one template', () => {
.mockImplementation(() => ({ data: [triggerTemplate] }));
const { queryByText } = renderWithRouter(, {
- route: '/triggerTemplates'
+ path: '/triggertemplates',
+ route: '/triggertemplates'
});
expect(queryByText(/TriggerTemplates/i)).toBeTruthy();
@@ -75,7 +77,7 @@ it('TriggerTemplates can be filtered on a single label filter', async () => {
const { queryByText, getByPlaceholderText, getByText } = renderWithRouter(
,
- { route: '/triggerTemplates' }
+ { path: '/triggertemplates', route: '/triggertemplates' }
);
const filterValue = 'baz:bam';
@@ -93,7 +95,8 @@ it('TriggerTemplates renders in loading state', () => {
.mockImplementation(() => ({ isLoading: true }));
const { queryByText } = renderWithRouter(, {
- route: '/triggerTemplates'
+ path: '/triggertemplates',
+ route: '/triggertemplates'
});
expect(queryByText(/TriggerTemplates/i)).toBeTruthy();
@@ -107,7 +110,8 @@ it('TriggerTemplates renders in error state', () => {
.mockImplementation(() => ({ error }));
const { queryByText } = renderWithRouter(, {
- route: '/triggerTemplates'
+ path: '/triggertemplates',
+ route: '/triggertemplates'
});
expect(queryByText(error)).toBeTruthy();
diff --git a/src/containers/Triggers/Triggers.js b/src/containers/Triggers/Triggers.js
index dd7eba711..eea71efcb 100644
--- a/src/containers/Triggers/Triggers.js
+++ b/src/containers/Triggers/Triggers.js
@@ -12,7 +12,8 @@ limitations under the License.
*/
import React from 'react';
-import { Link, useLocation, useParams } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation, useParams } from 'react-router-dom-v5-compat';
import { useIntl } from 'react-intl';
import { getFilters, urls, useTitleSync } from '@tektoncd/dashboard-utils';
import {
diff --git a/src/containers/Triggers/Triggers.test.js b/src/containers/Triggers/Triggers.test.js
index 9c5aa0ce2..0f3dfc11d 100644
--- a/src/containers/Triggers/Triggers.test.js
+++ b/src/containers/Triggers/Triggers.test.js
@@ -1,5 +1,5 @@
/*
-Copyright 2021 The Tekton Authors
+Copyright 2021-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -12,7 +12,7 @@ limitations under the License.
*/
import React from 'react';
-import { urls } from '@tektoncd/dashboard-utils';
+import { paths, urls } from '@tektoncd/dashboard-utils';
import { renderWithRouter } from '../../utils/test';
import * as API from '../../api/triggers';
@@ -28,6 +28,7 @@ describe('Triggers', () => {
.spyOn(API, 'useTriggers')
.mockImplementation(() => ({ isLoading: true }));
const { queryByText } = renderWithRouter(, {
+ path: paths.triggers.all(),
route: urls.triggers.all()
});
expect(queryByText('Triggers')).toBeTruthy();
@@ -49,6 +50,7 @@ describe('Triggers', () => {
]
}));
const { queryByText } = renderWithRouter(, {
+ path: paths.triggers.all(),
route: urls.triggers.all()
});
@@ -61,6 +63,7 @@ describe('Triggers', () => {
.spyOn(API, 'useTriggers')
.mockImplementation(() => ({ error: errorMessage }));
const { queryByText } = renderWithRouter(, {
+ path: paths.triggers.all(),
route: urls.triggers.all()
});
diff --git a/src/utils/index.js b/src/utils/index.js
index b9a3b35b8..cc099ed9d 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -1,5 +1,5 @@
/*
-Copyright 2019-2021 The Tekton Authors
+Copyright 2019-2022 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -121,14 +121,12 @@ export function isValidLabel(type, value) {
return regex.test(value);
}
-export function getViewChangeHandler({ history, location }) {
+export function getViewChangeHandler({ location, navigate }) {
return function handleViewChange(view) {
const queryParams = new URLSearchParams(location.search);
-
queryParams.set('view', view);
-
const browserURL = location.pathname.concat(`?${queryParams.toString()}`);
- history.push(browserURL);
+ navigate(browserURL);
};
}
diff --git a/src/utils/index.test.js b/src/utils/index.test.js
index 92a1b2440..d0d40ee41 100644
--- a/src/utils/index.test.js
+++ b/src/utils/index.test.js
@@ -229,12 +229,12 @@ describe('getLogsRetriever', () => {
it('getViewChangeHandler', () => {
const url = 'someURL';
- const history = { push: jest.fn() };
+ const navigate = jest.fn();
const location = { pathname: url, search: '?nonViewQueryParam=someValue' };
- const handleViewChange = getViewChangeHandler({ history, location });
+ const handleViewChange = getViewChangeHandler({ location, navigate });
const view = 'someView';
handleViewChange(view);
- expect(history.push).toHaveBeenCalledWith(
+ expect(navigate).toHaveBeenCalledWith(
`${url}?nonViewQueryParam=someValue&view=${view}`
);
});
diff --git a/webpack.dev.js b/webpack.dev.js
index 031646d61..6d54d1f3e 100644
--- a/webpack.dev.js
+++ b/webpack.dev.js
@@ -56,6 +56,11 @@ module.exports = merge(common({ mode }), {
},
module: {
rules: [
+ {
+ test: /\.js$/,
+ include: /node_modules\/react-dom/,
+ use: ['react-hot-loader/webpack']
+ },
{
test: /\.scss$/,
use: [