diff options
Diffstat (limited to 'web/react/components')
-rw-r--r-- | web/react/components/admin_console/admin_controller.jsx | 84 | ||||
-rw-r--r-- | web/react/components/admin_console/admin_sidebar.jsx | 179 | ||||
-rw-r--r-- | web/react/components/admin_console/reset_password_modal.jsx | 132 | ||||
-rw-r--r-- | web/react/components/admin_console/select_team_modal.jsx | 193 | ||||
-rw-r--r-- | web/react/components/admin_console/team_users.jsx | 178 | ||||
-rw-r--r-- | web/react/components/admin_console/user_item.jsx | 266 |
6 files changed, 896 insertions, 136 deletions
diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index 6fddfef07..92f0bbdce 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -3,6 +3,7 @@ var AdminSidebar = require('./admin_sidebar.jsx'); var AdminStore = require('../../stores/admin_store.jsx'); +var TeamStore = require('../../stores/team_store.jsx'); var AsyncClient = require('../../utils/async_client.jsx'); var LoadingScreen = require('../loading_screen.jsx'); @@ -16,38 +17,104 @@ var GitLabSettingsTab = require('./gitlab_settings.jsx'); var SqlSettingsTab = require('./sql_settings.jsx'); var TeamSettingsTab = require('./team_settings.jsx'); var ServiceSettingsTab = require('./service_settings.jsx'); +var TeamUsersTab = require('./team_users.jsx'); export default class AdminController extends React.Component { constructor(props) { super(props); this.selectTab = this.selectTab.bind(this); + this.removeSelectedTeam = this.removeSelectedTeam.bind(this); + this.addSelectedTeam = this.addSelectedTeam.bind(this); this.onConfigListenerChange = this.onConfigListenerChange.bind(this); + this.onAllTeamsListenerChange = this.onAllTeamsListenerChange.bind(this); + + var selectedTeams = AdminStore.getSelectedTeams(); + if (selectedTeams == null) { + selectedTeams = {}; + selectedTeams[TeamStore.getCurrentId()] = 'true'; + AdminStore.saveSelectedTeams(selectedTeams); + } this.state = { - config: null, - selected: 'service_settings' + config: AdminStore.getConfig(), + teams: AdminStore.getAllTeams(), + selectedTeams, + selected: 'service_settings', + selectedTeam: null }; } componentDidMount() { AdminStore.addConfigChangeListener(this.onConfigListenerChange); AsyncClient.getConfig(); + + AdminStore.addAllTeamsChangeListener(this.onAllTeamsListenerChange); + AsyncClient.getAllTeams(); } componentWillUnmount() { AdminStore.removeConfigChangeListener(this.onConfigListenerChange); + AdminStore.removeAllTeamsChangeListener(this.onAllTeamsListenerChange); } onConfigListenerChange() { this.setState({ config: AdminStore.getConfig(), - selected: this.state.selected + teams: AdminStore.getAllTeams(), + selectedTeams: AdminStore.getSelectedTeams(), + selected: this.state.selected, + selectedTeam: this.state.selectedTeam }); } - selectTab(tab) { - this.setState({selected: tab}); + onAllTeamsListenerChange() { + this.setState({ + config: AdminStore.getConfig(), + teams: AdminStore.getAllTeams(), + selectedTeams: AdminStore.getSelectedTeams(), + selected: this.state.selected, + selectedTeam: this.state.selectedTeam + + }); + } + + selectTab(tab, teamId) { + this.setState({ + config: AdminStore.getConfig(), + teams: AdminStore.getAllTeams(), + selectedTeams: AdminStore.getSelectedTeams(), + selected: tab, + selectedTeam: teamId + }); + } + + removeSelectedTeam(teamId) { + var selectedTeams = AdminStore.getSelectedTeams(); + Reflect.deleteProperty(selectedTeams, teamId); + AdminStore.saveSelectedTeams(selectedTeams); + + this.setState({ + config: AdminStore.getConfig(), + teams: AdminStore.getAllTeams(), + selectedTeams: AdminStore.getSelectedTeams(), + selected: this.state.selected, + selectedTeam: this.state.selectedTeam + }); + } + + addSelectedTeam(teamId) { + var selectedTeams = AdminStore.getSelectedTeams(); + selectedTeams[teamId] = 'true'; + AdminStore.saveSelectedTeams(selectedTeams); + + this.setState({ + config: AdminStore.getConfig(), + teams: AdminStore.getAllTeams(), + selectedTeams: AdminStore.getSelectedTeams(), + selected: this.state.selected, + selectedTeam: this.state.selectedTeam + }); } render() { @@ -74,6 +141,8 @@ export default class AdminController extends React.Component { tab = <TeamSettingsTab config={this.state.config} />; } else if (this.state.selected === 'service_settings') { tab = <ServiceSettingsTab config={this.state.config} />; + } else if (this.state.selected === 'team_users') { + tab = <TeamUsersTab team={this.state.teams[this.state.selectedTeam]} />; } } @@ -85,7 +154,12 @@ export default class AdminController extends React.Component { /> <AdminSidebar selected={this.state.selected} + selectedTeam={this.state.selectedTeam} selectTab={this.selectTab} + teams={this.state.teams} + selectedTeams={this.state.selectedTeams} + removeSelectedTeam={this.removeSelectedTeam} + addSelectedTeam={this.addSelectedTeam} /> <div className='inner__wrap channel__wrap'> <div className='row header'> diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index 17ce39c7c..cebb3ff20 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -2,6 +2,7 @@ // See License.txt for license information. var AdminSidebarHeader = require('./admin_sidebar_header.jsx'); +var SelectTeamModal = require('./select_team_modal.jsx'); export default class AdminSidebar extends React.Component { constructor(props) { @@ -9,28 +10,121 @@ export default class AdminSidebar extends React.Component { this.isSelected = this.isSelected.bind(this); this.handleClick = this.handleClick.bind(this); + this.removeTeam = this.removeTeam.bind(this); + + this.showTeamSelect = this.showTeamSelect.bind(this); + this.teamSelectedModal = this.teamSelectedModal.bind(this); + this.teamSelectedModalDismissed = this.teamSelectedModalDismissed.bind(this); this.state = { + showSelectModal: false }; } - handleClick(name, e) { + handleClick(name, teamId, e) { e.preventDefault(); - this.props.selectTab(name); + this.props.selectTab(name, teamId); } - isSelected(name) { + isSelected(name, teamId) { if (this.props.selected === name) { - return 'active'; + if (name === 'team_users') { + if (this.props.selectedTeam != null && this.props.selectedTeam === teamId) { + return 'active'; + } + } else { + return 'active'; + } } return ''; } + removeTeam(teamId, e) { + e.preventDefault(); + Reflect.deleteProperty(this.props.selectedTeams, teamId); + this.props.removeSelectedTeam(teamId); + + if (this.props.selected === 'team_users') { + if (this.props.selectedTeam != null && this.props.selectedTeam === teamId) { + this.props.selectTab('service_settings', null); + } + } + } + componentDidMount() { } + showTeamSelect(e) { + e.preventDefault(); + this.setState({showSelectModal: true}); + } + + teamSelectedModal(teamId) { + this.props.selectedTeams[teamId] = 'true'; + this.setState({showSelectModal: false}); + this.props.addSelectedTeam(teamId); + this.forceUpdate(); + } + + teamSelectedModalDismissed() { + this.setState({showSelectModal: false}); + } + render() { + var count = '*'; + var teams = 'Loading'; + + if (this.props.teams != null) { + count = '' + Object.keys(this.props.teams).length; + + teams = []; + for (var key in this.props.selectedTeams) { + if (this.props.selectedTeams.hasOwnProperty(key)) { + var team = this.props.teams[key]; + + if (team != null) { + teams.push( + <ul + key={'team_' + team.id} + className='nav nav__sub-menu' + > + <li> + <a + href='#' + onClick={this.handleClick.bind(this, 'team_users', team.id)} + className={'nav__sub-menu-item ' + this.isSelected('team_users', team.id)} + > + {team.name} + <span + className='menu-icon--right menu__close' + onClick={this.removeTeam.bind(this, team.id)} + style={{cursor: 'pointer'}} + > + {'x'} + </span> + </a> + </li> + <li> + <ul className='nav nav__inner-menu'> + <li> + <a + href='#' + className={this.isSelected('team_users', team.id)} + onClick={this.handleClick.bind(this, 'team_users', team.id)} + > + {'- Users'} + </a> + </li> + </ul> + </li> + </ul> + ); + } + } + } + } + return ( <div className='sidebar--left sidebar--collapsable'> <div> @@ -39,10 +133,16 @@ export default class AdminSidebar extends React.Component { <li> <ul className='nav nav__sub-menu'> <li> + <h4> + <span className='icon fa fa-gear'></span> + <span>{'SETTINGS'}</span> + </h4> + </li> + <li> <a href='#' className={this.isSelected('service_settings')} - onClick={this.handleClick.bind(this, 'service_settings')} + onClick={this.handleClick.bind(this, 'service_settings', null)} > {'Service Settings'} </a> @@ -51,7 +151,7 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('team_settings')} - onClick={this.handleClick.bind(this, 'team_settings')} + onClick={this.handleClick.bind(this, 'team_settings', null)} > {'Team Settings'} </a> @@ -60,7 +160,7 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('sql_settings')} - onClick={this.handleClick.bind(this, 'sql_settings')} + onClick={this.handleClick.bind(this, 'sql_settings', null)} > {'SQL Settings'} </a> @@ -69,7 +169,7 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('email_settings')} - onClick={this.handleClick.bind(this, 'email_settings')} + onClick={this.handleClick.bind(this, 'email_settings', null)} > {'Email Settings'} </a> @@ -78,7 +178,7 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('image_settings')} - onClick={this.handleClick.bind(this, 'image_settings')} + onClick={this.handleClick.bind(this, 'image_settings', null)} > {'File Settings'} </a> @@ -87,7 +187,7 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('log_settings')} - onClick={this.handleClick.bind(this, 'log_settings')} + onClick={this.handleClick.bind(this, 'log_settings', null)} > {'Log Settings'} </a> @@ -95,17 +195,8 @@ export default class AdminSidebar extends React.Component { <li> <a href='#' - className={this.isSelected('logs')} - onClick={this.handleClick.bind(this, 'logs')} - > - {'Logs'} - </a> - </li> - <li> - <a - href='#' className={this.isSelected('rate_settings')} - onClick={this.handleClick.bind(this, 'rate_settings')} + onClick={this.handleClick.bind(this, 'rate_settings', null)} > {'Rate Limit Settings'} </a> @@ -114,7 +205,7 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('privacy_settings')} - onClick={this.handleClick.bind(this, 'privacy_settings')} + onClick={this.handleClick.bind(this, 'privacy_settings', null)} > {'Privacy Settings'} </a> @@ -123,21 +214,65 @@ export default class AdminSidebar extends React.Component { <a href='#' className={this.isSelected('gitlab_settings')} - onClick={this.handleClick.bind(this, 'gitlab_settings')} + onClick={this.handleClick.bind(this, 'gitlab_settings', null)} > {'GitLab Settings'} </a> </li> + <li> + <h4> + <span className='icon fa fa-gear'></span> + <span>{'TEAMS (' + count + ')'}</span> + <span className='menu-icon--right'> + <a + href='#' + onClick={this.showTeamSelect} + > + <i className='fa fa-plus'></i> + </a> + </span> + </h4> + </li> + <li> + {teams} + </li> + <li> + <h4> + <span className='icon fa fa-gear'></span> + <span>{'OTHER'}</span> + </h4> + </li> + <li> + <a + href='#' + className={this.isSelected('logs')} + onClick={this.handleClick.bind(this, 'logs', null)} + > + {'Logs'} + </a> + </li> </ul> </li> </ul> </div> + + <SelectTeamModal + teams={this.props.teams} + show={this.state.showSelectModal} + onModalSubmit={this.teamSelectedModal} + onModalDismissed={this.teamSelectedModalDismissed} + /> </div> ); } } AdminSidebar.propTypes = { + teams: React.PropTypes.object, + selectedTeams: React.PropTypes.object, + removeSelectedTeam: React.PropTypes.func, + addSelectedTeam: React.PropTypes.func, selected: React.PropTypes.string, + selectedTeam: React.PropTypes.string, selectTab: React.PropTypes.func };
\ No newline at end of file diff --git a/web/react/components/admin_console/reset_password_modal.jsx b/web/react/components/admin_console/reset_password_modal.jsx new file mode 100644 index 000000000..0b83edb17 --- /dev/null +++ b/web/react/components/admin_console/reset_password_modal.jsx @@ -0,0 +1,132 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var Client = require('../../utils/client.jsx'); +var Modal = ReactBootstrap.Modal; + +export default class ResetPasswordModal extends React.Component { + constructor(props) { + super(props); + + this.doSubmit = this.doSubmit.bind(this); + this.doCancel = this.doCancel.bind(this); + + this.state = { + serverError: null + }; + } + + doSubmit(e) { + e.preventDefault(); + var password = React.findDOMNode(this.refs.password).value; + + if (!password || password.length < 5) { + this.setState({serverError: 'Please enter at least 5 characters.'}); + return; + } + + this.setState({serverError: null}); + + var data = {}; + data.new_password = password; + data.name = this.props.team.name; + data.user_id = this.props.user.id; + + Client.resetPassword(data, + () => { + this.props.onModalSubmit(React.findDOMNode(this.refs.password).value); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + doCancel() { + this.setState({serverError: null}); + this.props.onModalDismissed(); + } + + render() { + if (this.props.user == null) { + return <div/>; + } + + let urlClass = 'input-group input-group--limit'; + let serverError = null; + + if (this.state.serverError) { + urlClass += ' has-error'; + serverError = <div className='form-group has-error'><p className='input__help error'>{this.state.serverError}</p></div>; + } + + return ( + <Modal + show={this.props.show} + onHide={this.doCancel} + > + <Modal.Header closeButton={true}> + <Modal.Title>{'Reset Password'}</Modal.Title> + </Modal.Header> + <form + role='form' + className='form-horizontal' + > + <Modal.Body> + <div className='form-group'> + <div className='col-sm-10'> + <div className={urlClass}> + <span + data-toggle='tooltip' + title='New Password' + className='input-group-addon' + > + {'New Password'} + </span> + <input + type='password' + ref='password' + className='form-control' + maxLength='22' + autoFocus={true} + tabIndex='1' + /> + </div> + {serverError} + </div> + </div> + </Modal.Body> + <Modal.Footer> + <button + type='button' + className='btn btn-default' + onClick={this.doCancel} + > + {'Close'} + </button> + <button + onClick={this.doSubmit} + type='submit' + className='btn btn-primary' + tabIndex='2' + > + {'Select'} + </button> + </Modal.Footer> + </form> + </Modal> + ); + } +} + +ResetPasswordModal.defaultProps = { + show: false +}; + +ResetPasswordModal.propTypes = { + user: React.PropTypes.object, + team: React.PropTypes.object, + show: React.PropTypes.bool.isRequired, + onModalSubmit: React.PropTypes.func, + onModalDismissed: React.PropTypes.func +}; diff --git a/web/react/components/admin_console/select_team_modal.jsx b/web/react/components/admin_console/select_team_modal.jsx index fa30de7b2..343f65131 100644 --- a/web/react/components/admin_console/select_team_modal.jsx +++ b/web/react/components/admin_console/select_team_modal.jsx @@ -1,124 +1,99 @@ // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. -export default class SelectTeam extends React.Component { +var Modal = ReactBootstrap.Modal; + +export default class SelectTeamModal extends React.Component { constructor(props) { super(props); - this.state = { - }; + this.doSubmit = this.doSubmit.bind(this); + this.doCancel = this.doCancel.bind(this); } + doSubmit(e) { + e.preventDefault(); + this.props.onModalSubmit(React.findDOMNode(this.refs.team).value); + } + doCancel() { + this.props.onModalDismissed(); + } render() { + if (this.props.teams == null) { + return <div/>; + } + + var options = []; + + for (var key in this.props.teams) { + if (this.props.teams.hasOwnProperty(key)) { + var team = this.props.teams[key]; + options.push( + <option + key={'opt_' + team.id} + value={team.id} + > + {team.name} + </option> + ); + } + } + return ( - <div className='modal fade' - id='select-team' - tabIndex='-1' - role='dialog' - aria-labelledby='teamsModalLabel' + <Modal + show={this.props.show} + onHide={this.doCancel} > - <div className='modal-dialog' - role='document' + <Modal.Header closeButton={true}> + <Modal.Title>{'Select Team'}</Modal.Title> + </Modal.Header> + <form + role='form' + className='form-horizontal' > - <div className='modal-content'> - <div className='modal-header'> - <button - type='button' - className='close' - data-dismiss='modal' - aria-label='Close' - > - <span aria-hidden='true'>×</span> - </button> - <h4 - className='modal-title' - id='teamsModalLabel' - > - {'Select a team'} - </h4> - </div> - <div className='modal-body'> - <table className='more-channel-table table'> - <tbody> - <tr> - <td> - <p className='more-channel-name'>{'Descartes'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Grouping'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Adventure'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Crossroads'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Sky scraping'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Outdoors'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Microsoft'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - <tr> - <td> - <p className='more-channel-name'>{'Apple'}</p> - </td> - <td className='td--action'> - <button className='btn btn-primary'>{'Join'}</button> - </td> - </tr> - </tbody> - </table> - </div> - <div className='modal-footer'> - <button - type='button' - className='btn btn-default' - data-dismiss='modal' - > - {'Close'} - </button> + <Modal.Body> + <div className='form-group'> + <div className='col-sm-12'> + <select + ref='team' + size='10' + style={{width: '100%'}} + > + {options} + </select> + </div> </div> - </div> - </div> - </div> + </Modal.Body> + <Modal.Footer> + <button + type='button' + className='btn btn-default' + onClick={this.doCancel} + > + {'Close'} + </button> + <button + onClick={this.doSubmit} + type='submit' + className='btn btn-primary' + tabIndex='2' + > + {'Select'} + </button> + </Modal.Footer> + </form> + </Modal> ); } -}
\ No newline at end of file +} + +SelectTeamModal.defaultProps = { + show: false +}; + +SelectTeamModal.propTypes = { + teams: React.PropTypes.object, + show: React.PropTypes.bool.isRequired, + onModalSubmit: React.PropTypes.func, + onModalDismissed: React.PropTypes.func +}; diff --git a/web/react/components/admin_console/team_users.jsx b/web/react/components/admin_console/team_users.jsx new file mode 100644 index 000000000..0a971ff15 --- /dev/null +++ b/web/react/components/admin_console/team_users.jsx @@ -0,0 +1,178 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var Client = require('../../utils/client.jsx'); +var LoadingScreen = require('../loading_screen.jsx'); +var UserItem = require('./user_item.jsx'); +var ResetPasswordModal = require('./reset_password_modal.jsx'); + +export default class UserList extends React.Component { + constructor(props) { + super(props); + + this.getTeamProfiles = this.getTeamProfiles.bind(this); + this.getCurrentTeamProfiles = this.getCurrentTeamProfiles.bind(this); + this.doPasswordReset = this.doPasswordReset.bind(this); + this.doPasswordResetDismiss = this.doPasswordResetDismiss.bind(this); + this.doPasswordResetSubmit = this.doPasswordResetSubmit.bind(this); + + this.state = { + teamId: props.team.id, + users: null, + serverError: null, + showPasswordModal: false, + user: null + }; + } + + componentDidMount() { + this.getCurrentTeamProfiles(); + } + + getCurrentTeamProfiles() { + this.getTeamProfiles(this.props.team.id); + } + + // this.setState({ + // teamId: this.state.teamId, + // users: this.state.users, + // serverError: this.state.serverError, + // showPasswordModal: this.state.showPasswordModal, + // user: this.state.user + // }); + + getTeamProfiles(teamId) { + Client.getProfilesForTeam( + teamId, + (users) => { + var memberList = []; + for (var id in users) { + if (users.hasOwnProperty(id)) { + memberList.push(users[id]); + } + } + + memberList.sort((a, b) => { + if (a.username < b.username) { + return -1; + } + + if (a.username > b.username) { + return 1; + } + + return 0; + }); + + this.setState({ + teamId: this.state.teamId, + users: memberList, + serverError: this.state.serverError, + showPasswordModal: this.state.showPasswordModal, + user: this.state.user + }); + }, + (err) => { + this.setState({ + teamId: this.state.teamId, + users: null, + serverError: err.message, + showPasswordModal: this.state.showPasswordModal, + user: this.state.user + }); + } + ); + } + + doPasswordReset(user) { + this.setState({ + teamId: this.state.teamId, + users: this.state.users, + serverError: this.state.serverError, + showPasswordModal: true, + user + }); + } + + doPasswordResetDismiss() { + this.state.showPasswordModal = false; + this.state.user = null; + this.setState({ + teamId: this.state.teamId, + users: this.state.users, + serverError: this.state.serverError, + showPasswordModal: false, + user: null + }); + } + + doPasswordResetSubmit() { + this.setState({ + teamId: this.state.teamId, + users: this.state.users, + serverError: this.state.serverError, + showPasswordModal: false, + user: null + }); + } + + componentWillReceiveProps(newProps) { + this.getTeamProfiles(newProps.team.id); + } + + componentWillUnmount() { + } + + render() { + var serverError = ''; + if (this.state.serverError) { + serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>; + } + + if (this.state.users == null) { + return ( + <div className='wrapper--fixed'> + <h3>{'Users for ' + this.props.team.name}</h3> + {serverError} + <LoadingScreen /> + </div> + ); + } + + var memberList = this.state.users.map((user) => { + return ( + <UserItem + key={'user_' + user.id} + user={user} + refreshProfiles={this.getCurrentTeamProfiles} + doPasswordReset={this.doPasswordReset} + />); + }); + + return ( + <div className='wrapper--fixed'> + <h3>{'Users for ' + this.props.team.name + ' (' + this.state.users.length + ')'}</h3> + {serverError} + <form + className='form-horizontal' + role='form' + > + <div className='member-list-holder'> + {memberList} + </div> + </form> + <ResetPasswordModal + user={this.state.user} + show={this.state.showPasswordModal} + team={this.props.team} + onModalSubmit={this.doPasswordResetSubmit} + onModalDismissed={this.doPasswordResetDismiss} + /> + </div> + ); + } +} + +UserList.propTypes = { + team: React.PropTypes.object +}; diff --git a/web/react/components/admin_console/user_item.jsx b/web/react/components/admin_console/user_item.jsx new file mode 100644 index 000000000..32812e875 --- /dev/null +++ b/web/react/components/admin_console/user_item.jsx @@ -0,0 +1,266 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var Client = require('../../utils/client.jsx'); +var Utils = require('../../utils/utils.jsx'); + +export default class UserItem extends React.Component { + constructor(props) { + super(props); + + this.handleMakeMember = this.handleMakeMember.bind(this); + this.handleMakeActive = this.handleMakeActive.bind(this); + this.handleMakeNotActive = this.handleMakeNotActive.bind(this); + this.handleMakeAdmin = this.handleMakeAdmin.bind(this); + this.handleMakeSystemAdmin = this.handleMakeSystemAdmin.bind(this); + this.handleResetPassword = this.handleResetPassword.bind(this); + + this.state = {}; + } + + handleMakeMember(e) { + e.preventDefault(); + const data = { + user_id: this.props.user.id, + new_roles: '' + }; + + Client.updateRoles(data, + () => { + this.props.refreshProfiles(); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + handleMakeActive(e) { + e.preventDefault(); + Client.updateActive(this.props.user.id, true, + () => { + this.props.refreshProfiles(); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + handleMakeNotActive(e) { + e.preventDefault(); + Client.updateActive(this.props.user.id, false, + () => { + this.props.refreshProfiles(); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + handleMakeAdmin(e) { + e.preventDefault(); + const data = { + user_id: this.props.user.id, + new_roles: 'admin' + }; + + Client.updateRoles(data, + () => { + this.props.refreshProfiles(); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + handleMakeSystemAdmin(e) { + e.preventDefault(); + const data = { + user_id: this.props.user.id, + new_roles: 'system_admin' + }; + + Client.updateRoles(data, + () => { + this.props.refreshProfiles(); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + handleResetPassword(e) { + e.preventDefault(); + this.props.doPasswordReset(this.props.user); + } + + render() { + let serverError = null; + if (this.state.serverError) { + serverError = ( + <div className='has-error'> + <label className='has-error control-label'>{this.state.serverError}</label> + </div> + ); + } + + const user = this.props.user; + let currentRoles = 'Member'; + if (user.roles.length > 0) { + if (user.roles.indexOf('system_admin') > -1) { + currentRoles = 'System Admin'; + } else { + currentRoles = user.roles.charAt(0).toUpperCase() + user.roles.slice(1); + } + } + + const email = user.email; + let showMakeMember = user.roles === 'admin' || user.roles === 'system_admin'; + let showMakeAdmin = user.roles === '' || user.roles === 'system_admin'; + let showMakeSystemAdmin = user.roles === '' || user.roles === 'admin'; + let showMakeActive = false; + let showMakeNotActive = user.roles !== 'system_admin'; + + if (user.delete_at > 0) { + currentRoles = 'Inactive'; + currentRoles = 'Inactive'; + showMakeMember = false; + showMakeAdmin = false; + showMakeSystemAdmin = false; + showMakeActive = true; + showMakeNotActive = false; + } + + let makeSystemAdmin = null; + if (showMakeSystemAdmin) { + makeSystemAdmin = ( + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.handleMakeSystemAdmin} + > + {'Make System Admin'} + </a> + </li> + ); + } + + let makeAdmin = null; + if (showMakeAdmin) { + makeAdmin = ( + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.handleMakeAdmin} + > + {'Make Admin'} + </a> + </li> + ); + } + + let makeMember = null; + if (showMakeMember) { + makeMember = ( + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.handleMakeMember} + > + {'Make Member'} + </a> + </li> + ); + } + + let makeActive = null; + if (showMakeActive) { + makeActive = ( + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.handleMakeActive} + > + {'Make Active'} + </a> + </li> + ); + } + + let makeNotActive = null; + if (showMakeNotActive) { + makeNotActive = ( + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.handleMakeNotActive} + > + {'Make Inactive'} + </a> + </li> + ); + } + + return ( + <div className='row member-div'> + <img + className='post-profile-img pull-left' + src={`/api/v1/users/${user.id}/image?time=${user.update_at}`} + height='36' + width='36' + /> + <span className='member-name'>{Utils.getDisplayName(user)}</span> + <span className='member-email'>{email}</span> + <div className='dropdown member-drop'> + <a + href='#' + className='dropdown-toggle theme' + type='button' + id='channel_header_dropdown' + data-toggle='dropdown' + aria-expanded='true' + > + <span>{currentRoles} </span> + <span className='caret'></span> + </a> + <ul + className='dropdown-menu member-menu' + role='menu' + aria-labelledby='channel_header_dropdown' + > + {makeAdmin} + {makeMember} + {makeActive} + {makeNotActive} + {makeSystemAdmin} + <li role='presentation'> + <a + role='menuitem' + href='#' + onClick={this.handleResetPassword} + > + {'Reset Password'} + </a> + </li> + </ul> + </div> + {serverError} + </div> + ); + } +} + +UserItem.propTypes = { + user: React.PropTypes.object.isRequired, + refreshProfiles: React.PropTypes.func.isRequired, + doPasswordReset: React.PropTypes.func.isRequired +}; |