PLT-349 adding team mgt to admin console

Этот коммит содержится в:
=Corey Hulen
2015-09-23 12:49:28 -07:00
родитель 9e04909c0a
Коммит 1626a6de6f
22 изменённых файлов: 1154 добавлений и 166 удалений

Просмотреть файл

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

Просмотреть файл

@@ -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>
@@ -38,11 +132,17 @@ export default class AdminSidebar extends React.Component {
<ul className='nav nav-pills nav-stacked'>
<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)}
>
{'Image 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>
@@ -96,7 +196,7 @@ export default class AdminSidebar extends React.Component {
<a
href='#'
className={this.isSelected('logs')}
onClick={this.handleClick.bind(this, 'logs')}
onClick={this.handleClick.bind(this, 'logs', null)}
>
{'Logs'}
</a>
@@ -105,7 +205,7 @@ export default class AdminSidebar extends React.Component {
<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 +214,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 +223,50 @@ 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>
</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
};

Просмотреть файл

@@ -0,0 +1,136 @@
// 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.state.serverError = 'Please enter at least 5 characters.';
this.setState(this.state);
return;
}
this.state.serverError = null;
this.setState(this.state);
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.state.serverError = err.message;
this.setState(this.state);
}
);
}
doCancel() {
this.state.serverError = null;
this.setState(this.state);
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
};

Просмотреть файл

@@ -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'>&times;</span>
</button>
<h4
className='modal-title'
id='teamsModalLabel'
>
{'Select a team'}
</h4>
<Modal.Body>
<div className='form-group'>
<div className='col-sm-12'>
<select
ref='team'
size='10'
style={{width: '100%'}}
>
{options}
</select>
</div>
</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>
</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>
);
}
}
}
SelectTeamModal.defaultProps = {
show: false
};
SelectTeamModal.propTypes = {
teams: React.PropTypes.object,
show: React.PropTypes.bool.isRequired,
onModalSubmit: React.PropTypes.func,
onModalDismissed: React.PropTypes.func
};

Просмотреть файл

@@ -0,0 +1,147 @@
// 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);
}
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.state.users = memberList;
this.setState(this.state);
},
(err) => {
this.state.serverError = err.message;
this.state.users = null;
this.setState(this.state);
}
);
}
doPasswordReset(user) {
this.state.showPasswordModal = true;
this.state.user = user;
this.setState(this.state);
}
doPasswordResetDismiss() {
this.state.showPasswordModal = false;
this.state.user = null;
this.setState(this.state);
}
doPasswordResetSubmit() {
this.state.showPasswordModal = false;
this.state.user = null;
this.setState(this.state);
}
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
};

Просмотреть файл

@@ -0,0 +1,230 @@
// 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.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});
}
);
}
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 showMakeActive = false;
let showMakeNotActive = user.roles !== 'system_admin';
if (user.delete_at > 0) {
currentRoles = 'Inactive';
currentRoles = 'Inactive';
showMakeMember = false;
showMakeAdmin = false;
showMakeActive = true;
showMakeNotActive = false;
}
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}
<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
};

Просмотреть файл

@@ -4,11 +4,14 @@
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var EventEmitter = require('events').EventEmitter;
var BrowserStore = require('../stores/browser_store.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
var LOG_CHANGE_EVENT = 'log_change';
var CONFIG_CHANGE_EVENT = 'config_change';
var ALL_TEAMS_EVENT = 'all_team_change';
class AdminStoreClass extends EventEmitter {
constructor() {
@@ -16,6 +19,7 @@ class AdminStoreClass extends EventEmitter {
this.logs = null;
this.config = null;
this.teams = null;
this.emitLogChange = this.emitLogChange.bind(this);
this.addLogChangeListener = this.addLogChangeListener.bind(this);
@@ -24,6 +28,10 @@ class AdminStoreClass extends EventEmitter {
this.emitConfigChange = this.emitConfigChange.bind(this);
this.addConfigChangeListener = this.addConfigChangeListener.bind(this);
this.removeConfigChangeListener = this.removeConfigChangeListener.bind(this);
this.emitAllTeamsChange = this.emitAllTeamsChange.bind(this);
this.addAllTeamsChangeListener = this.addAllTeamsChangeListener.bind(this);
this.removeAllTeamsChangeListener = this.removeAllTeamsChangeListener.bind(this);
}
emitLogChange() {
@@ -50,6 +58,18 @@ class AdminStoreClass extends EventEmitter {
this.removeListener(CONFIG_CHANGE_EVENT, callback);
}
emitAllTeamsChange() {
this.emit(ALL_TEAMS_EVENT);
}
addAllTeamsChangeListener(callback) {
this.on(ALL_TEAMS_EVENT, callback);
}
removeAllTeamsChangeListener(callback) {
this.removeListener(ALL_TEAMS_EVENT, callback);
}
getLogs() {
return this.logs;
}
@@ -65,6 +85,22 @@ class AdminStoreClass extends EventEmitter {
saveConfig(config) {
this.config = config;
}
getAllTeams() {
return this.teams;
}
saveAllTeams(teams) {
this.teams = teams;
}
getSelectedTeams() {
return BrowserStore.getItem('seleted_teams');
}
saveSelectedTeams(teams) {
BrowserStore.setItem('seleted_teams', teams);
}
}
var AdminStore = new AdminStoreClass();
@@ -81,6 +117,10 @@ AdminStoreClass.dispatchToken = AppDispatcher.register((payload) => {
AdminStore.saveConfig(action.config);
AdminStore.emitConfigChange();
break;
case ActionTypes.RECIEVED_ALL_TEAMS:
AdminStore.saveAllTeams(action.teams);
AdminStore.emitAllTeamsChange();
break;
default:
}
});

Просмотреть файл

@@ -371,6 +371,32 @@ export function getConfig() {
);
}
export function getAllTeams() {
if (isCallInProgress('getAllTeams')) {
return;
}
callTracker.getAllTeams = utils.getTimestamp();
client.getAllTeams(
(data, textStatus, xhr) => {
callTracker.getAllTeams = 0;
if (xhr.status === 304 || !data) {
return;
}
AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_ALL_TEAMS,
teams: data
});
},
(err) => {
callTracker.getAllTeams = 0;
dispatchError(err, 'getAllTeams');
}
);
}
export function findTeams(email) {
if (isCallInProgress('findTeams_' + email)) {
return;

Просмотреть файл

@@ -347,6 +347,20 @@ export function testEmail(config, success, error) {
});
}
export function getAllTeams(success, error) {
$.ajax({
url: '/api/v1/teams/all',
dataType: 'json',
contentType: 'application/json',
type: 'GET',
success,
error: function onError(xhr, status, err) {
var e = handleError('getAllTeams', xhr, status, err);
error(e);
}
});
}
export function getMeSynchronous(success, error) {
var currentUser = null;
$.ajax({
@@ -890,6 +904,21 @@ export function getProfiles(success, error) {
});
}
export function getProfilesForTeam(teamId, success, error) {
$.ajax({
cache: false,
url: '/api/v1/users/profiles/' + teamId,
dataType: 'json',
contentType: 'application/json',
type: 'GET',
success,
error: function onError(xhr, status, err) {
var e = handleError('getProfilesForTeam', xhr, status, err);
error(e);
}
});
}
export function uploadFile(formData, success, error) {
var request = $.ajax({
url: '/api/v1/files/upload',

Просмотреть файл

@@ -35,8 +35,8 @@ module.exports = {
RECIEVED_TEAM: null,
RECIEVED_CONFIG: null,
RECIEVED_LOGS: null
RECIEVED_LOGS: null,
RECIEVED_ALL_TEAMS: null
}),
PayloadSources: keyMirror({

Просмотреть файл

@@ -19,6 +19,11 @@
background-color: $primary-color;
}
}
> h4 {
background: #333;
padding: 10px 10px;
margin-top: 1px;
}
}
.menu-icon--right {
vertical-align: top;
@@ -29,10 +34,10 @@
font-size: 13px;
right: -2px;
position: relative;
color: #fff;
}
}
&.nav__sub-menu {
padding: 5px 0;
background: #111;
-webkit-font-smoothing: auto;
li {
@@ -88,6 +93,7 @@
overflow: auto;
background-color: #f1f1f1;
padding: 0 20px 20px;
min-height: 600px;
}
.wrapper--fixed {
max-width: 800px;