diff options
Diffstat (limited to 'web/react/components/user_settings')
10 files changed, 548 insertions, 85 deletions
diff --git a/web/react/components/user_settings/import_theme_modal.jsx b/web/react/components/user_settings/import_theme_modal.jsx index de0663874..1a9ac0ad3 100644 --- a/web/react/components/user_settings/import_theme_modal.jsx +++ b/web/react/components/user_settings/import_theme_modal.jsx @@ -35,7 +35,7 @@ export default class ImportThemeModal extends React.Component { handleSubmit(e) { e.preventDefault(); - const text = React.findDOMNode(this.refs.input).value; + const text = ReactDOM.findDOMNode(this.refs.input).value; if (!this.isInputValid(text)) { this.setState({inputError: 'Invalid format, please try copying and pasting in again.'}); diff --git a/web/react/components/user_settings/manage_outgoing_hooks.jsx b/web/react/components/user_settings/manage_outgoing_hooks.jsx new file mode 100644 index 000000000..e83ae3bd6 --- /dev/null +++ b/web/react/components/user_settings/manage_outgoing_hooks.jsx @@ -0,0 +1,262 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var Client = require('../../utils/client.jsx'); +var Constants = require('../../utils/constants.jsx'); +var ChannelStore = require('../../stores/channel_store.jsx'); +var LoadingScreen = require('../loading_screen.jsx'); + +export default class ManageOutgoingHooks extends React.Component { + constructor() { + super(); + + this.getHooks = this.getHooks.bind(this); + this.addNewHook = this.addNewHook.bind(this); + this.updateChannelId = this.updateChannelId.bind(this); + this.updateTriggerWords = this.updateTriggerWords.bind(this); + this.updateCallbackURLs = this.updateCallbackURLs.bind(this); + + this.state = {hooks: [], channelId: '', triggerWords: '', callbackURLs: '', getHooksComplete: false}; + } + componentDidMount() { + this.getHooks(); + } + addNewHook(e) { + e.preventDefault(); + + if ((this.state.channelId === '' && this.state.triggerWords === '') || + this.state.callbackURLs === '') { + return; + } + + const hook = {}; + hook.channel_id = this.state.channelId; + if (this.state.triggerWords.length !== 0) { + hook.trigger_words = this.state.triggerWords.trim().split(','); + } + hook.callback_urls = this.state.callbackURLs.split('\n'); + + Client.addOutgoingHook( + hook, + (data) => { + let hooks = Object.assign([], this.state.hooks); + if (!hooks) { + hooks = []; + } + hooks.push(data); + this.setState({hooks, serverError: null, channelId: '', triggerWords: '', callbackURLs: ''}); + }, + (err) => { + this.setState({serverError: err}); + } + ); + } + removeHook(id) { + const data = {}; + data.id = id; + + Client.deleteOutgoingHook( + data, + () => { + const hooks = this.state.hooks; + let index = -1; + for (let i = 0; i < hooks.length; i++) { + if (hooks[i].id === id) { + index = i; + break; + } + } + + if (index !== -1) { + hooks.splice(index, 1); + } + + this.setState({hooks}); + }, + (err) => { + this.setState({serverError: err}); + } + ); + } + regenToken(id) { + const regenData = {}; + regenData.id = id; + + Client.regenOutgoingHookToken( + regenData, + (data) => { + const hooks = Object.assign([], this.state.hooks); + for (let i = 0; i < hooks.length; i++) { + if (hooks[i].id === id) { + hooks[i] = data; + break; + } + } + + this.setState({hooks, serverError: null}); + }, + (err) => { + this.setState({serverError: err}); + } + ); + } + getHooks() { + Client.listOutgoingHooks( + (data) => { + if (data) { + this.setState({hooks: data, getHooksComplete: true, serverError: null}); + } + }, + (err) => { + this.setState({serverError: err}); + } + ); + } + updateChannelId(e) { + this.setState({channelId: e.target.value}); + } + updateTriggerWords(e) { + this.setState({triggerWords: e.target.value}); + } + updateCallbackURLs(e) { + this.setState({callbackURLs: e.target.value}); + } + render() { + let serverError; + if (this.state.serverError) { + serverError = <label className='has-error'>{this.state.serverError}</label>; + } + + const channels = ChannelStore.getAll(); + const options = [<option value=''>{'--- Select a channel ---'}</option>]; + channels.forEach((channel) => { + if (channel.type === Constants.OPEN_CHANNEL) { + options.push(<option value={channel.id}>{channel.name}</option>); + } + }); + + const hooks = []; + this.state.hooks.forEach((hook) => { + const c = ChannelStore.get(hook.channel_id); + let channelDiv; + if (c) { + channelDiv = ( + <div className='padding-top'> + <strong>{'Channel: '}</strong>{c.name} + </div> + ); + } + + let triggerDiv; + if (hook.trigger_words && hook.trigger_words.length !== 0) { + triggerDiv = ( + <div className='padding-top'> + <strong>{'Trigger Words: '}</strong>{hook.trigger_words.join(', ')} + </div> + ); + } + + hooks.push( + <div className='font--small'> + <div className='padding-top x2 divider-light'></div> + <div className='padding-top x2'> + <strong>{'URLs: '}</strong><span className='word-break--all'>{hook.callback_urls.join(', ')}</span> + </div> + {channelDiv} + {triggerDiv} + <div className='padding-top'> + <strong>{'Token: '}</strong>{hook.token} + </div> + <div className='padding-top'> + <a + className='text-danger' + href='#' + onClick={this.regenToken.bind(this, hook.id)} + > + {'Regen Token'} + </a> + <span>{' - '}</span> + <a + className='text-danger' + href='#' + onClick={this.removeHook.bind(this, hook.id)} + > + {'Remove'} + </a> + </div> + </div> + ); + }); + + let displayHooks; + if (!this.state.getHooksComplete) { + displayHooks = <LoadingScreen/>; + } else if (hooks.length > 0) { + displayHooks = hooks; + } else { + displayHooks = <label>{': None'}</label>; + } + + const existingHooks = ( + <div className='padding-top x2'> + <label className='control-label padding-top x2'>{'Existing outgoing webhooks'}</label> + {displayHooks} + </div> + ); + + const disableButton = (this.state.channelId === '' && this.state.triggerWords === '') || this.state.callbackURLs === ''; + + return ( + <div key='addOutgoingHook'> + <label className='control-label'>{'Add a new outgoing webhook'}</label> + <div className='padding-top'> + <strong>{'Channel:'}</strong> + <select + ref='channelName' + className='form-control' + value={this.state.channelId} + onChange={this.updateChannelId} + > + {options} + </select> + <span>{'Only public channels can be used'}</span> + <br/> + <br/> + <strong>{'Trigger Words:'}</strong> + <input + ref='triggerWords' + className='form-control' + value={this.state.triggerWords} + onChange={this.updateTriggerWords} + placeholder='Optional if channel selected' + /> + <span>{'Comma separated words to trigger on'}</span> + <br/> + <br/> + <strong>{'Callback URLs:'}</strong> + <textarea + ref='callbackURLs' + className='form-control no-resize' + value={this.state.callbackURLs} + resize={false} + rows={3} + onChange={this.updateCallbackURLs} + /> + <span>{'New line separated URLs that will receive the HTTP POST event'}</span> + {serverError} + <div className='padding-top'> + <a + className={'btn btn-sm btn-primary'} + href='#' + disabled={disableButton} + onClick={this.addNewHook} + > + {'Add'} + </a> + </div> + </div> + {existingHooks} + </div> + ); + } +} diff --git a/web/react/components/user_settings/user_settings.jsx b/web/react/components/user_settings/user_settings.jsx index 5ce9b6330..15bf961d6 100644 --- a/web/react/components/user_settings/user_settings.jsx +++ b/web/react/components/user_settings/user_settings.jsx @@ -9,6 +9,7 @@ var GeneralTab = require('./user_settings_general.jsx'); var AppearanceTab = require('./user_settings_appearance.jsx'); var DeveloperTab = require('./user_settings_developer.jsx'); var IntegrationsTab = require('./user_settings_integrations.jsx'); +var DisplayTab = require('./user_settings_display.jsx'); export default class UserSettings extends React.Component { constructor(props) { @@ -98,6 +99,17 @@ export default class UserSettings extends React.Component { /> </div> ); + } else if (this.props.activeTab === 'display') { + return ( + <div> + <DisplayTab + user={this.state.user} + activeSection={this.props.activeSection} + updateSection={this.props.updateSection} + updateTab={this.props.updateTab} + /> + </div> + ); } return <div/>; diff --git a/web/react/components/user_settings/user_settings_appearance.jsx b/web/react/components/user_settings/user_settings_appearance.jsx index 6d64e83b6..8c62a189d 100644 --- a/web/react/components/user_settings/user_settings_appearance.jsx +++ b/web/react/components/user_settings/user_settings_appearance.jsx @@ -29,14 +29,14 @@ export default class UserSettingsAppearance extends React.Component { UserStore.addChangeListener(this.onChange); if (this.props.activeSection === 'theme') { - $(React.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); + $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); } $('#user_settings').on('hidden.bs.modal', this.handleClose); } componentDidUpdate() { if (this.props.activeSection === 'theme') { $('.color-btn').removeClass('active-border'); - $(React.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); + $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border'); } } componentWillUnmount() { @@ -152,9 +152,8 @@ export default class UserSettingsAppearance extends React.Component { <input type='radio' checked={!displayCustom} onChange={this.updateType.bind(this, 'premade')} - > - {'Theme Colors'} - </input> + /> + {'Theme Colors'} </label> <br/> </div> @@ -164,9 +163,8 @@ export default class UserSettingsAppearance extends React.Component { <input type='radio' checked={displayCustom} onChange={this.updateType.bind(this, 'custom')} - > - {'Custom Theme'} - </input> + /> + {'Custom Theme'} </label> <br/> </div> @@ -178,7 +176,7 @@ export default class UserSettingsAppearance extends React.Component { href='#' onClick={this.submitTheme} > - {'Submit'} + {'Save'} </a> <a className='btn btn-sm theme' diff --git a/web/react/components/user_settings/user_settings_display.jsx b/web/react/components/user_settings/user_settings_display.jsx new file mode 100644 index 000000000..22a62273c --- /dev/null +++ b/web/react/components/user_settings/user_settings_display.jsx @@ -0,0 +1,165 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {savePreferences} from '../../utils/client.jsx'; +import SettingItemMin from '../setting_item_min.jsx'; +import SettingItemMax from '../setting_item_max.jsx'; +import Constants from '../../utils/constants.jsx'; +import PreferenceStore from '../../stores/preference_store.jsx'; + +function getDisplayStateFromStores() { + const militaryTime = PreferenceStore.getPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', {value: 'false'}); + + return {militaryTime: militaryTime.value}; +} + +export default class UserSettingsDisplay extends React.Component { + constructor(props) { + super(props); + + this.handleSubmit = this.handleSubmit.bind(this); + this.handleClockRadio = this.handleClockRadio.bind(this); + this.updateSection = this.updateSection.bind(this); + this.handleClose = this.handleClose.bind(this); + + this.state = getDisplayStateFromStores(); + } + handleSubmit() { + const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', this.state.militaryTime); + + savePreferences([preference], + () => { + PreferenceStore.emitChange(); + this.updateSection(''); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + handleClockRadio(militaryTime) { + this.setState({militaryTime}); + } + updateSection(section) { + this.setState(getDisplayStateFromStores()); + this.props.updateSection(section); + } + handleClose() { + this.updateSection(''); + } + componentDidMount() { + $('#user_settings').on('hidden.bs.modal', this.handleClose); + } + componentWillUnmount() { + $('#user_settings').off('hidden.bs.modal', this.handleClose); + } + render() { + const serverError = this.state.serverError || null; + let clockSection; + if (this.props.activeSection === 'clock') { + const clockFormat = [false, false]; + if (this.state.militaryTime === 'true') { + clockFormat[1] = true; + } else { + clockFormat[0] = true; + } + + const handleUpdateClockSection = (e) => { + this.updateSection(''); + e.preventDefault(); + }; + + const inputs = [ + <div key='userDisplayClockOptions'> + <div className='radio'> + <label> + <input + type='radio' + checked={clockFormat[0]} + onChange={this.handleClockRadio.bind(this, 'false')} + /> + {'12-hour clock (example: 4:00 PM)'} + </label> + <br/> + </div> + <div className='radio'> + <label> + <input + type='radio' + checked={clockFormat[1]} + onChange={this.handleClockRadio.bind(this, 'true')} + /> + {'24-hour clock (example: 16:00)'} + </label> + <br/> + </div> + <div><br/>{'Select how you prefer time displayed.'}</div> + </div> + ]; + + clockSection = ( + <SettingItemMax + title='Clock Display' + inputs={inputs} + submit={this.handleSubmit} + server_error={serverError} + updateSection={handleUpdateClockSection} + /> + ); + } else { + let describe = ''; + if (this.state.militaryTime === 'true') { + describe = '24-hour clock (example: 16:00)'; + } else { + describe = '12-hour clock (example: 4:00 PM)'; + } + + const handleUpdateClockSection = () => { + this.props.updateSection('clock'); + }; + + clockSection = ( + <SettingItemMin + title='Clock Display' + describe={describe} + updateSection={handleUpdateClockSection} + /> + ); + } + + return ( + <div> + <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' + ref='title' + > + <i className='modal-back'></i> + {'Display Settings'} + </h4> + </div> + <div className='user-settings'> + <h3 className='tab-header'>{'Display Settings'}</h3> + <div className='divider-dark first'/> + {clockSection} + <div className='divider-dark'/> + </div> + </div> + ); + } +} + +UserSettingsDisplay.propTypes = { + user: React.PropTypes.object, + updateSection: React.PropTypes.func, + updateTab: React.PropTypes.func, + activeSection: React.PropTypes.string +}; diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx index ac3a2e37b..9c03f77a6 100644 --- a/web/react/components/user_settings/user_settings_general.jsx +++ b/web/react/components/user_settings/user_settings_general.jsx @@ -211,7 +211,7 @@ export default class UserSettingsGeneralTab extends React.Component { this.props.updateSection(section); } handleClose() { - $(React.findDOMNode(this)).find('.form-control').each(function clearForms() { + $(ReactDOM.findDOMNode(this)).find('.form-control').each(function clearForms() { this.value = ''; }); @@ -368,8 +368,7 @@ export default class UserSettingsGeneralTab extends React.Component { const extraInfo = ( <span> - {'Use Nickname for a name you might be called that is different from your first name and user name.'} - {'This is most often used when two or more people have similar sounding names and usernames.'} + {'Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.'} </span> ); diff --git a/web/react/components/user_settings/user_settings_integrations.jsx b/web/react/components/user_settings/user_settings_integrations.jsx index 5e20d41f1..231580cc3 100644 --- a/web/react/components/user_settings/user_settings_integrations.jsx +++ b/web/react/components/user_settings/user_settings_integrations.jsx @@ -4,6 +4,7 @@ var SettingItemMin = require('../setting_item_min.jsx'); var SettingItemMax = require('../setting_item_max.jsx'); var ManageIncomingHooks = require('./manage_incoming_hooks.jsx'); +var ManageOutgoingHooks = require('./manage_outgoing_hooks.jsx'); export default class UserSettingsIntegrationsTab extends React.Component { constructor(props) { @@ -19,6 +20,8 @@ export default class UserSettingsIntegrationsTab extends React.Component { } handleClose() { this.updateSection(''); + $('.ps-container.modal-body').scrollTop(0); + $('.ps-container.modal-body').perfectScrollbar('update'); } componentDidMount() { $('#user_settings').on('hidden.bs.modal', this.handleClose); @@ -28,33 +31,67 @@ export default class UserSettingsIntegrationsTab extends React.Component { } render() { let incomingHooksSection; + let outgoingHooksSection; var inputs = []; - if (this.props.activeSection === 'incoming-hooks') { - inputs.push( - <ManageIncomingHooks /> - ); + if (global.window.config.EnableIncomingWebhooks === 'true') { + if (this.props.activeSection === 'incoming-hooks') { + inputs.push( + <ManageIncomingHooks /> + ); - incomingHooksSection = ( - <SettingItemMax - title='Incoming Webhooks' - inputs={inputs} - updateSection={function clearSection(e) { - this.updateSection(''); - e.preventDefault(); - }.bind(this)} - /> - ); - } else { - incomingHooksSection = ( - <SettingItemMin - title='Incoming Webhooks' - describe='Manage your incoming webhooks (Developer feature)' - updateSection={function updateNameSection() { - this.updateSection('incoming-hooks'); - }.bind(this)} - /> - ); + incomingHooksSection = ( + <SettingItemMax + title='Incoming Webhooks' + width = 'full' + inputs={inputs} + updateSection={(e) => { + this.updateSection(''); + e.preventDefault(); + }} + /> + ); + } else { + incomingHooksSection = ( + <SettingItemMin + title='Incoming Webhooks' + width = 'full' + describe='Manage your incoming webhooks (Developer feature)' + updateSection={() => { + this.updateSection('incoming-hooks'); + }} + /> + ); + } + } + + if (global.window.config.EnableOutgoingWebhooks === 'true') { + if (this.props.activeSection === 'outgoing-hooks') { + inputs.push( + <ManageOutgoingHooks /> + ); + + outgoingHooksSection = ( + <SettingItemMax + title='Outgoing Webhooks' + inputs={inputs} + updateSection={(e) => { + this.updateSection(''); + e.preventDefault(); + }} + /> + ); + } else { + outgoingHooksSection = ( + <SettingItemMin + title='Outgoing Webhooks' + describe='Manage your outgoing webhooks' + updateSection={() => { + this.updateSection('outgoing-hooks'); + }} + /> + ); + } } return ( @@ -80,6 +117,8 @@ export default class UserSettingsIntegrationsTab extends React.Component { <h3 className='tab-header'>{'Integration Settings'}</h3> <div className='divider-dark first'/> {incomingHooksSection} + <div className='divider-light'/> + {outgoingHooksSection} <div className='divider-dark'/> </div> </div> diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx index 19b97fc85..44cd423b5 100644 --- a/web/react/components/user_settings/user_settings_modal.jsx +++ b/web/react/components/user_settings/user_settings_modal.jsx @@ -38,9 +38,10 @@ export default class UserSettingsModal extends React.Component { if (global.window.config.EnableOAuthServiceProvider === 'true') { tabs.push({name: 'developer', uiName: 'Developer', icon: 'glyphicon glyphicon-th'}); } - if (global.window.config.EnableIncomingWebhooks === 'true') { + if (global.window.config.EnableIncomingWebhooks === 'true' || global.window.config.EnableOutgoingWebhooks === 'true') { tabs.push({name: 'integrations', uiName: 'Integrations', icon: 'glyphicon glyphicon-transfer'}); } + tabs.push({name: 'display', uiName: 'Display', icon: 'glyphicon glyphicon-eye-open'}); return ( <div diff --git a/web/react/components/user_settings/user_settings_notifications.jsx b/web/react/components/user_settings/user_settings_notifications.jsx index 4728a33ee..8693af494 100644 --- a/web/react/components/user_settings/user_settings_notifications.jsx +++ b/web/react/components/user_settings/user_settings_notifications.jsx @@ -129,7 +129,7 @@ export default class NotificationsTab extends React.Component { ); } handleClose() { - $(React.findDOMNode(this)).find('.form-control').each(function clearField() { + $(ReactDOM.findDOMNode(this)).find('.form-control').each(function clearField() { this.value = ''; }); @@ -158,15 +158,15 @@ export default class NotificationsTab extends React.Component { } handleNotifyRadio(notifyLevel) { this.setState({notifyLevel: notifyLevel}); - React.findDOMNode(this.refs.wrapper).focus(); + ReactDOM.findDOMNode(this.refs.wrapper).focus(); } handleEmailRadio(enableEmail) { this.setState({enableEmail: enableEmail}); - React.findDOMNode(this.refs.wrapper).focus(); + ReactDOM.findDOMNode(this.refs.wrapper).focus(); } handleSoundRadio(enableSound) { this.setState({enableSound: enableSound}); - React.findDOMNode(this.refs.wrapper).focus(); + ReactDOM.findDOMNode(this.refs.wrapper).focus(); } updateUsernameKey(val) { this.setState({usernameKey: val}); @@ -184,10 +184,10 @@ export default class NotificationsTab extends React.Component { this.setState({channelKey: val}); } updateCustomMentionKeys() { - var checked = React.findDOMNode(this.refs.customcheck).checked; + var checked = ReactDOM.findDOMNode(this.refs.customcheck).checked; if (checked) { - var text = React.findDOMNode(this.refs.custommentions).value; + var text = ReactDOM.findDOMNode(this.refs.custommentions).value; // remove all spaces and split string into individual keys this.setState({customKeys: text.replace(/ /g, ''), customKeysChecked: true}); @@ -196,7 +196,7 @@ export default class NotificationsTab extends React.Component { } } onCustomChange() { - React.findDOMNode(this.refs.customcheck).checked = true; + ReactDOM.findDOMNode(this.refs.customcheck).checked = true; this.updateCustomMentionKeys(); } render() { @@ -228,9 +228,8 @@ export default class NotificationsTab extends React.Component { <input type='radio' checked={notifyActive[0]} onChange={this.handleNotifyRadio.bind(this, 'all')} - > - For all activity - </input> + /> + {'For all activity'} </label> <br/> </div> @@ -240,9 +239,8 @@ export default class NotificationsTab extends React.Component { type='radio' checked={notifyActive[1]} onChange={this.handleNotifyRadio.bind(this, 'mention')} - > - Only for mentions and direct messages - </input> + /> + {'Only for mentions and direct messages'} </label> <br/> </div> @@ -252,9 +250,8 @@ export default class NotificationsTab extends React.Component { type='radio' checked={notifyActive[2]} onChange={this.handleNotifyRadio.bind(this, 'none')} - > - Never - </input> + /> + {'Never'} </label> </div> </div> @@ -320,9 +317,8 @@ export default class NotificationsTab extends React.Component { type='radio' checked={soundActive[0]} onChange={this.handleSoundRadio.bind(this, 'true')} - > - On - </input> + /> + {'On'} </label> <br/> </div> @@ -332,9 +328,8 @@ export default class NotificationsTab extends React.Component { type='radio' checked={soundActive[1]} onChange={this.handleSoundRadio.bind(this, 'false')} - > - Off - </input> + /> + {'Off'} </label> <br/> </div> @@ -402,9 +397,8 @@ export default class NotificationsTab extends React.Component { type='radio' checked={emailActive[0]} onChange={this.handleEmailRadio.bind(this, 'true')} - > - On - </input> + /> + {'On'} </label> <br/> </div> @@ -414,9 +408,8 @@ export default class NotificationsTab extends React.Component { type='radio' checked={emailActive[1]} onChange={this.handleEmailRadio.bind(this, 'false')} - > - Off - </input> + /> + {'Off'} </label> <br/> </div> @@ -482,9 +475,8 @@ export default class NotificationsTab extends React.Component { type='checkbox' checked={this.state.firstNameKey} onChange={handleUpdateFirstNameKey} - > - {'Your case sensitive first name "' + user.first_name + '"'} - </input> + /> + {'Your case sensitive first name "' + user.first_name + '"'} </label> </div> </div> @@ -502,9 +494,8 @@ export default class NotificationsTab extends React.Component { type='checkbox' checked={this.state.usernameKey} onChange={handleUpdateUsernameKey} - > - {'Your non-case sensitive username "' + user.username + '"'} - </input> + /> + {'Your non-case sensitive username "' + user.username + '"'} </label> </div> </div> @@ -521,9 +512,8 @@ export default class NotificationsTab extends React.Component { type='checkbox' checked={this.state.mentionKey} onChange={handleUpdateMentionKey} - > - {'Your username mentioned "@' + user.username + '"'} - </input> + /> + {'Your username mentioned "@' + user.username + '"'} </label> </div> </div> @@ -540,9 +530,8 @@ export default class NotificationsTab extends React.Component { type='checkbox' checked={this.state.allKey} onChange={handleUpdateAllKey} - > - {'Team-wide mentions "@all"'} - </input> + /> + {'Team-wide mentions "@all"'} </label> </div> </div> @@ -559,9 +548,8 @@ export default class NotificationsTab extends React.Component { type='checkbox' checked={this.state.channelKey} onChange={handleUpdateChannelKey} - > - {'Channel-wide mentions "@channel"'} - </input> + /> + {'Channel-wide mentions "@channel"'} </label> </div> </div> @@ -576,9 +564,8 @@ export default class NotificationsTab extends React.Component { type='checkbox' checked={this.state.customKeysChecked} onChange={this.updateCustomMentionKeys} - > - {'Other non-case sensitive words, separated by commas:'} - </input> + /> + {'Other non-case sensitive words, separated by commas:'} </label> </div> <input diff --git a/web/react/components/user_settings/user_settings_security.jsx b/web/react/components/user_settings/user_settings_security.jsx index 74190781c..983a10df0 100644 --- a/web/react/components/user_settings/user_settings_security.jsx +++ b/web/react/components/user_settings/user_settings_security.jsx @@ -82,7 +82,7 @@ export default class SecurityTab extends React.Component { $('#user_settings').modal('hide'); } handleClose() { - $(React.findDOMNode(this)).find('.form-control').each(function resetValue() { + $(ReactDOM.findDOMNode(this)).find('.form-control').each(function resetValue() { this.value = ''; }); this.setState({currentPassword: '', newPassword: '', confirmPassword: '', serverError: null, passwordError: null}); |