load teams and store in redux
This commit is contained in:
@@ -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', () => {});
|
||||
@@ -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>
|
||||
`;
|
||||
@@ -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));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user