From 9d9eaec14f4e4a8bc3bda4ef19c980bef2bb467b Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Wed, 6 Jan 2016 14:18:05 -0800 Subject: Removed ability to drag n' drop text; drag n' drop ui no longer appears when non-files are dragged --- web/react/components/create_comment.jsx | 7 ------- web/react/components/create_post.jsx | 7 ------- web/react/components/file_upload.jsx | 34 +++++++++++++++++++++++---------- web/react/utils/utils.jsx | 6 ++++++ 4 files changed, 30 insertions(+), 24 deletions(-) (limited to 'web/react') diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx index c190b4dd8..cae94429c 100644 --- a/web/react/components/create_comment.jsx +++ b/web/react/components/create_comment.jsx @@ -32,7 +32,6 @@ export default class CreateComment extends React.Component { this.handleUploadStart = this.handleUploadStart.bind(this); this.handleFileUploadComplete = this.handleFileUploadComplete.bind(this); this.handleUploadError = this.handleUploadError.bind(this); - this.handleTextDrop = this.handleTextDrop.bind(this); this.removePreview = this.removePreview.bind(this); this.getFileCount = this.getFileCount.bind(this); this.handleResize = this.handleResize.bind(this); @@ -239,11 +238,6 @@ export default class CreateComment extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: err}); } } - handleTextDrop(text) { - const newText = this.state.messageText + text; - this.handleUserInput(newText); - Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.textbox.refs.message), newText.length); - } removePreview(id) { let previews = this.state.previews; let uploadsInProgress = this.state.uploadsInProgress; @@ -344,7 +338,6 @@ export default class CreateComment extends React.Component { onUploadStart={this.handleUploadStart} onFileUpload={this.handleFileUploadComplete} onUploadError={this.handleUploadError} - onTextDrop={this.handleTextDrop} postType='comment' channelId={this.props.channelId} /> diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index e901b272a..a476863a3 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -40,7 +40,6 @@ export default class CreatePost extends React.Component { this.handleUploadStart = this.handleUploadStart.bind(this); this.handleFileUploadComplete = this.handleFileUploadComplete.bind(this); this.handleUploadError = this.handleUploadError.bind(this); - this.handleTextDrop = this.handleTextDrop.bind(this); this.removePreview = this.removePreview.bind(this); this.onChange = this.onChange.bind(this); this.onPreferenceChange = this.onPreferenceChange.bind(this); @@ -281,11 +280,6 @@ export default class CreatePost extends React.Component { this.setState({uploadsInProgress: draft.uploadsInProgress, serverError: message}); } } - handleTextDrop(text) { - const newText = this.state.messageText + text; - this.handleUserInput(newText); - Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.textbox.refs.message), newText.length); - } removePreview(id) { const previews = Object.assign([], this.state.previews); const uploadsInProgress = this.state.uploadsInProgress; @@ -462,7 +456,6 @@ export default class CreatePost extends React.Component { onUploadStart={this.handleUploadStart} onFileUpload={this.handleFileUploadComplete} onUploadError={this.handleUploadError} - onTextDrop={this.handleTextDrop} postType='post' channelId='' /> diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 9316ca9a5..8c7353e86 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -109,8 +109,6 @@ export default class FileUpload extends React.Component { if (typeof files !== 'string' && files.length) { this.uploadFiles(files); - } else { - this.props.onTextDrop(e.originalEvent.dataTransfer.getData('Text')); } } @@ -120,11 +118,19 @@ export default class FileUpload extends React.Component { if (this.props.postType === 'post') { $('.row.main').dragster({ - enter() { - $('.center-file-overlay').removeClass('hidden'); + enter(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.center-file-overlay').removeClass('hidden'); + } }, - leave() { - $('.center-file-overlay').addClass('hidden'); + leave(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.center-file-overlay').addClass('hidden'); + } }, drop(dragsterEvent, e) { $('.center-file-overlay').addClass('hidden'); @@ -133,11 +139,19 @@ export default class FileUpload extends React.Component { }); } else if (this.props.postType === 'comment') { $('.post-right__container').dragster({ - enter() { - $('.right-file-overlay').removeClass('hidden'); + enter(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.right-file-overlay').removeClass('hidden'); + } }, - leave() { - $('.right-file-overlay').addClass('hidden'); + leave(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (utils.isFileTransfer(files)) { + $('.right-file-overlay').addClass('hidden'); + } }, drop(dragsterEvent, e) { $('.right-file-overlay').addClass('hidden'); diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 33aae7d1e..95eca7c3a 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -1276,3 +1276,9 @@ export function fillArray(value, length) { return arr; } + +// Checks if a data transfer contains files not text, folders, etc.. +// Slightly modified from http://stackoverflow.com/questions/6848043/how-do-i-detect-a-file-is-being-dragged-rather-than-a-draggable-element-on-my-pa +export function isFileTransfer(files) { + return files.types != null && (files.types.indexOf ? files.types.indexOf('Files') !== -1 : files.types.contains('application/x-moz-file')); +} -- cgit v1.2.3-1-g7c22 From d9f5e0097b28ba5efa105fea3c7da0bfbeb49070 Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Thu, 7 Jan 2016 13:07:22 +0500 Subject: Multiple UI Improvements --- web/react/components/file_attachment.jsx | 2 +- web/react/components/post_info.jsx | 2 +- web/react/components/posts_view.jsx | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'web/react') diff --git a/web/react/components/file_attachment.jsx b/web/react/components/file_attachment.jsx index c10269680..eeb218bfe 100644 --- a/web/react/components/file_attachment.jsx +++ b/web/react/components/file_attachment.jsx @@ -266,7 +266,7 @@ export default class FileAttachment extends React.Component { href={fileUrl} download={filenameString} data-toggle='tooltip' - title={'Download ' + filenameString} + title={'Download \"' + filenameString + '\"'} className='post-image__name' > {trimmedFilename} diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index 21683bb01..26bd6adde 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -223,13 +223,13 @@ export default class PostInfo extends React.Component { />
  • - {comments}
    {dropdown}
    + {comments} ReactDOM.findDOMNode(this.refs.dotMenu)} diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx index a28efbd04..41262f2da 100644 --- a/web/react/components/posts_view.jsx +++ b/web/react/components/posts_view.jsx @@ -24,6 +24,7 @@ export default class PostsView extends React.Component { this.updateScrolling = this.updateScrolling.bind(this); this.handleResize = this.handleResize.bind(this); this.scrollToBottom = this.scrollToBottom.bind(this); + this.scrollToBottomAnimated = this.scrollToBottomAnimated.bind(this); this.jumpToPostNode = null; this.wasAtBottom = true; @@ -339,6 +340,10 @@ export default class PostsView extends React.Component { this.refs.postlist.scrollTop = this.refs.postlist.scrollHeight; }); } + scrollToBottomAnimated() { + var postList = $(this.refs.postlist); + postList.animate({scrollTop:this.refs.postlist.scrollHeight}, '500'); + } componentDidMount() { if (this.props.postList != null) { this.updateScrolling(); @@ -458,7 +463,7 @@ export default class PostsView extends React.Component {
    Date: Thu, 7 Jan 2016 10:25:56 -0500 Subject: Made ChannelInviteModal pull all channel members before rendering --- web/react/components/channel_invite_modal.jsx | 31 +++++++++++++++++++++------ web/react/utils/async_client.jsx | 3 ++- web/react/utils/client.jsx | 11 ++++++++-- 3 files changed, 35 insertions(+), 10 deletions(-) (limited to 'web/react') diff --git a/web/react/components/channel_invite_modal.jsx b/web/react/components/channel_invite_modal.jsx index 7dac39942..8b7485e5f 100644 --- a/web/react/components/channel_invite_modal.jsx +++ b/web/react/components/channel_invite_modal.jsx @@ -20,9 +20,14 @@ export default class ChannelInviteModal extends React.Component { this.onListenerChange = this.onListenerChange.bind(this); this.handleInvite = this.handleInvite.bind(this); - this.state = this.getStateFromStores(); + // the state gets populated when the modal is shown + this.state = {}; } shouldComponentUpdate(nextProps, nextState) { + if (!this.props.show && !nextProps.show) { + return false; + } + if (!Utils.areObjectsEqual(this.props, nextProps)) { return true; } @@ -34,13 +39,25 @@ export default class ChannelInviteModal extends React.Component { return false; } getStateFromStores() { - function getId(user) { - return user.id; + const users = UserStore.getActiveOnlyProfiles(); + + if ($.isEmptyObject(users)) { + return { + loading: true + }; + } + + // make sure we have all members of this channel before rendering + const extraInfo = ChannelStore.getCurrentExtraInfo(); + if (extraInfo.member_count !== extraInfo.members.length) { + AsyncClient.getChannelExtraInfo(this.props.channel.id, -1); + + return { + loading: true + }; } - var users = UserStore.getActiveOnlyProfiles(); - var memberIds = ChannelStore.getCurrentExtraInfo().members.map(getId); - var loading = $.isEmptyObject(users); + const memberIds = extraInfo.members.map((user) => user.id); var nonmembers = []; for (var id in users) { @@ -55,7 +72,7 @@ export default class ChannelInviteModal extends React.Component { return { nonmembers, - loading + loading: false }; } onShow() { diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx index f218270da..0ee89b9fa 100644 --- a/web/react/utils/async_client.jsx +++ b/web/react/utils/async_client.jsx @@ -168,7 +168,7 @@ export function getMoreChannels(force) { } } -export function getChannelExtraInfo(id) { +export function getChannelExtraInfo(id, memberLimit) { let channelId; if (id) { channelId = id; @@ -185,6 +185,7 @@ export function getChannelExtraInfo(id) { client.getChannelExtraInfo( channelId, + memberLimit, (data, textStatus, xhr) => { callTracker['getChannelExtraInfo_' + channelId] = 0; diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index e1c331aff..96d1ef720 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -824,10 +824,17 @@ export function getChannelCounts(success, error) { }); } -export function getChannelExtraInfo(id, success, error) { +export function getChannelExtraInfo(id, memberLimit, success, error) { + let url = '/api/v1/channels/' + id + '/extra_info'; + + if (memberLimit) { + url += '/' + memberLimit; + } + $.ajax({ - url: '/api/v1/channels/' + id + '/extra_info', + url, dataType: 'json', + contentType: 'application/json', type: 'GET', success, error: function onError(xhr, status, err) { -- cgit v1.2.3-1-g7c22 From d7230e8753c848725ba5b61d11b29b6280fce94b Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 7 Jan 2016 10:26:43 -0500 Subject: Added a loading screen to ChannelMembersModal and made it pull all channel members before rendering --- web/react/components/channel_members_modal.jsx | 49 +++++++++++++++++++------- 1 file changed, 36 insertions(+), 13 deletions(-) (limited to 'web/react') diff --git a/web/react/components/channel_members_modal.jsx b/web/react/components/channel_members_modal.jsx index d1b9df988..513a720e7 100644 --- a/web/react/components/channel_members_modal.jsx +++ b/web/react/components/channel_members_modal.jsx @@ -1,6 +1,7 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import LoadingScreen from './loading_screen.jsx'; import MemberList from './member_list.jsx'; import ChannelInviteModal from './channel_invite_modal.jsx'; @@ -21,9 +22,10 @@ export default class ChannelMembersModal extends React.Component { this.onChange = this.onChange.bind(this); this.handleRemove = this.handleRemove.bind(this); - const state = this.getStateFromStores(); - state.showInviteModal = false; - this.state = state; + // the rest of the state gets populated when the modal is shown + this.state = { + showInviteModal: false + }; } shouldComponentUpdate(nextProps, nextState) { if (!Utils.areObjectsEqual(this.props, nextProps)) { @@ -37,8 +39,18 @@ export default class ChannelMembersModal extends React.Component { return false; } getStateFromStores() { + const extraInfo = ChannelStore.getCurrentExtraInfo(); + + if (extraInfo.member_count !== extraInfo.members.length) { + AsyncClient.getChannelExtraInfo(this.props.channel.id, -1); + + return { + loading: true + }; + } + const users = UserStore.getActiveOnlyProfiles(); - const memberList = ChannelStore.getCurrentExtraInfo().members; + const memberList = extraInfo.members; const nonmemberList = []; for (const id in users) { @@ -71,14 +83,14 @@ export default class ChannelMembersModal extends React.Component { return { nonmemberList, - memberList + memberList, + loading: false }; } onShow() { if ($(window).width() > 768) { $(ReactDOM.findDOMNode(this.refs.modalBody)).perfectScrollbar(); } - this.onChange(); } componentDidUpdate(prevProps) { if (this.props.show && !prevProps.show) { @@ -89,6 +101,8 @@ export default class ChannelMembersModal extends React.Component { if (!this.props.show && nextProps.show) { ChannelStore.addExtraInfoChangeListener(this.onChange); ChannelStore.addChangeListener(this.onChange); + + this.onChange(); } else if (this.props.show && !nextProps.show) { ChannelStore.removeExtraInfoChangeListener(this.onChange); ChannelStore.removeChangeListener(this.onChange); @@ -154,6 +168,21 @@ export default class ChannelMembersModal extends React.Component { isAdmin = Utils.isAdmin(currentMember.roles) || Utils.isAdmin(UserStore.getCurrentUser().roles); } + let content; + if (this.state.loading) { + content = (); + } else { + content = ( +
    + +
    + ); + } + return (
    -
    - -
    + {content} + >{'Add another'}

    - People invited automatically join Town Square channel. + {'People invited automatically join the '}{defaultChannelName}{' channel.'}
    ); -- cgit v1.2.3-1-g7c22 From 7f1f7885e73b2e54b590adc2207d807cf72b3843 Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Fri, 8 Jan 2016 12:01:20 +0500 Subject: Updating fix --- web/react/components/posts_view.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/react') diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx index 41262f2da..7d8c7e265 100644 --- a/web/react/components/posts_view.jsx +++ b/web/react/components/posts_view.jsx @@ -342,7 +342,7 @@ export default class PostsView extends React.Component { } scrollToBottomAnimated() { var postList = $(this.refs.postlist); - postList.animate({scrollTop:this.refs.postlist.scrollHeight}, '500'); + postList.animate({scrollTop: this.refs.postlist.scrollHeight}, '500'); } componentDidMount() { if (this.props.postList != null) { -- cgit v1.2.3-1-g7c22 From c2f7aadfa7fad3e6058af5c3be6d40d48727d8ac Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 8 Jan 2016 09:25:44 -0500 Subject: Fixed FileUpload to properly unbind drag handlers when unmounted --- web/react/components/file_upload.jsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'web/react') diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 8c7353e86..a0c930ffb 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -243,6 +243,18 @@ export default class FileUpload extends React.Component { }); } + componentWillUnmount() { + let target; + if (this.props.postType === 'post') { + target = $('.row.main'); + } else { + target = $('.post-right__container'); + } + + // jquery-dragster doesn't provide a function to unregister itself so do it manually + target.off('dragenter dragleave dragover drop dragster:enter dragster:leave dragster:over dragster:drop'); + } + cancelUpload(clientId) { var requests = this.state.requests; var request = requests[clientId]; -- cgit v1.2.3-1-g7c22 From bfc3012e6a059dc89b69b41ab3fe1fc43f1406f5 Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 9 Jan 2016 21:39:19 -0800 Subject: Documenting how Preview Mode turns off --- web/react/components/admin_console/email_settings.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx index 91d73dccd..48727e616 100644 --- a/web/react/components/admin_console/email_settings.jsx +++ b/web/react/components/admin_console/email_settings.jsx @@ -254,7 +254,7 @@ export default class EmailSettings extends React.Component { /> {'false'} -

    {'Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.'}

    +

    {'Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.\nSetting this to true removes the Preview Mode banner after logging out and logging back in.'}

    -- cgit v1.2.3-1-g7c22 From bf1f0d03191165b5735e1a4f5850971b507ec513 Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 9 Jan 2016 21:43:42 -0800 Subject: Update email_settings.jsx --- web/react/components/admin_console/email_settings.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx index 48727e616..6aec3c7b1 100644 --- a/web/react/components/admin_console/email_settings.jsx +++ b/web/react/components/admin_console/email_settings.jsx @@ -254,7 +254,7 @@ export default class EmailSettings extends React.Component { /> {'false'} -

    {'Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.\nSetting this to true removes the Preview Mode banner after logging out and logging back in.'}

    +

    {'Typically set to true in production. When true, Mattermost attempts to send email notifications. Developers may set this field to false to skip email setup for faster development.\nSetting this to true removes the Preview Mode banner (requires logging out and logging back in after setting is changed).'}

    -- cgit v1.2.3-1-g7c22 From e9c2fd7cbb0fd35531096af89345d400125809f0 Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 11 Jan 2016 20:32:31 +0500 Subject: Adding away icon and changing online and offline icons --- web/react/components/sidebar.jsx | 2 +- web/react/components/user_settings/import_theme_modal.jsx | 1 + web/react/utils/constants.jsx | 13 +++++++++++-- web/react/utils/utils.jsx | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'web/react') diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 18c360cb8..eaeb7bb91 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -372,7 +372,7 @@ export default class Sidebar extends React.Component { if (channel.status === 'online') { statusIcon = Constants.ONLINE_ICON_SVG; } else if (channel.status === 'away') { - statusIcon = Constants.ONLINE_ICON_SVG; + statusIcon = Constants.AWAY_ICON_SVG; } else { statusIcon = Constants.OFFLINE_ICON_SVG; } diff --git a/web/react/components/user_settings/import_theme_modal.jsx b/web/react/components/user_settings/import_theme_modal.jsx index 3df9dfedf..45b05f19b 100644 --- a/web/react/components/user_settings/import_theme_modal.jsx +++ b/web/react/components/user_settings/import_theme_modal.jsx @@ -55,6 +55,7 @@ export default class ImportThemeModal extends React.Component { theme.sidebarHeaderBg = colors[1]; theme.sidebarHeaderTextColor = colors[5]; theme.onlineIndicator = colors[6]; + theme.awayIndicator = '#E0B333'; theme.mentionBj = colors[7]; theme.mentionColor = '#ffffff'; theme.centerChannelBg = '#ffffff'; diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 0298ce533..d6ccb9edd 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -163,8 +163,9 @@ export default { OPEN_TEAM: 'O', MAX_POST_LEN: 4000, EMOJI_SIZE: 16, - ONLINE_ICON_SVG: "", - OFFLINE_ICON_SVG: "", + ONLINE_ICON_SVG: " ", + AWAY_ICON_SVG: " ", + OFFLINE_ICON_SVG: " ", MENU_ICON: " ", COMMENT_ICON: " ", UPDATE_TYPING_MS: 5000, @@ -180,6 +181,7 @@ export default { sidebarHeaderBg: '#2f81b7', sidebarHeaderTextColor: '#FFFFFF', onlineIndicator: '#7DBE00', + awayIndicator: '#DCBD4E', mentionBj: '#136197', mentionColor: '#bfcde8', centerChannelBg: '#f2f4f8', @@ -203,6 +205,7 @@ export default { sidebarHeaderBg: '#2389d7', sidebarHeaderTextColor: '#ffffff', onlineIndicator: '#7DBE00', + awayIndicator: '#DCBD4E', mentionBj: '#2389d7', mentionColor: '#ffffff', centerChannelBg: '#ffffff', @@ -226,6 +229,7 @@ export default { sidebarHeaderBg: '#1B2C3E', sidebarHeaderTextColor: '#FFFFFF', onlineIndicator: '#55C5B2', + awayIndicator: '#A9A14C', mentionBj: '#B74A4A', mentionColor: '#FFFFFF', centerChannelBg: '#2F3E4E', @@ -249,6 +253,7 @@ export default { sidebarHeaderBg: '#1f1f1f', sidebarHeaderTextColor: '#FFFFFF', onlineIndicator: '#0177e7', + awayIndicator: '#A9A14C', mentionBj: '#0177e7', mentionColor: '#FFFFFF', centerChannelBg: '#1F1F1F', @@ -299,6 +304,10 @@ export default { id: 'onlineIndicator', uiName: 'Online Indicator' }, + { + id: 'awayIndicator', + uiName: 'Away Indicator' + }, { id: 'mentionBj', uiName: 'Mention Jewel BG' diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 95eca7c3a..c0da0e2c6 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -557,7 +557,7 @@ export function applyTheme(theme) { changeCss('@media(max-width: 768px){.settings-modal .settings-table .nav>li>a', 'color:' + theme.sidebarText, 1); changeCss('.sidebar--left .nav-pills__container li>h4, .sidebar--left .add-channel-btn', 'color:' + changeOpacity(theme.sidebarText, 0.6), 1); changeCss('.sidebar--left .add-channel-btn:hover, .sidebar--left .add-channel-btn:focus', 'color:' + theme.sidebarText, 1); - changeCss('.sidebar--left .status path', 'fill:' + theme.sidebarText, 1); + changeCss('.sidebar--left .status .offline--icon, .sidebar--left .status .offline--icon', 'fill:' + theme.sidebarText, 1); changeCss('@media(max-width: 768px){.settings-modal .settings-table .nav>li>a', 'border-color:' + changeOpacity(theme.sidebarText, 0.2), 2); } @@ -602,6 +602,10 @@ export function applyTheme(theme) { changeCss('.sidebar--left .status .online--icon', 'fill:' + theme.onlineIndicator, 1); } + if (theme.awayIndicator) { + changeCss('.sidebar--left .status .away--icon', 'fill:' + theme.awayIndicator, 1); + } + if (theme.mentionBj) { changeCss('.sidebar--left .nav-pills__unread-indicator', 'background:' + theme.mentionBj, 1); changeCss('.sidebar--left .badge', 'background:' + theme.mentionBj, 1); -- cgit v1.2.3-1-g7c22 From 5de20f013323d59bb81f043c47c177157c4f68d3 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 9 Jan 2016 12:42:34 -0500 Subject: Restricted file uploads on iOS Chrome and the iOS app to work around iOS bugs --- web/react/components/file_upload.jsx | 29 +++++++++++++++++++++-------- web/react/utils/utils.jsx | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) (limited to 'web/react') diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index a0c930ffb..6337afabc 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -4,7 +4,7 @@ import * as client from '../utils/client.jsx'; import Constants from '../utils/constants.jsx'; import ChannelStore from '../stores/channel_store.jsx'; -import * as utils from '../utils/utils.jsx'; +import * as Utils from '../utils/utils.jsx'; export default class FileUpload extends React.Component { constructor(props) { @@ -52,7 +52,7 @@ export default class FileUpload extends React.Component { } // generate a unique id that can be used by other components to refer back to this upload - let clientId = utils.generateId(); + let clientId = Utils.generateId(); // prepare data to be uploaded var formData = new FormData(); @@ -121,14 +121,14 @@ export default class FileUpload extends React.Component { enter(dragsterEvent, e) { var files = e.originalEvent.dataTransfer; - if (utils.isFileTransfer(files)) { + if (Utils.isFileTransfer(files)) { $('.center-file-overlay').removeClass('hidden'); } }, leave(dragsterEvent, e) { var files = e.originalEvent.dataTransfer; - if (utils.isFileTransfer(files)) { + if (Utils.isFileTransfer(files)) { $('.center-file-overlay').addClass('hidden'); } }, @@ -142,14 +142,14 @@ export default class FileUpload extends React.Component { enter(dragsterEvent, e) { var files = e.originalEvent.dataTransfer; - if (utils.isFileTransfer(files)) { + if (Utils.isFileTransfer(files)) { $('.right-file-overlay').removeClass('hidden'); } }, leave(dragsterEvent, e) { var files = e.originalEvent.dataTransfer; - if (utils.isFileTransfer(files)) { + if (Utils.isFileTransfer(files)) { $('.right-file-overlay').addClass('hidden'); } }, @@ -205,7 +205,7 @@ export default class FileUpload extends React.Component { var channelId = self.props.channelId || ChannelStore.getCurrentId(); // generate a unique id that can be used by other components to refer back to this file upload - var clientId = utils.generateId(); + var clientId = Utils.generateId(); var formData = new FormData(); formData.append('channel_id', channelId); @@ -268,6 +268,18 @@ export default class FileUpload extends React.Component { } render() { + let multiple = true; + if (Utils.isMobileApp()) { + // iOS WebViews don't upload videos properly in multiple mode + multiple = false; + } + + let accept = ''; + if (Utils.isIosChrome()) { + // iOS Chrome can't upload videos at all + accept = 'image/*'; + } + return ( ); diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 95eca7c3a..2ddd0e5e3 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -74,6 +74,21 @@ export function isSafari() { return false; } +export function isIosChrome() { + // https://developer.chrome.com/multidevice/user-agent + return navigator.userAgent.indexOf('CriOS') !== -1; +} + +export function isMobileApp() { + const userAgent = navigator.userAgent; + + // the mobile app has different user agents for the native api calls and the shim, so handle them both + const isApi = userAgent.indexOf('Mattermost') !== -1; + const isShim = userAgent.indexOf('iPhone') !== -1 && userAgent.indexOf('Safari') === -1 && userAgent.indexOf('Chrome') === -1; + + return isApi || isShim; +} + export function isInRole(roles, inRole) { var parts = roles.split(' '); for (var i = 0; i < parts.length; i++) { -- cgit v1.2.3-1-g7c22 From fff7143a3175458d5a938cc91973ba475dc45456 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Mon, 11 Jan 2016 09:42:11 -0800 Subject: Changed statistics to show usernames with an email tooltip --- .../components/admin_console/team_analytics.jsx | 44 ++++++++++++++++++++-- web/react/components/channel_header.jsx | 2 +- web/react/components/time_since.jsx | 3 +- web/react/utils/constants.jsx | 3 +- 4 files changed, 45 insertions(+), 7 deletions(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx index e28699d3c..fe7230946 100644 --- a/web/react/components/admin_console/team_analytics.jsx +++ b/web/react/components/admin_console/team_analytics.jsx @@ -3,8 +3,12 @@ import * as Client from '../../utils/client.jsx'; import * as Utils from '../../utils/utils.jsx'; +import Constants from '../../utils/constants.jsx'; import LineChart from './line_chart.jsx'; +var Tooltip = ReactBootstrap.Tooltip; +var OverlayTrigger = ReactBootstrap.OverlayTrigger; + export default class TeamAnalytics extends React.Component { constructor(props) { super(props); @@ -314,9 +318,25 @@ export default class TeamAnalytics extends React.Component { { this.state.recent_active_users.map((user) => { + const tooltip = ( + + {user.email} + + ); + return ( - - {user.email} + + + + + + {Utils.displayDateTime(user.last_activity_at)} ); @@ -347,9 +367,25 @@ export default class TeamAnalytics extends React.Component { { this.state.newly_created_users.map((user) => { + const tooltip = ( + + {user.email} + + ); + return ( - - {user.email} + + + + + + {Utils.displayDateTime(user.create_at)} ); diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index 59ceb038e..f64834775 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -379,7 +379,7 @@ export default class ChannelHeader extends React.Component {
    diff --git a/web/react/components/time_since.jsx b/web/react/components/time_since.jsx index cffff6ee7..32947bd60 100644 --- a/web/react/components/time_since.jsx +++ b/web/react/components/time_since.jsx @@ -1,6 +1,7 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import Constants from '../utils/constants.jsx'; import * as Utils from '../utils/utils.jsx'; var Tooltip = ReactBootstrap.Tooltip; @@ -30,7 +31,7 @@ export default class TimeSince extends React.Component { return ( diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 0298ce533..f3fca0f7e 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -443,5 +443,6 @@ export default { label: 'embed_preview', description: 'Show preview snippet of links below message' } - } + }, + OVERLAY_TIME_DELAY: 400 }; -- cgit v1.2.3-1-g7c22 From 22f714bd029a25230b4e1caeb12e7fce512834d2 Mon Sep 17 00:00:00 2001 From: it33 Date: Mon, 11 Jan 2016 11:22:13 -0800 Subject: Adding push-test.mattermost.com --- web/react/components/admin_console/email_settings.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx index 91d73dccd..193fd4147 100644 --- a/web/react/components/admin_console/email_settings.jsx +++ b/web/react/components/admin_console/email_settings.jsx @@ -581,12 +581,12 @@ export default class EmailSettings extends React.Component { className='form-control' id='PushNotificationServer' ref='PushNotificationServer' - placeholder='E.g.: "https://push.mattermost.com"' + placeholder='E.g.: "https://push-test.mattermost.com"' defaultValue={this.props.config.EmailSettings.PushNotificationServer} onChange={this.handleChange} disabled={!this.state.sendPushNotifications} /> -

    {'Location of Mattermost push notification service you can set up behind your firewall using https://github.com/mattermost/push-proxy. For testing you can use https://push.mattermost.com, which connects to the sample Mattermost iOS app in the public Apple AppStore. Please do not use test service for production deployments.'}

    +

    {'Location of Mattermost push notification service you can set up behind your firewall using https://github.com/mattermost/push-proxy. For testing you can use https://push-test.mattermost.com, which connects to the sample Mattermost iOS app in the public Apple AppStore. Please do not use test service for production deployments.'}

    -- cgit v1.2.3-1-g7c22 From 9110dd54a15f3d0fcf6f60936e01d816b667b93c Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Mon, 4 Jan 2016 12:44:22 -0500 Subject: Added license validation and settings --- web/react/components/about_build_modal.jsx | 24 ++- .../components/admin_console/admin_controller.jsx | 3 + .../components/admin_console/admin_sidebar.jsx | 32 +++ .../components/admin_console/ldap_settings.jsx | 32 ++- .../components/admin_console/license_settings.jsx | 232 +++++++++++++++++++++ web/react/components/file_upload.jsx | 27 +-- web/react/utils/client.jsx | 35 ++++ web/react/utils/utils.jsx | 31 ++- 8 files changed, 391 insertions(+), 25 deletions(-) create mode 100644 web/react/components/admin_console/license_settings.jsx (limited to 'web/react') diff --git a/web/react/components/about_build_modal.jsx b/web/react/components/about_build_modal.jsx index 3143bec22..d54214632 100644 --- a/web/react/components/about_build_modal.jsx +++ b/web/react/components/about_build_modal.jsx @@ -15,6 +15,19 @@ export default class AboutBuildModal extends React.Component { render() { const config = global.window.mm_config; + const license = global.window.mm_license; + + let title = 'Team Edition'; + let licensee; + if (config.BuildEnterpriseReady === 'true' && license.IsLicensed === 'true') { + title = 'Enterprise Edition'; + licensee = ( +
    +
    {'Licensed by:'}
    +
    {license.Company}
    +
    + ); + } return ( - {`Mattermost ${config.Version}`} + {'About Mattermost'} +
    +
    {'Edition:'}
    +
    {`Mattermost ${title}`}
    +
    + {licensee} +
    +
    {'Version:'}
    +
    {config.Version}
    +
    {'Build Number:'}
    {config.BuildNumber}
    diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index 32b2e9bb7..0f85c238d 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -22,6 +22,7 @@ import LegalAndSupportSettingsTab from './legal_and_support_settings.jsx'; import TeamUsersTab from './team_users.jsx'; import TeamAnalyticsTab from './team_analytics.jsx'; import LdapSettingsTab from './ldap_settings.jsx'; +import LicenseSettingsTab from './license_settings.jsx'; export default class AdminController extends React.Component { constructor(props) { @@ -154,6 +155,8 @@ export default class AdminController extends React.Component { tab = ; } else if (this.state.selected === 'ldap_settings') { tab = ; + } else if (this.state.selected === 'license') { + tab = ; } else if (this.state.selected === 'team_users') { if (this.state.teams) { tab = ; diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index 1279f4d22..5a5eaa055 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -155,6 +155,36 @@ export default class AdminSidebar extends React.Component { } } + let ldapSettings; + let licenseSettings; + if (global.window.mm_config.BuildEnterpriseReady === 'true') { + if (global.window.mm_license.IsLicensed === 'true') { + ldapSettings = ( +
  • + + {'LDAP Settings'} + +
  • + ); + } + + licenseSettings = ( +
  • + + {'Edition and License'} + +
  • + ); + } + return (
    @@ -252,6 +282,7 @@ export default class AdminSidebar extends React.Component { {'GitLab Settings'} + {ldapSettings}
    • + {licenseSettings}
    • + const licenseEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.LDAP === 'true'; + + let bannerContent; + if (licenseEnabled) { + bannerContent = (

      {'Note:'}

      {'If a user attribute changes on the LDAP 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 an LDAP server. Synchronization with LDAP servers is planned in a future release.'}

      + ); + } else { + bannerContent = ( +
      + ); + } + + return ( +
      + {bannerContent}

      {'LDAP Settings'}

      {'true'} diff --git a/web/react/components/admin_console/license_settings.jsx b/web/react/components/admin_console/license_settings.jsx new file mode 100644 index 000000000..d49056601 --- /dev/null +++ b/web/react/components/admin_console/license_settings.jsx @@ -0,0 +1,232 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import * as Utils from '../../utils/utils.jsx'; +import * as Client from '../../utils/client.jsx'; + +export default class LicenseSettings extends React.Component { + constructor(props) { + super(props); + + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.handleRemove = this.handleRemove.bind(this); + + this.state = { + fileSelected: false, + serverError: null + }; + } + + handleChange() { + const element = $(ReactDOM.findDOMNode(this.refs.fileInput)); + if (element.prop('files').length > 0) { + this.setState({fileSelected: true}); + } + } + + handleSubmit(e) { + e.preventDefault(); + + const element = $(ReactDOM.findDOMNode(this.refs.fileInput)); + if (element.prop('files').length === 0) { + return; + } + const file = element.prop('files')[0]; + + $('#upload-button').button('loading'); + + const formData = new FormData(); + formData.append('license', file, file.name); + + Client.uploadLicenseFile(formData, + () => { + Utils.clearFileInput(element[0]); + $('#upload-button').button('reset'); + window.location.reload(true); + }, + (serverError) => { + this.setState({serverError}); + } + ); + } + + handleRemove(e) { + e.preventDefault(); + + $('#remove-button').button('loading'); + + Client.removeLicenseFile( + () => { + $('#remove-button').button('reset'); + window.location.reload(true); + }, + (serverError) => { + $('#remove-button').button('reset'); + this.setState({serverError}); + } + ); + } + + render() { + var serverError = ''; + if (this.state.serverError) { + serverError =
      ; + } + + var btnClass = 'btn'; + if (this.state.fileSelected) { + btnClass = 'btn btn-primary'; + } + + let edition; + let licenseType; + let licenseKey; + + if (global.window.mm_license.IsLicensed === 'true') { + edition = 'Mattermost Enterprise Edition. Designed for enterprise-scale communication.'; + licenseType = ( +
      +

      + {'This compiled release of Mattermost platform is provided under a '} + + {'commercial license'} + + {' from Mattermost, Inc. based on your subscription level and is subject to the '} + + {'Terms of Service.'} + +

      +

      {'Your subscription details are as follows:'}

      + {'Name: ' + global.window.mm_license.Name} +
      + {'Company or organization name: ' + global.window.mm_license.Company} +
      + {'Number of users: ' + global.window.mm_license.Users} +
      + {`License issued: ${Utils.displayDate(parseInt(global.window.mm_license.IssuedAt, 10))} ${Utils.displayTime(parseInt(global.window.mm_license.IssuedAt, 10), true)}`} +
      + {'Start date of license: ' + Utils.displayDate(parseInt(global.window.mm_license.StartsAt, 10))} +
      + {'Expiry date of license: ' + Utils.displayDate(parseInt(global.window.mm_license.ExpiresAt, 10))} +
      + {'LDAP: ' + global.window.mm_license.LDAP} +
      +
      + ); + + licenseKey = ( +
      + +
      +
      +

      + {'If you’re migrating servers you may need to remove your license key from this server in order to install it on a new server. To start, '} + + {'disable all Enterprise Edition features on this server'} + + {'. This will enable the ability to remove the license key and downgrade this server from Enterprise Edition to Team Edition.'} +

      +
      + ); + } else { + edition = 'Mattermost Team Edition. Designed for teams from 5 to 50 users.'; + + licenseType = ( + +

      {'This compiled release of Mattermost platform is offered under an MIT license.'}

      +

      {'See MIT-COMPILED-LICENSE.txt in your root install directory for details. See NOTICES.txt for information about open source software used in this system.'}

      +
      + ); + + licenseKey = ( +
      + + {serverError} + +
      +
      +

      + {'Upload a license key for Mattermost Enterprise Edition to upgrade this server. '} + + {'Visit us online'} + + {' to learn more about the benefits of Enterprise Edition or to purchase a key.'} +

      +
      + ); + } + + return ( +
      +

      {'Edition and License'}

      + +
      + +
      + {edition} +
      +
      +
      + +
      + {licenseType} +
      +
      +
      + + {licenseKey} +
      + +
      + ); + } +} diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 6337afabc..fef253c52 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -1,7 +1,7 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import * as client from '../utils/client.jsx'; +import * as Client from '../utils/client.jsx'; import Constants from '../utils/constants.jsx'; import ChannelStore from '../stores/channel_store.jsx'; import * as Utils from '../utils/utils.jsx'; @@ -26,7 +26,7 @@ export default class FileUpload extends React.Component { for (var j = 0; j < data.client_ids.length; j++) { delete requests[data.client_ids[j]]; } - this.setState({requests: requests}); + this.setState({requests}); } fileUploadFail(clientId, err) { @@ -52,7 +52,7 @@ export default class FileUpload extends React.Component { } // generate a unique id that can be used by other components to refer back to this upload - let clientId = Utils.generateId(); + const clientId = Utils.generateId(); // prepare data to be uploaded var formData = new FormData(); @@ -60,14 +60,14 @@ export default class FileUpload extends React.Component { formData.append('files', files[i], files[i].name); formData.append('client_ids', clientId); - var request = client.uploadFile(formData, + var request = Client.uploadFile(formData, this.fileUploadSuccess.bind(this, channelId), this.fileUploadFail.bind(this, clientId) ); var requests = this.state.requests; requests[clientId] = request; - this.setState({requests: requests}); + this.setState({requests}); this.props.onUploadStart([clientId], channelId); @@ -90,16 +90,7 @@ export default class FileUpload extends React.Component { this.uploadFiles(element.prop('files')); - // clear file input for all modern browsers - try { - element[0].value = ''; - if (element.value) { - element[0].type = 'text'; - element[0].type = 'file'; - } - } catch (e) { - // Do nothing - } + Utils.clearFileInput(element[0]); } handleDrop(e) { @@ -227,14 +218,14 @@ export default class FileUpload extends React.Component { formData.append('files', file, name); formData.append('client_ids', clientId); - var request = client.uploadFile(formData, + var request = Client.uploadFile(formData, self.fileUploadSuccess.bind(self, channelId), self.fileUploadFail.bind(self, clientId) ); var requests = self.state.requests; requests[clientId] = request; - self.setState({requests: requests}); + self.setState({requests}); self.props.onUploadStart([clientId], channelId); } @@ -263,7 +254,7 @@ export default class FileUpload extends React.Component { request.abort(); delete requests[clientId]; - this.setState({requests: requests}); + this.setState({requests}); } } diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index 96d1ef720..d60fea872 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -1392,3 +1392,38 @@ export function regenOutgoingHookToken(data, success, error) { } }); } + +export function uploadLicenseFile(formData, success, error) { + $.ajax({ + url: '/api/v1/license/add', + type: 'POST', + data: formData, + cache: false, + contentType: false, + processData: false, + success, + error: function onError(xhr, status, err) { + var e = handleError('uploadLicenseFile', xhr, status, err); + error(e); + } + }); + + track('api', 'api_license_upload'); +} + +export function removeLicenseFile(success, error) { + $.ajax({ + url: '/api/v1/license/remove', + type: 'POST', + cache: false, + contentType: false, + processData: false, + success, + error: function onError(xhr, status, err) { + var e = handleError('removeLicenseFile', xhr, status, err); + error(e); + } + }); + + track('api', 'api_license_upload'); +} diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 31bb2ba0b..24042321f 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -201,11 +201,21 @@ export function displayDate(ticks) { return monthNames[d.getMonth()] + ' ' + d.getDate() + ', ' + d.getFullYear(); } -export function displayTime(ticks) { +export function displayTime(ticks, utc) { const d = new Date(ticks); - let hours = d.getHours(); - let minutes = d.getMinutes(); + let hours; + let minutes; let ampm = ''; + let timezone = ''; + + if (utc) { + hours = d.getUTCHours(); + minutes = d.getUTCMinutes(); + timezone = ' UTC'; + } else { + hours = d.getHours(); + minutes = d.getMinutes(); + } if (minutes <= 9) { minutes = '0' + minutes; @@ -224,7 +234,7 @@ export function displayTime(ticks) { } } - return hours + ':' + minutes + ampm; + return hours + ':' + minutes + ampm + timezone; } export function displayDateTime(ticks) { @@ -1301,3 +1311,16 @@ export function fillArray(value, length) { export function isFileTransfer(files) { return files.types != null && (files.types.indexOf ? files.types.indexOf('Files') !== -1 : files.types.contains('application/x-moz-file')); } + +export function clearFileInput(elm) { + // clear file input for all modern browsers + try { + elm.value = ''; + if (elm.value) { + elm.type = 'text'; + elm.type = 'file'; + } + } catch (e) { + // Do nothing + } +} -- cgit v1.2.3-1-g7c22 From 537a220d070371b1a6f30a6144570a1e63a3a88e Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Wed, 13 Jan 2016 11:12:46 -0500 Subject: Minor update to about modal --- web/react/components/about_build_modal.jsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'web/react') diff --git a/web/react/components/about_build_modal.jsx b/web/react/components/about_build_modal.jsx index d54214632..f70027498 100644 --- a/web/react/components/about_build_modal.jsx +++ b/web/react/components/about_build_modal.jsx @@ -38,10 +38,7 @@ export default class AboutBuildModal extends React.Component { {'About Mattermost'} -
      -
      {'Edition:'}
      -
      {`Mattermost ${title}`}
      -
      +

      {`Mattermost ${title}`}

      {licensee}
      {'Version:'}
      -- cgit v1.2.3-1-g7c22 From 22c522178ce5a4b9e9533d91dd77518a2899f2b0 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Wed, 13 Jan 2016 12:56:35 -0500 Subject: Fix error message --- web/react/components/admin_console/license_settings.jsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/license_settings.jsx b/web/react/components/admin_console/license_settings.jsx index d49056601..ba953f3bd 100644 --- a/web/react/components/admin_console/license_settings.jsx +++ b/web/react/components/admin_console/license_settings.jsx @@ -43,10 +43,13 @@ export default class LicenseSettings extends React.Component { () => { Utils.clearFileInput(element[0]); $('#upload-button').button('reset'); + this.setState({serverError: null}); window.location.reload(true); }, - (serverError) => { - this.setState({serverError}); + (error) => { + Utils.clearFileInput(element[0]); + $('#upload-button').button('reset'); + this.setState({serverError: error.message}); } ); } @@ -59,11 +62,12 @@ export default class LicenseSettings extends React.Component { Client.removeLicenseFile( () => { $('#remove-button').button('reset'); + this.setState({serverError: null}); window.location.reload(true); }, - (serverError) => { + (error) => { $('#remove-button').button('reset'); - this.setState({serverError}); + this.setState({serverError: error.message}); } ); } @@ -164,7 +168,6 @@ export default class LicenseSettings extends React.Component { accept='.mattermost-license' onChange={this.handleChange} /> - {serverError}