From e5795c7b6d1ab883c633b51e00b4d520da930337 Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Tue, 15 Oct 2024 16:10:31 +0300 Subject: [PATCH] Routing: Update connections to react router 6 (#94461) * Update routes * Update test * Remove the useDataSourcesRoutes hook * Remove DataSourcesRoutesContext * Fix imports * Fix more imports * Add default * Betterer --- .betterer.results | 3 +- .../features/connections/Connections.test.tsx | 22 +++--- .../app/features/connections/Connections.tsx | 68 ++++++++++--------- .../hooks/useDataSourceSettingsNav.ts | 4 +- .../pages/DataSourceDashboardsPage.tsx | 4 +- .../pages/DataSourceDetailsPage.tsx | 4 +- .../connections/pages/EditDataSourcePage.tsx | 4 +- public/app/features/connections/routes.tsx | 4 +- .../tabs/ConnectData/ConnectData.tsx | 7 +- .../components/DataSourceAddButton.tsx | 6 +- .../components/DataSourcesList.tsx | 6 +- .../components/DataSourcesListCard.tsx | 5 +- .../datasources/components/NewDataSource.tsx | 10 ++- .../features/datasources/state/contexts.ts | 8 --- .../app/features/datasources/state/hooks.ts | 14 ++-- .../app/features/datasources/state/index.ts | 1 - .../GetStartedWithDataSource.tsx | 8 +-- 17 files changed, 80 insertions(+), 98 deletions(-) delete mode 100644 public/app/features/datasources/state/contexts.ts diff --git a/.betterer.results b/.betterer.results index 3b6f2de23a9..5b5be31e246 100644 --- a/.betterer.results +++ b/.betterer.results @@ -3513,8 +3513,7 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"], [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"], [0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"], - [0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"], - [0, 0, 0, "Do not use export all (\`export * from ...\`)", "6"] + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"] ], "public/app/features/datasources/state/navModel.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], diff --git a/public/app/features/connections/Connections.test.tsx b/public/app/features/connections/Connections.test.tsx index 1d752fda505..42995857cde 100644 --- a/public/app/features/connections/Connections.test.tsx +++ b/public/app/features/connections/Connections.test.tsx @@ -1,7 +1,7 @@ -import { render, RenderResult, screen } from '@testing-library/react'; -import { TestProvider } from 'test/helpers/TestProvider'; +import { RenderResult, screen } from '@testing-library/react'; +import { Route, Routes } from 'react-router-dom-v5-compat'; +import { render } from 'test/test-utils'; -import { locationService } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; import { getMockDataSources } from 'app/features/datasources/__mocks__'; import * as api from 'app/features/datasources/api'; @@ -11,7 +11,7 @@ import { getPluginsStateMock } from '../plugins/admin/__mocks__'; import Connections from './Connections'; import { navIndex } from './__mocks__/store.navIndex.mock'; -import { ROUTE_BASE_ID, ROUTES } from './constants'; +import { ROUTES } from './constants'; jest.mock('app/core/services/context_srv'); jest.mock('app/features/datasources/api'); @@ -21,15 +21,17 @@ jest.mock('@grafana/runtime', () => ({ })); const renderPage = ( - path = `/${ROUTE_BASE_ID}`, + path: string = ROUTES.Base, store = configureStore({ navIndex, plugins: getPluginsStateMock([]) }) ): RenderResult => { - locationService.push(path); - return render( - - - + + } /> + , + { + store, + historyOptions: { initialEntries: [path] }, + } ); }; diff --git a/public/app/features/connections/Connections.tsx b/public/app/features/connections/Connections.tsx index fd0a97b1125..05330a180b5 100644 --- a/public/app/features/connections/Connections.tsx +++ b/public/app/features/connections/Connections.tsx @@ -1,7 +1,5 @@ -import { Route, Switch, useLocation } from 'react-router-dom'; -import { Navigate } from 'react-router-dom-v5-compat'; +import { Navigate, Routes, Route, useLocation } from 'react-router-dom-v5-compat'; -import { DataSourcesRoutesContext } from 'app/features/datasources/state'; import { StoreState, useSelector } from 'app/types'; import { ROUTES } from './constants'; @@ -32,39 +30,43 @@ export default function Connections() { const isAddNewConnectionPageOverridden = Boolean(navIndex['standalone-plugin-page-/connections/add-new-connection']); return ( - - - {/* Redirect to "Add new connection" by default */} - } /> - - - - - - - {/* "Add new connection" page - we don't register a route in case a plugin already registers a standalone page for it */} - {!isAddNewConnectionPageOverridden && ( - - )} + + {/* Redirect to "Add new connection" by default */} + } /> + {/* The route paths need to be relative to the parent path (ROUTES.Base), so we need to remove that part */} + } /> + } /> + } + /> + } /> + } + /> - {/* Redirect from earlier routes to updated routes */} - + {/* "Add new connection" page - we don't register a route in case a plugin already registers a standalone page for it */} + {!isAddNewConnectionPageOverridden && ( } + caseSensitive + path={ROUTES.AddNewConnection.replace(ROUTES.Base, '')} + element={} /> - } /> + )} + + {/* Redirect from earlier routes to updated routes */} + } /> + } /> + } + /> - {/* Not found */} - } /> - - + {/* Not found */} + } /> + ); } diff --git a/public/app/features/connections/hooks/useDataSourceSettingsNav.ts b/public/app/features/connections/hooks/useDataSourceSettingsNav.ts index 1d94698a9a8..cbf26cc5f09 100644 --- a/public/app/features/connections/hooks/useDataSourceSettingsNav.ts +++ b/public/app/features/connections/hooks/useDataSourceSettingsNav.ts @@ -1,4 +1,4 @@ -import { useLocation, useParams } from 'react-router-dom'; +import { useLocation, useParams } from 'react-router-dom-v5-compat'; import { NavModel, NavModelItem } from '@grafana/data'; import { getDataSourceSrv } from '@grafana/runtime'; @@ -9,7 +9,7 @@ import { useGetSingle } from 'app/features/plugins/admin/state/hooks'; import { useSelector } from 'app/types'; export function useDataSourceSettingsNav(pageIdParam?: string) { - const { uid } = useParams<{ uid: string }>(); + const { uid = '' } = useParams<{ uid: string }>(); const location = useLocation(); const datasource = useDataSource(uid); const dataSourceMeta = useDataSourceMeta(datasource.type); diff --git a/public/app/features/connections/pages/DataSourceDashboardsPage.tsx b/public/app/features/connections/pages/DataSourceDashboardsPage.tsx index ecda29195d7..9a82b0f0d15 100644 --- a/public/app/features/connections/pages/DataSourceDashboardsPage.tsx +++ b/public/app/features/connections/pages/DataSourceDashboardsPage.tsx @@ -1,4 +1,4 @@ -import { useParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom-v5-compat'; import { Page } from 'app/core/components/Page/Page'; import { DataSourceDashboards } from 'app/features/datasources/components/DataSourceDashboards'; @@ -6,7 +6,7 @@ import { DataSourceDashboards } from 'app/features/datasources/components/DataSo import { useDataSourceSettingsNav } from '../hooks/useDataSourceSettingsNav'; export function DataSourceDashboardsPage() { - const { uid } = useParams<{ uid: string }>(); + const { uid = '' } = useParams<{ uid: string }>(); const { navId, pageNav } = useDataSourceSettingsNav('dashboards'); return ( diff --git a/public/app/features/connections/pages/DataSourceDetailsPage.tsx b/public/app/features/connections/pages/DataSourceDetailsPage.tsx index 9a72ddb5783..9ed3153764b 100644 --- a/public/app/features/connections/pages/DataSourceDetailsPage.tsx +++ b/public/app/features/connections/pages/DataSourceDetailsPage.tsx @@ -1,4 +1,4 @@ -import { useParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom-v5-compat'; import { Alert, Badge } from '@grafana/ui'; import { PluginDetailsPage } from 'app/features/plugins/admin/components/PluginDetailsPage'; @@ -8,7 +8,7 @@ import { ROUTES } from '../constants'; export function DataSourceDetailsPage() { const overrideNavId = 'standalone-plugin-page-/connections/add-new-connection'; - const { id } = useParams<{ id: string }>(); + const { id = '' } = useParams<{ id: string }>(); const navIndex = useSelector((state: StoreState) => state.navIndex); const isConnectDataPageOverriden = Boolean(navIndex[overrideNavId]); const navId = isConnectDataPageOverriden ? overrideNavId : 'connections-add-new-connection'; // The nav id changes (gets a prefix) if it is overriden by a plugin diff --git a/public/app/features/connections/pages/EditDataSourcePage.tsx b/public/app/features/connections/pages/EditDataSourcePage.tsx index be105116ca0..fe2d93bc888 100644 --- a/public/app/features/connections/pages/EditDataSourcePage.tsx +++ b/public/app/features/connections/pages/EditDataSourcePage.tsx @@ -1,9 +1,9 @@ -import { useLocation, useParams } from 'react-router-dom'; +import { useLocation, useParams } from 'react-router-dom-v5-compat'; import DataSourceTabPage from 'app/features/datasources/components/DataSourceTabPage'; export function EditDataSourcePage() { - const { uid } = useParams<{ uid: string }>(); + const { uid = '' } = useParams<{ uid: string }>(); const location = useLocation(); const params = new URLSearchParams(location.search); const pageId = params.get('page'); diff --git a/public/app/features/connections/routes.tsx b/public/app/features/connections/routes.tsx index d49a322e8f6..935caa40164 100644 --- a/public/app/features/connections/routes.tsx +++ b/public/app/features/connections/routes.tsx @@ -1,12 +1,12 @@ import { SafeDynamicImport } from 'app/core/components/DynamicImports/SafeDynamicImport'; import { RouteDescriptor } from 'app/core/navigation/types'; -import { ROUTE_BASE_ID } from './constants'; +import { ROUTES } from './constants'; export function getRoutes(): RouteDescriptor[] { return [ { - path: `/${ROUTE_BASE_ID}`, + path: ROUTES.Base, exact: false, component: SafeDynamicImport( () => import(/* webpackChunkName: "Connections"*/ 'app/features/connections/Connections') diff --git a/public/app/features/connections/tabs/ConnectData/ConnectData.tsx b/public/app/features/connections/tabs/ConnectData/ConnectData.tsx index 63737f4cdff..bc21502dfcb 100644 --- a/public/app/features/connections/tabs/ConnectData/ConnectData.tsx +++ b/public/app/features/connections/tabs/ConnectData/ConnectData.tsx @@ -1,6 +1,5 @@ import { css } from '@emotion/css'; -import { useMemo, useState } from 'react'; -import * as React from 'react'; +import { useMemo, useState, FormEvent, MouseEvent } from 'react'; import { GrafanaTheme2, PluginType } from '@grafana/data'; import { useStyles2, LoadingPlaceholder, EmptyState } from '@grafana/ui'; @@ -38,7 +37,7 @@ export function AddNewConnection() { const styles = useStyles2(getStyles); const canCreateDataSources = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate); - const handleSearchChange = (e: React.FormEvent) => { + const handleSearchChange = (e: FormEvent) => { setQueryParams({ search: e.currentTarget.value.toLowerCase(), }); @@ -62,7 +61,7 @@ export function AddNewConnection() { [plugins] ); - const onClickCardGridItem = (e: React.MouseEvent, item: CardGridItem) => { + const onClickCardGridItem = (e: MouseEvent, item: CardGridItem) => { if (!canCreateDataSources) { e.preventDefault(); e.stopPropagation(); diff --git a/public/app/features/datasources/components/DataSourceAddButton.tsx b/public/app/features/datasources/components/DataSourceAddButton.tsx index 8d7de1d5cc0..3d5d9fead3f 100644 --- a/public/app/features/datasources/components/DataSourceAddButton.tsx +++ b/public/app/features/datasources/components/DataSourceAddButton.tsx @@ -2,16 +2,14 @@ import { config } from '@grafana/runtime'; import { LinkButton } from '@grafana/ui'; import { contextSrv } from 'app/core/core'; import { Trans } from 'app/core/internationalization'; +import { ROUTES } from 'app/features/connections/constants'; import { AccessControlAction } from 'app/types'; -import { useDataSourcesRoutes } from '../state'; - export function DataSourceAddButton(): JSX.Element | null { const canCreateDataSource = contextSrv.hasPermission(AccessControlAction.DataSourcesCreate); - const dataSourcesRoutes = useDataSourcesRoutes(); return canCreateDataSource ? ( - + Add new data source ) : null; diff --git a/public/app/features/datasources/components/DataSourcesList.tsx b/public/app/features/datasources/components/DataSourcesList.tsx index bf5a3f2f829..e9cf467c97f 100644 --- a/public/app/features/datasources/components/DataSourcesList.tsx +++ b/public/app/features/datasources/components/DataSourcesList.tsx @@ -9,7 +9,8 @@ import { contextSrv } from 'app/core/core'; import { Trans, t } from 'app/core/internationalization'; import { StoreState, AccessControlAction, useSelector } from 'app/types'; -import { getDataSources, getDataSourcesCount, useDataSourcesRoutes, useLoadDataSources } from '../state'; +import { ROUTES } from '../../connections/constants'; +import { getDataSources, getDataSourcesCount, useLoadDataSources } from '../state'; import { trackDataSourcesListViewed } from '../tracking'; import { DataSourcesListCard } from './DataSourcesListCard'; @@ -54,7 +55,6 @@ export function DataSourcesListView({ hasExploreRights, }: ViewProps) { const styles = useStyles2(getStyles); - const dataSourcesRoutes = useDataSourcesRoutes(); const location = useLocation(); useEffect(() => { @@ -69,7 +69,7 @@ export function DataSourcesListView({ + Add data source } diff --git a/public/app/features/datasources/components/DataSourcesListCard.tsx b/public/app/features/datasources/components/DataSourcesListCard.tsx index f93c3d91def..0c77ea501aa 100644 --- a/public/app/features/datasources/components/DataSourcesListCard.tsx +++ b/public/app/features/datasources/components/DataSourcesListCard.tsx @@ -5,7 +5,7 @@ import { DataSourceSettings, GrafanaTheme2 } from '@grafana/data'; import { config } from '@grafana/runtime'; import { Card, LinkButton, Stack, Tag, useStyles2 } from '@grafana/ui'; -import { useDataSourcesRoutes } from '../state'; +import { ROUTES } from '../../connections/constants'; import { trackCreateDashboardClicked, trackExploreClicked } from '../tracking'; import { constructDataSourceExploreUrl } from '../utils'; @@ -16,8 +16,7 @@ export interface Props { } export function DataSourcesListCard({ dataSource, hasWriteRights, hasExploreRights }: Props) { - const dataSourcesRoutes = useDataSourcesRoutes(); - const dsLink = config.appSubUrl + dataSourcesRoutes.Edit.replace(/:uid/gi, dataSource.uid); + const dsLink = config.appSubUrl + ROUTES.DataSourcesEdit.replace(/:uid/gi, dataSource.uid); const styles = useStyles2(getStyles); return ( diff --git a/public/app/features/datasources/components/NewDataSource.tsx b/public/app/features/datasources/components/NewDataSource.tsx index 86501a76477..e24ab0953fa 100644 --- a/public/app/features/datasources/components/NewDataSource.tsx +++ b/public/app/features/datasources/components/NewDataSource.tsx @@ -1,4 +1,4 @@ -import { AnyAction } from 'redux'; +import { Action } from 'redux'; import { DataSourcePluginMeta, PluginType } from '@grafana/data'; import { LinkButton, FilterInput } from '@grafana/ui'; @@ -6,6 +6,7 @@ import PageLoader from 'app/core/components/PageLoader/PageLoader'; import { PluginsErrorsInfo } from 'app/features/plugins/components/PluginsErrorsInfo'; import { DataSourcePluginCategory, StoreState, useDispatch, useSelector } from 'app/types'; +import { ROUTES } from '../../connections/constants'; import { DataSourceCategories } from '../components/DataSourceCategories'; import { DataSourceTypeCardList } from '../components/DataSourceTypeCardList'; import { @@ -13,7 +14,6 @@ import { useLoadDataSourcePlugins, getFilteredDataSourcePlugins, setDataSourceTypeSearchQuery, - useDataSourcesRoutes, } from '../state'; export function NewDataSource() { @@ -45,7 +45,7 @@ export type ViewProps = { searchQuery: string; isLoading: boolean; onAddDataSource: (dataSource: DataSourcePluginMeta) => void; - onSetSearchQuery: (q: string) => AnyAction; + onSetSearchQuery: (q: string) => Action; }; export function NewDataSourceView({ @@ -56,8 +56,6 @@ export function NewDataSourceView({ onAddDataSource, onSetSearchQuery, }: ViewProps) { - const dataSourcesRoutes = useDataSourcesRoutes(); - if (isLoading) { return ; } @@ -68,7 +66,7 @@ export function NewDataSourceView({
- + Cancel
diff --git a/public/app/features/datasources/state/contexts.ts b/public/app/features/datasources/state/contexts.ts deleted file mode 100644 index df94279c2f5..00000000000 --- a/public/app/features/datasources/state/contexts.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createContext } from 'react'; - -import { DATASOURCES_ROUTES } from '../constants'; -import { DataSourcesRoutes } from '../types'; - -// The purpose of this context is to be able to override the data-sources routes (used for links for example) used under -// the app/features/datasources modules, so we can reuse them more easily in different parts of the application (e.g. under Connections) -export const DataSourcesRoutesContext = createContext(DATASOURCES_ROUTES); diff --git a/public/app/features/datasources/state/hooks.ts b/public/app/features/datasources/state/hooks.ts index 11587a60d42..d2c956a2a4b 100644 --- a/public/app/features/datasources/state/hooks.ts +++ b/public/app/features/datasources/state/hooks.ts @@ -1,4 +1,4 @@ -import { useContext, useEffect } from 'react'; +import { useEffect } from 'react'; import { DataSourcePluginMeta, DataSourceSettings } from '@grafana/data'; import { cleanUpAction } from 'app/core/actions/cleanUp'; @@ -7,6 +7,7 @@ import { contextSrv } from 'app/core/core'; import { AccessControlAction, useDispatch, useSelector } from 'app/types'; import { ShowConfirmModalEvent } from 'app/types/events'; +import { ROUTES } from '../../connections/constants'; import { DataSourceRights } from '../types'; import { constructDataSourceExploreUrl } from '../utils'; @@ -20,7 +21,6 @@ import { updateDataSource, deleteLoadedDataSource, } from './actions'; -import { DataSourcesRoutesContext } from './contexts'; import { initialDataSourceSettingsState } from './reducers'; import { getDataSource, getDataSourceMeta } from './selectors'; @@ -42,9 +42,8 @@ export const useInitDataSourceSettings = (uid: string) => { export const useTestDataSource = (uid: string) => { const dispatch = useDispatch(); - const dataSourcesRoutes = useDataSourcesRoutes(); - return () => dispatch(testDataSource(uid, dataSourcesRoutes.Edit)); + return () => dispatch(testDataSource(uid, ROUTES.DataSourcesEdit)); }; export const useLoadDataSources = () => { @@ -77,10 +76,9 @@ export const useLoadDataSourcePlugins = () => { export const useAddDatasource = () => { const dispatch = useDispatch(); - const dataSourcesRoutes = useDataSourcesRoutes(); return (plugin: DataSourcePluginMeta) => { - dispatch(addDataSource(plugin, dataSourcesRoutes.Edit)); + dispatch(addDataSource(plugin, ROUTES.DataSourcesEdit)); }; }; @@ -136,7 +134,3 @@ export const useDataSourceRights = (uid: string): DataSourceRights => { hasDeleteRights, }; }; - -export const useDataSourcesRoutes = () => { - return useContext(DataSourcesRoutesContext); -}; diff --git a/public/app/features/datasources/state/index.ts b/public/app/features/datasources/state/index.ts index 37a2d6f5cf0..42fae7a84a7 100644 --- a/public/app/features/datasources/state/index.ts +++ b/public/app/features/datasources/state/index.ts @@ -1,6 +1,5 @@ export * from './actions'; export * from './buildCategories'; -export * from './contexts'; export * from './hooks'; export * from './navModel'; export * from './reducers'; diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx index 2c45596367f..22ba118489b 100644 --- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx +++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx @@ -4,7 +4,8 @@ import * as React from 'react'; import { DataSourcePluginMeta } from '@grafana/data'; import { config } from '@grafana/runtime'; import { Button } from '@grafana/ui'; -import { useDataSourcesRoutes, addDataSource } from 'app/features/datasources/state'; +import { ROUTES } from 'app/features/connections/constants'; +import { addDataSource } from 'app/features/datasources/state'; import { useDispatch } from 'app/types'; import { isDataSourceEditor } from '../../permissions'; @@ -16,15 +17,14 @@ type Props = { export function GetStartedWithDataSource({ plugin }: Props): React.ReactElement | null { const dispatch = useDispatch(); - const dataSourcesRoutes = useDataSourcesRoutes(); const onAddDataSource = useCallback(() => { const meta = { name: plugin.name, id: plugin.id, } as DataSourcePluginMeta; - dispatch(addDataSource(meta, dataSourcesRoutes.Edit)); - }, [dispatch, plugin, dataSourcesRoutes]); + dispatch(addDataSource(meta, ROUTES.DataSourcesEdit)); + }, [dispatch, plugin]); if (!isDataSourceEditor()) { return null;