diff options
Diffstat (limited to 'web/react/components')
18 files changed, 105 insertions, 35 deletions
diff --git a/web/react/components/admin_console/user_item.jsx b/web/react/components/admin_console/user_item.jsx index 0c1a55cc1..009a9f004 100644 --- a/web/react/components/admin_console/user_item.jsx +++ b/web/react/components/admin_console/user_item.jsx @@ -353,7 +353,7 @@ export default class UserItem extends React.Component { return ( <tr> - <td className='row member-div'> + <td className='row member-div padding--equal'> <img className='post-profile-img pull-left' src={`/api/v1/users/${user.id}/image?time=${user.update_at}&${Utils.getSessionIndex()}`} diff --git a/web/react/components/channel_info_modal.jsx b/web/react/components/channel_info_modal.jsx index 5067f5913..83f5aba65 100644 --- a/web/react/components/channel_info_modal.jsx +++ b/web/react/components/channel_info_modal.jsx @@ -56,7 +56,7 @@ class ChannelInfoModal extends React.Component { </div> <div className='col-sm-9'>{channelURL}</div> </div> - <div className='row'> + <div className='row form-group'> <div className='col-sm-3 info__label'> <FormattedMessage id='channel_info.id' diff --git a/web/react/components/channel_loader.jsx b/web/react/components/channel_loader.jsx index 174c8c4e1..f3000ee05 100644 --- a/web/react/components/channel_loader.jsx +++ b/web/react/components/channel_loader.jsx @@ -95,6 +95,8 @@ class ChannelLoader extends React.Component { $(window).on('focus', function windowFocus() { AsyncClient.updateLastViewedAt(); + ChannelStore.resetCounts(ChannelStore.getCurrentId()); + ChannelStore.emitChange(); window.isActive = true; }); @@ -185,4 +187,4 @@ ChannelLoader.propTypes = { intl: intlShape.isRequired }; -export default injectIntl(ChannelLoader);
\ No newline at end of file +export default injectIntl(ChannelLoader); diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx index e6a9fbd25..835298635 100644 --- a/web/react/components/navbar.jsx +++ b/web/react/components/navbar.jsx @@ -25,6 +25,7 @@ const ActionTypes = Constants.ActionTypes; import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; import {FormattedMessage} from 'mm-intl'; +import attachFastClick from 'fastclick'; const Popover = ReactBootstrap.Popover; const OverlayTrigger = ReactBootstrap.OverlayTrigger; @@ -59,6 +60,7 @@ export default class Navbar extends React.Component { ChannelStore.addChangeListener(this.onChange); ChannelStore.addExtraInfoChangeListener(this.onChange); $('.inner__wrap').click(this.hideSidebars); + attachFastClick(document.body); } componentWillUnmount() { ChannelStore.removeChangeListener(this.onChange); diff --git a/web/react/components/popover_list_members.jsx b/web/react/components/popover_list_members.jsx index f217229ed..afff78bae 100644 --- a/web/react/components/popover_list_members.jsx +++ b/web/react/components/popover_list_members.jsx @@ -107,7 +107,7 @@ export default class PopoverListMembers extends React.Component { name = Utils.displayUsername(teamMembers[m.username].id); } - if (name && teamMembers[m.username].delete_at <= 0) { + if (name) { popoverHtml.push( <div className='text-nowrap' diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index 6d82423d5..c44223b1f 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -144,7 +144,8 @@ export default class PostInfo extends React.Component { ); } - handlePermalink() { + handlePermalink(e) { + e.preventDefault(); EventHelpers.showGetPostLinkModal(this.props.post); } diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx index ebe19abad..19ab7d5aa 100644 --- a/web/react/components/posts_view.jsx +++ b/web/react/components/posts_view.jsx @@ -535,7 +535,15 @@ function FloatingTimestamp({isScrolling, post}) { return <noscript />; } - const dateString = Utils.getDateForUnixTicks(post.create_at).toDateString(); + const dateString = ( + <FormattedDate + value={post.create_at} + weekday='short' + day='2-digit' + month='short' + year='numeric' + /> + ); let className = 'post-list__timestamp'; if (isScrolling) { diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index 9c85e9940..0d15c8599 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -31,6 +31,7 @@ class RhsComment extends React.Component { this.retryComment = this.retryComment.bind(this); this.parseEmojis = this.parseEmojis.bind(this); + this.handlePermalink = this.handlePermalink.bind(this); this.state = {}; } @@ -67,6 +68,10 @@ class RhsComment extends React.Component { parseEmojis() { twemoji.parse(ReactDOM.findDOMNode(this), {size: Constants.EMOJI_SIZE}); } + handlePermalink(e) { + e.preventDefault(); + EventHelpers.showGetPostLinkModal(this.props.post); + } componentDidMount() { this.parseEmojis(); } @@ -92,6 +97,23 @@ class RhsComment extends React.Component { var dropdownContents = []; + dropdownContents.push( + <li + key='rhs-root-permalink' + role='presentation' + > + <a + href='#' + onClick={this.handlePermalink} + > + <FormattedMessage + id='rhs_comment.permalink' + defaultMessage='Permalink' + /> + </a> + </li> + ); + if (isOwner) { dropdownContents.push( <li diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index f9f7f8f81..54f2e8262 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -21,6 +21,7 @@ export default class RhsRootPost extends React.Component { super(props); this.parseEmojis = this.parseEmojis.bind(this); + this.handlePermalink = this.handlePermalink.bind(this); this.state = {}; } @@ -31,6 +32,10 @@ export default class RhsRootPost extends React.Component { folder: Emoji.getImagePathForEmoticon() }); } + handlePermalink(e) { + e.preventDefault(); + EventHelpers.showGetPostLinkModal(this.props.post); + } componentDidMount() { this.parseEmojis(); } @@ -83,6 +88,23 @@ export default class RhsRootPost extends React.Component { var dropdownContents = []; + dropdownContents.push( + <li + key='rhs-root-permalink' + role='presentation' + > + <a + href='#' + onClick={this.handlePermalink} + > + <FormattedMessage + id='rhs_root.permalink' + defaultMessage='Permalink' + /> + </a> + </li> + ); + if (isOwner) { dropdownContents.push( <li diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index 4adc3afe0..12c066734 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -15,13 +15,16 @@ function getStateFromStores() { const results = SearchStore.getSearchResults(); const channels = new Map(); - const channelIds = results.order.map((postId) => results.posts[postId].channel_id); - for (const id of channelIds) { - if (channels.has(id)) { - continue; - } - channels.set(id, ChannelStore.get(id)); + if (results && results.order) { + const channelIds = results.order.map((postId) => results.posts[postId].channel_id); + for (const id of channelIds) { + if (channels.has(id)) { + continue; + } + + channels.set(id, ChannelStore.get(id)); + } } return { diff --git a/web/react/components/team_general_tab.jsx b/web/react/components/team_general_tab.jsx index 0a1b02853..c1b2a2e7f 100644 --- a/web/react/components/team_general_tab.jsx +++ b/web/react/components/team_general_tab.jsx @@ -486,13 +486,9 @@ class GeneralTab extends React.Component { inputs.push( <div key='teamInviteSetting'> <div className='row'> - <label className='col-sm-5 control-label'> - <FormattedMessage - id='general_tab.codeTitle' - defaultMessage='Invite Code' - /> + <label className='col-sm-5 control-label visible-xs-block'> </label> - <div className='col-sm-7'> + <div className='col-sm-12'> <input className='form-control' type='text' diff --git a/web/react/components/team_signup_email_item.jsx b/web/react/components/team_signup_email_item.jsx index feb70dc71..790ec2e5d 100644 --- a/web/react/components/team_signup_email_item.jsx +++ b/web/react/components/team_signup_email_item.jsx @@ -83,4 +83,4 @@ TeamSignupEmailItem.propTypes = { email: React.PropTypes.string }; -export default injectIntl(TeamSignupEmailItem);
\ No newline at end of file +export default injectIntl(TeamSignupEmailItem, {withRef: true}); diff --git a/web/react/components/team_signup_send_invites_page.jsx b/web/react/components/team_signup_send_invites_page.jsx index 46a6bc68e..343db13e8 100644 --- a/web/react/components/team_signup_send_invites_page.jsx +++ b/web/react/components/team_signup_send_invites_page.jsx @@ -33,8 +33,8 @@ export default class TeamSignupSendInvitesPage extends React.Component { var emails = []; for (var i = 0; i < this.props.state.invites.length; i++) { - if (this.refs['email_' + i].validate(this.props.state.team.email)) { - emails.push(this.refs['email_' + i].getValue()); + if (this.refs['email_' + i].getWrappedInstance().validate(this.props.state.team.email)) { + emails.push(this.refs['email_' + i].getWrappedInstance().getValue()); } else { valid = false; } diff --git a/web/react/components/user_settings/manage_command_hooks.jsx b/web/react/components/user_settings/manage_command_hooks.jsx index f4009aeaa..bd0659a47 100644 --- a/web/react/components/user_settings/manage_command_hooks.jsx +++ b/web/react/components/user_settings/manage_command_hooks.jsx @@ -257,7 +257,7 @@ export default class ManageCommandCmds extends React.Component { let triggerDiv; if (cmd.trigger && cmd.trigger.length !== 0) { triggerDiv = ( - <div className='padding-top'> + <div className='padding-top x2'> <strong> <FormattedMessage id='user.settings.cmds.trigger' @@ -371,7 +371,7 @@ export default class ManageCommandCmds extends React.Component { /> </a> <a - className='webcmd__remove' + className='webhook__remove webcmd__remove' href='#' onClick={this.removeCmd.bind(this, cmd.id)} > diff --git a/web/react/components/user_settings/manage_incoming_hooks.jsx b/web/react/components/user_settings/manage_incoming_hooks.jsx index c6532b018..e79ec6f6c 100644 --- a/web/react/components/user_settings/manage_incoming_hooks.jsx +++ b/web/react/components/user_settings/manage_incoming_hooks.jsx @@ -183,7 +183,7 @@ export default class ManageIncomingHooks extends React.Component { <div key='addIncomingHook'> <FormattedHTMLMessage id='user.settings.hooks_in.description' - defaultMessage='Create webhook URLs for use in external integrations. Please see<a href="http://mattermost.org/webhooks" target="_blank">http://mattermost.org/webhooks</a> to learn more.' + defaultMessage='Create webhook URLs for use in external integrations. Please see <a href="http://mattermost.org/webhooks" target="_blank">http://mattermost.org/webhooks</a> to learn more.' /> <div><label className='control-label padding-top x2'> <FormattedMessage diff --git a/web/react/components/user_settings/manage_outgoing_hooks.jsx b/web/react/components/user_settings/manage_outgoing_hooks.jsx index 3f88e9f41..44aab486e 100644 --- a/web/react/components/user_settings/manage_outgoing_hooks.jsx +++ b/web/react/components/user_settings/manage_outgoing_hooks.jsx @@ -18,6 +18,10 @@ const holders = defineMessages({ callbackHolder: { id: 'user.settings.hooks_out.callbackHolder', defaultMessage: 'Each URL must start with http:// or https://' + }, + select: { + id: 'user.settings.hooks_out.select', + defaultMessage: '--- Select a channel ---' } }); @@ -153,10 +157,7 @@ class ManageOutgoingHooks extends React.Component { key='select-channel' value='' > - <FormattedMessage - id='user.settings.hooks_out.select' - defaultMessage='--- Select a channel ---' - /> + {this.props.intl.formatMessage(holders.select)} </option> ); diff --git a/web/react/components/user_settings/user_settings_modal.jsx b/web/react/components/user_settings/user_settings_modal.jsx index a7541073e..5442f7ac4 100644 --- a/web/react/components/user_settings/user_settings_modal.jsx +++ b/web/react/components/user_settings/user_settings_modal.jsx @@ -7,6 +7,7 @@ import SettingsSidebar from '../settings_sidebar.jsx'; import UserStore from '../../stores/user_store.jsx'; import * as Utils from '../../utils/utils.jsx'; +import Constants from '../../utils/constants.jsx'; const Modal = ReactBootstrap.Modal; @@ -224,14 +225,19 @@ class UserSettingsModal extends React.Component { resetTheme() { const user = UserStore.getCurrentUser(); - if (user.theme_props != null) { + if (user.theme_props == null) { + Utils.applyTheme(Constants.THEMES.default); + } else { Utils.applyTheme(user.theme_props); } } render() { const {formatMessage} = this.props.intl; + var currentUser = UserStore.getCurrentUser(); + var isAdmin = Utils.isAdmin(currentUser.roles); var tabs = []; + tabs.push({name: 'general', uiName: formatMessage(holders.general), icon: 'glyphicon glyphicon-cog'}); tabs.push({name: 'security', uiName: formatMessage(holders.security), icon: 'glyphicon glyphicon-lock'}); tabs.push({name: 'notifications', uiName: formatMessage(holders.notifications), icon: 'glyphicon glyphicon-exclamation-sign'}); @@ -240,8 +246,17 @@ class UserSettingsModal extends React.Component { } if (global.window.mm_config.EnableIncomingWebhooks === 'true' || global.window.mm_config.EnableOutgoingWebhooks === 'true' || global.window.mm_config.EnableCommands === 'true') { - tabs.push({name: 'integrations', uiName: formatMessage(holders.integrations), icon: 'glyphicon glyphicon-transfer'}); + var show = global.window.mm_config.EnableOnlyAdminIntegrations !== 'true'; + + if (global.window.mm_config.EnableOnlyAdminIntegrations === 'true' && isAdmin) { + show = true; + } + + if (show) { + tabs.push({name: 'integrations', uiName: formatMessage(holders.integrations), icon: 'glyphicon glyphicon-transfer'}); + } } + tabs.push({name: 'display', uiName: formatMessage(holders.display), icon: 'glyphicon glyphicon-eye-open'}); tabs.push({name: 'advanced', uiName: formatMessage(holders.advanced), icon: 'glyphicon glyphicon-list-alt'}); diff --git a/web/react/components/user_settings/user_settings_security.jsx b/web/react/components/user_settings/user_settings_security.jsx index 5693047c2..53d79906f 100644 --- a/web/react/components/user_settings/user_settings_security.jsx +++ b/web/react/components/user_settings/user_settings_security.jsx @@ -11,6 +11,7 @@ import TeamStore from '../../stores/team_store.jsx'; import * as Client from '../../utils/client.jsx'; import * as AsyncClient from '../../utils/async_client.jsx'; +import * as Utils from '../../utils/utils.jsx'; import Constants from '../../utils/constants.jsx'; import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl'; @@ -216,15 +217,12 @@ class SecurityTab extends React.Component { var describe; var d = new Date(this.props.user.last_password_update); - var timeOfDay = ' am'; - if (d.getHours() >= 12) { - timeOfDay = ' pm'; - } const locale = global.window.mm_locale; + const hours12 = !Utils.isMilitaryTime(); describe = formatMessage(holders.lastUpdated, { date: d.toLocaleDateString(locale, {month: 'short', day: '2-digit', year: 'numeric'}), - time: d.toLocaleTimeString(locale, {hours12: true, hour: '2-digit', minute: '2-digit'}) + timeOfDay + time: d.toLocaleTimeString(locale, {hour12: hours12, hour: '2-digit', minute: '2-digit'}) }); updateSectionStatus = function updateSection() { |