Peter Holmberg 7 лет назад
Родитель
Сommit
167f009819

+ 3 - 1
public/app/features/alerting/AlertRuleList.tsx

@@ -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>

+ 61 - 0
public/app/features/teams/TeamList.test.tsx

@@ -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', () => {});

+ 29 - 34
public/app/features/teams/TeamList.tsx

@@ -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));
-  }
+  deleteTeam = (team: Team) => {
+    console.log('delete team', team);
+  };
 
-  onSearchQueryChange = evt => {
-    this.props.teams.setSearchQuery(evt.target.value);
+  onSearchQueryChange = event => {
+    console.log('set search', event.target.value);
   };
 
-  renderTeamMember(team: Team): JSX.Element {
+  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));

+ 204 - 0
public/app/features/teams/__snapshots__/TeamList.test.tsx.snap

@@ -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
public/app/features/teams/state/actions.ts

@@ -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
public/app/features/teams/state/reducers.ts

@@ -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 - 0
public/app/stores/configureStore.ts

@@ -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;

+ 0 - 3
public/app/types/index.ts

@@ -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;