Commit 59b3bfd3 by Peter Holmberg

team members, bug in fetching team

parent 05bfc365
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader'; import { hot } from 'react-hot-loader';
import SlideDown from 'app/core/components/Animations/SlideDown'; import SlideDown from 'app/core/components/Animations/SlideDown';
import { UserPicker, User } from 'app/core/components/Picker/UserPicker'; import { UserPicker, User } from 'app/core/components/Picker/UserPicker';
import DeleteButton from 'app/core/components/DeleteButton/DeleteButton'; import DeleteButton from 'app/core/components/DeleteButton/DeleteButton';
import { Team, TeamMember } from '../../types'; import { Team, TeamMember } from '../../types';
import { loadTeamMembers, addTeamMember, removeTeamMember, setSearchMemberQuery } from './state/actions';
import { getSearchMemberQuery, getTeam } from './state/selectors';
import { getRouteParamsId } from '../../core/selectors/location';
interface Props { interface Props {
team: Team; team: Team;
searchMemberQuery: string;
loadTeamMembers: typeof loadTeamMembers;
addTeamMember: typeof addTeamMember;
removeTeamMember: typeof removeTeamMember;
setSearchMemberQuery: typeof setSearchMemberQuery;
} }
interface State { interface State {
...@@ -21,20 +30,29 @@ export class TeamMembers extends PureComponent<Props, State> { ...@@ -21,20 +30,29 @@ export class TeamMembers extends PureComponent<Props, State> {
} }
componentDidMount() { componentDidMount() {
// this.props.team.loadMembers(); this.props.loadTeamMembers();
} }
onSearchQueryChange = evt => { onSearchQueryChange = event => {
// this.props.team.setSearchQuery(evt.target.value); this.props.setSearchMemberQuery(event.target.value);
}; };
removeMember(member: TeamMember) { removeMember(member: TeamMember) {
// this.props.team.removeMember(member); this.props.removeTeamMember(member.userId);
} }
removeMemberConfirmed(member: TeamMember) { onToggleAdding = () => {
// this.props.team.removeMember(member); this.setState({ isAdding: !this.state.isAdding });
} };
onUserSelected = (user: User) => {
this.setState({ newTeamMember: user });
};
onAddUserToTeam = async () => {
this.props.addTeamMember(this.state.newTeamMember.id);
this.setState({ newTeamMember: null });
};
renderMember(member: TeamMember) { renderMember(member: TeamMember) {
return ( return (
...@@ -51,23 +69,9 @@ export class TeamMembers extends PureComponent<Props, State> { ...@@ -51,23 +69,9 @@ export class TeamMembers extends PureComponent<Props, State> {
); );
} }
onToggleAdding = () => {
this.setState({ isAdding: !this.state.isAdding });
};
onUserSelected = (user: User) => {
this.setState({ newTeamMember: user });
};
onAddUserToTeam = async () => {
// await this.props.team.addMember(this.state.newTeamMember.id);
// await this.props.team.loadMembers();
// this.setState({ newTeamMember: null });
};
render() { render() {
const { newTeamMember, isAdding } = this.state; const { newTeamMember, isAdding } = this.state;
const { team } = this.props; const { team, searchMemberQuery } = this.props;
const newTeamMemberValue = newTeamMember && newTeamMember.id.toString(); const newTeamMemberValue = newTeamMember && newTeamMember.id.toString();
return ( return (
...@@ -79,7 +83,7 @@ export class TeamMembers extends PureComponent<Props, State> { ...@@ -79,7 +83,7 @@ export class TeamMembers extends PureComponent<Props, State> {
type="text" type="text"
className="gf-form-input" className="gf-form-input"
placeholder="Search members" placeholder="Search members"
value={team.search} value={searchMemberQuery}
onChange={this.onSearchQueryChange} onChange={this.onSearchQueryChange}
/> />
<i className="gf-form-input-icon fa fa-search" /> <i className="gf-form-input-icon fa fa-search" />
...@@ -129,4 +133,20 @@ export class TeamMembers extends PureComponent<Props, State> { ...@@ -129,4 +133,20 @@ export class TeamMembers extends PureComponent<Props, State> {
} }
} }
export default hot(module)(TeamMembers); function mapStateToProps(state) {
const teamId = getRouteParamsId(state.location);
return {
team: getTeam(state.team, teamId),
searchMemberQuery: getSearchMemberQuery(state.team),
};
}
const mapDispatchToProps = {
loadTeamMembers,
addTeamMember,
removeTeamMember,
setSearchMemberQuery,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(TeamMembers));
...@@ -63,7 +63,7 @@ export class TeamPages extends PureComponent<Props, State> { ...@@ -63,7 +63,7 @@ export class TeamPages extends PureComponent<Props, State> {
switch (currentPage) { switch (currentPage) {
case PageTypes.Members: case PageTypes.Members:
return <TeamMembers team={team} />; return <TeamMembers />;
case PageTypes.Settings: case PageTypes.Settings:
return <TeamSettings team={team} />; return <TeamSettings team={team} />;
...@@ -95,7 +95,7 @@ function mapStateToProps(state) { ...@@ -95,7 +95,7 @@ function mapStateToProps(state) {
navModel: getNavModel(state.navIndex, `team-${pageName}-${teamId}`), navModel: getNavModel(state.navIndex, `team-${pageName}-${teamId}`),
teamId: teamId, teamId: teamId,
pageName: pageName, pageName: pageName,
team: getTeam(state.team), team: getTeam(state.team, teamId),
}; };
} }
......
...@@ -30,3 +30,13 @@ export const getMockTeam = (): Team => { ...@@ -30,3 +30,13 @@ export const getMockTeam = (): Team => {
groups: [], groups: [],
}; };
}; };
export const getMockTeamMember = () => {
return {
userId: 1,
teamId: 1,
avatarUrl: 'some/url/',
email: 'test@test.com',
login: 'testUser',
};
};
import { ThunkAction } from 'redux-thunk'; import { ThunkAction } from 'redux-thunk';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
import { NavModelItem, StoreState, Team } from '../../../types'; import { NavModelItem, StoreState, Team, TeamMember } from '../../../types';
import { updateNavIndex } from '../../../core/actions'; import { updateNavIndex } from '../../../core/actions';
import { UpdateNavIndexAction } from '../../../core/actions/navModel'; import { UpdateNavIndexAction } from '../../../core/actions/navModel';
...@@ -8,6 +8,8 @@ export enum ActionTypes { ...@@ -8,6 +8,8 @@ export enum ActionTypes {
LoadTeams = 'LOAD_TEAMS', LoadTeams = 'LOAD_TEAMS',
LoadTeam = 'LOAD_TEAM', LoadTeam = 'LOAD_TEAM',
SetSearchQuery = 'SET_SEARCH_QUERY', SetSearchQuery = 'SET_SEARCH_QUERY',
SetSearchMemberQuery = 'SET_SEARCH_MEMBER_QUERY',
LoadTeamMembers = 'TEAM_MEMBERS_LOADED',
} }
export interface LoadTeamsAction { export interface LoadTeamsAction {
...@@ -20,12 +22,27 @@ export interface LoadTeamAction { ...@@ -20,12 +22,27 @@ export interface LoadTeamAction {
payload: Team; payload: Team;
} }
export interface LoadTeamMembersAction {
type: ActionTypes.LoadTeamMembers;
payload: TeamMember[];
}
export interface SetSearchQueryAction { export interface SetSearchQueryAction {
type: ActionTypes.SetSearchQuery; type: ActionTypes.SetSearchQuery;
payload: string; payload: string;
} }
export type Action = LoadTeamsAction | SetSearchQueryAction | LoadTeamAction; export interface SetSearchMemberQueryAction {
type: ActionTypes.SetSearchMemberQuery;
payload: string;
}
export type Action =
| LoadTeamsAction
| SetSearchQueryAction
| LoadTeamAction
| LoadTeamMembersAction
| SetSearchMemberQueryAction;
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action | UpdateNavIndexAction>; type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action | UpdateNavIndexAction>;
...@@ -39,6 +56,16 @@ const teamLoaded = (team: Team): LoadTeamAction => ({ ...@@ -39,6 +56,16 @@ const teamLoaded = (team: Team): LoadTeamAction => ({
payload: team, payload: team,
}); });
const teamMembersLoaded = (teamMembers: TeamMember[]): LoadTeamMembersAction => ({
type: ActionTypes.LoadTeamMembers,
payload: teamMembers,
});
export const setSearchMemberQuery = (searchQuery: string): SetSearchMemberQueryAction => ({
type: ActionTypes.SetSearchMemberQuery,
payload: searchQuery,
});
export const setSearchQuery = (searchQuery: string): SetSearchQueryAction => ({ export const setSearchQuery = (searchQuery: string): SetSearchQueryAction => ({
type: ActionTypes.SetSearchQuery, type: ActionTypes.SetSearchQuery,
payload: searchQuery, payload: searchQuery,
...@@ -89,6 +116,42 @@ export function loadTeam(id: number): ThunkResult<void> { ...@@ -89,6 +116,42 @@ export function loadTeam(id: number): ThunkResult<void> {
}; };
} }
export function loadTeamMembers(): ThunkResult<void> {
return async (dispatch, getStore) => {
const team = getStore().team.team;
await getBackendSrv()
.get(`/api/teams/${team.id}/members`)
.then(response => {
dispatch(teamMembersLoaded(response));
});
};
}
export function addTeamMember(id: number): ThunkResult<void> {
return async (dispatch, getStore) => {
const team = getStore().team.team;
await getBackendSrv()
.post(`/api/teams/${team.id}/members`, { userId: id })
.then(() => {
dispatch(loadTeamMembers());
});
};
}
export function removeTeamMember(id: number): ThunkResult<void> {
return async (dispatch, getStore) => {
const team = getStore().team.team;
await getBackendSrv()
.delete(`/api/teams/${team.id}/members/${id}`)
.then(() => {
dispatch(loadTeamMembers());
});
};
}
export function deleteTeam(id: number): ThunkResult<void> { export function deleteTeam(id: number): ThunkResult<void> {
return async dispatch => { return async dispatch => {
await getBackendSrv() await getBackendSrv()
......
import { Action, ActionTypes } from './actions'; import { Action, ActionTypes } from './actions';
import { initialTeamsState, teamsReducer } from './reducers'; import { initialTeamsState, initialTeamState, teamReducer, teamsReducer } from './reducers';
import { getMockTeam, getMockTeamMember } from '../__mocks__/teamMocks';
describe('teams reducer', () => { describe('teams reducer', () => {
it('should set teams', () => { it('should set teams', () => {
const payload = [ const payload = [getMockTeam()];
{
id: 1,
name: 'test',
avatarUrl: 'some/url/',
email: 'test@test.com',
memberCount: 1,
search: '',
members: [],
groups: [],
},
];
const action: Action = { const action: Action = {
type: ActionTypes.LoadTeams, type: ActionTypes.LoadTeams,
...@@ -39,3 +29,24 @@ describe('teams reducer', () => { ...@@ -39,3 +29,24 @@ describe('teams reducer', () => {
expect(result.searchQuery).toEqual('test'); expect(result.searchQuery).toEqual('test');
}); });
}); });
describe('team reducer', () => {
it('should set team members', () => {
const mockTeamMember = getMockTeamMember();
const mockTeam = getMockTeam();
const state = {
...initialTeamState,
team: mockTeam,
};
const action: Action = {
type: ActionTypes.LoadTeamMembers,
payload: [mockTeamMember],
};
const result = teamReducer(state, action);
const expectedState = { team: { ...mockTeam, members: [mockTeamMember] }, searchQuery: '' };
expect(result).toEqual(expectedState);
});
});
...@@ -2,7 +2,7 @@ import { Team, TeamsState, TeamState } from '../../../types'; ...@@ -2,7 +2,7 @@ import { Team, TeamsState, TeamState } from '../../../types';
import { Action, ActionTypes } from './actions'; import { Action, ActionTypes } from './actions';
export const initialTeamsState: TeamsState = { teams: [], searchQuery: '' }; export const initialTeamsState: TeamsState = { teams: [], searchQuery: '' };
export const initialTeamState: TeamState = { team: {} as Team, searchQuery: '' }; export const initialTeamState: TeamState = { team: {} as Team, searchMemberQuery: '' };
export const teamsReducer = (state = initialTeamsState, action: Action): TeamsState => { export const teamsReducer = (state = initialTeamsState, action: Action): TeamsState => {
switch (action.type) { switch (action.type) {
...@@ -19,6 +19,12 @@ export const teamReducer = (state = initialTeamState, action: Action): TeamState ...@@ -19,6 +19,12 @@ export const teamReducer = (state = initialTeamState, action: Action): TeamState
switch (action.type) { switch (action.type) {
case ActionTypes.LoadTeam: case ActionTypes.LoadTeam:
return { ...state, team: action.payload }; return { ...state, team: action.payload };
case ActionTypes.LoadTeamMembers:
return { ...state, team: { ...state.team, members: action.payload } };
case ActionTypes.SetSearchMemberQuery:
return { ...state, searchMemberQuery: action.payload };
} }
return state; return state;
......
export const getSearchQuery = state => state.searchQuery; export const getSearchQuery = state => state.searchQuery;
export const getSearchMemberQuery = state => state.searchMemberQuery;
export const getTeam = state => state.team; export const getTeam = (state, currentTeamId) => {
if (state.team.id === currentTeamId) {
console.log('yes');
return state.team;
}
};
export const getTeams = state => { export const getTeams = state => {
const regex = RegExp(state.searchQuery, 'i'); const regex = RegExp(state.searchQuery, 'i');
......
...@@ -124,7 +124,7 @@ export interface TeamsState { ...@@ -124,7 +124,7 @@ export interface TeamsState {
export interface TeamState { export interface TeamState {
team: Team; team: Team;
searchQuery: string; searchMemberQuery: string;
} }
export interface StoreState { export interface StoreState {
...@@ -132,4 +132,5 @@ export interface StoreState { ...@@ -132,4 +132,5 @@ export interface StoreState {
location: LocationState; location: LocationState;
alertRules: AlertRulesState; alertRules: AlertRulesState;
teams: TeamsState; teams: TeamsState;
team: TeamState;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment