diff options
Diffstat (limited to 'webapp')
-rw-r--r-- | webapp/components/backstage/add_incoming_webhook.jsx | 27 | ||||
-rw-r--r-- | webapp/components/backstage/add_outgoing_webhook.jsx | 29 | ||||
-rw-r--r-- | webapp/components/backstage/installed_incoming_webhook.jsx | 16 | ||||
-rw-r--r-- | webapp/components/backstage/installed_outgoing_webhook.jsx | 18 | ||||
-rw-r--r-- | webapp/components/post.jsx | 11 | ||||
-rw-r--r-- | webapp/components/posts_view.jsx | 2 | ||||
-rw-r--r-- | webapp/components/rhs_root_post.jsx | 13 | ||||
-rw-r--r-- | webapp/components/root.jsx | 23 | ||||
-rw-r--r-- | webapp/components/search_results_item.jsx | 35 | ||||
-rw-r--r-- | webapp/components/signup_team_complete/components/signup_team_complete.jsx | 4 | ||||
-rw-r--r-- | webapp/i18n/en.json | 1 | ||||
-rw-r--r-- | webapp/root.jsx | 20 | ||||
-rw-r--r-- | webapp/sass/routes/_backstage.scss | 7 | ||||
-rw-r--r-- | webapp/utils/async_client.jsx | 8 | ||||
-rw-r--r-- | webapp/utils/utils.jsx | 15 |
15 files changed, 143 insertions, 86 deletions
diff --git a/webapp/components/backstage/add_incoming_webhook.jsx b/webapp/components/backstage/add_incoming_webhook.jsx index 83027c6b3..f3601cb07 100644 --- a/webapp/components/backstage/add_incoming_webhook.jsx +++ b/webapp/components/backstage/add_incoming_webhook.jsx @@ -18,12 +18,12 @@ export default class AddIncomingWebhook extends React.Component { this.handleSubmit = this.handleSubmit.bind(this); - this.updateName = this.updateName.bind(this); + this.updateDisplayName = this.updateDisplayName.bind(this); this.updateDescription = this.updateDescription.bind(this); this.updateChannelId = this.updateChannelId.bind(this); this.state = { - name: '', + displayName: '', description: '', channelId: '', saving: false, @@ -60,7 +60,9 @@ export default class AddIncomingWebhook extends React.Component { } const hook = { - channel_id: this.state.channelId + channel_id: this.state.channelId, + display_name: this.state.displayName, + description: this.state.description }; AsyncClient.addIncomingHook( @@ -70,15 +72,16 @@ export default class AddIncomingWebhook extends React.Component { }, (err) => { this.setState({ + saving: false, serverError: err.message }); } ); } - updateName(e) { + updateDisplayName(e) { this.setState({ - name: e.target.value + displayName: e.target.value }); } @@ -112,20 +115,21 @@ export default class AddIncomingWebhook extends React.Component { <div className='form-group'> <label className='control-label col-sm-3' - htmlFor='name' + htmlFor='displayName' > <FormattedMessage - id='add_incoming_webhook.name' - defaultMessage='Name' + id='add_incoming_webhook.displayName' + defaultMessage='Display Name' /> </label> <div className='col-md-5 col-sm-9'> <input - id='name' + id='displayName' type='text' + maxLength='64' className='form-control' - value={this.state.name} - onChange={this.updateName} + value={this.state.displayName} + onChange={this.updateDisplayName} /> </div> </div> @@ -143,6 +147,7 @@ export default class AddIncomingWebhook extends React.Component { <input id='description' type='text' + maxLength='128' className='form-control' value={this.state.description} onChange={this.updateDescription} diff --git a/webapp/components/backstage/add_outgoing_webhook.jsx b/webapp/components/backstage/add_outgoing_webhook.jsx index 5d98138df..ef57c6d05 100644 --- a/webapp/components/backstage/add_outgoing_webhook.jsx +++ b/webapp/components/backstage/add_outgoing_webhook.jsx @@ -18,14 +18,14 @@ export default class AddOutgoingWebhook extends React.Component { this.handleSubmit = this.handleSubmit.bind(this); - this.updateName = this.updateName.bind(this); + this.updateDisplayName = this.updateDisplayName.bind(this); this.updateDescription = this.updateDescription.bind(this); this.updateChannelId = this.updateChannelId.bind(this); this.updateTriggerWords = this.updateTriggerWords.bind(this); this.updateCallbackUrls = this.updateCallbackUrls.bind(this); this.state = { - name: '', + displayName: '', description: '', channelId: '', triggerWords: '', @@ -80,7 +80,9 @@ export default class AddOutgoingWebhook extends React.Component { const hook = { channel_id: this.state.channelId, trigger_words: this.state.triggerWords.split('\n').map((word) => word.trim()), - callback_urls: this.state.callbackUrls.split('\n').map((url) => url.trim()) + callback_urls: this.state.callbackUrls.split('\n').map((url) => url.trim()), + display_name: this.state.displayName, + description: this.state.description }; AsyncClient.addOutgoingHook( @@ -90,15 +92,16 @@ export default class AddOutgoingWebhook extends React.Component { }, (err) => { this.setState({ + saving: false, serverError: err.message }); } ); } - updateName(e) { + updateDisplayName(e) { this.setState({ - name: e.target.value + displayName: e.target.value }); } @@ -144,20 +147,21 @@ export default class AddOutgoingWebhook extends React.Component { <div className='form-group'> <label className='control-label col-sm-3' - htmlFor='name' + htmlFor='displayName' > <FormattedMessage - id='add_outgoing_webhook.name' - defaultMessage='Name' + id='add_outgoing_webhook.displayName' + defaultMessage='Display Name' /> </label> <div className='col-md-5 col-sm-9'> <input - id='name' + id='displayName' type='text' + maxLength='64' className='form-control' - value={this.state.name} - onChange={this.updateName} + value={this.state.displayName} + onChange={this.updateDisplayName} /> </div> </div> @@ -175,6 +179,7 @@ export default class AddOutgoingWebhook extends React.Component { <input id='description' type='text' + maxLength='128' className='form-control' value={this.state.description} onChange={this.updateDescription} @@ -213,6 +218,7 @@ export default class AddOutgoingWebhook extends React.Component { <textarea id='triggerWords' rows='3' + maxLength='1000' className='form-control' value={this.state.triggerWords} onChange={this.updateTriggerWords} @@ -233,6 +239,7 @@ export default class AddOutgoingWebhook extends React.Component { <textarea id='callbackUrls' rows='3' + maxLength='1000' className='form-control' value={this.state.callbackUrls} onChange={this.updateCallbackUrls} diff --git a/webapp/components/backstage/installed_incoming_webhook.jsx b/webapp/components/backstage/installed_incoming_webhook.jsx index f65cf6327..95a303edc 100644 --- a/webapp/components/backstage/installed_incoming_webhook.jsx +++ b/webapp/components/backstage/installed_incoming_webhook.jsx @@ -39,7 +39,7 @@ export default class InstalledIncomingWebhook extends React.Component { <div className='item-details'> <div className='item-details__row'> <span className='item-details__name'> - {channelName} + {incomingWebhook.display_name || channelName} </span> <span className='item-details__type'> <FormattedMessage @@ -50,7 +50,19 @@ export default class InstalledIncomingWebhook extends React.Component { </div> <div className='item-details__row'> <span className='item-details__description'> - {Utils.getWindowLocationOrigin() + '/hooks/' + incomingWebhook.id} + {incomingWebhook.description} + </span> + </div> + <div className='tem-details__row'> + <span className='item-details__creation'> + <FormattedMessage + id='installed_integrations.creation' + defaultMessage='Created by {creator} on {createAt, date, full}' + values={{ + creator: Utils.displayUsername(incomingWebhook.user_id), + createAt: incomingWebhook.create_at + }} + /> </span> </div> </div> diff --git a/webapp/components/backstage/installed_outgoing_webhook.jsx b/webapp/components/backstage/installed_outgoing_webhook.jsx index fee427260..530474dc3 100644 --- a/webapp/components/backstage/installed_outgoing_webhook.jsx +++ b/webapp/components/backstage/installed_outgoing_webhook.jsx @@ -47,7 +47,7 @@ export default class InstalledOutgoingWebhook extends React.Component { <div className='item-details'> <div className='item-details__row'> <span className='item-details__name'> - {channelName} + {outgoingWebhook.display_name || channelName} </span> <span className='item-details__type'> <FormattedMessage @@ -58,9 +58,19 @@ export default class InstalledOutgoingWebhook extends React.Component { </div> <div className='item-details__row'> <span className='item-details__description'> - {Utils.getWindowLocationOrigin() + '/hooks/' + outgoingWebhook.id} - {' - '} - {outgoingWebhook.token} + {outgoingWebhook.description} + </span> + </div> + <div className='item-details__row'> + <span className='item-details__creation'> + <FormattedMessage + id='installed_integrations.creation' + defaultMessage='Created by {creator} on {createAt, date, full}' + values={{ + creator: Utils.displayUsername(outgoingWebhook.creator_id), + createAt: outgoingWebhook.create_at + }} + /> </span> </div> </div> diff --git a/webapp/components/post.jsx b/webapp/components/post.jsx index bbf8d9bf6..7294cf163 100644 --- a/webapp/components/post.jsx +++ b/webapp/components/post.jsx @@ -185,18 +185,9 @@ export default class Post extends React.Component { let profilePic = null; if (!this.props.hideProfilePic) { - let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp; - if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') { - if (post.props.override_icon_url) { - src = post.props.override_icon_url; - } else { - src = Constants.DEFAULT_WEBHOOK_LOGO; - } - } - profilePic = ( <img - src={src} + src={Utils.getProfilePicSrcForPost(post, timestamp)} height='36' width='36' /> diff --git a/webapp/components/posts_view.jsx b/webapp/components/posts_view.jsx index ffe04daa1..aa7f445ce 100644 --- a/webapp/components/posts_view.jsx +++ b/webapp/components/posts_view.jsx @@ -204,10 +204,12 @@ export default class PostsView extends React.Component { // the previous post was made by the same user as the current post, // the previous post is not a comment, // the current post is not a comment, + // the previous post is not from a webhook // the current post is not from a webhook if (prevPostUserId === postUserId && !prevPostIsComment && !postIsComment && + !prevPostFromWebhook && !postFromWebhook) { hideProfilePic = true; } diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx index 7a7c5f692..9a207e429 100644 --- a/webapp/components/rhs_root_post.jsx +++ b/webapp/components/rhs_root_post.jsx @@ -213,21 +213,10 @@ export default class RhsRootPost extends React.Component { ); } - let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp; - if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') { - if (post.props.override_icon_url) { - src = post.props.override_icon_url; - } else { - src = Constants.DEFAULT_WEBHOOK_LOGO; - } - } else if (Utils.isSystemMessage(post)) { - src = Constants.SYSTEM_MESSAGE_PROFILE_IMAGE; - } - const profilePic = ( <img className='post-profile-img' - src={src} + src={Utils.getProfilePicSrcForPost(post, timestamp)} height='36' width='36' /> diff --git a/webapp/components/root.jsx b/webapp/components/root.jsx index 3b85b23fd..59364d085 100644 --- a/webapp/components/root.jsx +++ b/webapp/components/root.jsx @@ -3,6 +3,7 @@ import $ from 'jquery'; import * as GlobalActions from 'action_creators/global_actions.jsx'; +import * as Client from 'utils/client.jsx'; import BrowserStore from 'stores/browser_store.jsx'; import LocalizationStore from 'stores/localization_store.jsx'; @@ -12,6 +13,8 @@ import React from 'react'; import FastClick from 'fastclick'; +import {browserHistory} from 'react-router'; + export default class Root extends React.Component { constructor(props) { super(props); @@ -21,10 +24,25 @@ export default class Root extends React.Component { }; this.localizationChanged = this.localizationChanged.bind(this); + this.redirectIfNecessary = this.redirectIfNecessary.bind(this); } localizationChanged() { this.setState({locale: LocalizationStore.getLocale(), translations: LocalizationStore.getTranslations()}); } + redirectIfNecessary(props) { + if (props.location.pathname === '/') { + Client.getMeLoggedIn((data) => { + if (!data || data.logged_in === 'false') { + browserHistory.push('/signup_team'); + } else { + browserHistory.push('/' + data.team_name + '/channels/town-square'); + } + }); + } + } + componentWillReceiveProps(newProps) { + this.redirectIfNecessary(newProps); + } componentWillMount() { // Setup localization listener LocalizationStore.addChangeListener(this.localizationChanged); @@ -70,12 +88,15 @@ export default class Root extends React.Component { // Get our localizaiton GlobalActions.loadBrowserLocale(); + + // Redirect if Necessary + this.redirectIfNecessary(this.props); } componentWillUnmount() { LocalizationStore.removeChangeListener(this.localizationChanged); } render() { - if (this.state.translations == null) { + if (this.state.translations == null || this.props.children == null) { return <div/>; } diff --git a/webapp/components/search_results_item.jsx b/webapp/components/search_results_item.jsx index 75cbcb2a0..58f09c0e0 100644 --- a/webapp/components/search_results_item.jsx +++ b/webapp/components/search_results_item.jsx @@ -1,11 +1,13 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import UserStore from 'stores/user_store.jsx'; import UserProfile from './user_profile.jsx'; + +import UserStore from 'stores/user_store.jsx'; + import * as GlobalActions from 'action_creators/global_actions.jsx'; import * as TextFormatting from 'utils/text_formatting.jsx'; - +import * as Utils from 'utils/utils.jsx'; import Constants from 'utils/constants.jsx'; import {FormattedMessage, FormattedDate} from 'react-intl'; @@ -29,6 +31,7 @@ export default class SearchResultsItem extends React.Component { const channel = this.props.channel; const timestamp = UserStore.getCurrentUser().update_at; const user = this.props.user || {}; + const post = this.props.post; if (channel) { channelName = channel.display_name; @@ -47,13 +50,23 @@ export default class SearchResultsItem extends React.Component { mentionHighlight: this.props.isMentionSearch }; + let overrideUsername; + let disableProfilePopover = false; + if (post.props && + post.props.from_webhook && + post.props.override_username && + global.window.mm_config.EnablePostUsernameOverride === 'true') { + overrideUsername = post.props.override_username; + disableProfilePopover = true; + } + return ( <div className='search-item__container'> <div className='date-separator'> <hr className='separator__hr'/> <div className='separator__text'> <FormattedDate - value={this.props.post.create_at} + value={post.create_at} day='numeric' month='long' year='numeric' @@ -67,18 +80,24 @@ export default class SearchResultsItem extends React.Component { <div className='post__content'> <div className='post__img'> <img - src={'/api/v1/users/' + this.props.post.user_id + '/image?time=' + timestamp} + src={Utils.getProfilePicSrcForPost(post, timestamp)} height='36' width='36' /> </div> <div> <ul className='post__header'> - <li className='col__name'><strong><UserProfile user={user}/></strong></li> + <li className='col__name'><strong> + <UserProfile + user={user} + overwriteName={overrideUsername} + disablePopover={disableProfilePopover} + /> + </strong></li> <li className='col'> <time className='search-item-time'> <FormattedDate - value={this.props.post.create_at} + value={post.create_at} hour12={true} hour='2-digit' minute='2-digit' @@ -87,7 +106,7 @@ export default class SearchResultsItem extends React.Component { </li> <li> <Link - to={'/' + window.location.pathname.split('/')[1] + '/pl/' + this.props.post.id} + to={'/' + window.location.pathname.split('/')[1] + '/pl/' + post.id} className='search-item__jump' > <FormattedMessage @@ -112,7 +131,7 @@ export default class SearchResultsItem extends React.Component { <div className='search-item-snippet'> <span onClick={TextFormatting.handleClick} - dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message, formattingOptions)}} + dangerouslySetInnerHTML={{__html: TextFormatting.formatText(post.message, formattingOptions)}} /> </div> </div> diff --git a/webapp/components/signup_team_complete/components/signup_team_complete.jsx b/webapp/components/signup_team_complete/components/signup_team_complete.jsx index e5d310151..95b41dbde 100644 --- a/webapp/components/signup_team_complete/components/signup_team_complete.jsx +++ b/webapp/components/signup_team_complete/components/signup_team_complete.jsx @@ -5,10 +5,8 @@ import BrowserStore from 'stores/browser_store.jsx'; import {FormattedMessage} from 'react-intl'; -import {browserHistory} from 'react-router'; - import React from 'react'; -import {Link} from 'react-router'; +import {Link, browserHistory} from 'react-router'; export default class SignupTeamComplete extends React.Component { constructor(props) { diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 7dc6486ab..8fdb42b4c 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -814,6 +814,7 @@ "get_team_invite_link_modal.title": "Team Invite Link", "installed_integrations.add": "Add Integration", "installed_integrations.allFilter": "All ({count})", + "installed_integrations.creation": "Created by {creator} on {createAt, date, full}", "installed_integrations.delete": "Delete", "installed_integrations.header": "Installed Integrations", "installed_integrations.incomingWebhookType": "(Incoming Webhook)", diff --git a/webapp/root.jsx b/webapp/root.jsx index 10cc63643..c88b0a7b3 100644 --- a/webapp/root.jsx +++ b/webapp/root.jsx @@ -158,23 +158,6 @@ function preLoggedIn(nextState, replace, callback) { }); } -function onRootEnter(nextState, replace, callback) { - if (nextState.location.pathname === '/') { - Client.getMeLoggedIn((data) => { - if (!data || data.logged_in === 'false') { - replace({pathname: '/signup_team'}); - callback(); - } else { - replace({pathname: '/' + data.team_name + '/channels/town-square'}); - callback(); - } - }); - return; - } - - callback(); -} - function onPermalinkEnter(nextState) { const postId = nextState.params.postid; @@ -231,7 +214,6 @@ function renderRootComponent() { <Route path='/' component={Root} - onEnter={onRootEnter} > <Route path='error' @@ -338,7 +320,7 @@ function renderRootComponent() { component={TeamURLPage} /> <Route - path='invites' + path='send_invites' component={SendInivtesPage} /> <Route diff --git a/webapp/sass/routes/_backstage.scss b/webapp/sass/routes/_backstage.scss index 729c8c912..13c51c8b4 100644 --- a/webapp/sass/routes/_backstage.scss +++ b/webapp/sass/routes/_backstage.scss @@ -196,7 +196,12 @@ margin-bottom: 1em; } - .list-item__actions { + .item-details__creation { + color: $dark-gray; + margin-bottom: 1em; + } + + .item-actions { flex-grow: 0; flex-shrink: 0; padding-left: 20px; diff --git a/webapp/utils/async_client.jsx b/webapp/utils/async_client.jsx index cc19baa7e..db0b2258c 100644 --- a/webapp/utils/async_client.jsx +++ b/webapp/utils/async_client.jsx @@ -1182,10 +1182,10 @@ export function addIncomingHook(hook, success, error) { } }, (err) => { - dispatchError(err, 'addIncomingHook'); - if (error) { error(err); + } else { + dispatchError(err, 'addIncomingHook'); } } ); @@ -1205,10 +1205,10 @@ export function addOutgoingHook(hook, success, error) { } }, (err) => { - dispatchError(err, 'addOutgoingHook'); - if (error) { error(err); + } else { + dispatchError(err, 'addOutgoingHook'); } } ); diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index 35c347f9f..399dd0985 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -1396,3 +1396,18 @@ export function localizeMessage(id, defaultMessage) { return id; } + +export function getProfilePicSrcForPost(post, timestamp) { + let src = '/api/v1/users/' + post.user_id + '/image?time=' + timestamp; + if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') { + if (post.props.override_icon_url) { + src = post.props.override_icon_url; + } else { + src = Constants.DEFAULT_WEBHOOK_LOGO; + } + } else if (isSystemMessage(post)) { + src = Constants.SYSTEM_MESSAGE_PROFILE_IMAGE; + } + + return src; +} |