TeamGroupSync.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import React, { PureComponent } from 'react';
  2. import { connect } from 'react-redux';
  3. import { SlideDown } from 'app/core/components/Animations/SlideDown';
  4. import { Tooltip } from '@grafana/ui';
  5. import { TeamGroup } from '../../types';
  6. import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions';
  7. import { getTeamGroups } from './state/selectors';
  8. export interface Props {
  9. groups: TeamGroup[];
  10. loadTeamGroups: typeof loadTeamGroups;
  11. addTeamGroup: typeof addTeamGroup;
  12. removeTeamGroup: typeof removeTeamGroup;
  13. }
  14. interface State {
  15. isAdding: boolean;
  16. newGroupId?: string;
  17. }
  18. const headerTooltip = `Sync LDAP or OAuth groups with your Grafana teams.`;
  19. export class TeamGroupSync extends PureComponent<Props, State> {
  20. constructor(props) {
  21. super(props);
  22. this.state = { isAdding: false, newGroupId: '' };
  23. }
  24. componentDidMount() {
  25. this.fetchTeamGroups();
  26. }
  27. async fetchTeamGroups() {
  28. await this.props.loadTeamGroups();
  29. }
  30. onToggleAdding = () => {
  31. this.setState({ isAdding: !this.state.isAdding });
  32. };
  33. onNewGroupIdChanged = event => {
  34. this.setState({ newGroupId: event.target.value });
  35. };
  36. onAddGroup = event => {
  37. event.preventDefault();
  38. this.props.addTeamGroup(this.state.newGroupId);
  39. this.setState({ isAdding: false, newGroupId: '' });
  40. };
  41. onRemoveGroup = (group: TeamGroup) => {
  42. this.props.removeTeamGroup(group.groupId);
  43. };
  44. isNewGroupValid() {
  45. return this.state.newGroupId.length > 1;
  46. }
  47. renderGroup(group: TeamGroup) {
  48. return (
  49. <tr key={group.groupId}>
  50. <td>{group.groupId}</td>
  51. <td style={{ width: '1%' }}>
  52. <a className="btn btn-danger btn-mini" onClick={() => this.onRemoveGroup(group)}>
  53. <i className="fa fa-remove" />
  54. </a>
  55. </td>
  56. </tr>
  57. );
  58. }
  59. render() {
  60. const { isAdding, newGroupId } = this.state;
  61. const groups = this.props.groups;
  62. return (
  63. <div>
  64. <div className="page-action-bar">
  65. <h3 className="page-sub-heading">External group sync</h3>
  66. <Tooltip placement="auto" content={headerTooltip}>
  67. <div className="page-sub-heading-icon">
  68. <i className="gicon gicon-question gicon--has-hover" />
  69. </div>
  70. </Tooltip>
  71. <div className="page-action-bar__spacer" />
  72. {groups.length > 0 && (
  73. <button className="btn btn-primary pull-right" onClick={this.onToggleAdding}>
  74. <i className="fa fa-plus" /> Add group
  75. </button>
  76. )}
  77. </div>
  78. <SlideDown in={isAdding}>
  79. <div className="cta-form">
  80. <button className="cta-form__close btn btn-transparent" onClick={this.onToggleAdding}>
  81. <i className="fa fa-close" />
  82. </button>
  83. <h5>Add External Group</h5>
  84. <form className="gf-form-inline" onSubmit={this.onAddGroup}>
  85. <div className="gf-form">
  86. <input
  87. type="text"
  88. className="gf-form-input width-30"
  89. value={newGroupId}
  90. onChange={this.onNewGroupIdChanged}
  91. placeholder="cn=ops,ou=groups,dc=grafana,dc=org"
  92. />
  93. </div>
  94. <div className="gf-form">
  95. <button className="btn btn-primary gf-form-btn" type="submit" disabled={!this.isNewGroupValid()}>
  96. Add group
  97. </button>
  98. </div>
  99. </form>
  100. </div>
  101. </SlideDown>
  102. {groups.length === 0 && !isAdding && (
  103. <div className="empty-list-cta">
  104. <div className="empty-list-cta__title">There are no external groups to sync with</div>
  105. <button onClick={this.onToggleAdding} className="empty-list-cta__button btn btn-xlarge btn-primary">
  106. <i className="gicon gicon-add-team" />
  107. Add Group
  108. </button>
  109. <div className="empty-list-cta__pro-tip">
  110. <i className="fa fa-rocket" /> {headerTooltip}
  111. <a
  112. className="text-link empty-list-cta__pro-tip-link"
  113. href="http://docs.grafana.org/auth/enhanced_ldap/"
  114. target="_blank"
  115. >
  116. Learn more
  117. </a>
  118. </div>
  119. </div>
  120. )}
  121. {groups.length > 0 && (
  122. <div className="admin-list-table">
  123. <table className="filter-table filter-table--hover form-inline">
  124. <thead>
  125. <tr>
  126. <th>External Group ID</th>
  127. <th style={{ width: '1%' }} />
  128. </tr>
  129. </thead>
  130. <tbody>{groups.map(group => this.renderGroup(group))}</tbody>
  131. </table>
  132. </div>
  133. )}
  134. </div>
  135. );
  136. }
  137. }
  138. function mapStateToProps(state) {
  139. return {
  140. groups: getTeamGroups(state.team),
  141. };
  142. }
  143. const mapDispatchToProps = {
  144. loadTeamGroups,
  145. addTeamGroup,
  146. removeTeamGroup,
  147. };
  148. export default connect(
  149. mapStateToProps,
  150. mapDispatchToProps
  151. )(TeamGroupSync);