summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
author=Corey Hulen <corey@hulen.com>2015-10-02 08:36:56 -0700
committer=Corey Hulen <corey@hulen.com>2015-10-02 08:36:56 -0700
commitb2052de746f8e5f4ca600142fd43b64ceb6c8b84 (patch)
tree99474e75e399fc530a73cfb3cdc10d74bcbc0b01 /web
parent9d688821aa8bb8d766793aeaec6920f9985a30a3 (diff)
parentc427e9c9d6fbd68662fdfbbe733af4b34ae69269 (diff)
downloadchat-b2052de746f8e5f4ca600142fd43b64ceb6c8b84.tar.gz
chat-b2052de746f8e5f4ca600142fd43b64ceb6c8b84.tar.bz2
chat-b2052de746f8e5f4ca600142fd43b64ceb6c8b84.zip
Merge branch 'master' into PLT-462
Diffstat (limited to 'web')
-rw-r--r--web/react/components/channel_notifications.jsx289
-rw-r--r--web/react/components/notify_counts.jsx2
-rw-r--r--web/react/components/post_info.jsx2
-rw-r--r--web/react/components/sidebar.jsx16
-rw-r--r--web/react/components/user_settings/manage_incoming_hooks.jsx2
-rw-r--r--web/react/components/user_settings/user_settings_appearance.jsx2
-rw-r--r--web/react/components/user_settings/user_settings_notifications.jsx2
-rw-r--r--web/react/utils/async_client.jsx16
-rw-r--r--web/react/utils/client.jsx6
-rw-r--r--web/react/utils/text_formatting.jsx6
10 files changed, 200 insertions, 143 deletions
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx
index 9eda68b38..45981b295 100644
--- a/web/react/components/channel_notifications.jsx
+++ b/web/react/components/channel_notifications.jsx
@@ -15,14 +15,24 @@ export default class ChannelNotifications extends React.Component {
this.onListenerChange = this.onListenerChange.bind(this);
this.updateSection = this.updateSection.bind(this);
- this.handleUpdate = this.handleUpdate.bind(this);
- this.handleRadioClick = this.handleRadioClick.bind(this);
- this.handleQuietToggle = this.handleQuietToggle.bind(this);
- this.createDesktopSection = this.createDesktopSection.bind(this);
- this.createQuietSection = this.createQuietSection.bind(this);
- this.state = {notifyLevel: '', title: '', channelId: '', activeSection: ''};
+ this.handleSubmitNotifyLevel = this.handleSubmitNotifyLevel.bind(this);
+ this.handleUpdateNotifyLevel = this.handleUpdateNotifyLevel.bind(this);
+ this.createNotifyLevelSection = this.createNotifyLevelSection.bind(this);
+
+ this.handleSubmitMarkUnreadLevel = this.handleSubmitMarkUnreadLevel.bind(this);
+ this.handleUpdateMarkUnreadLevel = this.handleUpdateMarkUnreadLevel.bind(this);
+ this.createMarkUnreadLevelSection = this.createMarkUnreadLevelSection.bind(this);
+
+ this.state = {
+ notifyLevel: '',
+ markUnreadLevel: '',
+ title: '',
+ channelId: '',
+ activeSection: ''
+ };
}
+
componentDidMount() {
ChannelStore.addChangeListener(this.onListenerChange);
@@ -30,33 +40,34 @@ export default class ChannelNotifications extends React.Component {
var button = e.relatedTarget;
var channelId = button.getAttribute('data-channelid');
- var notifyLevel = ChannelStore.getMember(channelId).notify_level;
- var quietMode = false;
-
- if (notifyLevel === 'quiet') {
- quietMode = true;
- }
+ const member = ChannelStore.getMember(channelId);
+ var notifyLevel = member.notify_props.desktop;
+ var markUnreadLevel = member.notify_props.mark_unread;
- this.setState({notifyLevel: notifyLevel, quietMode: quietMode, title: button.getAttribute('data-title'), channelId: channelId});
+ this.setState({
+ notifyLevel,
+ markUnreadLevel,
+ title: button.getAttribute('data-title'),
+ channelId: channelId
+ });
}.bind(this));
}
componentWillUnmount() {
ChannelStore.removeChangeListener(this.onListenerChange);
}
+
onListenerChange() {
if (!this.state.channelId) {
return;
}
- var notifyLevel = ChannelStore.getMember(this.state.channelId).notify_level;
- var quietMode = false;
- if (notifyLevel === 'quiet') {
- quietMode = true;
- }
+ const member = ChannelStore.getMember(this.state.channelId);
+ var notifyLevel = member.notify_props.desktop;
+ var markUnreadLevel = member.notify_props.mark_unread;
var newState = this.state;
newState.notifyLevel = notifyLevel;
- newState.quietMode = quietMode;
+ newState.markUnreadLevel = markUnreadLevel;
if (!Utils.areStatesEqual(this.state, newState)) {
this.setState(newState);
@@ -65,53 +76,64 @@ export default class ChannelNotifications extends React.Component {
updateSection(section) {
this.setState({activeSection: section});
}
- handleUpdate() {
+
+ handleSubmitNotifyLevel() {
var channelId = this.state.channelId;
var notifyLevel = this.state.notifyLevel;
- if (this.state.quietMode) {
- notifyLevel = 'quiet';
+
+ if (ChannelStore.getMember(channelId).notify_props.desktop === notifyLevel) {
+ this.updateSection('');
+ return;
}
var data = {};
data.channel_id = channelId;
data.user_id = UserStore.getCurrentId();
- data.notify_level = notifyLevel;
-
- if (!data.notify_level || data.notify_level.length === 0) {
- return;
- }
+ data.desktop = notifyLevel;
- Client.updateNotifyLevel(data,
- function success() {
+ Client.updateNotifyProps(data,
+ () => {
var member = ChannelStore.getMember(channelId);
- member.notify_level = notifyLevel;
+ member.notify_props.desktop = notifyLevel;
ChannelStore.setChannelMember(member);
this.updateSection('');
- }.bind(this),
- function error(err) {
+ },
+ (err) => {
this.setState({serverError: err.message});
- }.bind(this)
+ }
);
}
- handleRadioClick(notifyLevel) {
- this.setState({notifyLevel: notifyLevel, quietMode: false});
- React.findDOMNode(this.refs.modal).focus();
- }
- handleQuietToggle(quietMode) {
- this.setState({notifyLevel: 'none', quietMode: quietMode});
+
+ handleUpdateNotifyLevel(notifyLevel) {
+ this.setState({notifyLevel});
React.findDOMNode(this.refs.modal).focus();
}
- createDesktopSection(serverError) {
+
+ createNotifyLevelSection(serverError) {
var handleUpdateSection;
+ const user = UserStore.getCurrentUser();
+ const globalNotifyLevel = user.notify_props.desktop;
+
+ let globalNotifyLevelName;
+ if (globalNotifyLevel === 'all') {
+ globalNotifyLevelName = 'For all activity';
+ } else if (globalNotifyLevel === 'mention') {
+ globalNotifyLevelName = 'Only for mentions';
+ } else {
+ globalNotifyLevelName = 'Never';
+ }
+
if (this.state.activeSection === 'desktop') {
- var notifyActive = [false, false, false];
- if (this.state.notifyLevel === 'mention') {
- notifyActive[1] = true;
- } else if (this.state.notifyLevel === 'all') {
+ var notifyActive = [false, false, false, false];
+ if (this.state.notifyLevel === 'default') {
notifyActive[0] = true;
- } else {
+ } else if (this.state.notifyLevel === 'all') {
+ notifyActive[1] = true;
+ } else if (this.state.notifyLevel === 'mention') {
notifyActive[2] = true;
+ } else {
+ notifyActive[3] = true;
}
var inputs = [];
@@ -123,9 +145,9 @@ export default class ChannelNotifications extends React.Component {
<input
type='radio'
checked={notifyActive[0]}
- onChange={this.handleRadioClick.bind(this, 'all')}
+ onChange={this.handleUpdateNotifyLevel.bind(this, 'default')}
>
- For all activity
+ {`Global default (${globalNotifyLevelName})`}
</input>
</label>
<br/>
@@ -135,9 +157,9 @@ export default class ChannelNotifications extends React.Component {
<input
type='radio'
checked={notifyActive[1]}
- onChange={this.handleRadioClick.bind(this, 'mention')}
+ onChange={this.handleUpdateNotifyLevel.bind(this, 'all')}
>
- Only for mentions
+ {'For all activity'}
</input>
</label>
<br/>
@@ -147,9 +169,21 @@ export default class ChannelNotifications extends React.Component {
<input
type='radio'
checked={notifyActive[2]}
- onChange={this.handleRadioClick.bind(this, 'none')}
+ onChange={this.handleUpdateNotifyLevel.bind(this, 'mention')}
+ >
+ {'Only for mentions'}
+ </input>
+ </label>
+ <br/>
+ </div>
+ <div className='radio'>
+ <label>
+ <input
+ type='radio'
+ checked={notifyActive[3]}
+ onChange={this.handleUpdateNotifyLevel.bind(this, 'none')}
>
- Never
+ {'Never'}
</input>
</label>
</div>
@@ -162,30 +196,19 @@ export default class ChannelNotifications extends React.Component {
e.preventDefault();
}.bind(this);
- let curChannel = ChannelStore.get(this.state.channelId);
- let extraInfo = (
+ const extraInfo = (
<span>
- These settings will override the global notification settings.
+ {'Selecting an option other than "Default" will override the global notification settings.'}
<br/>
- Desktop notifications are available on Firefox, Safari, and Chrome.
+ {'Desktop notifications are available on Firefox, Safari, and Chrome.'}
</span>
);
- if (curChannel && curChannel.display_name) {
- extraInfo = (
- <span>
- These settings will override the global notification settings for the <b>{curChannel.display_name}</b> channel.
- <br/>
- Desktop notifications are available on Firefox, Safari, and Chrome.
- </span>
- );
- }
-
return (
<SettingItemMax
title='Send desktop notifications'
inputs={inputs}
- submit={this.handleUpdate}
+ submit={this.handleSubmitNotifyLevel}
server_error={serverError}
updateSection={handleUpdateSection}
extraInfo={extraInfo}
@@ -194,7 +217,9 @@ export default class ChannelNotifications extends React.Component {
}
var describe;
- if (this.state.notifyLevel === 'mention') {
+ if (this.state.notifyLevel === 'default') {
+ describe = `Global default (${globalNotifyLevelName})`;
+ } else if (this.state.notifyLevel === 'mention') {
describe = 'Only for mentions';
} else if (this.state.notifyLevel === 'all') {
describe = 'For all activity';
@@ -215,101 +240,123 @@ export default class ChannelNotifications extends React.Component {
/>
);
}
- createQuietSection(serverError) {
- var handleUpdateSection;
- if (this.state.activeSection === 'quiet') {
- var quietActive = [false, false];
- if (this.state.quietMode) {
- quietActive[0] = true;
- } else {
- quietActive[1] = true;
+
+ handleSubmitMarkUnreadLevel() {
+ const channelId = this.state.channelId;
+ const markUnreadLevel = this.state.markUnreadLevel;
+
+ if (ChannelStore.getMember(channelId).notify_props.mark_unread === markUnreadLevel) {
+ this.updateSection('');
+ return;
+ }
+
+ const data = {
+ channel_id: channelId,
+ user_id: UserStore.getCurrentId(),
+ mark_unread: markUnreadLevel
+ };
+
+ Client.updateNotifyProps(data,
+ () => {
+ var member = ChannelStore.getMember(channelId);
+ member.notify_props.mark_unread = markUnreadLevel;
+ ChannelStore.setChannelMember(member);
+ this.updateSection('');
+ },
+ (err) => {
+ this.setState({serverError: err.message});
}
+ );
+ }
- var inputs = [];
+ handleUpdateMarkUnreadLevel(markUnreadLevel) {
+ this.setState({markUnreadLevel});
+ React.findDOMNode(this.refs.modal).focus();
+ }
- inputs.push(
+ createMarkUnreadLevelSection(serverError) {
+ let content;
+
+ if (this.state.activeSection === 'markUnreadLevel') {
+ const inputs = [(
<div>
<div className='radio'>
<label>
<input
type='radio'
- checked={quietActive[0]}
- onChange={this.handleQuietToggle.bind(this, true)}
+ checked={this.state.markUnreadLevel === 'all'}
+ onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'all')}
>
- On
+ {'For all unread messages'}
</input>
</label>
- <br/>
+ <br />
</div>
<div className='radio'>
<label>
<input
type='radio'
- checked={quietActive[1]}
- onChange={this.handleQuietToggle.bind(this, false)}
+ checked={this.state.markUnreadLevel === 'mention'}
+ onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'mention')}
>
- Off
+ {'Only for mentions'}
</input>
</label>
- <br/>
+ <br />
</div>
</div>
- );
-
- inputs.push(
- <div>
- <br/>
- Enabling quiet mode will turn off desktop notifications and only mark the channel as unread if you have been mentioned.
- </div>
- );
+ )];
- handleUpdateSection = function updateSection(e) {
+ const handleUpdateSection = function handleUpdateSection(e) {
this.updateSection('');
this.onListenerChange();
e.preventDefault();
}.bind(this);
- return (
+ const extraInfo = <span>{'The channel name is bolded in the sidebar when there are unread messages. Selecting "Only for mentions" will bold the channel only when you are mentioned.'}</span>;
+
+ content = (
<SettingItemMax
- title='Quiet mode'
+ title='Mark Channel Unread'
inputs={inputs}
- submit={this.handleUpdate}
+ submit={this.handleSubmitMarkUnreadLevel}
server_error={serverError}
updateSection={handleUpdateSection}
+ extraInfo={extraInfo}
/>
);
- }
-
- var describe;
- if (this.state.quietMode) {
- describe = 'On';
} else {
- describe = 'Off';
- }
+ let describe;
- handleUpdateSection = function updateSection(e) {
- this.updateSection('quiet');
- e.preventDefault();
- }.bind(this);
+ if (!this.state.markUnreadLevel || this.state.markUnreadLevel === 'all') {
+ describe = 'For all unread messages';
+ } else {
+ describe = 'Only for mentions';
+ }
- return (
- <SettingItemMin
- title='Quiet mode'
- describe={describe}
- updateSection={handleUpdateSection}
- />
- );
+ const handleUpdateSection = function handleUpdateSection(e) {
+ this.updateSection('markUnreadLevel');
+ e.preventDefault();
+ }.bind(this);
+
+ content = (
+ <SettingItemMin
+ title='Mark Channel Unread'
+ describe={describe}
+ updateSection={handleUpdateSection}
+ />
+ );
+ }
+
+ return content;
}
+
render() {
var serverError = null;
if (this.state.serverError) {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
}
- var desktopSection = this.createDesktopSection(serverError);
-
- var quietSection = this.createQuietSection(serverError);
-
return (
<div
className='modal fade'
@@ -341,9 +388,9 @@ export default class ChannelNotifications extends React.Component {
>
<br/>
<div className='divider-dark first'/>
- {desktopSection}
+ {this.createNotifyLevelSection(serverError)}
<div className='divider-light'/>
- {quietSection}
+ {this.createMarkUnreadLevelSection(serverError)}
<div className='divider-dark'/>
</div>
</div>
diff --git a/web/react/components/notify_counts.jsx b/web/react/components/notify_counts.jsx
index 0b7c41b62..f34b4669f 100644
--- a/web/react/components/notify_counts.jsx
+++ b/web/react/components/notify_counts.jsx
@@ -15,7 +15,7 @@ function getCountsStateFromStores() {
count += channel.total_msg_count - channelMember.msg_count;
} else if (channelMember.mention_count > 0) {
count += channelMember.mention_count;
- } else if (channelMember.notify_level !== 'quiet' && channel.total_msg_count - channelMember.msg_count > 0) {
+ } else if (channelMember.notify_props.mark_unread !== 'mention' && channel.total_msg_count - channelMember.msg_count > 0) {
count += 1;
}
});
diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx
index 82e746dc0..dba75ac5f 100644
--- a/web/react/components/post_info.jsx
+++ b/web/react/components/post_info.jsx
@@ -150,7 +150,7 @@ export default class PostInfo extends React.Component {
var dropdown = this.createDropdown();
- let tooltip = <Tooltip id={post.id + 'tooltip'}>{utils.displayDate(post.create_at)} at ${utils.displayTime(post.create_at)}</Tooltip>;
+ let tooltip = <Tooltip id={post.id + 'tooltip'}>{`${utils.displayDate(post.create_at)} at ${utils.displayTime(post.create_at)}`}</Tooltip>;
return (
<ul className='post-header post-info'>
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 6033f200f..6d4b56b7b 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -200,13 +200,17 @@ export default class Sidebar extends React.Component {
}
var channel = ChannelStore.get(msg.channel_id);
- var user = UserStore.getCurrentUser();
- if (user.notify_props && ((user.notify_props.desktop === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== 'D') || user.notify_props.desktop === 'none')) {
- return;
+ const user = UserStore.getCurrentUser();
+ const member = ChannelStore.getMember(msg.channel_id);
+
+ var notifyLevel = member.notify_props.desktop;
+ if (notifyLevel === 'default') {
+ notifyLevel = user.notify_props.desktop;
}
- var member = ChannelStore.getMember(msg.channel_id);
- if ((member.notify_level === 'mention' && mentions.indexOf(user.id) === -1) || member.notify_level === 'none' || member.notify_level === 'quiet') {
+ if (notifyLevel === 'none') {
+ return;
+ } else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== 'D') {
return;
}
@@ -330,7 +334,7 @@ export default class Sidebar extends React.Component {
var unread = false;
if (channelMember) {
msgCount = channel.total_msg_count - channelMember.msg_count;
- unread = (msgCount > 0 && channelMember.notify_level !== 'quiet') || channelMember.mention_count > 0;
+ unread = (msgCount > 0 && channelMember.notify_props.mark_unread !== 'mention') || channelMember.mention_count > 0;
}
var titleClass = '';
diff --git a/web/react/components/user_settings/manage_incoming_hooks.jsx b/web/react/components/user_settings/manage_incoming_hooks.jsx
index fa2e2e5e4..899dbcd05 100644
--- a/web/react/components/user_settings/manage_incoming_hooks.jsx
+++ b/web/react/components/user_settings/manage_incoming_hooks.jsx
@@ -148,6 +148,8 @@ export default class ManageIncomingHooks extends React.Component {
return (
<div key='addIncomingHook'>
+ {'Create webhook URLs for channels and private groups. These URLs can be used by outside applications to create posts in any channels or private groups you have access to. The specified channel will be used as the default.'}
+ <br/>
<label className='control-label'>{'Add a new incoming webhook'}</label>
<div className='padding-top'>
<select
diff --git a/web/react/components/user_settings/user_settings_appearance.jsx b/web/react/components/user_settings/user_settings_appearance.jsx
index 4372069e7..c4a137ed8 100644
--- a/web/react/components/user_settings/user_settings_appearance.jsx
+++ b/web/react/components/user_settings/user_settings_appearance.jsx
@@ -220,7 +220,7 @@ export default class UserSettingsAppearance extends React.Component {
className='theme'
onClick={this.handleImportModal}
>
- {'Import from Slack'}
+ {'Import theme colors from Slack'}
</a>
</div>
);
diff --git a/web/react/components/user_settings/user_settings_notifications.jsx b/web/react/components/user_settings/user_settings_notifications.jsx
index 42c65ef5d..e83f18aab 100644
--- a/web/react/components/user_settings/user_settings_notifications.jsx
+++ b/web/react/components/user_settings/user_settings_notifications.jsx
@@ -17,7 +17,7 @@ function getNotificationsStateFromStores() {
if (user.notify_props && user.notify_props.desktop_sound) {
sound = user.notify_props.desktop_sound;
}
- var desktop = 'all';
+ var desktop = 'default';
if (user.notify_props && user.notify_props.desktop) {
desktop = user.notify_props.desktop;
}
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx
index ab2965000..7db3ef30d 100644
--- a/web/react/utils/async_client.jsx
+++ b/web/react/utils/async_client.jsx
@@ -152,21 +152,23 @@ export function getChannel(id) {
}
export function updateLastViewedAt() {
- if (isCallInProgress('updateLastViewed')) {
+ const channelId = ChannelStore.getCurrentId();
+
+ if (channelId === null) {
return;
}
- if (ChannelStore.getCurrentId() == null) {
+ if (isCallInProgress(`updateLastViewed${channelId}`)) {
return;
}
- callTracker.updateLastViewed = utils.getTimestamp();
+ callTracker[`updateLastViewed${channelId}`] = utils.getTimestamp();
client.updateLastViewedAt(
- ChannelStore.getCurrentId(),
- function updateLastViewedAtSuccess() {
+ channelId,
+ () => {
callTracker.updateLastViewed = 0;
},
- function updateLastViewdAtFailure(err) {
+ (err) => {
callTracker.updateLastViewed = 0;
dispatchError(err, 'updateLastViewedAt');
}
@@ -634,4 +636,4 @@ export function getMyTeam() {
dispatchError(err, 'getMyTeam');
}
);
-} \ No newline at end of file
+}
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
index b1be61fc7..5cb165b4c 100644
--- a/web/react/utils/client.jsx
+++ b/web/react/utils/client.jsx
@@ -582,16 +582,16 @@ export function updateChannelDesc(data, success, error) {
track('api', 'api_channels_desc');
}
-export function updateNotifyLevel(data, success, error) {
+export function updateNotifyProps(data, success, error) {
$.ajax({
- url: '/api/v1/channels/update_notify_level',
+ url: '/api/v1/channels/update_notify_props',
dataType: 'json',
contentType: 'application/json',
type: 'POST',
data: JSON.stringify(data),
success,
error: function onError(xhr, status, err) {
- var e = handleError('updateNotifyLevel', xhr, status, err);
+ var e = handleError('updateNotifyProps', xhr, status, err);
error(e);
}
});
diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx
index 56bf49c3f..34e42cbae 100644
--- a/web/react/utils/text_formatting.jsx
+++ b/web/react/utils/text_formatting.jsx
@@ -87,8 +87,10 @@ function autolinkUrls(text, tokens) {
const linkText = match.getMatchedText();
let url = linkText;
- if (url.lastIndexOf('http', 0) !== 0) {
- url = `http://${linkText}`;
+ if (match.getType() === 'email') {
+ url = `mailto:${url}`;
+ } else if (url.lastIndexOf('http', 0) !== 0) {
+ url = `http://${url}`;
}
const index = tokens.size;