diff options
Diffstat (limited to 'webapp/components/admin_console/team_settings.jsx')
-rw-r--r-- | webapp/components/admin_console/team_settings.jsx | 297 |
1 files changed, 283 insertions, 14 deletions
diff --git a/webapp/components/admin_console/team_settings.jsx b/webapp/components/admin_console/team_settings.jsx index 654f0085d..d361c989f 100644 --- a/webapp/components/admin_console/team_settings.jsx +++ b/webapp/components/admin_console/team_settings.jsx @@ -2,11 +2,11 @@ // See License.txt for license information. import $ from 'jquery'; -import ReactDOM from 'react-dom'; import * as Client from 'utils/client.jsx'; import * as AsyncClient from 'utils/async_client.jsx'; +import * as Utils from 'utils/utils.jsx'; -import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl'; +import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl'; const holders = defineMessages({ siteNameExample: { @@ -29,42 +29,91 @@ const holders = defineMessages({ import React from 'react'; +const ENABLE_BRAND_ACTION = 'enable_brand_action'; +const DISABLE_BRAND_ACTION = 'disable_brand_action'; + class TeamSettings extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); + this.handleImageChange = this.handleImageChange.bind(this); + this.handleImageSubmit = this.handleImageSubmit.bind(this); + + this.uploading = false; this.state = { saveNeeded: false, + brandImageExists: false, + enableCustomBrand: this.props.config.TeamSettings.EnableCustomBrand, serverError: null }; } - handleChange() { - var s = {saveNeeded: true, serverError: this.state.serverError}; + componentWillMount() { + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true') { + $.get('/api/v1/admin/get_brand_image').done(() => this.setState({brandImageExists: true})); + } + } + + componentDidUpdate() { + if (this.refs.image) { + const reader = new FileReader(); + + const img = this.refs.image; + reader.onload = (e) => { + $(img).attr('src', e.target.result); + }; + + reader.readAsDataURL(this.state.brandImage); + } + } + + handleChange(action) { + var s = {saveNeeded: true}; + + if (action === ENABLE_BRAND_ACTION) { + s.enableCustomBrand = true; + } + + if (action === DISABLE_BRAND_ACTION) { + s.enableCustomBrand = false; + } + this.setState(s); } + handleImageChange() { + const element = $(this.refs.fileInput); + if (element.prop('files').length > 0) { + this.setState({fileSelected: true, brandImage: element.prop('files')[0]}); + } + } + handleSubmit(e) { e.preventDefault(); $('#save-button').button('loading'); var config = this.props.config; - config.TeamSettings.SiteName = ReactDOM.findDOMNode(this.refs.SiteName).value.trim(); - config.TeamSettings.RestrictCreationToDomains = ReactDOM.findDOMNode(this.refs.RestrictCreationToDomains).value.trim(); - config.TeamSettings.EnableTeamCreation = ReactDOM.findDOMNode(this.refs.EnableTeamCreation).checked; - config.TeamSettings.EnableUserCreation = ReactDOM.findDOMNode(this.refs.EnableUserCreation).checked; - config.TeamSettings.RestrictTeamNames = ReactDOM.findDOMNode(this.refs.RestrictTeamNames).checked; - config.TeamSettings.EnableTeamListing = ReactDOM.findDOMNode(this.refs.EnableTeamListing).checked; + config.TeamSettings.SiteName = this.refs.SiteName.value.trim(); + config.TeamSettings.RestrictCreationToDomains = this.refs.RestrictCreationToDomains.value.trim(); + config.TeamSettings.EnableTeamCreation = this.refs.EnableTeamCreation.checked; + config.TeamSettings.EnableUserCreation = this.refs.EnableUserCreation.checked; + config.TeamSettings.RestrictTeamNames = this.refs.RestrictTeamNames.checked; + config.TeamSettings.EnableTeamListing = this.refs.EnableTeamListing.checked; + config.TeamSettings.EnableCustomBrand = this.refs.EnableCustomBrand.checked; + + if (this.refs.CustomBrandText) { + config.TeamSettings.CustomBrandText = this.refs.CustomBrandText.value; + } var MaxUsersPerTeam = 50; - if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MaxUsersPerTeam).value, 10))) { - MaxUsersPerTeam = parseInt(ReactDOM.findDOMNode(this.refs.MaxUsersPerTeam).value, 10); + if (!isNaN(parseInt(this.refs.MaxUsersPerTeam.value, 10))) { + MaxUsersPerTeam = parseInt(this.refs.MaxUsersPerTeam.value, 10); } config.TeamSettings.MaxUsersPerTeam = MaxUsersPerTeam; - ReactDOM.findDOMNode(this.refs.MaxUsersPerTeam).value = MaxUsersPerTeam; + this.refs.MaxUsersPerTeam.value = MaxUsersPerTeam; Client.saveConfig( config, @@ -86,6 +135,219 @@ class TeamSettings extends React.Component { ); } + handleImageSubmit(e) { + e.preventDefault(); + + if (!this.state.brandImage) { + return; + } + + if (this.uploading) { + return; + } + + $('#upload-button').button('loading'); + this.uploading = true; + + Client.uploadBrandImage(this.state.brandImage, + () => { + $('#upload-button').button('complete'); + this.setState({brandImageExists: true, brandImage: null}); + this.uploading = false; + }, + (err) => { + $('#upload-button').button('reset'); + this.uploading = false; + this.setState({serverImageError: err.message}); + } + ); + } + + createBrandSettings() { + var btnClass = 'btn'; + if (this.state.fileSelected) { + btnClass = 'btn btn-primary'; + } + + var serverImageError = ''; + if (this.state.serverImageError) { + serverImageError = <div className='form-group has-error'><label className='control-label'>{this.state.serverImageError}</label></div>; + } + + let uploadImage; + let uploadText; + if (this.state.enableCustomBrand) { + let img; + if (this.state.brandImage) { + img = ( + <img + ref='image' + className='brand-img' + src='' + /> + ); + } else if (this.state.brandImageExists) { + img = ( + <img + className='brand-img' + src='/api/v1/admin/get_brand_image' + /> + ); + } else { + img = ( + <p> + <FormattedMessage + id='admin.team.noBrandImage' + defaultMessage='No brand image uploaded' + /> + </p> + ); + } + + uploadImage = ( + <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='CustomBrandImage' + > + <FormattedMessage + id='admin.team.brandImageTitle' + defaultMessage='Custom Brand Image:' + /> + </label> + <div className='col-sm-8'> + {img} + </div> + <div className='col-sm-4'/> + <div className='col-sm-8'> + <div className='file__upload'> + <button className='btn btn-default'> + <FormattedMessage + id='admin.team.chooseImage' + defaultMessage='Choose New Image' + /> + </button> + <input + ref='fileInput' + type='file' + accept='.jpg,.png,.bmp' + onChange={this.handleImageChange} + /> + </div> + <button + className={btnClass} + disabled={!this.state.fileSelected} + onClick={this.handleImageSubmit} + id='upload-button' + data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + Utils.localizeMessage('admin.team.uploading', 'Uploading..')} + data-complete-text={'<span class=\'glyphicon glyphicon-ok\'></span> ' + Utils.localizeMessage('admin.team.uploaded', 'Uploaded!')} + > + <FormattedMessage + id='admin.team.upload' + defaultMessage='Upload' + /> + </button> + <br/> + {serverImageError} + <p className='help-text no-margin'> + <FormattedHTMLMessage + id='admin.team.uploadDesc' + defaultMessage='Customize your user experience by adding a custom image to your login screen. See examples at <a href="http://docs.mattermost.com/administration/config-settings.html#custom-branding" target="_blank">docs.mattermost.com/administration/config-settings.html#custom-branding</a>.' + /> + </p> + </div> + </div> + ); + + uploadText = ( + <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='CustomBrandText' + > + <FormattedMessage + id='admin.team.brandTextTitle' + defaultMessage='Custom Brand Text:' + /> + </label> + <div className='col-sm-8'> + <textarea + type='text' + rows='5' + maxLength='1024' + className='form-control admin-textarea' + id='CustomBrandText' + ref='CustomBrandText' + onChange={this.handleChange} + > + {this.props.config.TeamSettings.CustomBrandText} + </textarea> + <p className='help-text'> + <FormattedMessage + id='admin.team.brandTextDescription' + defaultMessage='The custom branding Markdown-formatted text you would like to appear below your custom brand image on your login sreen.' + /> + </p> + </div> + </div> + ); + } + + return ( + <div> + <div className='form-group'> + <label + className='control-label col-sm-4' + htmlFor='EnableCustomBrand' + > + <FormattedMessage + id='admin.team.brandTitle' + defaultMessage='Enable Custom Branding: ' + /> + </label> + <div className='col-sm-8'> + <label className='radio-inline'> + <input + type='radio' + name='EnableCustomBrand' + value='true' + ref='EnableCustomBrand' + defaultChecked={this.props.config.TeamSettings.EnableCustomBrand} + onChange={this.handleChange.bind(this, ENABLE_BRAND_ACTION)} + /> + <FormattedMessage + id='admin.team.true' + defaultMessage='true' + /> + </label> + <label className='radio-inline'> + <input + type='radio' + name='EnableCustomBrand' + value='false' + defaultChecked={!this.props.config.TeamSettings.EnableCustomBrand} + onChange={this.handleChange.bind(this, DISABLE_BRAND_ACTION)} + /> + <FormattedMessage + id='admin.team.false' + defaultMessage='false' + /> + </label> + <p className='help-text'> + <FormattedMessage + id='admin.team.brandDesc' + defaultMessage='Enable custom branding to show an image of your choice, uploaded below, and some help text, written below, on the login page.' + /> + </p> + </div> + </div> + + {uploadImage} + {uploadText} + </div> + ); + } + render() { const {formatMessage} = this.props.intl; var serverError = ''; @@ -98,6 +360,11 @@ class TeamSettings extends React.Component { saveClass = 'btn btn-primary'; } + let brand; + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true') { + brand = this.createBrandSettings(); + } + return ( <div className='wrapper--fixed'> @@ -387,6 +654,8 @@ class TeamSettings extends React.Component { </div> </div> + {brand} + <div className='form-group'> <div className='col-sm-12'> {serverError} @@ -417,4 +686,4 @@ TeamSettings.propTypes = { config: React.PropTypes.object }; -export default injectIntl(TeamSettings);
\ No newline at end of file +export default injectIntl(TeamSettings); |