Procházet zdrojové kódy

actions for group sync

Peter Holmberg před 7 roky
rodič
revize
0cfcf2685e

+ 0 - 0
public/app/features/teams/TeamGroupSync.test.tsx


+ 44 - 23
public/app/features/teams/TeamGroupSync.tsx

@@ -1,11 +1,16 @@
-import React from 'react';
-import { hot } from 'react-hot-loader';
+import React, { PureComponent } from 'react';
+import { connect } from 'react-redux';
 import SlideDown from 'app/core/components/Animations/SlideDown';
 import Tooltip from 'app/core/components/Tooltip/Tooltip';
-import { Team, TeamGroup } from '../../types';
-
-interface Props {
-  team: Team;
+import { TeamGroup } from '../../types';
+import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';
+import { getTeamGroups } from './state/selectors';
+
+export interface Props {
+  groups: TeamGroup[];
+  loadTeamGroups: typeof loadTeamGroups;
+  addTeamGroup: typeof addTeamGroup;
+  removeTeamGroup: typeof removeTeamGroup;
 }
 
 interface State {
@@ -15,27 +20,18 @@ interface State {
 
 const headerTooltip = `Sync LDAP or OAuth groups with your Grafana teams.`;
 
-export class TeamGroupSync extends React.Component<Props, State> {
+export class TeamGroupSync extends PureComponent<Props, State> {
   constructor(props) {
     super(props);
     this.state = { isAdding: false, newGroupId: '' };
   }
 
   componentDidMount() {
-    // this.props.team.loadGroups();
+    this.fetchTeamGroups();
   }
 
-  renderGroup(group: TeamGroup) {
-    return (
-      <tr key={group.groupId}>
-        <td>{group.groupId}</td>
-        <td style={{ width: '1%' }}>
-          <a className="btn btn-danger btn-mini" onClick={() => this.onRemoveGroup(group)}>
-            <i className="fa fa-remove" />
-          </a>
-        </td>
-      </tr>
-    );
+  async fetchTeamGroups() {
+    await this.props.loadTeamGroups();
   }
 
   onToggleAdding = () => {
@@ -47,21 +43,34 @@ export class TeamGroupSync extends React.Component<Props, State> {
   };
 
   onAddGroup = () => {
-    // this.props.team.addGroup(this.state.newGroupId);
+    this.props.addTeamGroup(this.state.newGroupId);
     this.setState({ isAdding: false, newGroupId: '' });
   };
 
   onRemoveGroup = (group: TeamGroup) => {
-    // this.props.team.removeGroup(group.groupId);
+    this.props.removeTeamGroup(group.groupId);
   };
 
   isNewGroupValid() {
     return this.state.newGroupId.length > 1;
   }
 
+  renderGroup(group: TeamGroup) {
+    return (
+      <tr key={group.groupId}>
+        <td>{group.groupId}</td>
+        <td style={{ width: '1%' }}>
+          <a className="btn btn-danger btn-mini" onClick={() => this.onRemoveGroup(group)}>
+            <i className="fa fa-remove" />
+          </a>
+        </td>
+      </tr>
+    );
+  }
+
   render() {
     const { isAdding, newGroupId } = this.state;
-    const groups = this.props.team.groups;
+    const groups = this.props.groups;
 
     return (
       <div>
@@ -144,4 +153,16 @@ export class TeamGroupSync extends React.Component<Props, State> {
   }
 }
 
-export default hot(module)(TeamGroupSync);
+function mapStateToProps(state) {
+  return {
+    groups: getTeamGroups(state.team),
+  };
+}
+
+const mapDispatchToProps = {
+  loadTeamGroups,
+  addTeamGroup,
+  removeTeamGroup,
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(TeamGroupSync);

+ 1 - 2
public/app/features/teams/TeamPages.tsx

@@ -57,7 +57,6 @@ export class TeamPages extends PureComponent<Props, State> {
   }
 
   renderPage() {
-    const { team } = this.props;
     const { isSyncEnabled } = this.state;
     const currentPage = this.getCurrentPage();
 
@@ -69,7 +68,7 @@ export class TeamPages extends PureComponent<Props, State> {
         return <TeamSettings />;
 
       case PageTypes.GroupSync:
-        return isSyncEnabled && <TeamGroupSync team={team} />;
+        return isSyncEnabled && <TeamGroupSync />;
     }
 
     return null;

+ 64 - 4
public/app/features/teams/state/actions.ts

@@ -1,8 +1,9 @@
 import { ThunkAction } from 'redux-thunk';
 import { getBackendSrv } from 'app/core/services/backend_srv';
-import { NavModelItem, StoreState, Team, TeamMember } from '../../../types';
+import { NavModelItem, StoreState, Team, TeamGroup, TeamMember } from '../../../types';
 import { updateNavIndex } from '../../../core/actions';
 import { UpdateNavIndexAction } from '../../../core/actions/navModel';
+import config from 'app/core/config';
 
 export enum ActionTypes {
   LoadTeams = 'LOAD_TEAMS',
@@ -10,6 +11,7 @@ export enum ActionTypes {
   SetSearchQuery = 'SET_SEARCH_QUERY',
   SetSearchMemberQuery = 'SET_SEARCH_MEMBER_QUERY',
   LoadTeamMembers = 'TEAM_MEMBERS_LOADED',
+  LoadTeamGroups = 'TEAM_GROUPS_LOADED',
 }
 
 export interface LoadTeamsAction {
@@ -27,6 +29,11 @@ export interface LoadTeamMembersAction {
   payload: TeamMember[];
 }
 
+export interface LoadTeamGroupsAction {
+  type: ActionTypes.LoadTeamGroups;
+  payload: TeamGroup[];
+}
+
 export interface SetSearchQueryAction {
   type: ActionTypes.SetSearchQuery;
   payload: string;
@@ -42,7 +49,8 @@ export type Action =
   | SetSearchQueryAction
   | LoadTeamAction
   | LoadTeamMembersAction
-  | SetSearchMemberQueryAction;
+  | SetSearchMemberQueryAction
+  | LoadTeamGroupsAction;
 
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action | UpdateNavIndexAction>;
 
@@ -61,6 +69,11 @@ const teamMembersLoaded = (teamMembers: TeamMember[]): LoadTeamMembersAction =>
   payload: teamMembers,
 });
 
+const teamGroupsLoaded = (teamGroups: TeamGroup[]): LoadTeamGroupsAction => ({
+  type: ActionTypes.LoadTeamGroups,
+  payload: teamGroups,
+});
+
 export const setSearchMemberQuery = (searchQuery: string): SetSearchMemberQueryAction => ({
   type: ActionTypes.SetSearchMemberQuery,
   payload: searchQuery,
@@ -79,7 +92,7 @@ export function loadTeams(): ThunkResult<void> {
 }
 
 function buildNavModel(team: Team): NavModelItem {
-  return {
+  const navModel = {
     img: team.avatarUrl,
     id: 'team-' + team.id,
     subTitle: 'Manage members & settings',
@@ -103,6 +116,18 @@ function buildNavModel(team: Team): NavModelItem {
       },
     ],
   };
+
+  if (config.buildInfo.isEnterprise) {
+    navModel.children.push({
+      active: false,
+      icon: 'fa fa-fw fa-refresh',
+      id: 'team-settings',
+      text: 'External group sync',
+      url: `org/teams/edit/${team.id}/groupsync`,
+    });
+  }
+
+  return navModel;
 }
 
 export function loadTeam(id: number): ThunkResult<void> {
@@ -117,7 +142,6 @@ export function loadTeam(id: number): ThunkResult<void> {
 }
 
 export function loadTeamMembers(): ThunkResult<void> {
-  console.log('loading team members');
   return async (dispatch, getStore) => {
     const team = getStore().team.team;
 
@@ -167,6 +191,42 @@ export function updateTeam(name: string, email: string): ThunkResult<void> {
   };
 }
 
+export function loadTeamGroups(): ThunkResult<void> {
+  return async (dispatch, getStore) => {
+    const team = getStore().team.team;
+
+    await getBackendSrv()
+      .get(`/api/teams/${team.id}/groups`)
+      .then(response => {
+        dispatch(teamGroupsLoaded(response));
+      });
+  };
+}
+
+export function addTeamGroup(groupId: string): ThunkResult<void> {
+  return async (dispatch, getStore) => {
+    const team = getStore().team.team;
+
+    await getBackendSrv()
+      .post(`/api/teams/${team.id}/groups`, { groupId: groupId })
+      .then(() => {
+        dispatch(loadTeamGroups());
+      });
+  };
+}
+
+export function removeTeamGroup(groupId: string): ThunkResult<void> {
+  return async (dispatch, getStore) => {
+    const team = getStore().team.team;
+
+    await getBackendSrv()
+      .delete(`/api/teams/${team.id}/groups/${groupId}`)
+      .then(() => {
+        dispatch(loadTeamGroups());
+      });
+  };
+}
+
 export function deleteTeam(id: number): ThunkResult<void> {
   return async dispatch => {
     await getBackendSrv()

+ 3 - 0
public/app/features/teams/state/reducers.ts

@@ -30,6 +30,9 @@ export const teamReducer = (state = initialTeamState, action: Action): TeamState
 
     case ActionTypes.SetSearchMemberQuery:
       return { ...state, searchMemberQuery: action.payload };
+
+    case ActionTypes.LoadTeamGroups:
+      return { ...state, groups: action.payload };
   }
 
   return state;

+ 1 - 0
public/app/features/teams/state/selectors.ts

@@ -1,5 +1,6 @@
 export const getSearchQuery = state => state.searchQuery;
 export const getSearchMemberQuery = state => state.searchMemberQuery;
+export const getTeamGroups = state => state.groups;
 
 export const getTeam = (state, currentTeamId) => {
   if (state.team.id === parseInt(currentTeamId)) {