summaryrefslogtreecommitdiffstats
path: root/webapp/components
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2017-01-12 19:59:37 -0500
committerChristopher Speller <crspeller@gmail.com>2017-01-12 19:59:37 -0500
commit8fb66c2b834ee4e0669de173e5ddfebd56c34d58 (patch)
tree9e8e66772d44c4f9010a48c8e0afed70421238b1 /webapp/components
parent4208e42ba9df02b9c4bd7081179922c21206d83d (diff)
parentaafb8be87c79c60df7534b3b69f967c6301b157e (diff)
downloadchat-8fb66c2b834ee4e0669de173e5ddfebd56c34d58.tar.gz
chat-8fb66c2b834ee4e0669de173e5ddfebd56c34d58.tar.bz2
chat-8fb66c2b834ee4e0669de173e5ddfebd56c34d58.zip
Merge branch 'release-3.6'
Diffstat (limited to 'webapp/components')
-rw-r--r--webapp/components/admin_console/admin_team_members_dropdown.jsx4
-rw-r--r--webapp/components/admin_console/policy_settings.jsx12
-rw-r--r--webapp/components/admin_console/saml_settings.jsx4
-rw-r--r--webapp/components/analytics/system_analytics.jsx314
-rw-r--r--webapp/components/channel_members_modal.jsx4
-rw-r--r--webapp/components/create_comment.jsx9
-rw-r--r--webapp/components/create_post.jsx10
-rw-r--r--webapp/components/mfa/components/setup.jsx2
-rw-r--r--webapp/components/more_channels.jsx16
-rw-r--r--webapp/components/more_direct_channels.jsx6
-rw-r--r--webapp/components/notify_counts.jsx4
-rw-r--r--webapp/components/post_view/components/post_body_additional_content.jsx2
-rw-r--r--webapp/components/search_bar.jsx53
-rw-r--r--webapp/components/searchable_channel_list.jsx6
-rw-r--r--webapp/components/suggestion/suggestion_box.jsx5
-rw-r--r--webapp/components/team_sidebar/components/team_button.jsx22
-rw-r--r--webapp/components/team_sidebar/team_sidebar_controller.jsx14
17 files changed, 281 insertions, 206 deletions
diff --git a/webapp/components/admin_console/admin_team_members_dropdown.jsx b/webapp/components/admin_console/admin_team_members_dropdown.jsx
index 0019dfbc0..ee9e53f6c 100644
--- a/webapp/components/admin_console/admin_team_members_dropdown.jsx
+++ b/webapp/components/admin_console/admin_team_members_dropdown.jsx
@@ -432,10 +432,6 @@ export default class AdminTeamMembersDropdown extends React.Component {
);
}
- if (global.window.mm_config.EnableSignInWithEmail !== 'true') {
- passwordReset = null;
- }
-
let makeDemoteModal = null;
if (this.props.user.id === me.id) {
const title = (
diff --git a/webapp/components/admin_console/policy_settings.jsx b/webapp/components/admin_console/policy_settings.jsx
index 50b9d4033..0e224af73 100644
--- a/webapp/components/admin_console/policy_settings.jsx
+++ b/webapp/components/admin_console/policy_settings.jsx
@@ -146,7 +146,11 @@ export default class PolicySettings extends AdminSettings {
defaultMessage='Set policy on who can delete public channels. Deleted channels can be recovered from the database using a {commandLineToolLink}.'
values={{
commandLineToolLink: (
- <a href='https://docs.mattermost.com/administration/command-line-tools.html'>
+ <a
+ href='https://docs.mattermost.com/administration/command-line-tools.html'
+ target='_blank'
+ rel='noopener noreferrer'
+ >
<FormattedMessage
id='admin.general.policy.restrictPublicChannelDeletionCommandLineToolLink'
defaultMessage='command line tool'
@@ -222,7 +226,11 @@ export default class PolicySettings extends AdminSettings {
defaultMessage='Set policy on who can delete private groups. Deleted groups can be recovered from the database using a {commandLineToolLink}.'
values={{
commandLineToolLink: (
- <a href='https://docs.mattermost.com/administration/command-line-tools.html'>
+ <a
+ href='https://docs.mattermost.com/administration/command-line-tools.html'
+ target='_blank'
+ rel='noopener noreferrer'
+ >
<FormattedMessage
id='admin.general.policy.restrictPrivateChannelDeletionCommandLineToolLink'
defaultMessage='command line tool'
diff --git a/webapp/components/admin_console/saml_settings.jsx b/webapp/components/admin_console/saml_settings.jsx
index 1391df0b6..ad7a82553 100644
--- a/webapp/components/admin_console/saml_settings.jsx
+++ b/webapp/components/admin_console/saml_settings.jsx
@@ -296,9 +296,9 @@ export default class SamlSettings extends AdminSettings {
<SettingsGroup>
<div className='banner'>
<div className='banner__content'>
- <FormattedMessage
+ <FormattedHTMLMessage
id='admin.saml.bannerDesc'
- defaultMessage='If a user attribute changes on the SAML server it will be updated the next time the user enters their credentials to log in to Mattermost. This includes if a user is made inactive or removed from a SAML Identity Provider. Remote logout with SAML servers is considered in a future release.'
+ defaultMessage='User attributes in SAML server, including user deactivation or removal, are updated in Mattermost during user login. Learn more at: <a href=\"https://docs.mattermost.com/deployment/sso-saml.html\">https://docs.mattermost.com/deployment/sso-saml.html</a>'
/>
</div>
</div>
diff --git a/webapp/components/analytics/system_analytics.jsx b/webapp/components/analytics/system_analytics.jsx
index 244e1ff07..dd7b90260 100644
--- a/webapp/components/analytics/system_analytics.jsx
+++ b/webapp/components/analytics/system_analytics.jsx
@@ -80,69 +80,141 @@ class SystemAnalytics extends React.Component {
render() {
const stats = this.state.stats;
+ const isLicensed = global.window.mm_license.IsLicensed === 'true';
+ const skippedIntensiveQueries = stats[StatTypes.TOTAL_POSTS] === -1;
+ const postCountsDay = formatPostsPerDayData(stats[StatTypes.POST_PER_DAY]);
+ const userCountsWithPostsDay = formatUsersWithPostsPerDayData(stats[StatTypes.USERS_WITH_POSTS_PER_DAY]);
let banner;
- if (stats[StatTypes.TOTAL_POSTS] === -1) {
+ let postCount;
+ let postTotalGraph;
+ let activeUserGraph;
+ if (skippedIntensiveQueries) {
banner = (
- <Banner
- description={
+ <div className='banner'>
+ <div className='banner__content'>
<FormattedHTMLMessage
id='analytics.system.skippedIntensiveQueries'
- defaultMessage="Some statistics have been omitted because they put too much load on the system to calculate. See <a href='https://docs.mattermost.com/administration/statistics.html' target='_blank'>https://docs.mattermost.com/administration/statistics.html</a> for more details."
+ defaultMessage="To maximize performance, some statistics are disabled. You can re-enable them in config.json. See: <a href='https://docs.mattermost.com/administration/statistics.html' target='_blank'>https://docs.mattermost.com/administration/statistics.html</a>"
+ />
+ </div>
+ </div>
+ );
+ } else {
+ postCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalPosts'
+ defaultMessage='Total Posts'
/>
}
+ icon='fa-comment'
+ count={stats[StatTypes.TOTAL_POSTS]}
/>
);
- }
- let advancedCounts;
- let advancedStats;
- let advancedGraphs;
- if (global.window.mm_license.IsLicensed === 'true') {
- advancedCounts = (
+ postTotalGraph = (
<div className='row'>
- <StatisticCount
- title={
- <FormattedMessage
- id='analytics.system.totalSessions'
- defaultMessage='Total Sessions'
- />
- }
- icon='fa-signal'
- count={stats[StatTypes.TOTAL_SESSIONS]}
- />
- <StatisticCount
- title={
- <FormattedMessage
- id='analytics.system.totalCommands'
- defaultMessage='Total Commands'
- />
- }
- icon='fa-terminal'
- count={stats[StatTypes.TOTAL_COMMANDS]}
- />
- <StatisticCount
+ <LineChart
title={
<FormattedMessage
- id='analytics.system.totalIncomingWebhooks'
- defaultMessage='Incoming Webhooks'
+ id='analytics.system.totalPosts'
+ defaultMessage='Total Posts'
/>
}
- icon='fa-arrow-down'
- count={stats[StatTypes.TOTAL_IHOOKS]}
+ data={postCountsDay}
+ options={{
+ legend: {
+ display: false
+ }
+ }}
+ width='740'
+ height='225'
/>
- <StatisticCount
+ </div>
+ );
+
+ activeUserGraph = (
+ <div className='row'>
+ <LineChart
title={
<FormattedMessage
- id='analytics.system.totalOutgoingWebhooks'
- defaultMessage='Outgoing Webhooks'
+ id='analytics.system.activeUsers'
+ defaultMessage='Active Users With Posts'
/>
}
- icon='fa-arrow-up'
- count={stats[StatTypes.TOTAL_OHOOKS]}
+ data={userCountsWithPostsDay}
+ options={{
+ legend: {
+ display: false
+ }
+ }}
+ width='740'
+ height='225'
/>
</div>
);
+ }
+
+ let advancedStats;
+ let advancedGraphs;
+ let sessionCount;
+ let commandCount;
+ let incomingCount;
+ let outgoingCount;
+ if (global.window.mm_license.IsLicensed === 'true') {
+ sessionCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalSessions'
+ defaultMessage='Total Sessions'
+ />
+ }
+ icon='fa-signal'
+ count={stats[StatTypes.TOTAL_SESSIONS]}
+ />
+ );
+
+ commandCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalCommands'
+ defaultMessage='Total Commands'
+ />
+ }
+ icon='fa-terminal'
+ count={stats[StatTypes.TOTAL_COMMANDS]}
+ />
+ );
+
+ incomingCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalIncomingWebhooks'
+ defaultMessage='Incoming Webhooks'
+ />
+ }
+ icon='fa-arrow-down'
+ count={stats[StatTypes.TOTAL_IHOOKS]}
+ />
+ );
+
+ outgoingCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalOutgoingWebhooks'
+ defaultMessage='Outgoing Webhooks'
+ />
+ }
+ icon='fa-arrow-up'
+ count={stats[StatTypes.TOTAL_OHOOKS]}
+ />
+ );
advancedStats = (
<div className='row'>
@@ -247,65 +319,89 @@ class SystemAnalytics extends React.Component {
}
}
- const postCountsDay = formatPostsPerDayData(stats[StatTypes.POST_PER_DAY]);
- const userCountsWithPostsDay = formatUsersWithPostsPerDayData(stats[StatTypes.USERS_WITH_POSTS_PER_DAY]);
+ const userCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalUsers'
+ defaultMessage='Total Users'
+ />
+ }
+ icon='fa-user'
+ count={stats[StatTypes.TOTAL_USERS]}
+ />
+ );
- let totalPostsCount;
- let postTotalGraph;
- let activeUserGraph;
- if (stats[StatTypes.TOTAL_POSTS] !== -1) {
- totalPostsCount = (
- <StatisticCount
- title={
- <FormattedMessage
- id='analytics.system.totalPosts'
- defaultMessage='Total Posts'
- />
- }
- icon='fa-comment'
- count={stats[StatTypes.TOTAL_POSTS]}
- />
+ const teamCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalTeams'
+ defaultMessage='Total Teams'
+ />
+ }
+ icon='fa-users'
+ count={stats[StatTypes.TOTAL_TEAMS]}
+ />
+ );
+
+ const channelCount = (
+ <StatisticCount
+ title={
+ <FormattedMessage
+ id='analytics.system.totalChannels'
+ defaultMessage='Total Channels'
+ />
+ }
+ icon='fa-globe'
+ count={stats[StatTypes.TOTAL_PUBLIC_CHANNELS] + stats[StatTypes.TOTAL_PRIVATE_GROUPS]}
+ />
+ );
+
+ let firstRow;
+ let secondRow;
+ if (isLicensed && skippedIntensiveQueries) {
+ firstRow = (
+ <div className='row'>
+ {userCount}
+ {teamCount}
+ {channelCount}
+ {sessionCount}
+ </div>
);
- postTotalGraph = (
+ secondRow = (
<div className='row'>
- <LineChart
- title={
- <FormattedMessage
- id='analytics.system.totalPosts'
- defaultMessage='Total Posts'
- />
- }
- data={postCountsDay}
- options={{
- legend: {
- display: false
- }
- }}
- width='740'
- height='225'
- />
+ {commandCount}
+ {incomingCount}
+ {outgoingCount}
+ </div>
+ );
+ } else if (isLicensed && !skippedIntensiveQueries) {
+ firstRow = (
+ <div className='row'>
+ {userCount}
+ {teamCount}
+ {channelCount}
+ {postCount}
</div>
);
- activeUserGraph = (
+ secondRow = (
<div className='row'>
- <LineChart
- title={
- <FormattedMessage
- id='analytics.system.activeUsers'
- defaultMessage='Active Users With Posts'
- />
- }
- data={userCountsWithPostsDay}
- options={{
- legend: {
- display: false
- }
- }}
- width='740'
- height='225'
- />
+ {sessionCount}
+ {commandCount}
+ {incomingCount}
+ {outgoingCount}
+ </div>
+ );
+ } else if (!isLicensed) {
+ firstRow = (
+ <div className='row'>
+ {userCount}
+ {teamCount}
+ {channelCount}
+ {postCount}
</div>
);
}
@@ -319,40 +415,8 @@ class SystemAnalytics extends React.Component {
/>
</h3>
{banner}
- <div className='row'>
- <StatisticCount
- title={
- <FormattedMessage
- id='analytics.system.totalUsers'
- defaultMessage='Total Users'
- />
- }
- icon='fa-user'
- count={stats[StatTypes.TOTAL_USERS]}
- />
- <StatisticCount
- title={
- <FormattedMessage
- id='analytics.system.totalTeams'
- defaultMessage='Total Teams'
- />
- }
- icon='fa-users'
- count={stats[StatTypes.TOTAL_TEAMS]}
- />
- {totalPostsCount}
- <StatisticCount
- title={
- <FormattedMessage
- id='analytics.system.totalChannels'
- defaultMessage='Total Channels'
- />
- }
- icon='fa-globe'
- count={stats[StatTypes.TOTAL_PUBLIC_CHANNELS] + stats[StatTypes.TOTAL_PRIVATE_GROUPS]}
- />
- </div>
- {advancedCounts}
+ {firstRow}
+ {secondRow}
{advancedStats}
{advancedGraphs}
{postTotalGraph}
diff --git a/webapp/components/channel_members_modal.jsx b/webapp/components/channel_members_modal.jsx
index 9f6a2a2eb..351efed96 100644
--- a/webapp/components/channel_members_modal.jsx
+++ b/webapp/components/channel_members_modal.jsx
@@ -168,7 +168,7 @@ export default class ChannelMembersModal extends React.Component {
return (
<div>
<Modal
- dialogClassName='more-modal'
+ dialogClassName='more-modal more-modal--action'
show={this.state.show}
onHide={this.onHide}
onExited={this.props.onModalDismissed}
@@ -210,4 +210,4 @@ ChannelMembersModal.propTypes = {
onModalDismissed: React.PropTypes.func.isRequired,
showInviteModal: React.PropTypes.func.isRequired,
channel: React.PropTypes.object.isRequired
-};
+}; \ No newline at end of file
diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx
index 09ec32b6b..0e9d2a41a 100644
--- a/webapp/components/create_comment.jsx
+++ b/webapp/components/create_comment.jsx
@@ -67,9 +67,10 @@ export default class CreateComment extends React.Component {
fileInfos: draft.fileInfos,
submitting: false,
ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'),
- showPostDeletedModal: false,
- lastBlurAt: 0
+ showPostDeletedModal: false
};
+
+ this.lastBlurAt = 0;
}
componentDidMount() {
@@ -145,7 +146,7 @@ export default class CreateComment extends React.Component {
});
const fasterThanHumanWillClick = 150;
- const forceFocus = (Date.now() - this.state.lastBlurAt < fasterThanHumanWillClick);
+ const forceFocus = (Date.now() - this.lastBlurAt < fasterThanHumanWillClick);
this.focusTextbox(forceFocus);
}
@@ -405,7 +406,7 @@ export default class CreateComment extends React.Component {
}
handleBlur() {
- this.setState({lastBlurAt: Date.now()});
+ this.lastBlurAt = Date.now();
}
render() {
diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx
index 13a8c729f..e1b2ca059 100644
--- a/webapp/components/create_post.jsx
+++ b/webapp/components/create_post.jsx
@@ -76,9 +76,10 @@ export default class CreatePost extends React.Component {
ctrlSend: PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, 'send_on_ctrl_enter'),
fullWidthTextBox: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN,
showTutorialTip: false,
- showPostDeletedModal: false,
- lastBlurAt: 0
+ showPostDeletedModal: false
};
+
+ this.lastBlurAt = 0;
}
handlePostError(postError) {
@@ -154,7 +155,8 @@ export default class CreatePost extends React.Component {
this.setState({message: '', submitting: false, postError: null, fileInfos: [], serverError: null});
const fasterThanHumanWillClick = 150;
- const forceFocus = (Date.now() - this.state.lastBlurAt < fasterThanHumanWillClick);
+ const forceFocus = (Date.now() - this.lastBlurAt < fasterThanHumanWillClick);
+
this.focusTextbox(forceFocus);
}
@@ -438,7 +440,7 @@ export default class CreatePost extends React.Component {
}
handleBlur() {
- this.setState({lastBlurAt: Date.now()});
+ this.lastBlurAt = Date.now();
}
showPostDeletedModal() {
diff --git a/webapp/components/mfa/components/setup.jsx b/webapp/components/mfa/components/setup.jsx
index f7a287c15..a19e5d9fb 100644
--- a/webapp/components/mfa/components/setup.jsx
+++ b/webapp/components/mfa/components/setup.jsx
@@ -67,7 +67,7 @@ export default class Setup extends React.Component {
}
let mfaRequired;
- if (global.window.mm_config.EnforceMultifactorAuthentication) {
+ if (global.window.mm_config.EnforceMultifactorAuthentication === 'true') {
mfaRequired = (
<p>
<FormattedHTMLMessage
diff --git a/webapp/components/more_channels.jsx b/webapp/components/more_channels.jsx
index 783aeff50..e4cff451d 100644
--- a/webapp/components/more_channels.jsx
+++ b/webapp/components/more_channels.jsx
@@ -9,7 +9,6 @@ import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as ChannelUtils from 'utils/channel_utils.jsx';
import {joinChannel, searchMoreChannels} from 'actions/channel_actions.jsx';
import React from 'react';
@@ -152,14 +151,19 @@ export default class MoreChannels extends React.Component {
const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
- if (!ChannelUtils.showCreateOption(Constants.OPEN_CHANNEL, isAdmin, isSystemAdmin)) {
- createNewChannelButton = null;
- createChannelHelpText = null;
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ createNewChannelButton = null;
+ createChannelHelpText = null;
+ } else if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ createNewChannelButton = null;
+ createChannelHelpText = null;
+ }
}
return (
<Modal
- dialogClassName='more-modal more-public-channels'
+ dialogClassName='more-modal more-modal--action'
show={this.state.show}
onHide={this.handleHide}
onExited={this.handleExit}
@@ -192,4 +196,4 @@ export default class MoreChannels extends React.Component {
MoreChannels.propTypes = {
onModalDismissed: React.PropTypes.func,
handleNewChannel: React.PropTypes.func
-};
+}; \ No newline at end of file
diff --git a/webapp/components/more_direct_channels.jsx b/webapp/components/more_direct_channels.jsx
index 1b287b3b2..13ee50b4d 100644
--- a/webapp/components/more_direct_channels.jsx
+++ b/webapp/components/more_direct_channels.jsx
@@ -195,7 +195,9 @@ export default class MoreDirectChannels extends React.Component {
render() {
let teamToggle;
+ let memberClass = '';
if (global.window.mm_config.RestrictDirectMessage === 'any') {
+ memberClass = 'more-system-members';
teamToggle = (
<div className='member-select__container'>
<select
@@ -226,7 +228,7 @@ export default class MoreDirectChannels extends React.Component {
return (
<Modal
- dialogClassName='more-modal more-direct-channels'
+ dialogClassName={'more-modal more-direct-channels ' + memberClass}
show={this.state.show}
onHide={this.handleHide}
onExited={this.handleExit}
@@ -258,4 +260,4 @@ export default class MoreDirectChannels extends React.Component {
MoreDirectChannels.propTypes = {
onModalDismissed: React.PropTypes.func
-};
+}; \ No newline at end of file
diff --git a/webapp/components/notify_counts.jsx b/webapp/components/notify_counts.jsx
index d49925780..55ede2d90 100644
--- a/webapp/components/notify_counts.jsx
+++ b/webapp/components/notify_counts.jsx
@@ -13,7 +13,7 @@ function getCountsStateFromStores() {
teamMembers.forEach((member) => {
if (member.team_id !== TeamStore.getCurrentId()) {
- count += ((member.msg_count || 0) + (member.mention_count || 0));
+ count += (member.mention_count || 0);
}
});
@@ -27,8 +27,6 @@ function getCountsStateFromStores() {
count += channel.total_msg_count - channelMember.msg_count;
} else if (channelMember.mention_count > 0) {
count += channelMember.mention_count;
- } else if (channelMember.notify_props.mark_unread !== 'mention' && channel.total_msg_count - channelMember.msg_count > 0) {
- count += 1;
}
});
diff --git a/webapp/components/post_view/components/post_body_additional_content.jsx b/webapp/components/post_view/components/post_body_additional_content.jsx
index 5cdbef050..a65b608d7 100644
--- a/webapp/components/post_view/components/post_body_additional_content.jsx
+++ b/webapp/components/post_view/components/post_body_additional_content.jsx
@@ -136,7 +136,7 @@ export default class PostBodyAdditionalContent extends React.Component {
}
generateStaticEmbed() {
- if (this.props.post.type === Constants.POST_TYPE_ATTACHMENT) {
+ if (this.props.post.props && this.props.post.props.attachments) {
return this.getSlackAttachment();
}
diff --git a/webapp/components/search_bar.jsx b/webapp/components/search_bar.jsx
index bea722243..a7e9bfcac 100644
--- a/webapp/components/search_bar.jsx
+++ b/webapp/components/search_bar.jsx
@@ -111,9 +111,8 @@ export default class SearchBar extends React.Component {
}
handleUserFocus() {
- $('.search-bar__container').addClass('focused');
-
this.setState({focused: true});
+ $('.search-bar__container').addClass('focused');
}
performSearch(terms, isMentionSearch) {
@@ -193,19 +192,6 @@ export default class SearchBar extends React.Component {
</Tooltip>
);
- const searchPopover = (
- <Popover
- id='searchbar-help-popup'
- placement='bottom'
- className={helpClass}
- >
- <FormattedHTMLMessage
- id='search_bar.usage'
- defaultMessage='<h4>Search Options</h4><ul><li><span>Use </span><b>"quotation marks"</b><span> to search for phrases</span></li><li><span>Use </span><b>from:</b><span> to find posts from specific users and </span><b>in:</b><span> to find posts in specific channels</span></li></ul>'
- />
- </Popover>
- );
-
const flaggedTooltip = (
<Tooltip id='flaggedTooltip'>
<FormattedMessage
@@ -289,28 +275,29 @@ export default class SearchBar extends React.Component {
autoComplete='off'
>
<span className='fa fa-search sidebar__search-icon'/>
- <OverlayTrigger
- delayShow={Constants.OVERLAY_TIME_DELAY_SMALL}
+ <SuggestionBox
+ ref='search'
+ className='form-control search-bar'
+ placeholder={Utils.localizeMessage('search_bar.search', 'Search')}
+ value={this.state.searchTerm}
+ onFocus={this.handleUserFocus}
+ onBlur={this.handleUserBlur}
+ onChange={this.handleChange}
+ listComponent={SearchSuggestionList}
+ providers={this.suggestionProviders}
+ type='search'
+ />
+ {isSearching}
+ <Popover
+ id='searchbar-help-popup'
placement='bottom'
- overlay={searchPopover}
- trigger='focus'
- rootClose={true}
className={helpClass}
>
- <SuggestionBox
- ref='search'
- className='form-control search-bar'
- placeholder={Utils.localizeMessage('search_bar.search', 'Search')}
- value={this.state.searchTerm}
- onFocus={this.handleUserFocus}
- onBlur={this.handleUserBlur}
- onChange={this.handleChange}
- listComponent={SearchSuggestionList}
- providers={this.suggestionProviders}
- type='search'
+ <FormattedHTMLMessage
+ id='search_bar.usage'
+ defaultMessage='<h4>Search Options</h4><ul><li><span>Use </span><b>"quotation marks"</b><span> to search for phrases</span></li><li><span>Use </span><b>from:</b><span> to find posts from specific users and </span><b>in:</b><span> to find posts in specific channels</span></li></ul>'
/>
- </OverlayTrigger>
- {isSearching}
+ </Popover>
</form>
{mentionBtn}
diff --git a/webapp/components/searchable_channel_list.jsx b/webapp/components/searchable_channel_list.jsx
index afd113975..1bbaa3e57 100644
--- a/webapp/components/searchable_channel_list.jsx
+++ b/webapp/components/searchable_channel_list.jsx
@@ -180,7 +180,9 @@ export default class SearchableChannelList extends React.Component {
ref='channelList'
className='more-modal__list'
>
- {listContent}
+ <div>
+ {listContent}
+ </div>
</div>
<div className='filter-controls'>
{previousButton}
@@ -202,4 +204,4 @@ SearchableChannelList.propTypes = {
search: React.PropTypes.func.isRequired,
handleJoin: React.PropTypes.func.isRequired,
noResultsText: React.PropTypes.object
-};
+}; \ No newline at end of file
diff --git a/webapp/components/suggestion/suggestion_box.jsx b/webapp/components/suggestion/suggestion_box.jsx
index b3f9843c6..e9f7c3699 100644
--- a/webapp/components/suggestion/suggestion_box.jsx
+++ b/webapp/components/suggestion/suggestion_box.jsx
@@ -64,6 +64,10 @@ export default class SuggestionBox extends React.Component {
// Delay this slightly so that we don't clear the suggestions before we run click handlers on SuggestionList
GlobalActions.emitClearSuggestions(this.suggestionId);
}, 100);
+
+ if (this.props.onBlur) {
+ this.props.onBlur();
+ }
}
handleChange(e) {
@@ -272,6 +276,7 @@ SuggestionBox.propTypes = {
renderDividers: React.PropTypes.bool,
// explicitly name any input event handlers we override and need to manually call
+ onBlur: React.PropTypes.func,
onChange: React.PropTypes.func,
onKeyDown: React.PropTypes.func,
onItemSelected: React.PropTypes.func
diff --git a/webapp/components/team_sidebar/components/team_button.jsx b/webapp/components/team_sidebar/components/team_button.jsx
index 203e1de00..2df21b20b 100644
--- a/webapp/components/team_sidebar/components/team_button.jsx
+++ b/webapp/components/team_sidebar/components/team_button.jsx
@@ -7,9 +7,6 @@ import React from 'react';
import {Link} from 'react-router/es6';
import {Tooltip, OverlayTrigger} from 'react-bootstrap';
-import {isMobile} from 'utils/utils.jsx';
-import {isMobileApp} from 'utils/user_agent.jsx';
-
export default class TeamButton extends React.Component {
constructor(props) {
super(props);
@@ -50,14 +47,21 @@ export default class TeamButton extends React.Component {
</div>
);
}
- if (!isMobile() && !isMobileApp()) {
+ if (this.props.isMobile) {
+ btn = (
+ <div className={'team-btn ' + btnClass}>
+ {badge}
+ {content}
+ </div>
+ );
+ } else {
btn = (
<OverlayTrigger
delayShow={Constants.OVERLAY_TIME_DELAY}
placement={this.props.placement}
overlay={
<Tooltip id={`tooltip-${this.props.url}`}>
- {this.props.displayName}
+ {this.props.tip}
</Tooltip>
}
>
@@ -67,13 +71,6 @@ export default class TeamButton extends React.Component {
</div>
</OverlayTrigger>
);
- } else {
- btn = (
- <div className={'team-btn ' + btnClass}>
- {badge}
- {content}
- </div>
- );
}
return (
@@ -110,6 +107,7 @@ TeamButton.propTypes = {
tip: React.PropTypes.node.isRequired,
active: React.PropTypes.bool,
disabled: React.PropTypes.bool,
+ isMobile: React.PropTypes.bool,
unread: React.PropTypes.bool,
mentions: React.PropTypes.number,
placement: React.PropTypes.oneOf(['left', 'right', 'top', 'bottom'])
diff --git a/webapp/components/team_sidebar/team_sidebar_controller.jsx b/webapp/components/team_sidebar/team_sidebar_controller.jsx
index 24cd48d39..ac3a9f894 100644
--- a/webapp/components/team_sidebar/team_sidebar_controller.jsx
+++ b/webapp/components/team_sidebar/team_sidebar_controller.jsx
@@ -34,7 +34,8 @@ export default class TeamSidebar extends React.Component {
teamListings: TeamStore.getTeamListings(),
teamMembers,
currentTeamId,
- show: teamMembers && teamMembers.length > 1
+ show: teamMembers && teamMembers.length > 1,
+ isMobile: Utils.isMobile()
};
}
@@ -53,12 +54,16 @@ export default class TeamSidebar extends React.Component {
}
componentDidUpdate(prevProps, prevState) {
- $('.team-wrapper').perfectScrollbar();
+ if (!this.state.isMobile) {
+ $('.team-wrapper').perfectScrollbar();
+ }
// reset the scrollbar upon switching teams
if (this.state.currentTeam !== prevState.currentTeam) {
this.refs.container.scrollTop = 0;
- $('.team-wrapper').perfectScrollbar('update');
+ if (!this.state.isMobile) {
+ $('.team-wrapper').perfectScrollbar('update');
+ }
}
}
@@ -121,6 +126,7 @@ export default class TeamSidebar extends React.Component {
url={`/${team.name}`}
tip={team.display_name}
active={team.id === this.state.currentTeamId}
+ isMobile={this.state.isMobile}
displayName={team.display_name}
unread={team.unread}
mentions={team.mentions}
@@ -134,6 +140,7 @@ export default class TeamSidebar extends React.Component {
btnClass='team-btn__add'
key='more_teams'
url='/select_team'
+ isMobile={this.state.isMobile}
tip={
<FormattedMessage
id='team_sidebar.join'
@@ -149,6 +156,7 @@ export default class TeamSidebar extends React.Component {
btnClass='team-btn__add'
key='more_teams'
url='/create_team'
+ isMobile={this.state.isMobile}
tip={
<FormattedMessage
id='navbar_dropdown.create'