diff --git a/src/action_types/groups.js b/src/action_types/groups.js index 99a62dbb5..d52239f06 100644 --- a/src/action_types/groups.js +++ b/src/action_types/groups.js @@ -32,4 +32,21 @@ export default keyMirror({ GET_GROUP_SUCCESS: null, GET_GROUP_FAILURE: null, RECEIVED_GROUP: null, + + RECEIVED_GROUPS: null, + + GET_GROUPS_ASSOCIATED_TO_TEAM_REQUEST: null, + GET_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS: null, + GET_GROUPS_ASSOCIATED_TO_TEAM_FAILURE: null, + RECEIVED_GROUPS_ASSOCIATED_TO_TEAM: null, + + GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_REQUEST: null, + GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS: null, + GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_FAILURE: null, + RECEIVED_ALL_GROUPS_ASSOCIATED_TO_TEAM: null, + + GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_REQUEST: null, + GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_SUCCESS: null, + GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_FAILURE: null, + RECEIVED_GROUPS_NOT_ASSOCIATED_TO_TEAM: null, }); diff --git a/src/actions/groups.js b/src/actions/groups.js index c9618ffcb..7e05425e5 100644 --- a/src/actions/groups.js +++ b/src/actions/groups.js @@ -30,9 +30,12 @@ export function linkGroupSyncable(groupID: string, syncableID: string, syncableT return {error}; } + const dispatches = []; + let type; switch (syncableType) { case Groups.SYNCABLE_TYPE_TEAM: + dispatches.push({type: GroupTypes.RECEIVED_GROUPS_ASSOCIATED_TO_TEAM, data: {teamID: syncableID, groups: [{id: groupID}]}}); type = GroupTypes.LINKED_GROUP_TEAM; break; case Groups.SYNCABLE_TYPE_CHANNEL: @@ -42,10 +45,9 @@ export function linkGroupSyncable(groupID: string, syncableID: string, syncableT console.warn(`unhandled syncable type ${syncableType}`); // eslint-disable-line no-console } - dispatch(batchActions([ - {type: GroupTypes.LINK_GROUP_SYNCABLE_SUCCESS, data: null}, - {type, data}, - ])); + dispatches.push(...[{type: GroupTypes.LINK_GROUP_SYNCABLE_SUCCESS, data: null}, {type, data}]); + + dispatch(batchActions(dispatches)); return {data: true}; }; @@ -66,12 +68,15 @@ export function unlinkGroupSyncable(groupID: string, syncableID: string, syncabl return {error}; } + const dispatches = []; + let type; const data = {group_id: groupID, syncable_id: syncableID}; switch (syncableType) { case Groups.SYNCABLE_TYPE_TEAM: type = GroupTypes.UNLINKED_GROUP_TEAM; data.syncable_id = syncableID; + dispatches.push({type: GroupTypes.RECEIVED_GROUPS_NOT_ASSOCIATED_TO_TEAM, data: {teamID: syncableID, groups: [{id: groupID}]}}); break; case Groups.SYNCABLE_TYPE_CHANNEL: type = GroupTypes.UNLINKED_GROUP_CHANNEL; @@ -81,10 +86,9 @@ export function unlinkGroupSyncable(groupID: string, syncableID: string, syncabl console.warn(`unhandled syncable type ${syncableType}`); // eslint-disable-line no-console } - dispatch(batchActions([ - {type: GroupTypes.UNLINK_GROUP_SYNCABLE_SUCCESS, data: null}, - {type, data}, - ])); + dispatches.push(...[{type: GroupTypes.UNLINK_GROUP_SYNCABLE_SUCCESS, data: null}, {type, data}]); + + dispatch(batchActions(dispatches)); return {data: true}; }; @@ -163,3 +167,52 @@ export function getGroup(id: string): ActionFunc { ], }); } + +export function getGroupsNotAssociatedToTeam(teamID: string, q: string = '', page: number = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { + return bindClientFunc({ + clientFunc: Client4.getGroupsNotAssociatedToTeam, + onRequest: GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_REQUEST, + onSuccess: [GroupTypes.RECEIVED_GROUPS, GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_SUCCESS], + onFailure: GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_FAILURE, + params: [ + teamID, + q, + page, + perPage, + ], + }); +} + +export function getAllGroupsAssociatedToTeam(teamID: string): ActionFunc { + return bindClientFunc({ + clientFunc: async (param1) => { + const result = await Client4.getAllGroupsAssociatedToTeam(param1); + result.teamID = param1; + return result; + }, + onRequest: GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_REQUEST, + onSuccess: [GroupTypes.RECEIVED_ALL_GROUPS_ASSOCIATED_TO_TEAM, GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS], + onFailure: GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_FAILURE, + params: [ + teamID, + ], + }); +} + +export function getGroupsAssociatedToTeam(teamID: string, q: string = '', page: number = 0, perPage: number = General.PAGE_SIZE_DEFAULT): ActionFunc { + return bindClientFunc({ + clientFunc: async (param1, param2, param3, param4) => { + const result = await Client4.getGroupsAssociatedToTeam(param1, param2, param3, param4); + return {groups: result.groups, totalGroupCount: result.total_group_count, teamID: param1}; + }, + onRequest: GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_REQUEST, + onSuccess: [GroupTypes.RECEIVED_GROUPS_ASSOCIATED_TO_TEAM, GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS], + onFailure: GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_FAILURE, + params: [ + teamID, + q, + page, + perPage, + ], + }); +} \ No newline at end of file diff --git a/test/actions/groups.test.js b/src/actions/groups.test.js similarity index 63% rename from test/actions/groups.test.js rename to src/actions/groups.test.js index fa332591e..9741eecb4 100644 --- a/test/actions/groups.test.js +++ b/src/actions/groups.test.js @@ -304,4 +304,185 @@ describe('Actions.Groups', () => { assert.ok(syncables[groupID].teams.length === beforeTeamsLength - 1); assert.ok(syncables[groupID].channels.length === beforeChannelsLength - 1); }); + + it('getAllGroupsAssociatedToTeam', async () => { + const teamID = '5rgoajywb3nfbdtyafbod47ryb'; + + const response = { + groups: [ + { + id: 'xh585kyz3tn55q6ipfo57btwnc', + name: '9uobsi3xb3y5tfjb3ze7umnh1o', + display_name: 'abc', + description: '', + source: 'ldap', + remote_id: 'abc', + create_at: 1553808969975, + update_at: 1553808969975, + delete_at: 0, + has_syncables: false, + member_count: 2, + }, + { + id: 'tnd8zod9f3fdtqosxjmhwucbth', + name: 'nobctj4brfgtpj3a1peiyq47tc', + display_name: 'engineering', + description: '', + source: 'ldap', + remote_id: 'engineering', + create_at: 1553808971099, + update_at: 1553808971099, + delete_at: 0, + has_syncables: false, + member_count: 8, + }, + { + id: 'qhdp6g7aubbpiyja7c4sgpe7tc', + name: 'x5bjwa4kwirpmqudhp5dterine', + display_name: 'qa', + description: '', + source: 'ldap', + remote_id: 'qa', + create_at: 1553808971548, + update_at: 1553808971548, + delete_at: 0, + has_syncables: false, + member_count: 2, + }, + ], + total_group_count: 3, + }; + + nock(Client4.getBaseRoute()). + get(`/teams/${teamID}/groups?paginate=false`). + reply(200, response); + + await Actions.getAllGroupsAssociatedToTeam(teamID)(store.dispatch, store.getState); + + const state = store.getState(); + const request = state.requests.groups.getAllGroupsAssociatedToTeam; + if (request.status === RequestStatus.FAILURE) { + throw new Error('getGroup request failed err=' + request.error); + } + + const groupIDs = state.entities.teams.groupsAssociatedToTeam[teamID]; + assert.strictEqual(groupIDs.length, response.groups.length); + groupIDs.forEach((id) => { + assert.ok(response.groups.map((group) => group.id).includes(id)); + }); + }); + + it('getGroupsAssociatedToTeam', async () => { + const teamID = '5rgoajywb3nfbdtyafbod47ryb'; + + store = await configureStore({ + entities: { + teams: { + groupsAssociatedToTeam: { + [teamID]: ['existing1', 'existing2'], + }, + }, + }, + }); + + const response = { + groups: [ + { + id: 'tnd8zod9f3fdtqosxjmhwucbth', + name: 'nobctj4brfgtpj3a1peiyq47tc', + display_name: 'engineering', + description: '', + source: 'ldap', + remote_id: 'engineering', + create_at: 1553808971099, + update_at: 1553808971099, + delete_at: 0, + has_syncables: false, + member_count: 8, + }, + { + id: 'qhdp6g7aubbpiyja7c4sgpe7tc', + name: 'x5bjwa4kwirpmqudhp5dterine', + display_name: 'qa', + description: '', + source: 'ldap', + remote_id: 'qa', + create_at: 1553808971548, + update_at: 1553808971548, + delete_at: 0, + has_syncables: false, + member_count: 2, + }, + ], + total_group_count: 3, + }; + + nock(Client4.getBaseRoute()). + get(`/teams/${teamID}/groups?page=100&per_page=60&q=0&include_member_count=true`). + reply(200, response); + + await Actions.getGroupsAssociatedToTeam(teamID, 0, 100)(store.dispatch, store.getState); + + const state = store.getState(); + const request = state.requests.groups.getGroupsAssociatedToTeam; + if (request.status === RequestStatus.FAILURE) { + throw new Error('getGroup request failed err=' + request.error); + } + + const groupIDs = state.entities.teams.groupsAssociatedToTeam[teamID]; + var expectedIDs = ['existing1', 'existing2'].concat(response.groups.map((group) => group.id)); + assert.strictEqual(groupIDs.length, expectedIDs.length); + groupIDs.forEach((id) => { + assert.ok(expectedIDs.includes(id)); + }); + }); + + it('getGroupsNotAssociatedToTeam', async () => { + const teamID = '5rgoajywb3nfbdtyafbod47ryb'; + + store = await configureStore({ + entities: { + teams: { + groupsAssociatedToTeam: { + [teamID]: ['existing1', 'existing2'], + }, + }, + }, + }); + + const response = [ + { + id: 'existing1', + name: 'nobctj4brfgtpj3a1peiyq47tc', + display_name: 'engineering', + description: '', + source: 'ldap', + remote_id: 'engineering', + create_at: 1553808971099, + update_at: 1553808971099, + delete_at: 0, + has_syncables: false, + member_count: 8, + }, + ]; + + nock(Client4.getBaseRoute()). + get(`/groups?not_associated_to_team=${teamID}&page=100&per_page=60&q=0&include_member_count=true`). + reply(200, response); + + await Actions.getGroupsNotAssociatedToTeam(teamID, 0, 100)(store.dispatch, store.getState); + + const state = store.getState(); + const request = state.requests.groups.getGroupsNotAssociatedToTeam; + if (request.status === RequestStatus.FAILURE) { + throw new Error('getGroup request failed err=' + request.error); + } + + const groupIDs = state.entities.teams.groupsAssociatedToTeam[teamID]; + var expectedIDs = ['existing2'].concat(response.map((group) => group.id)); + assert.strictEqual(groupIDs.length, expectedIDs.length); + groupIDs.forEach((id) => { + assert.ok(expectedIDs.includes(id)); + }); + }); }); diff --git a/src/client/client4.js b/src/client/client4.js index 812e9ec6e..d0a66c860 100644 --- a/src/client/client4.js +++ b/src/client/client4.js @@ -2588,6 +2588,29 @@ export default class Client4 { ); }; + getGroupsNotAssociatedToTeam = async (teamID, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => { + this.trackEvent('api', 'api_groups_get_not_associated_to_team', {team_id: teamID}); + return this.doFetch( + `${this.getBaseRoute()}/groups${buildQueryString({not_associated_to_team: teamID, page, per_page: perPage, q, include_member_count: true})}`, + {method: 'get'} + ); + }; + + getGroupsAssociatedToTeam = async (teamID, q = '', page = 0, perPage = PER_PAGE_DEFAULT) => { + this.trackEvent('api', 'api_groups_get_not_associated_to_team', {team_id: teamID}); + return this.doFetch( + `${this.getBaseRoute()}/teams/${teamID}/groups${buildQueryString({page, per_page: perPage, q, include_member_count: true})}`, + {method: 'get'} + ); + }; + + getAllGroupsAssociatedToTeam = async (teamID) => { + return this.doFetch( + `${this.getBaseRoute()}/teams/${teamID}/groups?paginate=false`, + {method: 'get'} + ); + }; + // Redirect Location getRedirectLocation = async (urlParam) => { diff --git a/src/reducers/entities/groups.js b/src/reducers/entities/groups.js index 92b37bb38..365cc3a65 100644 --- a/src/reducers/entities/groups.js +++ b/src/reducers/entities/groups.js @@ -69,6 +69,9 @@ function syncables(state = {}, action) { }; } case GroupTypes.UNLINKED_GROUP_TEAM: { + if (!state[action.data.group_id]) { + return state; + } const nextTeams = state[action.data.group_id].teams.slice(); const index = nextTeams.findIndex((groupTeam) => { @@ -135,6 +138,13 @@ function groups(state = {}, action) { [action.data.id]: action.data, }; } + case GroupTypes.RECEIVED_GROUPS: { + const nextState = {...state}; + for (const group of action.data) { + nextState[group.id] = group; + } + return nextState; + } default: return state; } diff --git a/src/reducers/entities/teams.js b/src/reducers/entities/teams.js index 3a9e38ff4..047214ba6 100644 --- a/src/reducers/entities/teams.js +++ b/src/reducers/entities/teams.js @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import {combineReducers} from 'redux'; -import {ChannelTypes, TeamTypes, UserTypes, SchemeTypes} from 'action_types'; +import {ChannelTypes, TeamTypes, UserTypes, SchemeTypes, GroupTypes} from 'action_types'; import {teamListToMap} from 'utils/team_utils'; function currentTeamId(state = '', action) { @@ -320,6 +320,43 @@ function stats(state = {}, action) { } } +function groupsAssociatedToTeam(state = {}, action) { + switch (action.type) { + case GroupTypes.RECEIVED_GROUPS_ASSOCIATED_TO_TEAM: { + const {teamID, groups} = action.data; + const nextState = {...state}; + const associatedGroupIDs = new Set(state[teamID] || []); + for (const group of groups) { + associatedGroupIDs.add(group.id); + } + nextState[teamID] = Array.from(associatedGroupIDs); + return nextState; + } + case GroupTypes.RECEIVED_ALL_GROUPS_ASSOCIATED_TO_TEAM: { + const {teamID, groups} = action.data; + const nextState = {...state}; + const associatedGroupIDs = new Set([]); + for (const group of groups) { + associatedGroupIDs.add(group.id); + } + nextState[teamID] = Array.from(associatedGroupIDs); + return nextState; + } + case GroupTypes.RECEIVED_GROUPS_NOT_ASSOCIATED_TO_TEAM: { + const {teamID, groups} = action.data; + const nextState = {...state}; + const associatedGroupIDs = new Set(state[teamID] || []); + for (const group of groups) { + associatedGroupIDs.delete(group.id); + } + nextState[teamID] = Array.from(associatedGroupIDs); + return nextState; + } + default: + return state; + } +} + function updateTeamMemberSchemeRoles(state, action) { const {teamId, userId, isSchemeUser, isSchemeAdmin} = action.data; const team = state[teamId]; @@ -358,4 +395,6 @@ export default combineReducers({ // object where every key is the team id and has an object with the team stats stats, + + groupsAssociatedToTeam, }); diff --git a/src/reducers/requests/groups.js b/src/reducers/requests/groups.js index fa6d5b795..27c1fe525 100644 --- a/src/reducers/requests/groups.js +++ b/src/reducers/requests/groups.js @@ -60,11 +60,44 @@ function getGroup(state: RequestStatusType = initialRequestState(), action: Gene ); } +function getAllGroupsAssociatedToTeam(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { + return handleRequest( + GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_REQUEST, + GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS, + GroupTypes.GET_ALL_GROUPS_ASSOCIATED_TO_TEAM_FAILURE, + state, + action + ); +} + +function getGroupsAssociatedToTeam(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { + return handleRequest( + GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_REQUEST, + GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_SUCCESS, + GroupTypes.GET_GROUPS_ASSOCIATED_TO_TEAM_FAILURE, + state, + action + ); +} + +function getGroupsNotAssociatedToTeam(state: RequestStatusType = initialRequestState(), action: GenericAction): RequestStatusType { + return handleRequest( + GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_REQUEST, + GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_SUCCESS, + GroupTypes.GET_GROUPS_NOT_ASSOCIATED_TO_TEAM_FAILURE, + state, + action + ); +} + export default (combineReducers({ linkGroupSyncable, unlinkGroupSyncable, getGroupSyncables, getGroupMembers, getGroup, + getAllGroupsAssociatedToTeam, + getGroupsAssociatedToTeam, + getGroupsNotAssociatedToTeam, }): (GroupsRequestsStatuses, GenericAction) => GroupsRequestsStatuses); diff --git a/src/selectors/entities/groups.js b/src/selectors/entities/groups.js index bffd8b9cc..7e9674e52 100644 --- a/src/selectors/entities/groups.js +++ b/src/selectors/entities/groups.js @@ -1,6 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {createSelector} from 'reselect'; + const emptyList = []; const emptySyncables = { teams: [], @@ -43,3 +45,24 @@ export function getGroupMembers(state, id) { } return groupMemberData.members; } + +function getTeamGroupIDSet(state, teamID) { + var arr = state.entities.teams.groupsAssociatedToTeam[teamID] || []; + return new Set(arr); +} + +export const getGroupsNotAssociatedToTeam = createSelector( + getAllGroups, + (state, teamID) => getTeamGroupIDSet(state, teamID), + (allGroups, teamGroupIDSet) => { + return Object.entries(allGroups).filter(([groupID]) => !teamGroupIDSet.has(groupID)).map((entry) => entry[1]); + } +); + +export const getGroupsAssociatedToTeam = createSelector( + getAllGroups, + (state, teamID) => getTeamGroupIDSet(state, teamID), + (allGroups, teamGroupIDSet) => { + return Object.entries(allGroups).filter(([groupID]) => teamGroupIDSet.has(groupID)).map((entry) => entry[1]); + } +); diff --git a/src/selectors/entities/groups.test.js b/src/selectors/entities/groups.test.js new file mode 100644 index 000000000..13d2b2428 --- /dev/null +++ b/src/selectors/entities/groups.test.js @@ -0,0 +1,94 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import assert from 'assert'; + +import deepFreezeAndThrowOnMutation from 'utils/deep_freeze'; +import * as Selectors from 'selectors/entities/groups'; + +describe('Selectors.Schemes', () => { + const teamID = 'c6ubwm63apgftbjs71enbjjpsh'; + const expectedAssociatedGroupID1 = 'xh585kyz3tn55q6ipfo57btwnc'; + const expectedAssociatedGroupID2 = 'emdwu98u6jg9xfn9p5zu48bojo'; + const associatedGroupIDs = [expectedAssociatedGroupID1, expectedAssociatedGroupID2]; + const testState = deepFreezeAndThrowOnMutation({ + entities: { + groups: { + syncables: {}, + members: {}, + groups: { + xh585kyz3tn55q6ipfo57btwnc: { + id: expectedAssociatedGroupID1, + name: '9uobsi3xb3y5tfjb3ze7umnh1o', + display_name: 'abc', + description: '', + source: 'ldap', + remote_id: 'abc', + create_at: 1553808969975, + update_at: 1553808969975, + delete_at: 0, + has_syncables: false, + member_count: 2, + }, + xos794c6tfb57eog481acokozc: { + id: 'xos794c6tfb57eog481acokozc', + name: '5mte953ncbfpunpr3zmtopiwbo', + display_name: 'developers', + description: '', + source: 'ldap', + remote_id: 'developers', + create_at: 1553808970570, + update_at: 1553808970570, + delete_at: 0, + has_syncables: false, + member_count: 5, + }, + tnd8zod9f3fdtqosxjmhwucbth: { + id: 'tnd8zod9f3fdtqosxjmhwucbth', + name: 'nobctj4brfgtpj3a1peiyq47tc', + display_name: 'engineering', + description: '', + source: 'ldap', + remote_id: 'engineering', + create_at: 1553808971099, + update_at: 1553808971099, + delete_at: 0, + has_syncables: false, + member_count: 8, + }, + emdwu98u6jg9xfn9p5zu48bojo: { + id: expectedAssociatedGroupID2, + name: '7ybu9oy77jgedqp4pph8f4j5ge', + display_name: 'xyz', + description: '', + source: 'ldap', + remote_id: 'xyz', + create_at: 1553808972099, + update_at: 1553808972099, + delete_at: 0, + has_syncables: false, + member_count: 2, + }, + }, + }, + teams: { + groupsAssociatedToTeam: { + c6ubwm63apgftbjs71enbjjpsh: associatedGroupIDs, + }, + }, + }, + }); + + it('getGroupsAssociatedToTeam', () => { + const expected = [ + testState.entities.groups.groups[expectedAssociatedGroupID1], + testState.entities.groups.groups[expectedAssociatedGroupID2], + ]; + assert.deepEqual(Selectors.getGroupsAssociatedToTeam(testState, teamID), expected); + }); + + it('getGroupsNotAssociatedToTeam', () => { + const expected = Object.entries(testState.entities.groups.groups).filter(([groupID]) => !associatedGroupIDs.includes(groupID)).map(([, group]) => group); + assert.deepEqual(Selectors.getGroupsNotAssociatedToTeam(testState, teamID), expected); + }); +}); diff --git a/src/store/initial_state.js b/src/store/initial_state.js index bb8d21f97..75a364c59 100644 --- a/src/store/initial_state.js +++ b/src/store/initial_state.js @@ -35,6 +35,7 @@ const state: GlobalState = { myMembers: {}, membersInTeam: {}, stats: {}, + groupsAssociatedToTeam: {}, }, channels: { currentChannelId: '', @@ -599,6 +600,18 @@ const state: GlobalState = { status: 'not_started', error: null, }, + getAllGroupsAssociatedToTeam: { + status: 'not_started', + error: null, + }, + getGroupsAssociatedToTeam: { + status: 'not_started', + error: null, + }, + getGroupsNotAssociatedToTeam: { + status: 'not_started', + error: null, + }, }, }, }; diff --git a/src/types/groups.js b/src/types/groups.js index 960ebd641..ac9b8a776 100644 --- a/src/types/groups.js +++ b/src/types/groups.js @@ -19,6 +19,7 @@ export type Group = {| update_at: number, delete_at: number, has_syncables: boolean, + member_count: number, |}; export type GroupTeam = {| diff --git a/src/types/requests.js b/src/types/requests.js index c119b8433..7084c1adb 100644 --- a/src/types/requests.js +++ b/src/types/requests.js @@ -152,6 +152,9 @@ export type GroupsRequestsStatuses = {| getGroupSyncables: RequestStatusType, getGroupMembers: RequestStatusType, getGroup: RequestStatusType, + getAllGroupsAssociatedToTeam: RequestStatusType, + getGroupsAssociatedToTeam: RequestStatusType, + getGroupsNotAssociatedToTeam: RequestStatusType, |}; export type JobsRequestsStatuses = {| diff --git a/src/types/teams.js b/src/types/teams.js index 5e8e19f63..d4ba8ccdf 100644 --- a/src/types/teams.js +++ b/src/types/teams.js @@ -38,5 +38,6 @@ export type TeamsState = {| teams: { [string]: Team }, myMembers: { [string]: TeamMembership }, membersInTeam: Object, - stats: Object + stats: Object, + groupsAssociatedToTeam: Object, |};