summaryrefslogtreecommitdiffstats
path: root/web/react/components/user_settings
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components/user_settings')
-rw-r--r--web/react/components/user_settings/code_theme_chooser.jsx55
-rw-r--r--web/react/components/user_settings/manage_incoming_hooks.jsx80
-rw-r--r--web/react/components/user_settings/manage_outgoing_hooks.jsx127
-rw-r--r--web/react/components/user_settings/user_settings_appearance.jsx23
-rw-r--r--web/react/components/user_settings/user_settings_general.jsx8
-rw-r--r--web/react/components/user_settings/user_settings_integrations.jsx10
-rw-r--r--web/react/components/user_settings/user_settings_modal.jsx5
-rw-r--r--web/react/components/user_settings/user_settings_notifications.jsx2
8 files changed, 217 insertions, 93 deletions
diff --git a/web/react/components/user_settings/code_theme_chooser.jsx b/web/react/components/user_settings/code_theme_chooser.jsx
new file mode 100644
index 000000000..eef4b24ba
--- /dev/null
+++ b/web/react/components/user_settings/code_theme_chooser.jsx
@@ -0,0 +1,55 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Constants = require('../../utils/constants.jsx');
+
+export default class CodeThemeChooser extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+ render() {
+ const theme = this.props.theme;
+
+ const premadeThemes = [];
+ for (const k in Constants.CODE_THEMES) {
+ if (Constants.CODE_THEMES.hasOwnProperty(k)) {
+ let activeClass = '';
+ if (k === theme.codeTheme) {
+ activeClass = 'active';
+ }
+
+ premadeThemes.push(
+ <div
+ className='col-xs-6 col-sm-3 premade-themes'
+ key={'premade-theme-key' + k}
+ >
+ <div
+ className={activeClass}
+ onClick={() => this.props.updateTheme(k)}
+ >
+ <label>
+ <img
+ className='img-responsive'
+ src={'/static/images/themes/code_themes/' + k + '.png'}
+ />
+ <div className='theme-label'>{Constants.CODE_THEMES[k]}</div>
+ </label>
+ </div>
+ </div>
+ );
+ }
+ }
+
+ return (
+ <div className='row'>
+ {premadeThemes}
+ </div>
+ );
+ }
+}
+
+CodeThemeChooser.propTypes = {
+ theme: React.PropTypes.object.isRequired,
+ updateTheme: React.PropTypes.func.isRequired
+};
diff --git a/web/react/components/user_settings/manage_incoming_hooks.jsx b/web/react/components/user_settings/manage_incoming_hooks.jsx
index f5a2774a0..6b8c09718 100644
--- a/web/react/components/user_settings/manage_incoming_hooks.jsx
+++ b/web/react/components/user_settings/manage_incoming_hooks.jsx
@@ -96,7 +96,14 @@ export default class ManageIncomingHooks extends React.Component {
const options = [];
channels.forEach((channel) => {
if (channel.type !== Constants.DM_CHANNEL) {
- options.push(<option value={channel.id}>{channel.name}</option>);
+ options.push(
+ <option
+ key={'incoming-hook' + channel.id}
+ value={channel.id}
+ >
+ {channel.display_name}
+ </option>
+ );
}
});
@@ -108,26 +115,30 @@ export default class ManageIncomingHooks extends React.Component {
const hooks = [];
this.state.hooks.forEach((hook) => {
const c = ChannelStore.get(hook.channel_id);
- hooks.push(
- <div className='font--small'>
- <div className='padding-top x2 divider-light'></div>
- <div className='padding-top x2'>
- <strong>{'URL: '}</strong><span className='word-break--all'>{Utils.getWindowLocationOrigin() + '/hooks/' + hook.id}</span>
- </div>
- <div className='padding-top'>
- <strong>{'Channel: '}</strong>{c.name}
- </div>
- <div className='padding-top'>
+ if (c) {
+ hooks.push(
+ <div
+ key={hook.id}
+ className='webhook__item'
+ >
+ <div className='padding-top x2 webhook__url'>
+ <strong>{'URL: '}</strong>
+ <span className='word-break--all'>{Utils.getWindowLocationOrigin() + '/hooks/' + hook.id}</span>
+ </div>
+ <div className='padding-top'>
+ <strong>{'Channel: '}</strong>{c.display_name}
+ </div>
<a
- className={'text-danger'}
+ className={'webhook__remove'}
href='#'
onClick={this.removeHook.bind(this, hook.id)}
>
- {'Remove'}
+ <span aria-hidden='true'>{'×'}</span>
</a>
+ <div className='padding-top x2 divider-light'></div>
</div>
- </div>
- );
+ );
+ }
});
let displayHooks;
@@ -136,35 +147,38 @@ export default class ManageIncomingHooks extends React.Component {
} else if (hooks.length > 0) {
displayHooks = hooks;
} else {
- displayHooks = <label>{': None'}</label>;
+ displayHooks = <div className='padding-top x2'>{'None'}</div>;
}
const existingHooks = (
- <div className='padding-top x2'>
+ <div className='webhooks__container'>
<label className='control-label padding-top x2'>{'Existing incoming webhooks'}</label>
- {displayHooks}
+ <div className='padding-top divider-light'></div>
+ <div className='webhooks__list'>
+ {displayHooks}
+ </div>
</div>
);
return (
<div key='addIncomingHook'>
{'Create webhook URLs for use in external integrations. Please see '}<a href='http://mattermost.org/webhooks'>{'http://mattermost.org/webhooks'}</a> {' to learn more.'}
- <br/>
- <br/>
- <label className='control-label'>{'Add a new incoming webhook'}</label>
- <div className='padding-top'>
- <select
- ref='channelName'
- className='form-control'
- value={this.state.channelId}
- onChange={this.updateChannelId}
- >
- {options}
- </select>
- {serverError}
- <div className='padding-top'>
+ <label className='control-label padding-top x2'>{'Add a new incoming webhook'}</label>
+ <div className='row padding-top'>
+ <div className='col-sm-10 padding-bottom'>
+ <select
+ ref='channelName'
+ className='form-control'
+ value={this.state.channelId}
+ onChange={this.updateChannelId}
+ >
+ {options}
+ </select>
+ {serverError}
+ </div>
+ <div className='col-sm-2 col-xs-4 no-padding--left padding-bottom'>
<a
- className={'btn btn-sm btn-primary' + disableButton}
+ className={'btn form-control no-padding btn-sm btn-primary' + disableButton}
href='#'
onClick={this.addNewHook}
>
diff --git a/web/react/components/user_settings/manage_outgoing_hooks.jsx b/web/react/components/user_settings/manage_outgoing_hooks.jsx
index e83ae3bd6..6e9b2205d 100644
--- a/web/react/components/user_settings/manage_outgoing_hooks.jsx
+++ b/web/react/components/user_settings/manage_outgoing_hooks.jsx
@@ -6,6 +6,7 @@ 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();
@@ -128,21 +129,42 @@ export default class ManageOutgoingHooks extends React.Component {
}
const channels = ChannelStore.getAll();
- const options = [<option value=''>{'--- Select a channel ---'}</option>];
+ const options = [];
+ options.push(
+ <option
+ key='select-channel'
+ value=''
+ >
+ {'--- Select a channel ---'}
+ </option>
+ );
+
channels.forEach((channel) => {
if (channel.type === Constants.OPEN_CHANNEL) {
- options.push(<option value={channel.id}>{channel.name}</option>);
+ options.push(
+ <option
+ key={'outgoing-hook' + channel.id}
+ value={channel.id}
+ >
+ {channel.display_name}
+ </option>
+ );
}
});
const hooks = [];
this.state.hooks.forEach((hook) => {
const c = ChannelStore.get(hook.channel_id);
+
+ if (!c && hook.channel_id && hook.channel_id.length !== 0) {
+ return;
+ }
+
let channelDiv;
if (c) {
channelDiv = (
<div className='padding-top'>
- <strong>{'Channel: '}</strong>{c.name}
+ <strong>{'Channel: '}</strong>{c.display_name}
</div>
);
}
@@ -157,8 +179,10 @@ export default class ManageOutgoingHooks extends React.Component {
}
hooks.push(
- <div className='font--small'>
- <div className='padding-top x2 divider-light'></div>
+ <div
+ key={hook.id}
+ className='webhook__item'
+ >
<div className='padding-top x2'>
<strong>{'URLs: '}</strong><span className='word-break--all'>{hook.callback_urls.join(', ')}</span>
</div>
@@ -175,15 +199,15 @@ export default class ManageOutgoingHooks extends React.Component {
>
{'Regen Token'}
</a>
- <span>{' - '}</span>
<a
- className='text-danger'
+ className='webhook__remove'
href='#'
onClick={this.removeHook.bind(this, hook.id)}
>
- {'Remove'}
+ <span aria-hidden='true'>{'×'}</span>
</a>
</div>
+ <div className='padding-top x2 divider-light'></div>
</div>
);
});
@@ -194,13 +218,16 @@ export default class ManageOutgoingHooks extends React.Component {
} else if (hooks.length > 0) {
displayHooks = hooks;
} else {
- displayHooks = <label>{': None'}</label>;
+ displayHooks = <div className='padding-top x2'>{'None'}</div>;
}
const existingHooks = (
- <div className='padding-top x2'>
+ <div className='webhooks__container'>
<label className='control-label padding-top x2'>{'Existing outgoing webhooks'}</label>
- {displayHooks}
+ <div className='padding-top divider-light'></div>
+ <div className='webhooks__list'>
+ {displayHooks}
+ </div>
</div>
);
@@ -210,41 +237,49 @@ export default class ManageOutgoingHooks extends React.Component {
<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'>
+ <div>
+ <label className='control-label'>{'Channel'}</label>
+ <div className='padding-top'>
+ <select
+ ref='channelName'
+ className='form-control'
+ value={this.state.channelId}
+ onChange={this.updateChannelId}
+ >
+ {options}
+ </select>
+ </div>
+ <div className='padding-top'>{'Only public channels can be used'}</div>
+ </div>
+ <div className='padding-top x2'>
+ <label className='control-label'>{'Trigger Words:'}</label>
+ <div className='padding-top'>
+ <input
+ ref='triggerWords'
+ className='form-control'
+ value={this.state.triggerWords}
+ onChange={this.updateTriggerWords}
+ placeholder='Optional if channel selected'
+ />
+ </div>
+ <div className='padding-top'>{'Comma separated words to trigger on'}</div>
+ </div>
+ <div className='padding-top x2'>
+ <label className='control-label'>{'Callback URLs:'}</label>
+ <div className='padding-top'>
+ <textarea
+ ref='callbackURLs'
+ className='form-control no-resize'
+ value={this.state.callbackURLs}
+ resize={false}
+ rows={3}
+ onChange={this.updateCallbackURLs}
+ />
+ </div>
+ <div className='padding-top'>{'New line separated URLs that will receive the HTTP POST event'}</div>
+ {serverError}
+ </div>
+ <div className='padding-top padding-bottom'>
<a
className={'btn btn-sm btn-primary'}
href='#'
diff --git a/web/react/components/user_settings/user_settings_appearance.jsx b/web/react/components/user_settings/user_settings_appearance.jsx
index 8c62a189d..e94894a1d 100644
--- a/web/react/components/user_settings/user_settings_appearance.jsx
+++ b/web/react/components/user_settings/user_settings_appearance.jsx
@@ -7,6 +7,7 @@ var Utils = require('../../utils/utils.jsx');
const CustomThemeChooser = require('./custom_theme_chooser.jsx');
const PremadeThemeChooser = require('./premade_theme_chooser.jsx');
+const CodeThemeChooser = require('./code_theme_chooser.jsx');
const AppDispatcher = require('../../dispatcher/app_dispatcher.jsx');
const Constants = require('../../utils/constants.jsx');
const ActionTypes = Constants.ActionTypes;
@@ -18,12 +19,14 @@ export default class UserSettingsAppearance extends React.Component {
this.onChange = this.onChange.bind(this);
this.submitTheme = this.submitTheme.bind(this);
this.updateTheme = this.updateTheme.bind(this);
+ this.updateCodeTheme = this.updateCodeTheme.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleImportModal = this.handleImportModal.bind(this);
this.state = this.getStateFromStores();
this.originalTheme = this.state.theme;
+ this.originalCodeTheme = this.state.theme.codeTheme;
}
componentDidMount() {
UserStore.addChangeListener(this.onChange);
@@ -58,6 +61,10 @@ export default class UserSettingsAppearance extends React.Component {
type = 'custom';
}
+ if (!theme.codeTheme) {
+ theme.codeTheme = Constants.DEFAULT_CODE_THEME;
+ }
+
return {theme, type};
}
onChange() {
@@ -93,6 +100,13 @@ export default class UserSettingsAppearance extends React.Component {
);
}
updateTheme(theme) {
+ theme.codeTheme = this.state.theme.codeTheme;
+ this.setState({theme});
+ Utils.applyTheme(theme);
+ }
+ updateCodeTheme(codeTheme) {
+ var theme = this.state.theme;
+ theme.codeTheme = codeTheme;
this.setState({theme});
Utils.applyTheme(theme);
}
@@ -102,6 +116,7 @@ export default class UserSettingsAppearance extends React.Component {
handleClose() {
const state = this.getStateFromStores();
state.serverError = null;
+ state.theme.codeTheme = this.originalCodeTheme;
Utils.applyTheme(state.theme);
@@ -170,7 +185,13 @@ export default class UserSettingsAppearance extends React.Component {
</div>
{custom}
<hr />
- {serverError}
+ <strong className='radio'>{'Code Theme'}</strong>
+ <CodeThemeChooser
+ theme={this.state.theme}
+ updateTheme={this.updateCodeTheme}
+ />
+ <hr />
+ {serverError}
<a
className='btn btn-sm btn-primary'
href='#'
diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx
index 9c03f77a6..70e559c30 100644
--- a/web/react/components/user_settings/user_settings_general.jsx
+++ b/web/react/components/user_settings/user_settings_general.jsx
@@ -122,7 +122,7 @@ export default class UserSettingsGeneralTab extends React.Component {
() => {
this.updateSection('');
AsyncClient.getMe();
- const verificationEnabled = global.window.config.SendEmailNotifications === 'true' && global.window.config.RequireEmailVerification === 'true' && emailUpdated;
+ const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated;
if (verificationEnabled) {
ErrorStore.storeLastError({message: 'Check your email at ' + user.email + ' to verify the address.'});
@@ -451,8 +451,8 @@ export default class UserSettingsGeneralTab extends React.Component {
}
var emailSection;
if (this.props.activeSection === 'email') {
- const emailEnabled = global.window.config.SendEmailNotifications === 'true';
- const emailVerificationEnabled = global.window.config.RequireEmailVerification === 'true';
+ const emailEnabled = global.window.mm_config.SendEmailNotifications === 'true';
+ const emailVerificationEnabled = global.window.mm_config.RequireEmailVerification === 'true';
let helpText = 'Email is used for notifications, and requires verification if changed.';
if (!emailEnabled) {
@@ -542,7 +542,7 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingPicture
title='Profile Picture'
submit={this.submitPicture}
- src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update}
+ src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + utils.getSessionIndex()}
server_error={serverError}
client_error={clientError}
updateSection={function clearSection(e) {
diff --git a/web/react/components/user_settings/user_settings_integrations.jsx b/web/react/components/user_settings/user_settings_integrations.jsx
index 231580cc3..4b1e5e532 100644
--- a/web/react/components/user_settings/user_settings_integrations.jsx
+++ b/web/react/components/user_settings/user_settings_integrations.jsx
@@ -34,16 +34,15 @@ export default class UserSettingsIntegrationsTab extends React.Component {
let outgoingHooksSection;
var inputs = [];
- if (global.window.config.EnableIncomingWebhooks === 'true') {
+ if (global.window.mm_config.EnableIncomingWebhooks === 'true') {
if (this.props.activeSection === 'incoming-hooks') {
inputs.push(
- <ManageIncomingHooks />
+ <ManageIncomingHooks key='incoming-hook-ui' />
);
incomingHooksSection = (
<SettingItemMax
title='Incoming Webhooks'
- width = 'full'
inputs={inputs}
updateSection={(e) => {
this.updateSection('');
@@ -55,7 +54,6 @@ export default class UserSettingsIntegrationsTab extends React.Component {
incomingHooksSection = (
<SettingItemMin
title='Incoming Webhooks'
- width = 'full'
describe='Manage your incoming webhooks (Developer feature)'
updateSection={() => {
this.updateSection('incoming-hooks');
@@ -65,10 +63,10 @@ export default class UserSettingsIntegrationsTab extends React.Component {
}
}
- if (global.window.config.EnableOutgoingWebhooks === 'true') {
+ if (global.window.mm_config.EnableOutgoingWebhooks === 'true') {
if (this.props.activeSection === 'outgoing-hooks') {
inputs.push(
- <ManageOutgoingHooks />
+ <ManageOutgoingHooks key='outgoing-hook-ui' />
);
outgoingHooksSection = (
diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx
index 44cd423b5..5449ae91e 100644
--- a/web/react/components/user_settings/user_settings_modal.jsx
+++ b/web/react/components/user_settings/user_settings_modal.jsx
@@ -35,10 +35,11 @@ export default class UserSettingsModal extends React.Component {
tabs.push({name: 'security', uiName: 'Security', icon: 'glyphicon glyphicon-lock'});
tabs.push({name: 'notifications', uiName: 'Notifications', icon: 'glyphicon glyphicon-exclamation-sign'});
tabs.push({name: 'appearance', uiName: 'Appearance', icon: 'glyphicon glyphicon-wrench'});
- if (global.window.config.EnableOAuthServiceProvider === 'true') {
+ if (global.window.mm_config.EnableOAuthServiceProvider === 'true') {
tabs.push({name: 'developer', uiName: 'Developer', icon: 'glyphicon glyphicon-th'});
}
- if (global.window.config.EnableIncomingWebhooks === 'true' || global.window.config.EnableOutgoingWebhooks === 'true') {
+
+ if (global.window.mm_config.EnableIncomingWebhooks === 'true' || global.window.mm_config.EnableOutgoingWebhooks === 'true') {
tabs.push({name: 'integrations', uiName: 'Integrations', icon: 'glyphicon glyphicon-transfer'});
}
tabs.push({name: 'display', uiName: 'Display', icon: 'glyphicon glyphicon-eye-open'});
diff --git a/web/react/components/user_settings/user_settings_notifications.jsx b/web/react/components/user_settings/user_settings_notifications.jsx
index 8693af494..61d49acb2 100644
--- a/web/react/components/user_settings/user_settings_notifications.jsx
+++ b/web/react/components/user_settings/user_settings_notifications.jsx
@@ -413,7 +413,7 @@ export default class NotificationsTab extends React.Component {
</label>
<br/>
</div>
- <div><br/>{'Email notifications are sent for mentions and direct messages after you’ve been offline for more than 60 seconds or away from ' + global.window.config.SiteName + ' for more than 5 minutes.'}</div>
+ <div><br/>{'Email notifications are sent for mentions and direct messages after you’ve been offline for more than 60 seconds or away from ' + global.window.mm_config.SiteName + ' for more than 5 minutes.'}</div>
</div>
);