Orgs: move duplicate API calls to Redux (#43030)
* WIP: move user/using api call to redux * WIP: use redux instead in NewOrgPage component * moved all the createOrg logic into redux * type the redux state and action creators automatically * adds test for setUserOrganization thunk * update selectOrgPage to use Redux instead * removes unnecessary dispatch call
This commit is contained in:
@@ -2,18 +2,10 @@ import React, { FC } from 'react';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { Button, Input, Field, Form } from '@grafana/ui';
|
||||
import { getConfig } from 'app/core/config';
|
||||
import { StoreState } from 'app/types';
|
||||
import { connect } from 'react-redux';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
|
||||
const createOrg = async (newOrg: { name: string }) => {
|
||||
const result = await getBackendSrv().post('/api/orgs/', newOrg);
|
||||
|
||||
await getBackendSrv().post('/api/user/using/' + result.orgId);
|
||||
window.location.href = getConfig().appSubUrl + '/org';
|
||||
};
|
||||
import { createOrganization } from './state/actions';
|
||||
|
||||
const validateOrg = async (orgName: string) => {
|
||||
try {
|
||||
@@ -28,15 +20,27 @@ const validateOrg = async (orgName: string) => {
|
||||
return 'Organization already exists';
|
||||
};
|
||||
|
||||
interface PropsWithState {
|
||||
navModel: NavModel;
|
||||
}
|
||||
const mapStateToProps = (state: StoreState) => {
|
||||
return { navModel: getNavModel(state.navIndex, 'global-orgs') };
|
||||
};
|
||||
|
||||
const mapDispatchToProps = {
|
||||
createOrganization,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
type Props = ConnectedProps<typeof connector>;
|
||||
|
||||
interface CreateOrgFormDTO {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const NewOrgPage: FC<PropsWithState> = ({ navModel }) => {
|
||||
export const NewOrgPage: FC<Props> = ({ navModel, createOrganization }) => {
|
||||
const createOrg = (newOrg: { name: string }) => {
|
||||
createOrganization(newOrg);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>
|
||||
@@ -71,8 +75,4 @@ export const NewOrgPage: FC<PropsWithState> = ({ navModel }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: StoreState) => {
|
||||
return { navModel: getNavModel(state.navIndex, 'global-orgs') };
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(NewOrgPage);
|
||||
export default connector(NewOrgPage);
|
||||
|
||||
@@ -4,6 +4,8 @@ import { getBackendSrv, config } from '@grafana/runtime';
|
||||
import { UserOrg } from 'app/types';
|
||||
import { useAsync } from 'react-use';
|
||||
import { Button, HorizontalGroup } from '@grafana/ui';
|
||||
import { setUserOrganization } from './state/actions';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
|
||||
const navModel = {
|
||||
main: {
|
||||
@@ -19,17 +21,23 @@ const navModel = {
|
||||
const getUserOrgs = async () => {
|
||||
return await getBackendSrv().get('/api/user/orgs');
|
||||
};
|
||||
const setUserOrg = async (org: UserOrg) => {
|
||||
return await getBackendSrv()
|
||||
.post('/api/user/using/' + org.orgId)
|
||||
.then(() => {
|
||||
window.location.href = config.appSubUrl + '/';
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
setUserOrganization,
|
||||
};
|
||||
|
||||
export const SelectOrgPage: FC = () => {
|
||||
const connector = connect(null, mapDispatchToProps);
|
||||
|
||||
type Props = ConnectedProps<typeof connector>;
|
||||
|
||||
export const SelectOrgPage: FC<Props> = ({ setUserOrganization }) => {
|
||||
const [orgs, setOrgs] = useState<UserOrg[]>();
|
||||
|
||||
const setUserOrg = async (org: UserOrg) => {
|
||||
setUserOrganization(org.orgId);
|
||||
window.location.href = config.appSubUrl + '/';
|
||||
};
|
||||
|
||||
useAsync(async () => {
|
||||
setOrgs(await getUserOrgs());
|
||||
}, []);
|
||||
@@ -55,4 +63,4 @@ export const SelectOrgPage: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectOrgPage;
|
||||
export default connector(SelectOrgPage);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { updateOrganization } from './actions';
|
||||
import { updateOrganization, setUserOrganization } from './actions';
|
||||
import { updateConfigurationSubtitle } from 'app/core/actions';
|
||||
import { thunkTester } from 'test/core/thunk/thunkTester';
|
||||
|
||||
@@ -38,3 +38,26 @@ describe('updateOrganization', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setUserOrganization', () => {
|
||||
describe('when setUserOrganization thunk is dispatched', () => {
|
||||
const postMock = jest.fn().mockResolvedValue({ id: 1, name: 'New Org Name' });
|
||||
|
||||
const backendSrvMock: any = {
|
||||
post: postMock,
|
||||
};
|
||||
|
||||
const orgId = 1;
|
||||
|
||||
it('then it should dispatch updateConfigurationSubtitle', async () => {
|
||||
const { initialState } = setup();
|
||||
|
||||
const dispatchedActions = await thunkTester(initialState)
|
||||
.givenThunk(setUserOrganization)
|
||||
.whenThunkIsDispatched(orgId, { getBackendSrv: () => backendSrvMock });
|
||||
|
||||
expect(dispatchedActions[0].type).toEqual(updateConfigurationSubtitle.type);
|
||||
expect(dispatchedActions[0].payload).toEqual(initialState.organization.organization.name);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ThunkResult } from 'app/types';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { organizationLoaded } from './reducers';
|
||||
import { updateConfigurationSubtitle } from 'app/core/actions';
|
||||
import { getConfig } from 'app/core/config';
|
||||
|
||||
type OrganizationDependencies = { getBackendSrv: typeof getBackendSrv };
|
||||
|
||||
@@ -28,3 +29,26 @@ export function updateOrganization(
|
||||
dispatch(loadOrganization(dependencies));
|
||||
};
|
||||
}
|
||||
|
||||
export function setUserOrganization(
|
||||
orgId: number,
|
||||
dependencies: OrganizationDependencies = { getBackendSrv: getBackendSrv }
|
||||
): ThunkResult<any> {
|
||||
return async (dispatch) => {
|
||||
const organizationResponse = await dependencies.getBackendSrv().post('/api/user/using/' + orgId);
|
||||
|
||||
dispatch(updateConfigurationSubtitle(organizationResponse.name));
|
||||
};
|
||||
}
|
||||
|
||||
export function createOrganization(
|
||||
newOrg: { name: string },
|
||||
dependencies: OrganizationDependencies = { getBackendSrv: getBackendSrv }
|
||||
): ThunkResult<any> {
|
||||
return async (dispatch) => {
|
||||
const result = await dependencies.getBackendSrv().post('/api/orgs/', newOrg);
|
||||
|
||||
dispatch(setUserOrganization(result.orgId));
|
||||
window.location.href = getConfig().appSubUrl + '/org';
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user