diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | web/react/components/channel_notifications.jsx | 8 | ||||
-rw-r--r-- | web/react/components/file_upload.jsx | 88 | ||||
-rw-r--r-- | web/react/components/setting_item_max.jsx | 2 | ||||
-rw-r--r-- | web/react/components/user_settings_notifications.jsx | 14 | ||||
-rw-r--r-- | web/react/package.json | 5 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 2 |
7 files changed, 49 insertions, 81 deletions
@@ -5,7 +5,7 @@ GOFLAGS ?= $(GOFLAGS:) BUILD_NUMBER ?= $(BUILD_NUMBER:) GO=$(GOPATH)/bin/godep go -ESLINT=web/react/node_modules/eslint/bin/eslint.js +ESLINT=node_modules/eslint/bin/eslint.js ifeq ($(BUILD_NUMBER),) BUILD_NUMBER := dev @@ -37,6 +37,9 @@ travis: @cd web/react/ && npm install + @echo Checking for style guide compliance + cd web/react && $(ESLINT) components/* dispatcher/* pages/* stores/* utils/* + @$(GO) build $(GOFLAGS) ./... @$(GO) install $(GOFLAGS) -a ./... @@ -103,11 +106,7 @@ install: check: install @echo Running ESLint... - @$(ESLINT) web/react/components/* - @$(ESLINT) web/react/dispatcher/* - @$(ESLINT) web/react/pages/* - @$(ESLINT) web/react/stores/* - @$(ESLINT) web/react/utils/* + -cd web/react && $(ESLINT) components/* dispatcher/* pages/* stores/* utils/* test: install @mkdir -p logs diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx index 173646597..83067240d 100644 --- a/web/react/components/channel_notifications.jsx +++ b/web/react/components/channel_notifications.jsx @@ -162,6 +162,13 @@ export default class ChannelNotifications extends React.Component { e.preventDefault(); }.bind(this); + let curChannel = ChannelStore.get(this.state.channelId); + let extraInfo = (<span>These settings will override the global notification settings</span>); + + if (curChannel && curChannel.display_name) { + extraInfo = (<span>These settings will override the global notification settings for the <b>{curChannel.display_name}</b> channel</span>); + } + return ( <SettingItemMax title='Send desktop notifications' @@ -169,6 +176,7 @@ export default class ChannelNotifications extends React.Component { submit={this.handleUpdate} server_error={serverError} updateSection={handleUpdateSection} + extraInfo={extraInfo} /> ); } diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index dcb938cbf..534f0136e 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -10,6 +10,7 @@ export default class FileUpload extends React.Component { constructor(props) { super(props); + this.uploadFiles = this.uploadFiles.bind(this); this.handleChange = this.handleChange.bind(this); this.handleDrop = this.handleDrop.bind(this); @@ -33,39 +34,28 @@ export default class FileUpload extends React.Component { this.props.onUploadError(err, clientId); } - handleChange() { - var element = $(React.findDOMNode(this.refs.fileInput)); - var files = element.prop('files'); + uploadFiles(files) { + // clear any existing errors + this.props.onUploadError(null); var channelId = this.props.channelId || ChannelStore.getCurrentId(); - this.props.onUploadError(null); - - // This looks redundant, but must be done this way due to - // setState being an asynchronous call - var numFiles = 0; - for (let i = 0; i < files.length; i++) { - if (files[i].size <= Constants.MAX_FILE_SIZE) { - numFiles++; - } - } + var uploadsRemaining = Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId); + var numUploads = 0; - var numToUpload = Math.min(Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId), numFiles); + // keep track of how many files have been too large + var tooLargeFiles = []; - if (numFiles > numToUpload) { - this.props.onUploadError('Uploads limited to ' + Constants.MAX_UPLOAD_FILES + ' files maximum. Please use additional posts for more files.'); - } - - for (let i = 0; i < files.length && i < numToUpload; i++) { + for (let i = 0; i < files.length && numUploads < uploadsRemaining; i++) { if (files[i].size > Constants.MAX_FILE_SIZE) { - this.props.onUploadError('Files must be no more than ' + Constants.MAX_FILE_SIZE / 1000000 + ' MB'); + tooLargeFiles.push(files[i]); continue; } - // generate a unique id that can be used by other components to refer back to this file upload + // generate a unique id that can be used by other components to refer back to this upload var clientId = utils.generateId(); - // Prepare data to be uploaded. + // prepare data to be uploaded var formData = new FormData(); formData.append('channel_id', channelId); formData.append('files', files[i], files[i].name); @@ -81,8 +71,26 @@ export default class FileUpload extends React.Component { this.setState({requests: requests}); this.props.onUploadStart([clientId], channelId); + + numUploads += 1; } + if (files.length > uploadsRemaining) { + this.props.onUploadError(`Uploads limited to ${Constants.MAX_UPLOAD_FILES} files maximum. Please use additional posts for more files.`); + } else if (tooLargeFiles.length > 1) { + var tooLargeFilenames = tooLargeFiles.map((file) => file.name).join(', '); + + this.props.onUploadError(`Files above ${Constants.MAX_FILE_SIZE / 1000000}MB could not be uploaded: ${tooLargeFilenames}`); + } else if (tooLargeFiles.length > 0) { + this.props.onUploadError(`File above ${Constants.MAX_FILE_SIZE / 1000000}MB could not be uploaded: ${tooLargeFiles[0].name}`); + } + } + + handleChange() { + var element = $(React.findDOMNode(this.refs.fileInput)); + + this.uploadFiles(element.prop('files')); + // clear file input for all modern browsers try { element[0].value = ''; @@ -99,43 +107,9 @@ export default class FileUpload extends React.Component { this.props.onUploadError(null); var files = e.originalEvent.dataTransfer.files; - var channelId = this.props.channelId || ChannelStore.getCurrentId(); if (typeof files !== 'string' && files.length) { - var numFiles = files.length; - - var numToUpload = Math.min(Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId), numFiles); - - if (numFiles > numToUpload) { - this.props.onUploadError('Uploads limited to ' + Constants.MAX_UPLOAD_FILES + ' files maximum. Please use additional posts for more files.'); - } - - for (var i = 0; i < files.length && i < numToUpload; i++) { - if (files[i].size > Constants.MAX_FILE_SIZE) { - this.props.onUploadError('Files must be no more than ' + Constants.MAX_FILE_SIZE / 1000000 + ' MB'); - continue; - } - - // generate a unique id that can be used by other components to refer back to this file upload - var clientId = utils.generateId(); - - // Prepare data to be uploaded. - var formData = new FormData(); - formData.append('channel_id', channelId); - formData.append('files', files[i], files[i].name); - formData.append('client_ids', clientId); - - 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.props.onUploadStart([clientId], channelId); - } + this.uploadFiles(files); } else { this.props.onUploadError('Invalid file upload', -1); } diff --git a/web/react/components/setting_item_max.jsx b/web/react/components/setting_item_max.jsx index e67e458af..996b63873 100644 --- a/web/react/components/setting_item_max.jsx +++ b/web/react/components/setting_item_max.jsx @@ -15,7 +15,7 @@ export default class SettingItemMax extends React.Component { var extraInfo = null; if (this.props.extraInfo) { - extraInfo = this.props.extraInfo; + extraInfo = (<div className='setting-list__hint'>{this.props.extraInfo}</div>); } var submit = ''; diff --git a/web/react/components/user_settings_notifications.jsx b/web/react/components/user_settings_notifications.jsx index 5fe6bbb4e..33db1a332 100644 --- a/web/react/components/user_settings_notifications.jsx +++ b/web/react/components/user_settings_notifications.jsx @@ -1,7 +1,6 @@ // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. -var ChannelStore = require('../stores/channel_store.jsx'); var UserStore = require('../stores/user_store.jsx'); var SettingItemMin = require('./setting_item_min.jsx'); var SettingItemMax = require('./setting_item_max.jsx'); @@ -69,11 +68,9 @@ function getNotificationsStateFromStores() { } } - var curChannel = ChannelStore.getCurrent().display_name; - return {notifyLevel: desktop, enableEmail: email, soundNeeded: soundNeeded, enableSound: sound, usernameKey: usernameKey, mentionKey: mentionKey, customKeys: customKeys, customKeysChecked: customKeys.length > 0, - firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey, curChannel: curChannel}; + firstNameKey: firstNameKey, allKey: allKey, channelKey: channelKey}; } export default class NotificationsTab extends React.Component { @@ -147,12 +144,10 @@ export default class NotificationsTab extends React.Component { } componentDidMount() { UserStore.addChangeListener(this.onListenerChange); - ChannelStore.addChangeListener(this.onListenerChange); $('#user_settings').on('hidden.bs.modal', this.handleClose); } componentWillUnmount() { UserStore.removeChangeListener(this.onListenerChange); - ChannelStore.removeChangeListener(this.onListenerChange); $('#user_settings').off('hidden.bs.modal', this.handleClose); this.props.updateSection(''); } @@ -271,12 +266,6 @@ export default class NotificationsTab extends React.Component { e.preventDefault(); }.bind(this); - let extraInfo = ( - <div className='setting-list__hint'> - These settings will override the global notification settings for the <b>{this.state.curChannel}</b> channel - </div> - ); - desktopSection = ( <SettingItemMax title='Send desktop notifications' @@ -284,7 +273,6 @@ export default class NotificationsTab extends React.Component { submit={this.handleSubmit} server_error={serverError} updateSection={handleUpdateDesktopSection} - extraInfo={extraInfo} /> ); } else { diff --git a/web/react/package.json b/web/react/package.json index c930c4db6..5c33e2186 100644 --- a/web/react/package.json +++ b/web/react/package.json @@ -21,13 +21,12 @@ }, "scripts": { "start": "watchify --extension=jsx -o ../static/js/bundle.js -v -d ./**/*.jsx", - "build": "NODE_ENV=production browserify ./**/*.jsx | uglifyjs > ../static/js/bundle.min.js", - "build_old": "NODE_ENV=production browserify ./**/*.jsx | uglifyjs -cm > ../static/js/bundle.min.js", + "build": "NODE_ENV=production browserify ./**/*.jsx | uglifyjs > ../static/js/bundle.min.js", "test": "jest" }, "browserify": { "transform": [ - ["babelify", {"blacklist": ["strict"]}], + "babelify", "envify" ] }, diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index dc229bd36..ea42256aa 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -457,7 +457,7 @@ export function textToJsx(textin, options) { var inner = []; // Function specific regex - var hashRegex = /^href="#[^']+"|(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$/g; + var hashRegex = /^href="#[^']+"|(^#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$/g; var implicitKeywords = UserStore.getCurrentMentionKeys(); |