Merge pull request #648 from mattermost/PLT-12
PLT-12: Work in progress for Admin Console UI
Этот коммит содержится в:
59
web/react/components/admin_console/admin_controller.jsx
Обычный файл
59
web/react/components/admin_console/admin_controller.jsx
Обычный файл
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
var AdminSidebar = require('./admin_sidebar.jsx');
|
||||
var EmailTab = require('./email_settings.jsx');
|
||||
var JobsTab = require('./jobs_settings.jsx');
|
||||
var Navbar = require('../../components/navbar.jsx');
|
||||
|
||||
export default class AdminController extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.selectTab = this.selectTab.bind(this);
|
||||
|
||||
this.state = {
|
||||
selected: 'email_settings'
|
||||
};
|
||||
}
|
||||
|
||||
selectTab(tab) {
|
||||
this.setState({selected: tab});
|
||||
}
|
||||
|
||||
render() {
|
||||
var tab = '';
|
||||
|
||||
if (this.state.selected === 'email_settings') {
|
||||
tab = <EmailTab />;
|
||||
} else if (this.state.selected === 'job_settings') {
|
||||
tab = <JobsTab />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='container-fluid'>
|
||||
<div
|
||||
className='sidebar--menu'
|
||||
id='sidebar-menu'
|
||||
/>
|
||||
<AdminSidebar
|
||||
selected={this.state.selected}
|
||||
selectTab={this.selectTab}
|
||||
/>
|
||||
<div className='inner__wrap channel__wrap'>
|
||||
<div className='row header'>
|
||||
<Navbar teamDisplayName='Admin Console' />
|
||||
</div>
|
||||
<div className='row main'>
|
||||
<div
|
||||
id='app-content'
|
||||
className='app__content admin'
|
||||
>
|
||||
{tab}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
197
web/react/components/admin_console/admin_sidebar.jsx
Обычный файл
197
web/react/components/admin_console/admin_sidebar.jsx
Обычный файл
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
var SidebarHeader = require('../sidebar_header.jsx');
|
||||
|
||||
export default class AdminSidebar extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.isSelected = this.isSelected.bind(this);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
};
|
||||
}
|
||||
|
||||
handleClick(name) {
|
||||
this.props.selectTab(name);
|
||||
}
|
||||
|
||||
isSelected(name) {
|
||||
if (this.props.selected === name) {
|
||||
return 'active';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$('.nav__menu-item').on('click', function clickme(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.sidebar--collapsable').find('.nav__menu-item').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
$(this).closest('.sidebar--collapsable').find('.nav__sub-menu').addClass('hide');
|
||||
$(this).next('.nav__sub-menu').removeClass('hide');
|
||||
});
|
||||
|
||||
$('.nav__sub-menu a').on('click', function clickme(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.nav__sub-menu').find('a').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
});
|
||||
|
||||
$('.nav__sub-menu-item').on('click', function clickme(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.sidebar--collapsable').find('.nav__inner-menu').addClass('hide');
|
||||
$(this).closest('li').next('li').find('.nav__inner-menu').removeClass('hide');
|
||||
$(this).closest('li').next('li').find('.nav__inner-menu li:first a').addClass('active');
|
||||
});
|
||||
|
||||
$('.nav__inner-menu a').on('click', function clickme() {
|
||||
$(this).closest('.nav__inner-menu').closest('li').prev('li').find('a').addClass('active');
|
||||
});
|
||||
|
||||
$('.nav__sub-menu .menu__close').on('click', function close() {
|
||||
var menuItem = $(this).closest('li');
|
||||
menuItem.next('li').remove();
|
||||
menuItem.remove();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='sidebar--left sidebar--collapsable'>
|
||||
<div>
|
||||
<SidebarHeader
|
||||
teamDisplayName='Admin Console'
|
||||
teamType='I'
|
||||
/>
|
||||
<ul className='nav nav-pills nav-stacked'>
|
||||
<li>
|
||||
<a href='#'
|
||||
className='nav__menu-item active'
|
||||
>
|
||||
<span className='icon fa fa-gear'></span> <span>{'Basic Settings'}</span></a>
|
||||
<ul className='nav nav__sub-menu'>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className={this.isSelected('email_settings')}
|
||||
onClick={this.handleClick.bind(null, 'email_settings')}
|
||||
>
|
||||
{'Email Settings'}
|
||||
</a>
|
||||
</li>
|
||||
<li><a href='#'>{'Other Settings'}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className='nav__menu-item'
|
||||
>
|
||||
<span className='icon fa fa-gear'></span> <span>{'Jobs'}</span>
|
||||
</a>
|
||||
<ul className='nav nav__sub-menu hide'>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className={this.isSelected('job_settings')}
|
||||
onClick={this.handleClick.bind(null, 'job_settings')}
|
||||
>
|
||||
{'Job Settings'}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className='nav__menu-item'
|
||||
>
|
||||
<span className='icon fa fa-gear'></span>
|
||||
<span>{'Team Settings (306)'}</span>
|
||||
<span className='menu-icon--right'>
|
||||
<i className='fa fa-plus'></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul className='nav nav__sub-menu hide'>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className='nav__sub-menu-item active'
|
||||
>
|
||||
{'Adal '}
|
||||
<span className='menu-icon--right menu__close'>{'x'}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<ul className='nav nav__inner-menu'>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className='active'
|
||||
>
|
||||
{'- Users'}
|
||||
</a>
|
||||
</li>
|
||||
<li><a href='#'>{'- View Statistics'}</a></li>
|
||||
<li>
|
||||
<a href='#'>
|
||||
{'- View Audit Log'}
|
||||
<span className='badge pull-right small'>{'1'}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className='nav__sub-menu-item'
|
||||
>
|
||||
{'Boole '}
|
||||
<span className='menu-icon--right menu__close'>{'x'}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<ul className='nav nav__inner-menu hide'>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
className='active'
|
||||
>
|
||||
{'- Users'}
|
||||
</a>
|
||||
</li>
|
||||
<li><a href='#'>{'- View Statistics'}</a></li>
|
||||
<li>
|
||||
<a href='#'>
|
||||
{'- View Audit Log'}
|
||||
<span className='badge pull-right small'>{'1'}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<span
|
||||
data-toggle='modal'
|
||||
data-target='#select-team'
|
||||
className='nav-more'
|
||||
>
|
||||
{'Select a team'}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AdminSidebar.propTypes = {
|
||||
selected: React.PropTypes.string,
|
||||
selectTab: React.PropTypes.func
|
||||
};
|
||||
311
web/react/components/admin_console/email_settings.jsx
Обычный файл
311
web/react/components/admin_console/email_settings.jsx
Обычный файл
@@ -0,0 +1,311 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
export default class EmailSettings extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{'Email Settings'}</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='email'
|
||||
>
|
||||
{'Bypass Email: '}
|
||||
<a
|
||||
href='#'
|
||||
data-trigger='hover click'
|
||||
data-toggle='popover'
|
||||
data-position='bottom'
|
||||
data-content={'Here\'s some more help text inside a popover for the Bypass Email field just to show how popovers look.'}
|
||||
>
|
||||
{'(?)'}
|
||||
</a>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='byPassEmail'
|
||||
value='option1'
|
||||
/>
|
||||
{'True'}
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='byPassEmail'
|
||||
value='option2'
|
||||
/>
|
||||
{'False'}
|
||||
</label>
|
||||
<p className='help-text'>{'This is some sample help text for the Bypass Email field'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='smtpUsername'
|
||||
>
|
||||
{'SMTP Username:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='email'
|
||||
className='form-control'
|
||||
id='smtpUsername'
|
||||
placeholder='Enter your SMTP username'
|
||||
value=''
|
||||
/>
|
||||
<div className='help-text'>
|
||||
<div className='alert alert-warning'><i className='fa fa-warning'></i>{' This is some error text for the Bypass Email field'}</div>
|
||||
</div>
|
||||
<p className='help-text'>{'This is some sample help text for the SMTP username field'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='smtpPassword'
|
||||
>
|
||||
{'SMTP Password:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='password'
|
||||
className='form-control'
|
||||
id='smtpPassword'
|
||||
placeholder='Enter your SMTP password'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='smtpServer'
|
||||
>
|
||||
{'SMTP Server:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='smtpServer'
|
||||
placeholder='Enter your SMTP server'
|
||||
value=''
|
||||
/>
|
||||
<div className='help-text'>
|
||||
<a
|
||||
href='#'
|
||||
className='help-link'
|
||||
>
|
||||
{'Test Connection'}
|
||||
</a>
|
||||
<div className='alert alert-success'><i className='fa fa-check'></i>{' Connection successful'}</div>
|
||||
<div className='alert alert-warning hide'><i className='fa fa-warning'></i>{' Connection unsuccessful'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label className='control-label col-sm-4'>{'Use TLS:'}</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='tls'
|
||||
value='option1'
|
||||
/>
|
||||
{'True'}
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='tls'
|
||||
value='option2'
|
||||
/>
|
||||
{'False'}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label className='control-label col-sm-4'>{'Use Start TLS:'}</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='starttls'
|
||||
value='option1'
|
||||
/>
|
||||
{'True'}
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='starttls'
|
||||
value='option2'
|
||||
/>
|
||||
{'False'}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackEmail'
|
||||
>
|
||||
{'Feedback Email:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackEmail'
|
||||
placeholder='Enter your feedback email'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Feedback Username:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your feedback username'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<div className='col-sm-offset-4 col-sm-8'>
|
||||
<div className='checkbox'>
|
||||
<label><input type='checkbox' />{'Remember me'}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className='panel-group'
|
||||
id='accordion'
|
||||
role='tablist'
|
||||
aria-multiselectable='true'
|
||||
>
|
||||
<div className='panel panel-default'>
|
||||
<div
|
||||
className='panel-heading'
|
||||
role='tab'
|
||||
id='headingOne'
|
||||
>
|
||||
<h3 className='panel-title'>
|
||||
<a
|
||||
className='collapsed'
|
||||
role='button'
|
||||
data-toggle='collapse'
|
||||
data-parent='#accordion'
|
||||
href='#collapseOne'
|
||||
aria-expanded='true'
|
||||
aria-controls='collapseOne'
|
||||
>
|
||||
{'Advanced Settings '}
|
||||
<i className='fa fa-plus'></i>
|
||||
<i className='fa fa-minus'></i>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
id='collapseOne'
|
||||
className='panel-collapse collapse'
|
||||
role='tabpanel'
|
||||
aria-labelledby='headingOne'
|
||||
>
|
||||
<div className='panel-body'>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Apple push server:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your Apple push server'
|
||||
value=''
|
||||
/>
|
||||
<p className='help-text'>{'This is some sample help text for the Apple push server field'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Apple push certificate public:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your public apple push certificate'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Apple push certificate private:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your private apple push certificate'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='form-group'>
|
||||
<div className='col-sm-12'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
{'Submit'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
183
web/react/components/admin_console/jobs_settings.jsx
Обычный файл
183
web/react/components/admin_console/jobs_settings.jsx
Обычный файл
@@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
export default class Jobs extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='wrapper--fixed'>
|
||||
<h3>{' ************** JOB Settings'}</h3>
|
||||
<form
|
||||
className='form-horizontal'
|
||||
role='form'
|
||||
>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='email'
|
||||
>
|
||||
{'Bypass Email: '}
|
||||
<a
|
||||
href='#'
|
||||
data-trigger='hover click'
|
||||
data-toggle='popover'
|
||||
data-position='bottom'
|
||||
data-content={'Here\'s some more help text inside a popover for the Bypass Email field just to show how popovers look.'}
|
||||
>
|
||||
{'(?)'}
|
||||
</a>
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='byPassEmail'
|
||||
value='option1'
|
||||
/>
|
||||
{'True'}
|
||||
</label>
|
||||
<label className='radio-inline'>
|
||||
<input
|
||||
type='radio'
|
||||
name='byPassEmail'
|
||||
value='option2'
|
||||
/>
|
||||
{'False'}
|
||||
</label>
|
||||
<p className='help-text'>{'This is some sample help text for the Bypass Email field'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='smtpUsername'
|
||||
>
|
||||
{'SMTP Username:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='email'
|
||||
className='form-control'
|
||||
id='smtpUsername'
|
||||
placeholder='Enter your SMTP username'
|
||||
value=''
|
||||
/>
|
||||
<div className='help-text'>
|
||||
<div className='alert alert-warning'><i className='fa fa-warning'></i>{' This is some error text for the Bypass Email field'}</div>
|
||||
</div>
|
||||
<p className='help-text'>{'This is some sample help text for the SMTP username field'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className='panel-group'
|
||||
id='accordion'
|
||||
role='tablist'
|
||||
aria-multiselectable='true'
|
||||
>
|
||||
<div className='panel panel-default'>
|
||||
<div
|
||||
className='panel-heading'
|
||||
role='tab'
|
||||
id='headingOne'
|
||||
>
|
||||
<h3 className='panel-title'>
|
||||
<a
|
||||
className='collapsed'
|
||||
role='button'
|
||||
data-toggle='collapse'
|
||||
data-parent='#accordion'
|
||||
href='#collapseOne'
|
||||
aria-expanded='true'
|
||||
aria-controls='collapseOne'
|
||||
>
|
||||
{'Advanced Settings '}
|
||||
<i className='fa fa-plus'></i>
|
||||
<i className='fa fa-minus'></i>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
id='collapseOne'
|
||||
className='panel-collapse collapse'
|
||||
role='tabpanel'
|
||||
aria-labelledby='headingOne'
|
||||
>
|
||||
<div className='panel-body'>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Apple push server:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your Apple push server'
|
||||
value=''
|
||||
/>
|
||||
<p className='help-text'>{'This is some sample help text for the Apple push server field'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Apple push certificate public:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your public apple push certificate'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='form-group'>
|
||||
<label
|
||||
className='control-label col-sm-4'
|
||||
htmlFor='feedbackUsername'
|
||||
>
|
||||
{'Apple push certificate private:'}
|
||||
</label>
|
||||
<div className='col-sm-8'>
|
||||
<input
|
||||
type='text'
|
||||
className='form-control'
|
||||
id='feedbackUsername'
|
||||
placeholder='Enter your private apple push certificate'
|
||||
value=''
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='form-group'>
|
||||
<div className='col-sm-12'>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary'
|
||||
>
|
||||
{'Submit'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
124
web/react/components/admin_console/select_team_modal.jsx
Обычный файл
124
web/react/components/admin_console/select_team_modal.jsx
Обычный файл
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
export default class SelectTeam extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className='modal fade'
|
||||
id='select-team'
|
||||
tabIndex='-1'
|
||||
role='dialog'
|
||||
aria-labelledby='teamsModalLabel'
|
||||
>
|
||||
<div className='modal-dialog'
|
||||
role='document'
|
||||
>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
25
web/react/pages/admin_console.jsx
Обычный файл
25
web/react/pages/admin_console.jsx
Обычный файл
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
var ErrorBar = require('../components/error_bar.jsx');
|
||||
var SelectTeamModal = require('../components/admin_console/select_team_modal.jsx');
|
||||
var AdminController = require('../components/admin_console/admin_controller.jsx');
|
||||
|
||||
export function setupAdminConsolePage() {
|
||||
React.render(
|
||||
<AdminController />,
|
||||
document.getElementById('admin_controller')
|
||||
);
|
||||
|
||||
React.render(
|
||||
<SelectTeamModal />,
|
||||
document.getElementById('select_team_modal')
|
||||
);
|
||||
|
||||
React.render(
|
||||
<ErrorBar/>,
|
||||
document.getElementById('error_bar')
|
||||
);
|
||||
}
|
||||
|
||||
global.window.setup_admin_console_page = setupAdminConsolePage;
|
||||
175
web/sass-files/sass/partials/_admin-console.scss
Обычный файл
175
web/sass-files/sass/partials/_admin-console.scss
Обычный файл
@@ -0,0 +1,175 @@
|
||||
.sidebar--left {
|
||||
&.sidebar--collapsable {
|
||||
background: #333;
|
||||
.team__header {
|
||||
background: transparent;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.nav {
|
||||
li {
|
||||
padding: 0;
|
||||
.icon {
|
||||
width: 15px;
|
||||
}
|
||||
> a {
|
||||
color: #fff;
|
||||
padding: 9px 15px;
|
||||
display: block;
|
||||
&:hover, &.active, &:focus {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.menu-icon--right {
|
||||
vertical-align: top;
|
||||
padding: 5px 10px;
|
||||
margin: -5px;
|
||||
float: right;
|
||||
.fa {
|
||||
font-size: 13px;
|
||||
right: -2px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
&.nav__sub-menu {
|
||||
padding: 5px 0;
|
||||
background: #111;
|
||||
-webkit-font-smoothing: auto;
|
||||
li {
|
||||
> a {
|
||||
font-size: 13px;
|
||||
padding: 5px 15px;
|
||||
background: transparent;
|
||||
color: #bbb;
|
||||
&:hover {
|
||||
color: lighten($primary-color, 10);
|
||||
}
|
||||
&.active {
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.nav-more {
|
||||
font-size: 13px;
|
||||
padding: 5px 15px;
|
||||
background: transparent;
|
||||
color: #bbb;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: lighten($primary-color, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.nav__inner-menu {
|
||||
li {
|
||||
> a {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app__content {
|
||||
&.admin {
|
||||
overflow: auto;
|
||||
background-color: #f1f1f1;
|
||||
padding: 0 20px 20px;
|
||||
}
|
||||
.wrapper--fixed {
|
||||
max-width: 800px;
|
||||
}
|
||||
.form-horizontal {
|
||||
margin-top: 40px;
|
||||
.control-label {
|
||||
text-align: left;
|
||||
padding-right: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
.help-text {
|
||||
margin: 10px 0 0 15px;
|
||||
color: #777;
|
||||
.help-link {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.btn {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.alert {
|
||||
display: inline-block;
|
||||
padding: 5px 7px;
|
||||
margin: 0;
|
||||
top: 1px;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
.banner {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
padding: 0.7em 1.5em;
|
||||
font-size: 0.95em;
|
||||
margin: 2em 0;
|
||||
.banner__heading {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.banner__content {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
.popover {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
width: 100%;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
.panel {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
.panel-default {
|
||||
> .panel-heading {
|
||||
padding: 10px 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
.panel-body {
|
||||
padding: 30px 0 10px;
|
||||
}
|
||||
}
|
||||
.panel-group {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
.panel-title {
|
||||
font-size: 24px;
|
||||
line-height: 1.5;
|
||||
a {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
@include clearfix;
|
||||
&.collapsed {
|
||||
.fa-minus {
|
||||
display: none;
|
||||
}
|
||||
.fa-plus {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.fa {
|
||||
font-size: 18px;
|
||||
float: right;
|
||||
margin-top: 8px;
|
||||
color: #aaa;
|
||||
}
|
||||
.fa-plus {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,30 +4,20 @@
|
||||
width: 100%;
|
||||
border: $border-gray;
|
||||
bottom: 38px;
|
||||
overflow: auto;
|
||||
@extend %popover-box-shadow;
|
||||
.sidebar--right & {
|
||||
bottom: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.command-name {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
line-height: 24px;
|
||||
padding: 5px 10px 8px;
|
||||
height: 37px;
|
||||
line-height: 37px;
|
||||
padding: 2px 10px 2px 5px;
|
||||
z-index: 101;
|
||||
font-size: 0.95em;
|
||||
border-bottom: 1px solid #ddd;
|
||||
&:hover {
|
||||
background-color: #e8eaed;
|
||||
}
|
||||
.command__desc {
|
||||
margin-left: 5px;
|
||||
color: #999;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.command-desc {
|
||||
|
||||
@@ -687,10 +687,10 @@
|
||||
}
|
||||
}
|
||||
.app__content {
|
||||
padding-top: 50px;
|
||||
padding-top: 45px;
|
||||
margin: 0;
|
||||
.channel__wrap & {
|
||||
padding-top: 50px;
|
||||
padding-top: 45px;
|
||||
}
|
||||
.channel-header {
|
||||
display: none;
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
top: 66px;
|
||||
}
|
||||
.nav-pills__unread-indicator-bottom {
|
||||
bottom: 10px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
@import "partials/sidebar--left";
|
||||
@import "partials/sidebar--right";
|
||||
@import "partials/sidebar--menu";
|
||||
@import "partials/admin-console";
|
||||
@import "partials/signup";
|
||||
@import "partials/files";
|
||||
@import "partials/videos";
|
||||
|
||||
24
web/templates/admin_console.html
Обычный файл
24
web/templates/admin_console.html
Обычный файл
@@ -0,0 +1,24 @@
|
||||
|
||||
{{define "admin_console"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
{{template "head" . }}
|
||||
<body>
|
||||
|
||||
<div id="error_bar"></div>
|
||||
|
||||
<div id="admin_controller"></div>
|
||||
|
||||
<div id="select_team_modal"></div>
|
||||
|
||||
<script>
|
||||
window.setup_admin_console_page();
|
||||
|
||||
$(document).ready(function(){
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('[data-toggle="popover"]').popover();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
47
web/web.go
47
web/web.go
@@ -52,31 +52,30 @@ func InitWeb() {
|
||||
mainrouter.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))
|
||||
|
||||
mainrouter.Handle("/", api.AppHandlerIndependent(root)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}", api.AppHandler(login)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/", api.AppHandler(login)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/login", api.AppHandler(login)).Methods("GET")
|
||||
|
||||
// Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/login/{service}", api.AppHandler(loginWithOAuth)).Methods("GET")
|
||||
mainrouter.Handle("/login/{service:[A-Za-z]+}/complete", api.AppHandlerIndependent(loginCompleteOAuth)).Methods("GET")
|
||||
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/logout", api.AppHandler(logout)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/reset_password", api.AppHandler(resetPassword)).Methods("GET")
|
||||
// Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/channels/{channelname}", api.UserRequired(getChannel)).Methods("GET")
|
||||
|
||||
// Anything added here must have an _ in it so it does not conflict with team names
|
||||
mainrouter.Handle("/signup_team_complete/", api.AppHandlerIndependent(signupTeamComplete)).Methods("GET")
|
||||
mainrouter.Handle("/signup_user_complete/", api.AppHandlerIndependent(signupUserComplete)).Methods("GET")
|
||||
mainrouter.Handle("/signup_team_confirm/", api.AppHandlerIndependent(signupTeamConfirm)).Methods("GET")
|
||||
|
||||
// Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/signup/{service}", api.AppHandler(signupWithOAuth)).Methods("GET")
|
||||
mainrouter.Handle("/signup/{service:[A-Za-z]+}/complete", api.AppHandlerIndependent(signupCompleteOAuth)).Methods("GET")
|
||||
|
||||
mainrouter.Handle("/verify_email", api.AppHandlerIndependent(verifyEmail)).Methods("GET")
|
||||
mainrouter.Handle("/find_team", api.AppHandlerIndependent(findTeam)).Methods("GET")
|
||||
mainrouter.Handle("/signup_team", api.AppHandlerIndependent(signup)).Methods("GET")
|
||||
mainrouter.Handle("/login/{service:[A-Za-z]+}/complete", api.AppHandlerIndependent(loginCompleteOAuth)).Methods("GET")
|
||||
mainrouter.Handle("/signup/{service:[A-Za-z]+}/complete", api.AppHandlerIndependent(signupCompleteOAuth)).Methods("GET")
|
||||
|
||||
mainrouter.Handle("/admin_console", api.UserRequired(adminConsole)).Methods("GET")
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// *ANYTHING* team spefic should go below this line
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}", api.AppHandler(login)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/", api.AppHandler(login)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/login", api.AppHandler(login)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/logout", api.AppHandler(logout)).Methods("GET")
|
||||
mainrouter.Handle("/{team:[A-Za-z0-9-]+(__)?[A-Za-z0-9-]+}/reset_password", api.AppHandler(resetPassword)).Methods("GET")
|
||||
mainrouter.Handle("/{team}/login/{service}", api.AppHandler(loginWithOAuth)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/channels/{channelname}", api.UserRequired(getChannel)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here.
|
||||
mainrouter.Handle("/{team}/signup/{service}", api.AppHandler(signupWithOAuth)).Methods("GET") // Bug in gorilla.mux prevents us from using regex here.
|
||||
|
||||
watchAndParseTemplates()
|
||||
}
|
||||
@@ -641,3 +640,15 @@ func loginCompleteOAuth(c *api.Context, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func adminConsole(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if !c.IsSystemAdmin() {
|
||||
c.Err = model.NewAppError("adminConsole", "You do not have permission to access the admin console.", "")
|
||||
c.Err.StatusCode = http.StatusForbidden
|
||||
return
|
||||
} else {
|
||||
page := NewHtmlTemplatePage("admin_console", "Admin Console")
|
||||
page.Render(c, w)
|
||||
}
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user