load teams and store in redux

This commit is contained in:
Peter Holmberg
2018-09-05 15:13:21 +02:00
parent 306c3e6c10
commit 167f009819
8 changed files with 305 additions and 42 deletions
@@ -115,7 +115,9 @@ export class AlertRuleList extends PureComponent<Props, any> {
</div>
<section>
<ol className="alert-rule-list">
{alertRules.map(rule => <AlertRuleItem rule={rule} key={rule.id} search={search} />)}
{alertRules.map(rule => (
<AlertRuleItem rule={rule} key={rule.id} search={search} togglePauseAlertRule={() => {}} />
))}
</ol>
</section>
</div>
@@ -0,0 +1,61 @@
import React from 'react';
import { shallow } from 'enzyme';
import { TeamList, Props } from './TeamList';
import { NavModel, Team } from '../../types';
const setup = (propOverrides?: object) => {
const props: Props = {
navModel: {} as NavModel,
teams: [] as Team[],
loadTeams: jest.fn(),
search: '',
};
Object.assign(props, propOverrides);
const wrapper = shallow(<TeamList {...props} />);
const instance = wrapper.instance() as TeamList;
return {
wrapper,
instance,
};
};
describe('Render', () => {
it('should render component', () => {
const { wrapper } = setup();
expect(wrapper).toMatchSnapshot();
});
it('should render teams table', () => {
const { wrapper } = setup({
teams: [
{
id: 1,
name: 'test',
avatarUrl: 'some/url/',
email: 'test@test.com',
memberCount: 1,
search: '',
members: [],
groups: [],
},
],
});
expect(wrapper).toMatchSnapshot();
});
});
describe('Life cycle', () => {
it('should call loadTeams', () => {
const { instance } = setup();
instance.componentDidMount();
expect(instance.props.loadTeams).toHaveBeenCalled();
});
});
describe('Functions', () => {});
+30 -35
View File
@@ -1,44 +1,38 @@
import React from 'react';
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { inject, observer } from 'mobx-react';
import PageHeader from 'app/core/components/PageHeader/PageHeader';
import { NavStore } from 'app/stores/NavStore/NavStore';
import { TeamsStore, Team } from 'app/stores/TeamsStore/TeamsStore';
import { BackendSrv } from 'app/core/services/backend_srv';
import DeleteButton from 'app/core/components/DeleteButton/DeleteButton';
import { NavModel, Team } from '../../types';
import { loadTeams } from './state/actions';
import { getTeams } from './state/selectors';
import { getNavModel } from 'app/core/selectors/navModel';
interface Props {
nav: typeof NavStore.Type;
teams: typeof TeamsStore.Type;
backendSrv: BackendSrv;
export interface Props {
navModel: NavModel;
teams: Team[];
loadTeams: typeof loadTeams;
search: string;
}
@inject('nav', 'teams')
@observer
export class TeamList extends React.Component<Props, any> {
constructor(props) {
super(props);
this.props.nav.load('cfg', 'teams');
export class TeamList extends PureComponent<Props, any> {
componentDidMount() {
this.fetchTeams();
}
fetchTeams() {
this.props.teams.loadTeams();
async fetchTeams() {
await this.props.loadTeams();
}
deleteTeam(team: Team) {
this.props.backendSrv.delete('/api/teams/' + team.id).then(this.fetchTeams.bind(this));
}
onSearchQueryChange = evt => {
this.props.teams.setSearchQuery(evt.target.value);
deleteTeam = (team: Team) => {
console.log('delete team', team);
};
renderTeamMember(team: Team): JSX.Element {
onSearchQueryChange = event => {
console.log('set search', event.target.value);
};
renderTeamMember(team: Team) {
const teamUrl = `org/teams/edit/${team.id}`;
return (
@@ -65,10 +59,11 @@ export class TeamList extends React.Component<Props, any> {
}
render() {
const { nav, teams } = this.props;
const { navModel, teams, search } = this.props;
return (
<div>
<PageHeader model={nav as any} />
<PageHeader model={navModel as NavModel} />
<div className="page-container page-body">
<div className="page-action-bar">
<div className="gf-form gf-form--grow">
@@ -77,7 +72,7 @@ export class TeamList extends React.Component<Props, any> {
type="text"
className="gf-form-input"
placeholder="Search teams"
value={teams.search}
value={search}
onChange={this.onSearchQueryChange}
/>
<i className="gf-form-input-icon fa fa-search" />
@@ -102,7 +97,7 @@ export class TeamList extends React.Component<Props, any> {
<th style={{ width: '1%' }} />
</tr>
</thead>
<tbody>{teams.filteredTeams.map(team => this.renderTeamMember(team))}</tbody>
<tbody>{teams.map(team => this.renderTeamMember(team))}</tbody>
</table>
</div>
</div>
@@ -113,14 +108,14 @@ export class TeamList extends React.Component<Props, any> {
function mapStateToProps(state) {
return {
teams: getTeams(state),
navModel: getNavModel(state.navIndex, 'teams'),
teams: getTeams(state.teams),
search: '',
};
}
function mapDispatchToProps() {
return {
loadTeams,
};
}
const mapDispatchToProps = {
loadTeams,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(TeamList));
@@ -0,0 +1,204 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Render should render component 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<div
className="page-action-bar"
>
<div
className="gf-form gf-form--grow"
>
<label
className="gf-form--has-input-icon gf-form--grow"
>
<input
className="gf-form-input"
onChange={[Function]}
placeholder="Search teams"
type="text"
value=""
/>
<i
className="gf-form-input-icon fa fa-search"
/>
</label>
</div>
<div
className="page-action-bar__spacer"
/>
<a
className="btn btn-success"
href="org/teams/new"
>
<i
className="fa fa-plus"
/>
New team
</a>
</div>
<div
className="admin-list-table"
>
<table
className="filter-table filter-table--hover form-inline"
>
<thead>
<tr>
<th />
<th>
Name
</th>
<th>
Email
</th>
<th>
Members
</th>
<th
style={
Object {
"width": "1%",
}
}
/>
</tr>
</thead>
<tbody />
</table>
</div>
</div>
</div>
`;
exports[`Render should render teams table 1`] = `
<div>
<PageHeader
model={Object {}}
/>
<div
className="page-container page-body"
>
<div
className="page-action-bar"
>
<div
className="gf-form gf-form--grow"
>
<label
className="gf-form--has-input-icon gf-form--grow"
>
<input
className="gf-form-input"
onChange={[Function]}
placeholder="Search teams"
type="text"
value=""
/>
<i
className="gf-form-input-icon fa fa-search"
/>
</label>
</div>
<div
className="page-action-bar__spacer"
/>
<a
className="btn btn-success"
href="org/teams/new"
>
<i
className="fa fa-plus"
/>
New team
</a>
</div>
<div
className="admin-list-table"
>
<table
className="filter-table filter-table--hover form-inline"
>
<thead>
<tr>
<th />
<th>
Name
</th>
<th>
Email
</th>
<th>
Members
</th>
<th
style={
Object {
"width": "1%",
}
}
/>
</tr>
</thead>
<tbody>
<tr
key="1"
>
<td
className="width-4 text-center link-td"
>
<a
href="org/teams/edit/1"
>
<img
className="filter-table__avatar"
src="some/url/"
/>
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
test
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
test@test.com
</a>
</td>
<td
className="link-td"
>
<a
href="org/teams/edit/1"
>
1
</a>
</td>
<td
className="text-right"
>
<DeleteButton
onConfirmDelete={[Function]}
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
`;
+2 -2
View File
@@ -22,7 +22,7 @@ const teamsLoaded = (teams: Team[]): LoadTeamsAction => ({
export function loadTeams(): ThunkResult<void> {
return async dispatch => {
const teams = await getBackendSrv().get('/api/teams/search/', { perpage: 50, page: 1 });
dispatch(teamsLoaded(teams));
const response = await getBackendSrv().get('/api/teams/search', { perpage: 1000, page: 1 });
dispatch(teamsLoaded(response.teams));
};
}
+3 -1
View File
@@ -1,10 +1,12 @@
import { TeamsState } from '../../../types';
import { Action } from './actions';
import { Action, ActionTypes } from './actions';
const initialState: TeamsState = { teams: [] };
export const teamsReducer = (state = initialState, action: Action): TeamsState => {
switch (action.type) {
case ActionTypes.LoadTeams:
return { teams: action.payload };
}
return state;
};
+2
View File
@@ -3,10 +3,12 @@ import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import sharedReducers from 'app/core/reducers';
import alertingReducers from 'app/features/alerting/state/reducers';
import teamsReducers from 'app/features/teams/state/reducers';
const rootReducer = combineReducers({
...sharedReducers,
...alertingReducers,
...teamsReducers,
});
export let store;
-3
View File
@@ -2,9 +2,6 @@
// Location
//
import { TeamGroupModel, TeamMemberModel } from '../stores/TeamsStore/TeamsStore';
import { types } from 'mobx-state-tree';
export interface LocationUpdate {
path?: string;
query?: UrlQueryMap;