diff --git a/public/app/features/org/SelectOrgPage.tsx b/public/app/features/org/SelectOrgPage.tsx
index 01295c13742..1367e5d6573 100644
--- a/public/app/features/org/SelectOrgPage.tsx
+++ b/public/app/features/org/SelectOrgPage.tsx
@@ -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;
-export const SelectOrgPage: FC = ({ setUserOrganization }) => {
- const [orgs, setOrgs] = useState();
-
+export const SelectOrgPage: FC = ({ 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 (
@@ -50,8 +52,8 @@ export const SelectOrgPage: FC = ({ setUserOrganization }) => {
now. You can change this later at any time.
- {orgs &&
- orgs.map((org) => (
+ {userOrgs &&
+ userOrgs.map((org) => (
diff --git a/public/app/features/org/state/actions.test.ts b/public/app/features/org/state/actions.test.ts
index 7a772a0268d..9dd97426e5f 100644
--- a/public/app/features/org/state/actions.test.ts
+++ b/public/app/features/org/state/actions.test.ts
@@ -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]);
+ });
+ });
+});
diff --git a/public/app/features/org/state/actions.ts b/public/app/features/org/state/actions.ts
index 554f153b8b2..6b01d1b2f91 100644
--- a/public/app/features/org/state/actions.ts
+++ b/public/app/features/org/state/actions.ts
@@ -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 {
+ return async (dispatch) => {
+ const result = await dependencies.getBackendSrv().get('/api/user/orgs');
+ dispatch(userOrganizationsLoaded(result));
+
+ return result;
+ };
+}
diff --git a/public/app/features/org/state/reducers.test.ts b/public/app/features/org/state/reducers.test.ts
index 49982c12273..00d47a26c6c 100644
--- a/public/app/features/org/state/reducers.test.ts
+++ b/public/app/features/org/state/reducers.test.ts
@@ -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()
+ .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 }],
});
});
});
diff --git a/public/app/features/org/state/reducers.ts b/public/app/features/org/state/reducers.ts
index 0c459c58541..9ce9f058cd6 100644
--- a/public/app/features/org/state/reducers.ts
+++ b/public/app/features/org/state/reducers.ts
@@ -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): OrganizationState => {
return { ...state, organization: { ...state.organization, name: action.payload } };
},
+ userOrganizationsLoaded: (state, action: PayloadAction): OrganizationState => {
+ return { ...state, userOrgs: action.payload };
+ },
},
});
-export const { setOrganizationName, organizationLoaded } = organizationSlice.actions;
+export const { setOrganizationName, organizationLoaded, userOrganizationsLoaded } = organizationSlice.actions;
export const organizationReducer = organizationSlice.reducer;
diff --git a/public/app/types/organization.ts b/public/app/types/organization.ts
index da67ead34ae..926bced7bd5 100644
--- a/public/app/types/organization.ts
+++ b/public/app/types/organization.ts
@@ -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[];
}