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 { getBackendSrv } from '@grafana/runtime';
|
||||||
import Page from 'app/core/components/Page/Page';
|
import Page from 'app/core/components/Page/Page';
|
||||||
import { Button, Input, Field, Form } from '@grafana/ui';
|
import { Button, Input, Field, Form } from '@grafana/ui';
|
||||||
import { getConfig } from 'app/core/config';
|
|
||||||
import { StoreState } from 'app/types';
|
import { StoreState } from 'app/types';
|
||||||
import { connect } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
import { NavModel } from '@grafana/data';
|
|
||||||
import { getNavModel } from '../../core/selectors/navModel';
|
import { getNavModel } from '../../core/selectors/navModel';
|
||||||
|
import { createOrganization } from './state/actions';
|
||||||
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';
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateOrg = async (orgName: string) => {
|
const validateOrg = async (orgName: string) => {
|
||||||
try {
|
try {
|
||||||
@@ -28,15 +20,27 @@ const validateOrg = async (orgName: string) => {
|
|||||||
return 'Organization already exists';
|
return 'Organization already exists';
|
||||||
};
|
};
|
||||||
|
|
||||||
interface PropsWithState {
|
const mapStateToProps = (state: StoreState) => {
|
||||||
navModel: NavModel;
|
return { navModel: getNavModel(state.navIndex, 'global-orgs') };
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
createOrganization,
|
||||||
|
};
|
||||||
|
|
||||||
|
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||||
|
|
||||||
|
type Props = ConnectedProps<typeof connector>;
|
||||||
|
|
||||||
interface CreateOrgFormDTO {
|
interface CreateOrgFormDTO {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NewOrgPage: FC<PropsWithState> = ({ navModel }) => {
|
export const NewOrgPage: FC<Props> = ({ navModel, createOrganization }) => {
|
||||||
|
const createOrg = (newOrg: { name: string }) => {
|
||||||
|
createOrganization(newOrg);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page navModel={navModel}>
|
<Page navModel={navModel}>
|
||||||
<Page.Contents>
|
<Page.Contents>
|
||||||
@@ -71,8 +75,4 @@ export const NewOrgPage: FC<PropsWithState> = ({ navModel }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state: StoreState) => {
|
export default connector(NewOrgPage);
|
||||||
return { navModel: getNavModel(state.navIndex, 'global-orgs') };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(NewOrgPage);
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { getBackendSrv, config } from '@grafana/runtime';
|
|||||||
import { UserOrg } from 'app/types';
|
import { UserOrg } from 'app/types';
|
||||||
import { useAsync } from 'react-use';
|
import { useAsync } from 'react-use';
|
||||||
import { Button, HorizontalGroup } from '@grafana/ui';
|
import { Button, HorizontalGroup } from '@grafana/ui';
|
||||||
|
import { setUserOrganization } from './state/actions';
|
||||||
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
|
|
||||||
const navModel = {
|
const navModel = {
|
||||||
main: {
|
main: {
|
||||||
@@ -19,17 +21,23 @@ const navModel = {
|
|||||||
const getUserOrgs = async () => {
|
const getUserOrgs = async () => {
|
||||||
return await getBackendSrv().get('/api/user/orgs');
|
return await getBackendSrv().get('/api/user/orgs');
|
||||||
};
|
};
|
||||||
const setUserOrg = async (org: UserOrg) => {
|
|
||||||
return await getBackendSrv()
|
const mapDispatchToProps = {
|
||||||
.post('/api/user/using/' + org.orgId)
|
setUserOrganization,
|
||||||
.then(() => {
|
|
||||||
window.location.href = config.appSubUrl + '/';
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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 [orgs, setOrgs] = useState<UserOrg[]>();
|
||||||
|
|
||||||
|
const setUserOrg = async (org: UserOrg) => {
|
||||||
|
setUserOrganization(org.orgId);
|
||||||
|
window.location.href = config.appSubUrl + '/';
|
||||||
|
};
|
||||||
|
|
||||||
useAsync(async () => {
|
useAsync(async () => {
|
||||||
setOrgs(await getUserOrgs());
|
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 { updateConfigurationSubtitle } from 'app/core/actions';
|
||||||
import { thunkTester } from 'test/core/thunk/thunkTester';
|
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 { getBackendSrv } from '@grafana/runtime';
|
||||||
import { organizationLoaded } from './reducers';
|
import { organizationLoaded } from './reducers';
|
||||||
import { updateConfigurationSubtitle } from 'app/core/actions';
|
import { updateConfigurationSubtitle } from 'app/core/actions';
|
||||||
|
import { getConfig } from 'app/core/config';
|
||||||
|
|
||||||
type OrganizationDependencies = { getBackendSrv: typeof getBackendSrv };
|
type OrganizationDependencies = { getBackendSrv: typeof getBackendSrv };
|
||||||
|
|
||||||
@@ -28,3 +29,26 @@ export function updateOrganization(
|
|||||||
dispatch(loadOrganization(dependencies));
|
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