diff options
Diffstat (limited to 'webapp')
-rw-r--r-- | webapp/actions/websocket_actions.jsx | 3 | ||||
-rw-r--r-- | webapp/components/admin_console/storage_settings.jsx | 20 | ||||
-rw-r--r-- | webapp/components/create_post.jsx | 7 | ||||
-rw-r--r-- | webapp/components/file_upload.jsx | 100 | ||||
-rwxr-xr-x | webapp/i18n/en.json | 3 | ||||
-rw-r--r-- | webapp/root.jsx | 14 | ||||
-rw-r--r-- | webapp/sass/responsive/_tablet.scss | 16 | ||||
-rw-r--r-- | webapp/stores/browser_store.jsx | 13 | ||||
-rw-r--r-- | webapp/utils/async_client.jsx | 19 |
9 files changed, 133 insertions, 62 deletions
diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index c6de42647..4d2b5a2b5 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -35,6 +35,7 @@ import store from 'stores/redux_store.jsx'; const dispatch = store.dispatch; const getState = store.getState; import {viewChannel, getChannelAndMyMember, getChannelStats} from 'mattermost-redux/actions/channels'; +import {setServerVersion} from 'mattermost-redux/actions/general'; import {ChannelTypes} from 'mattermost-redux/action_types'; const MAX_WEBSOCKET_FAILS = 7; @@ -390,7 +391,7 @@ function handleStatusChangedEvent(msg) { function handleHelloEvent(msg) { Client.serverVersion = msg.data.server_version; - AsyncClient.checkVersion(); + setServerVersion(msg.data.server_version)(dispatch, getState); } function handleWebrtc(msg) { diff --git a/webapp/components/admin_console/storage_settings.jsx b/webapp/components/admin_console/storage_settings.jsx index 3b634dc53..1400b673c 100644 --- a/webapp/components/admin_console/storage_settings.jsx +++ b/webapp/components/admin_console/storage_settings.jsx @@ -25,6 +25,7 @@ export default class StorageSettings extends AdminSettings { } getConfigFromState(config) { + config.FileSettings.EnableFileAttachments = this.state.enableFileAttachments; config.FileSettings.MaxFileSize = this.parseInt(this.state.maxFileSize) * 1024 * 1024; config.FileSettings.DriverName = this.state.driverName; config.FileSettings.Directory = this.state.directory; @@ -39,6 +40,7 @@ export default class StorageSettings extends AdminSettings { getStateFromConfig(config) { return { + enableFileAttachments: config.FileSettings.EnableFileAttachments, maxFileSize: config.FileSettings.MaxFileSize / 1024 / 1024, driverName: config.FileSettings.DriverName, directory: config.FileSettings.Directory, @@ -199,6 +201,23 @@ export default class StorageSettings extends AdminSettings { onChange={this.handleChange} disabled={this.state.driverName !== DRIVER_S3} /> + <BooleanSetting + id='enableFileAttachments' + label={ + <FormattedMessage + id='admin.file.enableFileAttachments' + defaultMessage='Enable File Attachments:' + /> + } + helpText={ + <FormattedMessage + id='admin.file.enableFileAttachmentsDesc' + defaultMessage='When false, disable file and image uploads on messages.' + /> + } + value={this.state.enableFileAttachments} + onChange={this.handleChange} + /> <TextSetting id='maxFileSize' label={ @@ -216,6 +235,7 @@ export default class StorageSettings extends AdminSettings { } value={this.state.maxFileSize} onChange={this.handleChange} + disabled={!this.state.enableFileAttachments} /> </SettingsGroup> ); diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx index 390940914..6e59b88b1 100644 --- a/webapp/components/create_post.jsx +++ b/webapp/components/create_post.jsx @@ -630,6 +630,11 @@ export default class CreatePost extends React.Component { ); } + let attachmentsDisabled = ''; + if (global.window.mm_config.EnableFileAttachments === 'false') { + attachmentsDisabled = ' post-create--attachment-disabled'; + } + return ( <form id='create_post' @@ -638,7 +643,7 @@ export default class CreatePost extends React.Component { className={centerClass} onSubmit={this.handleSubmit} > - <div className='post-create'> + <div className={'post-create' + attachmentsDisabled}> <div className='post-create-body'> <div className='post-body__cell'> <Textbox diff --git a/webapp/components/file_upload.jsx b/webapp/components/file_upload.jsx index af5d76829..4ef8cd28c 100644 --- a/webapp/components/file_upload.jsx +++ b/webapp/components/file_upload.jsx @@ -132,6 +132,11 @@ class FileUpload extends React.Component { } handleDrop(e) { + if (global.window.mm_config.EnableFileAttachments === 'false') { + this.props.onUploadError(Utils.localizeMessage('file_upload.disabled', 'File attachments are disabled.')); + return; + } + this.props.onUploadError(null); var files = e.originalEvent.dataTransfer.files; @@ -163,36 +168,47 @@ class FileUpload extends React.Component { } }); - $(containerSelector).dragster({ - enter(dragsterEvent, e) { - var files = e.originalEvent.dataTransfer; - - if (Utils.isFileTransfer(files)) { - $(overlaySelector).removeClass('hidden'); + let dragsterActions = {}; + if (global.window.mm_config.EnableFileAttachments === 'true') { + dragsterActions = { + enter(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (Utils.isFileTransfer(files)) { + $(overlaySelector).removeClass('hidden'); + } + }, + leave(dragsterEvent, e) { + var files = e.originalEvent.dataTransfer; + + if (Utils.isFileTransfer(files) && !overlay.hasClass('hidden')) { + overlay.addClass('hidden'); + } + + dragTimeout.cancel(); + }, + over() { + dragTimeout.fireAfter(OverlayTimeout); + }, + drop(dragsterEvent, e) { + if (!overlay.hasClass('hidden')) { + overlay.addClass('hidden'); + } + + dragTimeout.cancel(); + + self.handleDrop(e); } - }, - leave(dragsterEvent, e) { - var files = e.originalEvent.dataTransfer; - - if (Utils.isFileTransfer(files) && !overlay.hasClass('hidden')) { - overlay.addClass('hidden'); - } - - dragTimeout.cancel(); - }, - over() { - dragTimeout.fireAfter(OverlayTimeout); - }, - drop(dragsterEvent, e) { - if (!overlay.hasClass('hidden')) { - overlay.addClass('hidden'); + }; + } else { + dragsterActions = { + drop(dragsterEvent, e) { + self.handleDrop(e); } + }; + } - dragTimeout.cancel(); - - self.handleDrop(e); - } - }); + $(containerSelector).dragster(dragsterActions); this.props.onFileUploadChange(); } @@ -247,7 +263,12 @@ class FileUpload extends React.Component { // This looks redundant, but must be done this way due to // setState being an asynchronous call - if (items) { + if (items && items.length > 0) { + if (global.window.mm_config.EnableFileAttachments === 'false') { + this.props.onUploadError(Utils.localizeMessage('file_upload.disabled', 'File attachments are disabled.')); + return; + } + var numToUpload = Math.min(Constants.MAX_UPLOAD_FILES - this.props.getFileCount(ChannelStore.getCurrentId()), items.length); if (items.length > numToUpload) { @@ -305,6 +326,12 @@ class FileUpload extends React.Component { keyUpload(e) { if (Utils.cmdOrCtrlPressed(e) && e.keyCode === Constants.KeyCodes.U) { e.preventDefault(); + + if (global.window.mm_config.EnableFileAttachments === 'false') { + this.props.onUploadError(Utils.localizeMessage('file_upload.disabled', 'File attachments are disabled.')); + return; + } + if ((this.props.postType === 'post' && document.activeElement.id === 'post_textbox') || (this.props.postType === 'comment' && document.activeElement.id === 'reply_textbox')) { $(this.refs.fileInput).focus().trigger('click'); @@ -361,11 +388,9 @@ class FileUpload extends React.Component { ); } - return ( - <span - ref='input' - className={'btn btn-file' + (uploadsRemaining <= 0 ? ' btn-file__disabled' : '')} - > + let fileDiv; + if (global.window.mm_config.EnableFileAttachments === 'true') { + fileDiv = ( <div className='icon--attachment'> <span className='icon' @@ -380,6 +405,15 @@ class FileUpload extends React.Component { accept={accept} /> </div> + ); + } + + return ( + <span + ref='input' + className={'btn btn-file' + (uploadsRemaining <= 0 ? ' btn-file__disabled' : '')} + > + {fileDiv} {emojiSpan} </span> ); diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 1ac5854ee..cb9d9686c 100755 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -300,6 +300,8 @@ "admin.email.smtpUsernameTitle": "SMTP Server Username:", "admin.email.testing": "Testing...", "admin.false": "false", + "admin.file.enableFileAttachments": "Enable File Attachments:", + "admin.file.enableFileAttachmentsDesc": "When false, disable file and image uploads on messages.", "admin.file_upload.chooseFile": "Choose File", "admin.file_upload.noFile": "No file uploaded", "admin.file_upload.uploadFile": "Upload", @@ -1324,6 +1326,7 @@ "file_info_preview.type": "File type ", "file_upload.fileAbove": "File above {max}MB cannot be uploaded: {filename}", "file_upload.filesAbove": "Files above {max}MB cannot be uploaded: {filenames}", + "file_upload.disabled": "File attachments are disabled.", "file_upload.limited": "Uploads limited to {count} files maximum. Please use additional posts for more files.", "file_upload.pasted": "Image Pasted at ", "filtered_channels_list.count": "{count} {count, plural, =0 {0 channels} one {channel} other {channels}}", diff --git a/webapp/root.jsx b/webapp/root.jsx index 6a63e6dad..03595f85c 100644 --- a/webapp/root.jsx +++ b/webapp/root.jsx @@ -12,7 +12,6 @@ import PDFJS from 'pdfjs-dist'; import * as Websockets from 'actions/websocket_actions.jsx'; import {loadMeAndConfig} from 'actions/user_actions.jsx'; -import BrowserStore from 'stores/browser_store.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import UserStore from 'stores/user_store.jsx'; import * as I18n from 'i18n/i18n.jsx'; @@ -86,7 +85,6 @@ function preRenderSetup(callwhendone) { () => { // Turn off to prevent getting stuck in a loop $(window).off('beforeunload'); - BrowserStore.setLastServerVersion(''); if (UserStore.getCurrentUser()) { viewChannel('', ChannelStore.getCurrentId() || '')(dispatch, getState); } @@ -120,6 +118,18 @@ function renderRootComponent() { document.getElementById('root')); } +let serverVersion = ''; + +store.subscribe(() => { + const newServerVersion = getState().entities.general.serverVersion; + if (serverVersion && serverVersion !== newServerVersion) { + console.log('Detected version update refreshing the page'); //eslint-disable-line no-console + window.location.reload(true); + } + + serverVersion = newServerVersion; +}); + global.window.setup_root = () => { // Do the pre-render setup and call renderRootComponent when done preRenderSetup(renderRootComponent); diff --git a/webapp/sass/responsive/_tablet.scss b/webapp/sass/responsive/_tablet.scss index 1a0a27267..7bf1efe2f 100644 --- a/webapp/sass/responsive/_tablet.scss +++ b/webapp/sass/responsive/_tablet.scss @@ -32,6 +32,18 @@ } .post-create__container { + .post-create { + &.post-create--attachment-disabled { + .post-body__cell { + padding-left: 1em; + } + + .post-create-footer { + padding-left: 1em; + } + } + } + form { padding: .5em 0 0; } @@ -71,6 +83,10 @@ padding: 0; top: auto; width: 25px; + + .icon--emoji-picker { + display: none; + } } } diff --git a/webapp/stores/browser_store.jsx b/webapp/stores/browser_store.jsx index b0c923594..18fcc452d 100644 --- a/webapp/stores/browser_store.jsx +++ b/webapp/stores/browser_store.jsx @@ -75,14 +75,6 @@ class BrowserStoreClass { } } - getLastServerVersion() { - return this.getGlobalItem('last_server_version'); - } - - setLastServerVersion(version) { - this.setGlobalItem('last_server_version', version); - } - signalLogout() { if (this.isLocalStorageSupported()) { // PLT-1285 store an identifier in session storage so we can catch if the logout came from this tab on IE11 @@ -144,7 +136,6 @@ class BrowserStoreClass { clear() { // persist some values through logout since they're independent of which user is logged in const logoutId = sessionStorage.getItem('__logout__'); - const serverVersion = this.getLastServerVersion(); const landingPageSeen = this.hasSeenLandingPage(); const selectedTeams = this.getItem('selected_teams'); const recentEmojis = localStorage.getItem(Constants.RECENT_EMOJI_KEY); @@ -160,10 +151,6 @@ class BrowserStoreClass { sessionStorage.setItem('__logout__', logoutId); } - if (serverVersion) { - this.setLastServerVersion(serverVersion); - } - if (landingPageSeen) { this.setLandingPageSeen(landingPageSeen); } diff --git a/webapp/utils/async_client.jsx b/webapp/utils/async_client.jsx index 712d447e8..deb967e3a 100644 --- a/webapp/utils/async_client.jsx +++ b/webapp/utils/async_client.jsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import BrowserStore from 'stores/browser_store.jsx'; import UserStore from 'stores/user_store.jsx'; import TeamStore from 'stores/team_store.jsx'; @@ -21,6 +20,12 @@ const callTracker = {}; const ASYNC_CLIENT_TIMEOUT = 5000; +// Redux actions +import store from 'stores/redux_store.jsx'; +const dispatch = store.dispatch; +const getState = store.getState; +import {setServerVersion} from 'mattermost-redux/actions/general'; + export function dispatchError(err, method) { AppDispatcher.handleServerAction({ type: ActionTypes.RECEIVED_ERROR, @@ -47,17 +52,7 @@ function isCallInProgress(callName) { } export function checkVersion() { - var serverVersion = Client.getServerVersion(); - - if (serverVersion !== BrowserStore.getLastServerVersion()) { - if (!BrowserStore.getLastServerVersion() || BrowserStore.getLastServerVersion() === '') { - BrowserStore.setLastServerVersion(serverVersion); - } else { - BrowserStore.setLastServerVersion(serverVersion); - window.location.reload(true); - console.log('Detected version update refreshing the page'); //eslint-disable-line no-console - } - } + setServerVersion(Client.getServerVersion())(dispatch, getState); } export function getUser(userId, success, error) { |