mirror of
https://github.com/grafana/grafana.git
synced 2025-02-09 23:16:16 -06:00
SelectOrgPage: migrate API function calls to Redux (#43133)
* SelectOrgPage: migrate API function calls to Redux * used a much better approach * writes test for getUserOrganizations action * writes test for userOrganizationsLoaded reducer * change userOrg to plural
This commit is contained in:
parent
8206802f19
commit
d03aef1951
@ -1,10 +1,10 @@
|
||||
import React, { FC, useState } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { getBackendSrv, config } from '@grafana/runtime';
|
||||
import { UserOrg } from 'app/types';
|
||||
import { useAsync } from 'react-use';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { StoreState, UserOrg } from 'app/types';
|
||||
import { useEffectOnce } from 'react-use';
|
||||
import { Button, HorizontalGroup } from '@grafana/ui';
|
||||
import { setUserOrganization } from './state/actions';
|
||||
import { getUserOrganizations, setUserOrganization } from './state/actions';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
|
||||
const navModel = {
|
||||
@ -18,29 +18,31 @@ const navModel = {
|
||||
},
|
||||
};
|
||||
|
||||
const getUserOrgs = async () => {
|
||||
return await getBackendSrv().get('/api/user/orgs');
|
||||
const mapStateToProps = (state: StoreState) => {
|
||||
return {
|
||||
userOrgs: state.organization.userOrgs,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setUserOrganization,
|
||||
getUserOrganizations,
|
||||
};
|
||||
|
||||
const connector = connect(null, mapDispatchToProps);
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
type Props = ConnectedProps<typeof connector>;
|
||||
|
||||
export const SelectOrgPage: FC<Props> = ({ setUserOrganization }) => {
|
||||
const [orgs, setOrgs] = useState<UserOrg[]>();
|
||||
|
||||
export const SelectOrgPage: FC<Props> = ({ setUserOrganization, getUserOrganizations, userOrgs }) => {
|
||||
const setUserOrg = async (org: UserOrg) => {
|
||||
await setUserOrganization(org.orgId);
|
||||
window.location.href = config.appSubUrl + '/';
|
||||
};
|
||||
|
||||
useAsync(async () => {
|
||||
setOrgs(await getUserOrgs());
|
||||
}, []);
|
||||
useEffectOnce(() => {
|
||||
getUserOrganizations();
|
||||
});
|
||||
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>
|
||||
@ -50,8 +52,8 @@ export const SelectOrgPage: FC<Props> = ({ setUserOrganization }) => {
|
||||
now. You can change this later at any time.
|
||||
</p>
|
||||
<HorizontalGroup wrap>
|
||||
{orgs &&
|
||||
orgs.map((org) => (
|
||||
{userOrgs &&
|
||||
userOrgs.map((org) => (
|
||||
<Button key={org.orgId} icon="signin" onClick={() => setUserOrg(org)}>
|
||||
{org.name}
|
||||
</Button>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { updateOrganization, setUserOrganization } from './actions';
|
||||
import { updateOrganization, setUserOrganization, getUserOrganizations } from './actions';
|
||||
import { updateConfigurationSubtitle } from 'app/core/actions';
|
||||
import { thunkTester } from 'test/core/thunk/thunkTester';
|
||||
import { OrgRole } from 'app/types';
|
||||
|
||||
const setup = () => {
|
||||
const initialState = {
|
||||
@ -9,6 +10,7 @@ const setup = () => {
|
||||
id: 1,
|
||||
name: 'New Org Name',
|
||||
},
|
||||
userOrg: [{ orgId: 1, name: 'New Org Name', role: OrgRole.Editor }],
|
||||
},
|
||||
};
|
||||
|
||||
@ -61,3 +63,22 @@ describe('setUserOrganization', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserOrganizations', () => {
|
||||
describe('when getUserOrganizations thunk is dispatched', () => {
|
||||
const getMock = jest.fn().mockResolvedValue({ orgId: 1, name: 'New Org Name', role: OrgRole.Editor });
|
||||
const backendSrvMock: any = {
|
||||
get: getMock,
|
||||
};
|
||||
|
||||
it('then it should dispatch updateConfigurationSubtitle', async () => {
|
||||
const { initialState } = setup();
|
||||
|
||||
const dispatchedActions = await thunkTester(initialState)
|
||||
.givenThunk(getUserOrganizations)
|
||||
.whenThunkIsDispatched({ getBackendSrv: () => backendSrvMock });
|
||||
|
||||
expect(dispatchedActions[0].payload).toEqual(initialState.organization.userOrg[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ThunkResult } from 'app/types';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { organizationLoaded } from './reducers';
|
||||
import { organizationLoaded, userOrganizationsLoaded } from './reducers';
|
||||
import { updateConfigurationSubtitle } from 'app/core/actions';
|
||||
|
||||
type OrganizationDependencies = { getBackendSrv: typeof getBackendSrv };
|
||||
@ -50,3 +50,14 @@ export function createOrganization(
|
||||
dispatch(setUserOrganization(result.orgId));
|
||||
};
|
||||
}
|
||||
|
||||
export function getUserOrganizations(
|
||||
dependencies: OrganizationDependencies = { getBackendSrv: getBackendSrv }
|
||||
): ThunkResult<any> {
|
||||
return async (dispatch) => {
|
||||
const result = await dependencies.getBackendSrv().get('/api/user/orgs');
|
||||
dispatch(userOrganizationsLoaded(result));
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { reducerTester } from '../../../../test/core/redux/reducerTester';
|
||||
import { OrganizationState } from '../../../types';
|
||||
import { initialState, organizationLoaded, organizationReducer, setOrganizationName } from './reducers';
|
||||
import { OrganizationState, OrgRole } from '../../../types';
|
||||
import {
|
||||
initialState,
|
||||
organizationLoaded,
|
||||
organizationReducer,
|
||||
userOrganizationsLoaded,
|
||||
setOrganizationName,
|
||||
} from './reducers';
|
||||
|
||||
describe('organizationReducer', () => {
|
||||
describe('when organizationLoaded is dispatched', () => {
|
||||
@ -10,6 +16,7 @@ describe('organizationReducer', () => {
|
||||
.whenActionIsDispatched(organizationLoaded({ id: 1, name: 'An org' }))
|
||||
.thenStateShouldEqual({
|
||||
organization: { id: 1, name: 'An org' },
|
||||
userOrgs: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -21,6 +28,23 @@ describe('organizationReducer', () => {
|
||||
.whenActionIsDispatched(setOrganizationName('New Name'))
|
||||
.thenStateShouldEqual({
|
||||
organization: { id: 1, name: 'New Name' },
|
||||
userOrgs: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when userOrganizationsLoaded is dispatched', () => {
|
||||
it('then state should be correct', () => {
|
||||
reducerTester<OrganizationState>()
|
||||
.givenReducer(organizationReducer, {
|
||||
...initialState,
|
||||
organization: { id: 1, name: 'An org' },
|
||||
userOrgs: [],
|
||||
})
|
||||
.whenActionIsDispatched(userOrganizationsLoaded([{ orgId: 1, name: 'New org', role: OrgRole.Editor }]))
|
||||
.thenStateShouldEqual({
|
||||
organization: { id: 1, name: 'An org' },
|
||||
userOrgs: [{ orgId: 1, name: 'New org', role: OrgRole.Editor }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
import { Organization, OrganizationState } from 'app/types';
|
||||
import { Organization, OrganizationState, UserOrg } from 'app/types';
|
||||
|
||||
export const initialState: OrganizationState = {
|
||||
organization: {} as Organization,
|
||||
userOrgs: [] as UserOrg[],
|
||||
};
|
||||
|
||||
const organizationSlice = createSlice({
|
||||
@ -16,10 +17,13 @@ const organizationSlice = createSlice({
|
||||
setOrganizationName: (state, action: PayloadAction<string>): OrganizationState => {
|
||||
return { ...state, organization: { ...state.organization, name: action.payload } };
|
||||
},
|
||||
userOrganizationsLoaded: (state, action: PayloadAction<UserOrg[]>): OrganizationState => {
|
||||
return { ...state, userOrgs: action.payload };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setOrganizationName, organizationLoaded } = organizationSlice.actions;
|
||||
export const { setOrganizationName, organizationLoaded, userOrganizationsLoaded } = organizationSlice.actions;
|
||||
|
||||
export const organizationReducer = organizationSlice.reducer;
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { UserOrg } from 'app/types';
|
||||
|
||||
export interface Organization {
|
||||
name: string;
|
||||
id: number;
|
||||
@ -5,4 +7,5 @@ export interface Organization {
|
||||
|
||||
export interface OrganizationState {
|
||||
organization: Organization;
|
||||
userOrgs: UserOrg[];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user