diff options
Diffstat (limited to 'web')
-rw-r--r-- | web/react/components/admin_console/admin_controller.jsx | 59 | ||||
-rw-r--r-- | web/react/components/admin_console/admin_sidebar.jsx | 197 | ||||
-rw-r--r-- | web/react/components/admin_console/email_settings.jsx | 311 | ||||
-rw-r--r-- | web/react/components/admin_console/jobs_settings.jsx | 183 | ||||
-rw-r--r-- | web/react/components/admin_console/select_team_modal.jsx | 124 | ||||
-rw-r--r-- | web/react/pages/admin_console.jsx | 25 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_admin-console.scss | 175 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_command-box.scss | 16 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_headers.scss | 2 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_responsive.scss | 4 | ||||
-rw-r--r-- | web/sass-files/sass/partials/_sidebar--left.scss | 7 | ||||
-rw-r--r-- | web/sass-files/sass/styles.scss | 1 | ||||
-rw-r--r-- | web/templates/admin_console.html | 24 | ||||
-rw-r--r-- | web/web.go | 47 |
14 files changed, 1140 insertions, 35 deletions
diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx new file mode 100644 index 000000000..bb43af802 --- /dev/null +++ b/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> + ); + } +}
\ No newline at end of file diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx new file mode 100644 index 000000000..6b3be89d0 --- /dev/null +++ b/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 +};
\ No newline at end of file diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx new file mode 100644 index 000000000..3c53a8ee1 --- /dev/null +++ b/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> + ); + } +}
\ No newline at end of file diff --git a/web/react/components/admin_console/jobs_settings.jsx b/web/react/components/admin_console/jobs_settings.jsx new file mode 100644 index 000000000..34ec9693d --- /dev/null +++ b/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> + ); + } +}
\ No newline at end of file diff --git a/web/react/components/admin_console/select_team_modal.jsx b/web/react/components/admin_console/select_team_modal.jsx new file mode 100644 index 000000000..fa30de7b2 --- /dev/null +++ b/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> + ); + } +}
\ No newline at end of file diff --git a/web/react/pages/admin_console.jsx b/web/react/pages/admin_console.jsx new file mode 100644 index 000000000..689a6b3a2 --- /dev/null +++ b/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; diff --git a/web/sass-files/sass/partials/_admin-console.scss b/web/sass-files/sass/partials/_admin-console.scss new file mode 100644 index 000000000..b32cc1218 --- /dev/null +++ b/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; + } + } + } + +}
\ No newline at end of file diff --git a/web/sass-files/sass/partials/_command-box.scss b/web/sass-files/sass/partials/_command-box.scss index 565296fae..44eb9b8df 100644 --- a/web/sass-files/sass/partials/_command-box.scss +++ b/web/sass-files/sass/partials/_command-box.scss @@ -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 { diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index c311941b6..e83981397 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -145,6 +145,8 @@ li a { padding: 3px 20px; color: #555; + text-overflow: ellipsis; + overflow: hidden; } } .dropdown__icon { diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss index 32d65b86b..a30782dd0 100644 --- a/web/sass-files/sass/partials/_responsive.scss +++ b/web/sass-files/sass/partials/_responsive.scss @@ -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; diff --git a/web/sass-files/sass/partials/_sidebar--left.scss b/web/sass-files/sass/partials/_sidebar--left.scss index 63426dae9..514d22f24 100644 --- a/web/sass-files/sass/partials/_sidebar--left.scss +++ b/web/sass-files/sass/partials/_sidebar--left.scss @@ -12,7 +12,10 @@ } .dropdown-menu { max-height: 300px; - overflow: auto; + overflow-x: hidden; + overflow-y: auto; + max-width: 200px; + width: 200px; } .search__form { margin: 0; @@ -63,7 +66,7 @@ top: 66px; } .nav-pills__unread-indicator-bottom { - bottom: 10px; + bottom: 0px; } .nav { diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss index eb5152a2c..422447b6e 100644 --- a/web/sass-files/sass/styles.scss +++ b/web/sass-files/sass/styles.scss @@ -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"; diff --git a/web/templates/admin_console.html b/web/templates/admin_console.html new file mode 100644 index 000000000..1444d9b17 --- /dev/null +++ b/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}} diff --git a/web/web.go b/web/web.go index 1709e1eec..9cb81226b 100644 --- a/web/web.go +++ b/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) + } +} |