mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Users/teams: Update to be compatible with react router 6 (#93163)
* UserCreatePage: Make compatible with react router 6 * ServiceAccountPage.test: Make compatible with react router 6 * Update TeamPages
This commit is contained in:
parent
cb372d3fa8
commit
25ebb5b76f
@ -1,6 +1,6 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||||
|
|
||||||
import { NavModelItem } from '@grafana/data';
|
import { NavModelItem } from '@grafana/data';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv } from '@grafana/runtime';
|
||||||
@ -24,7 +24,7 @@ const pageNav: NavModelItem = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const UserCreatePage = () => {
|
const UserCreatePage = () => {
|
||||||
const history = useHistory();
|
const navigate = useNavigate();
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
register,
|
register,
|
||||||
@ -35,9 +35,9 @@ const UserCreatePage = () => {
|
|||||||
async (data: UserDTO) => {
|
async (data: UserDTO) => {
|
||||||
const { id } = await createUser(data);
|
const { id } = await createUser(data);
|
||||||
|
|
||||||
history.push(`/admin/users/edit/${id}`);
|
navigate(`/admin/users/edit/${id}`);
|
||||||
},
|
},
|
||||||
[history]
|
[navigate]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { History, Location } from 'history';
|
|
||||||
import { TestProvider } from 'test/helpers/TestProvider';
|
import { TestProvider } from 'test/helpers/TestProvider';
|
||||||
|
|
||||||
import { RouteDescriptor } from 'app/core/navigation/types';
|
import { RouteDescriptor } from 'app/core/navigation/types';
|
||||||
@ -24,6 +23,12 @@ const setup = (propOverrides: Partial<Props>) => {
|
|||||||
const loadServiceAccountTokensMock = jest.fn();
|
const loadServiceAccountTokensMock = jest.fn();
|
||||||
const updateServiceAccountMock = jest.fn();
|
const updateServiceAccountMock = jest.fn();
|
||||||
|
|
||||||
|
const mockLocation = {
|
||||||
|
search: '',
|
||||||
|
pathname: '',
|
||||||
|
state: undefined,
|
||||||
|
hash: '',
|
||||||
|
};
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
serviceAccount: {} as ServiceAccountDTO,
|
serviceAccount: {} as ServiceAccountDTO,
|
||||||
tokens: [],
|
tokens: [],
|
||||||
@ -34,8 +39,20 @@ const setup = (propOverrides: Partial<Props>) => {
|
|||||||
path: '/org/serviceaccounts/1',
|
path: '/org/serviceaccounts/1',
|
||||||
url: 'http://localhost:3000/org/serviceaccounts/1',
|
url: 'http://localhost:3000/org/serviceaccounts/1',
|
||||||
},
|
},
|
||||||
history: {} as History,
|
history: {
|
||||||
location: {} as Location,
|
length: 0,
|
||||||
|
action: 'PUSH',
|
||||||
|
location: mockLocation,
|
||||||
|
push: jest.fn(),
|
||||||
|
replace: jest.fn(),
|
||||||
|
go: jest.fn(),
|
||||||
|
goBack: jest.fn(),
|
||||||
|
goForward: jest.fn(),
|
||||||
|
block: jest.fn(),
|
||||||
|
listen: jest.fn(),
|
||||||
|
createHref: jest.fn(),
|
||||||
|
},
|
||||||
|
location: mockLocation,
|
||||||
queryParams: {},
|
queryParams: {},
|
||||||
route: {} as RouteDescriptor,
|
route: {} as RouteDescriptor,
|
||||||
timezone: '',
|
timezone: '',
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
import { Route, Router } from 'react-router-dom';
|
import { useParams } from 'react-router-dom-v5-compat';
|
||||||
import { render } from 'test/test-utils';
|
import { render } from 'test/test-utils';
|
||||||
|
|
||||||
import { locationService } from '@grafana/runtime';
|
|
||||||
|
|
||||||
import TeamPages from './TeamPages';
|
import TeamPages from './TeamPages';
|
||||||
import { getMockTeam } from './__mocks__/teamMocks';
|
import { getMockTeam } from './__mocks__/teamMocks';
|
||||||
|
|
||||||
@ -58,18 +56,16 @@ jest.mock('./TeamGroupSync', () => {
|
|||||||
return () => <div>Team group sync</div>;
|
return () => <div>Team group sync</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('react-router-dom-v5-compat', () => ({
|
||||||
|
...jest.requireActual('react-router-dom-v5-compat'),
|
||||||
|
useParams: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
const setup = (propOverrides: { teamId?: number; pageName?: string } = {}) => {
|
const setup = (propOverrides: { teamId?: number; pageName?: string } = {}) => {
|
||||||
const pageName = propOverrides.pageName ?? 'members';
|
const pageName = propOverrides.pageName ?? 'members';
|
||||||
const teamId = propOverrides.teamId ?? 1;
|
const teamId = propOverrides.teamId ?? 1;
|
||||||
locationService.push({ pathname: `/org/teams/edit/${teamId}/${pageName}` });
|
(useParams as jest.Mock).mockReturnValue({ id: `${teamId}`, page: pageName });
|
||||||
|
render(<TeamPages />);
|
||||||
render(
|
|
||||||
<Router history={locationService.getHistory()}>
|
|
||||||
<Route path="/org/teams/edit/:id/:page?">
|
|
||||||
<TeamPages />
|
|
||||||
</Route>
|
|
||||||
</Router>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('TeamPages', () => {
|
describe('TeamPages', () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { memo, useMemo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router-dom-v5-compat';
|
||||||
import { useAsync } from 'react-use';
|
import { useAsync } from 'react-use';
|
||||||
|
|
||||||
import { featureEnabled } from '@grafana/runtime';
|
import { featureEnabled } from '@grafana/runtime';
|
||||||
@ -18,10 +18,10 @@ import { loadTeam } from './state/actions';
|
|||||||
import { getTeamLoadingNav } from './state/navModel';
|
import { getTeamLoadingNav } from './state/navModel';
|
||||||
import { getTeam } from './state/selectors';
|
import { getTeam } from './state/selectors';
|
||||||
|
|
||||||
interface TeamPageRouteParams {
|
type TeamPageRouteParams = {
|
||||||
id: string;
|
id: string;
|
||||||
page?: string;
|
page?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
enum PageTypes {
|
enum PageTypes {
|
||||||
Members = 'members',
|
Members = 'members',
|
||||||
@ -32,7 +32,7 @@ enum PageTypes {
|
|||||||
const PAGES = ['members', 'settings', 'groupsync'];
|
const PAGES = ['members', 'settings', 'groupsync'];
|
||||||
|
|
||||||
const teamSelector = createSelector(
|
const teamSelector = createSelector(
|
||||||
[(state: StoreState) => state.team, (_: StoreState, teamId: number) => teamId],
|
[(state: StoreState) => state.team, (_: StoreState, teamId: string) => teamId],
|
||||||
(team, teamId) => getTeam(team, teamId)
|
(team, teamId) => getTeam(team, teamId)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ const pageNavSelector = createSelector(
|
|||||||
[
|
[
|
||||||
(state: StoreState) => state.navIndex,
|
(state: StoreState) => state.navIndex,
|
||||||
(_state: StoreState, pageName: string) => pageName,
|
(_state: StoreState, pageName: string) => pageName,
|
||||||
(_state: StoreState, _pageName: string, teamId: number) => teamId,
|
(_state: StoreState, _pageName: string, teamId: string) => teamId,
|
||||||
],
|
],
|
||||||
(navIndex, pageName, teamId) => {
|
(navIndex, pageName, teamId) => {
|
||||||
const teamLoadingNav = getTeamLoadingNav(pageName);
|
const teamLoadingNav = getTeamLoadingNav(pageName);
|
||||||
@ -50,8 +50,7 @@ const pageNavSelector = createSelector(
|
|||||||
|
|
||||||
const TeamPages = memo(() => {
|
const TeamPages = memo(() => {
|
||||||
const isSyncEnabled = useRef(featureEnabled('teamsync'));
|
const isSyncEnabled = useRef(featureEnabled('teamsync'));
|
||||||
const params = useParams<TeamPageRouteParams>();
|
const { id: teamId = '', page } = useParams<TeamPageRouteParams>();
|
||||||
const teamId = useMemo(() => parseInt(params.id, 10), [params]);
|
|
||||||
const team = useSelector((state) => teamSelector(state, teamId));
|
const team = useSelector((state) => teamSelector(state, teamId));
|
||||||
|
|
||||||
let defaultPage = 'members';
|
let defaultPage = 'members';
|
||||||
@ -59,7 +58,7 @@ const TeamPages = memo(() => {
|
|||||||
if (!team || !contextSrv.hasPermissionInMetadata(AccessControlAction.ActionTeamsPermissionsRead, team)) {
|
if (!team || !contextSrv.hasPermissionInMetadata(AccessControlAction.ActionTeamsPermissionsRead, team)) {
|
||||||
defaultPage = 'settings';
|
defaultPage = 'settings';
|
||||||
}
|
}
|
||||||
const pageName = params.page ?? defaultPage;
|
const pageName = page ?? defaultPage;
|
||||||
const pageNav = useSelector((state) => pageNavSelector(state, pageName, teamId));
|
const pageNav = useSelector((state) => pageNavSelector(state, pageName, teamId));
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -83,6 +82,7 @@ const TeamPages = memo(() => {
|
|||||||
if (canReadTeamPermissions) {
|
if (canReadTeamPermissions) {
|
||||||
return <TeamPermissions team={team!} />;
|
return <TeamPermissions team={team!} />;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
case PageTypes.Settings:
|
case PageTypes.Settings:
|
||||||
return canReadTeam && <TeamSettings team={team!} />;
|
return canReadTeam && <TeamSettings team={team!} />;
|
||||||
case PageTypes.GroupSync:
|
case PageTypes.GroupSync:
|
||||||
|
@ -60,7 +60,7 @@ export function loadTeams(initial = false): ThunkResult<void> {
|
|||||||
|
|
||||||
const loadTeamsWithDebounce = debounce((dispatch) => dispatch(loadTeams()), 500);
|
const loadTeamsWithDebounce = debounce((dispatch) => dispatch(loadTeams()), 500);
|
||||||
|
|
||||||
export function loadTeam(id: number): ThunkResult<Promise<void>> {
|
export function loadTeam(id: string | number): ThunkResult<Promise<void>> {
|
||||||
return async (dispatch) => {
|
return async (dispatch) => {
|
||||||
const response = await getBackendSrv().get(`/api/teams/${id}`, accessControlQueryParam());
|
const response = await getBackendSrv().get(`/api/teams/${id}`, accessControlQueryParam());
|
||||||
dispatch(teamLoaded(response));
|
dispatch(teamLoaded(response));
|
||||||
|
Loading…
Reference in New Issue
Block a user