TeamMembers.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import React from 'react';
  2. import { hot } from 'react-hot-loader';
  3. import { observer } from 'mobx-react';
  4. import { ITeam, ITeamMember } from 'app/stores/TeamsStore/TeamsStore';
  5. import appEvents from 'app/core/app_events';
  6. import SlideDown from 'app/core/components/Animations/SlideDown';
  7. import { UserPicker, User } from 'app/core/components/Picker/UserPicker';
  8. interface Props {
  9. team: ITeam;
  10. }
  11. interface State {
  12. isAdding: boolean;
  13. newTeamMember?: User;
  14. }
  15. @observer
  16. export class TeamMembers extends React.Component<Props, State> {
  17. constructor(props) {
  18. super(props);
  19. this.state = { isAdding: false, newTeamMember: null };
  20. }
  21. componentDidMount() {
  22. this.props.team.loadMembers();
  23. }
  24. onSearchQueryChange = evt => {
  25. this.props.team.setSearchQuery(evt.target.value);
  26. };
  27. removeMember(member: ITeamMember) {
  28. appEvents.emit('confirm-modal', {
  29. title: 'Remove Member',
  30. text: 'Are you sure you want to remove ' + member.login + ' from this group?',
  31. yesText: 'Remove',
  32. icon: 'fa-warning',
  33. onConfirm: () => {
  34. this.removeMemberConfirmed(member);
  35. },
  36. });
  37. }
  38. removeMemberConfirmed(member: ITeamMember) {
  39. this.props.team.removeMember(member);
  40. }
  41. renderMember(member: ITeamMember) {
  42. return (
  43. <tr key={member.userId}>
  44. <td className="width-4 text-center">
  45. <img className="filter-table__avatar" src={member.avatarUrl} />
  46. </td>
  47. <td>{member.login}</td>
  48. <td>{member.email}</td>
  49. <td style={{ width: '1%' }}>
  50. <a onClick={() => this.removeMember(member)} className="btn btn-danger btn-mini">
  51. <i className="fa fa-remove" />
  52. </a>
  53. </td>
  54. </tr>
  55. );
  56. }
  57. onToggleAdding = () => {
  58. this.setState({ isAdding: !this.state.isAdding });
  59. };
  60. onUserSelected = (user: User) => {
  61. this.setState({ newTeamMember: user });
  62. };
  63. onAddUserToTeam = async () => {
  64. await this.props.team.addMember(this.state.newTeamMember.id);
  65. await this.props.team.loadMembers();
  66. this.setState({ newTeamMember: null });
  67. };
  68. render() {
  69. const { newTeamMember, isAdding } = this.state;
  70. const members = this.props.team.members.values();
  71. const newTeamMemberValue = newTeamMember && newTeamMember.id.toString();
  72. return (
  73. <div>
  74. <div className="page-action-bar">
  75. <div className="gf-form gf-form--grow">
  76. <label className="gf-form--has-input-icon gf-form--grow">
  77. <input
  78. type="text"
  79. className="gf-form-input"
  80. placeholder="Search members"
  81. value={''}
  82. onChange={this.onSearchQueryChange}
  83. />
  84. <i className="gf-form-input-icon fa fa-search" />
  85. </label>
  86. </div>
  87. <div className="page-action-bar__spacer" />
  88. <button className="btn btn-success pull-right" onClick={this.onToggleAdding} disabled={isAdding}>
  89. <i className="fa fa-plus" /> Add a member
  90. </button>
  91. </div>
  92. <SlideDown in={isAdding}>
  93. <div className="cta-form">
  94. <button className="cta-form__close btn btn-transparent" onClick={this.onToggleAdding}>
  95. <i className="fa fa-close" />
  96. </button>
  97. <h5>Add Team Member</h5>
  98. <div className="gf-form-inline">
  99. <UserPicker onSelected={this.onUserSelected} className="width-30" value={newTeamMemberValue} />
  100. {this.state.newTeamMember && (
  101. <button className="btn btn-success gf-form-btn" type="submit" onClick={this.onAddUserToTeam}>
  102. Add to team
  103. </button>
  104. )}
  105. </div>
  106. </div>
  107. </SlideDown>
  108. <div className="admin-list-table">
  109. <table className="filter-table filter-table--hover form-inline">
  110. <thead>
  111. <tr>
  112. <th />
  113. <th>Name</th>
  114. <th>Email</th>
  115. <th style={{ width: '1%' }} />
  116. </tr>
  117. </thead>
  118. <tbody>{members.map(member => this.renderMember(member))}</tbody>
  119. </table>
  120. </div>
  121. </div>
  122. );
  123. }
  124. }
  125. export default hot(module)(TeamMembers);