From c8133c1250fe31a20c0c66918a20fb37419297ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Thu, 28 Sep 2017 11:20:36 +0200 Subject: [PATCH 01/19] xhrupload: Merge headers from different options locations --- src/plugins/XHRUpload.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/XHRUpload.js b/src/plugins/XHRUpload.js index e4a3e3fdb..8f6962b3f 100644 --- a/src/plugins/XHRUpload.js +++ b/src/plugins/XHRUpload.js @@ -62,6 +62,14 @@ module.exports = class XHRUpload extends Plugin { this.core.state.xhrUpload || {}, file.xhrUpload || {} ) + opts.headers = {} + Object.assign(opts.headers, this.opts.headers) + if (this.core.state.xhrUpload) { + Object.assign(opts.headers, this.core.state.xhrUpload.headers) + } + if (file.xhrUpload) { + Object.assign(opts.headers, file.xhrUpload.headers) + } this.core.log(`uploading ${current} of ${total}`) return new Promise((resolve, reject) => { @@ -100,14 +108,6 @@ module.exports = class XHRUpload extends Plugin { this.core.emit('core:upload-error', file.id, error) return reject(error) } - - // var upload = {} - // - // if (opts.bundle) { - // upload = {files: files} - // } else { - // upload = {file: files[current]} - // } }) xhr.addEventListener('error', (ev) => { From eee3142d4280a4cda6230814bd6ee84c34d0c4cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Thu, 28 Sep 2017 11:21:12 +0200 Subject: [PATCH 02/19] s3: Allow request headers to be returned from getUploadParameters Closes #243 This way headers like `Content-Disposition` can be added without requiring support for that on the signing server side. ```js uppy.use(AwsS3, { getUploadParameters (file) { return fetch(`/sign?name=${file.name}&type=${file.type.mime}`) .then((response) => response.json()) .then((data) => Object.assign(data, { 'Content-Disposition': file.meta.contentDisposition })) } }) // later uppy.addFile({ name: 'xyz.jpg', mime: 'image/jpeg', data: someArrayBuffer, meta: { contentDisposition: 'inline' } }) ``` --- src/plugins/AwsS3/index.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/plugins/AwsS3/index.js b/src/plugins/AwsS3/index.js index 31f6af444..aab3b442e 100644 --- a/src/plugins/AwsS3/index.js +++ b/src/plugins/AwsS3/index.js @@ -99,17 +99,24 @@ module.exports = class AwsS3 extends Plugin { const { method = 'post', url, - fields + fields, + headers } = responses[index] + const xhrOpts = { + method, + formData: method.toLowerCase() === 'post', + endpoint: url, + fieldName: 'file', + metaFields: Object.keys(fields) + } + + if (headers) { + xhrOpts.headers = headers + } + const updatedFile = Object.assign({}, file, { meta: Object.assign({}, file.meta, fields), - xhrUpload: { - method, - formData: method.toLowerCase() === 'post', - endpoint: url, - fieldName: 'file', - metaFields: Object.keys(fields) - } + xhrUpload: xhrOpts }) updatedFiles[id] = updatedFile From df6d4f06c10b481ad4cff6bd164da938234eb7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Thu, 28 Sep 2017 11:26:24 +0200 Subject: [PATCH 03/19] xhrupload: DRY options merging --- src/plugins/XHRUpload.js | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/plugins/XHRUpload.js b/src/plugins/XHRUpload.js index 8f6962b3f..3c34c6ad3 100644 --- a/src/plugins/XHRUpload.js +++ b/src/plugins/XHRUpload.js @@ -36,6 +36,24 @@ module.exports = class XHRUpload extends Plugin { this.handleUpload = this.handleUpload.bind(this) } + getOptions (file) { + const opts = Object.assign({}, + this.opts, + this.core.state.xhrUpload || {}, + file.xhrUpload || {} + ) + opts.headers = {} + Object.assign(opts.headers, this.opts.headers) + if (this.core.state.xhrUpload) { + Object.assign(opts.headers, this.core.state.xhrUpload.headers) + } + if (file.xhrUpload) { + Object.assign(opts.headers, file.xhrUpload.headers) + } + + return opts + } + createFormDataUpload (file, opts) { const formPost = new FormData() @@ -57,19 +75,7 @@ module.exports = class XHRUpload extends Plugin { } upload (file, current, total) { - const opts = Object.assign({}, - this.opts, - this.core.state.xhrUpload || {}, - file.xhrUpload || {} - ) - opts.headers = {} - Object.assign(opts.headers, this.opts.headers) - if (this.core.state.xhrUpload) { - Object.assign(opts.headers, this.core.state.xhrUpload.headers) - } - if (file.xhrUpload) { - Object.assign(opts.headers, file.xhrUpload.headers) - } + const opts = this.getOptions(file) this.core.log(`uploading ${current} of ${total}`) return new Promise((resolve, reject) => { @@ -140,7 +146,7 @@ module.exports = class XHRUpload extends Plugin { } uploadRemote (file, current, total) { - const opts = Object.assign({}, this.opts, file.xhrUpload || {}) + const opts = this.getOptions(file) return new Promise((resolve, reject) => { this.core.emit('core:upload-started', file.id) From f65c899562e5354d75f166bb471654c889f8b45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Thu, 28 Sep 2017 11:31:19 +0200 Subject: [PATCH 04/19] =?UTF-8?q?changelog:=20=E2=98=91=20s3=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 252707acd..1193f17b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,7 +115,7 @@ Theme: React and Retry - [x] goldenretriever: Omit completed uploads from saved file state—previously, when an upload was finished and the user refreshed the page, all the finished files would still be there because we saved the entire list of files. Changed this to only store files that are part of an in-progress upload, or that have yet to be uploaded (#358, #324 / @goto-bus-stop) - [x] goldenretriever: Remove files from cache when upload finished—this uses the deleteBlobs function when core:success fires (#358, #324 / @goto-bus-stop) - [ ] goldenretriever: add a timestamp to cached blobs, and to delete old blobs on boot (#358, #324 / @goto-bus-stop) -- [ ] s3: have some way to configure content-disposition for uploads, see #243 (@goto-bus-stop) +- [x] s3: have some way to configure content-disposition for uploads, see #243 (@goto-bus-stop) - [x] core: move `setPluginState` and add `getPluginState` to `Plugin` class (#363 / @goto-bus-stop) ## 0.19.1 From 4a2a5abc937914bb37497a6d80705cc9262c5229 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 29 Sep 2017 17:06:53 -0400 Subject: [PATCH 05/19] refactor `log` by adding timestamps and warnings; check for uploader plugins and 0 files in `upload` --- src/core/Core.js | 40 ++++++++++++++++++++++++---------------- src/core/Utils.js | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/core/Core.js b/src/core/Core.js index 973bf67ef..07826c911 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -783,25 +783,33 @@ class Uppy { /** * Logs stuff to console, only if `debug` is set to true. Silent in production. * - * @return {String|Object} to log + * @param {String|Object} msg to log + * @param {String} type optional `error` or `warning` */ log (msg, type) { + let message = `[Uppy] [${Utils.getTimeStamp()}] ${msg}` + + global.uppyLog = global.uppyLog + '\n' + 'DEBUG LOG: ' + msg + if (!this.opts.debug) { return } if (type === 'error') { - console.error(`LOG: ${msg}`) + console.error(message) + return + } + + if (type === 'warning') { + console.warn(message) return } if (msg === `${msg}`) { - console.log(`LOG: ${msg}`) + console.log(message) } else { - console.dir(msg) + console.dir(message) } - - global.uppyLog = global.uppyLog + '\n' + 'DEBUG LOG: ' + msg } initSocket (opts) { @@ -934,7 +942,15 @@ class Uppy { * * @return {Promise} */ - upload (forceUpload) { + upload () { + if (!this.plugins.uploader) { + this.log('No uploader type plugins are used', 'warning') + } + + if (Object.keys(this.state.files).length === 0) { + this.log('No files have been added', 'warning') + } + const isMinNumberOfFilesReached = this.checkMinNumberOfFiles() if (!isMinNumberOfFilesReached) { return Promise.reject(new Error('Minimum number of files has not been reached')) @@ -952,15 +968,7 @@ class Uppy { Object.keys(this.state.files).forEach((fileID) => { const file = this.getFile(fileID) - // TODO: replace files[file].isRemote with some logic - // - // filter files that are now yet being uploaded / haven’t been uploaded - // and remote too - - if (forceUpload) { - this.resetProgress() - waitingFileIDs.push(file.id) - } else if (!file.progress.uploadStarted || file.isRemote) { + if (!file.progress.uploadStarted || file.isRemote) { waitingFileIDs.push(file.id) } }) diff --git a/src/core/Utils.js b/src/core/Utils.js index 72068388a..ac64b3223 100644 --- a/src/core/Utils.js +++ b/src/core/Utils.js @@ -41,6 +41,24 @@ function toArray (list) { return Array.prototype.slice.call(list || [], 0) } +/** + * Returns a timestamp in the format of `hours:minutes:seconds` +*/ +function getTimeStamp () { + var date = new Date() + var hours = pad(date.getHours().toString()) + var minutes = pad(date.getMinutes().toString()) + var seconds = pad(date.getSeconds().toString()) + return hours + ':' + minutes + ':' + seconds +} + +/** + * Adds zero to strings shorter than two characters +*/ +function pad (str) { + return str.length !== 2 ? 0 + str : str +} + /** * Takes a file object and turns it into fileID, by converting file.name to lowercase, * removing extra characters and adding type, size and lastModified @@ -519,6 +537,7 @@ function settle (promises) { module.exports = { generateFileID, toArray, + getTimeStamp, runPromiseSequence, supportsMediaRecorder, isTouchDevice, From 39d8ee114c23679bc4a6509713aa5588b58764a0 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 29 Sep 2017 17:15:35 -0400 Subject: [PATCH 06/19] Update CHANGELOG.md --- CHANGELOG.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 252707acd..81276e540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,7 +84,8 @@ What we need to do to release Uppy 1.0 To be released: 2017-10-27 - [ ] webcam: look into simplifying / improving webcam plugin, only showing the tab when webcam is available (@arturi, @goto-bus-stop) -- [ ] provider: improve UI, add icons for file types? (@arturi) +- [ ] core: Redux PR (#216, #338 / @arturi, @goto-bus-stop, @richardwillars) +- [ ] provider: improve UI, add icons for file types (@arturi) - [ ] core: css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop) - [ ] core: research !important styles to be immune to any environment/page. Maybe use smth like `postcss-safe-important`. Or increase specificity (with .Uppy) (@arturi) - [ ] test: add https://github.com/pa11y/pa11y for automated accessibility testing (@arturi) @@ -92,25 +93,24 @@ To be released: 2017-10-27 - [ ] core: allow setting custom `id` for plugins: https://github.com/transloadit/uppy/pull/328#issuecomment-328242214 (@arturi) - [ ] add `FormEncapsulator`: a plugin that is used in conjunction with any other acquirer, responsible for injecting any result (like from Transloadit plugin) back into the form (jquery-sdk includes the whole Assembly Status JSON in a hidden field i think) - [ ] dashboard: allow minimizing the Dashboard during upload (Uppy then becomes just a tiny progress indicator) (@arturi) +- [ ] dashboard: cancel button for any kind of uploads? currently resume/pause only for tus, and cancel for XHR (@arturi, @goto-bus-stop) - [ ] goldenretriever: Ability to clear upload history or set expiry date (#324 / @arturi) -- [ ] core: return `{ successful, failed }` from `uppy.upload()` +- [ ] core: return `{ successful, failed }` from `uppy.upload()` (@goto-bus-stop) +- [ ] core: refactor `uppy-base` (@arturi) - [ ] uppy-server: look into storing tokens in user’s browser only (@ifedapoolarewaju) # next ## 0.20.0 -To be released: 2017-09-29. +To be released: 2017-10-02. Theme: React and Retry -- [ ] core: Redux PR (#216, #338 / @arturi, @goto-bus-stop, @richardwillars) -- [ ] dashboard: cancel button for any kind of uploads? currently resume/pause only for tus, and cancel for XHR (@arturi, @goto-bus-stop) -- [ ] core: show error and offer retry when upload can’t start and/or fails (offline, wrong endpoint) — now it just sits there; add error in file progress state, UI, question mark button (#307 / @arturi) +- [ ] core: retry/error when upload can’t start or fails (offline, connection lost, wrong endpoint); add error in file progress state, UI, question mark button (#307 / @arturi) - [x] core: improve and merge the React PR (#170 / @goto-bus-stop, @arturi) - [ ] goldenretriever: add “ghost” files (@arturi) - [x] uploaders: upload resolution changes, followup to #323 (#347 / @goto-bus-stop) -- [ ] uploaders: issue warning when no uploading plugins are used -- [ ] core: refactor `uppy-base` +- [ ] uploaders: issue warning when no uploading plugins are used (@arturi) - [x] core: fix `replaceTargetContent` and add tests for `Plugin` (#354 / @gavboulton) - [x] goldenretriever: Omit completed uploads from saved file state—previously, when an upload was finished and the user refreshed the page, all the finished files would still be there because we saved the entire list of files. Changed this to only store files that are part of an in-progress upload, or that have yet to be uploaded (#358, #324 / @goto-bus-stop) - [x] goldenretriever: Remove files from cache when upload finished—this uses the deleteBlobs function when core:success fires (#358, #324 / @goto-bus-stop) From 1d0e43254214749a51248cd31dbb6d8bbc614570 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 29 Sep 2017 17:31:43 -0400 Subject: [PATCH 07/19] =?UTF-8?q?IE6=20-->=20IE8,=20SauceLabs=20don?= =?UTF-8?q?=E2=80=99t=20seem=20to=20offer=20Win=20XP=20and=20IE=206=20anym?= =?UTF-8?q?ore:=20https://saucelabs.com/platforms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/acceptance/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/acceptance/index.js b/test/acceptance/index.js index 9bdd55711..d3a79da65 100644 --- a/test/acceptance/index.js +++ b/test/acceptance/index.js @@ -100,8 +100,8 @@ function buildDriver (platform) { var specificTests = { fallback: function () { - var ancientPlatform = { browser: 'internet explorer', version: '6.0', os: 'Windows XP' } - var driver = buildDriver({ browser: 'internet explorer', version: '6.0', os: 'Windows XP' }) + var ancientPlatform = { browser: 'internet explorer', version: '8.0', os: 'Windows 7' } + var driver = buildDriver({ browser: 'internet explorer', version: '8.0', os: 'Windows 7' }) var test = require('./fallback.spec.js') test(driver, ancientPlatform, host) @@ -113,7 +113,7 @@ var specificTests = { function runAllTests () { if (isRemoteTest) { // run custom platform-specific tests here - // fallback test + //
fallback test specificTests.fallback() // run all tests for all platforms From cc14a46057a7491efb3eefc0b8f875cbb55a7503 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 29 Sep 2017 23:36:49 -0400 Subject: [PATCH 08/19] no win xp in tests --- test/acceptance/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/acceptance/index.js b/test/acceptance/index.js index d3a79da65..f5c295b71 100644 --- a/test/acceptance/index.js +++ b/test/acceptance/index.js @@ -52,7 +52,7 @@ var platforms = [ { browser: 'Firefox', version: '38.0', os: 'Linux' }, { browser: 'Internet Explorer', version: '10.0', os: 'Windows 8' }, { browser: 'Internet Explorer', version: '11.103', os: 'Windows 10' }, - { browser: 'Chrome', version: '48.0', os: 'Windows XP' }, + { browser: 'Chrome', version: '48.0', os: 'Windows 7' }, { browser: 'Firefox', version: '34.0', os: 'Windows 7' } ] From fcc2b7cb8922d42f6ef0ff1a608f54869b7d70b9 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sat, 30 Sep 2017 00:23:41 -0400 Subject: [PATCH 09/19] Add support for Redux DevTools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sends state updates to devtools - sets uppy state to state provided by devtools for time traveling - we could add support for custom action type names, and then we’ll get actions like `UPPY_ADD_FILE` and such try by installing and activating: https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en --- src/core/Core.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/core/Core.js b/src/core/Core.js index 973bf67ef..064ba7d62 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -106,7 +106,23 @@ class Uppy { } // for debugging and testing - this.updateNum = 0 + + this.withDevTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ + + if (this.withDevTools) { + this.devTools = window.devToolsExtension.connect() + this.devToolsUnsubscribe = this.devTools.subscribe((message) => { + // Implement monitors actions. For example time traveling: + if (message.type === 'DISPATCH' && message.payload.type === 'JUMP_TO_STATE') { + const state = JSON.parse(message.state) + // this.setState(state) + this.state = Object.assign({}, this.state, state) + this.updateAll(this.state) + } + }) + } + + // this.updateNum = 0 if (this.opts.debug) { global.UppyState = this.state global.uppyLog = '' @@ -475,6 +491,12 @@ class Uppy { // this.setState({bla: 'bla'}) // }, 20) + this.on('core:state-update', (prevState, nextState, patch) => { + if (this.withDevTools) { + this.devTools.send('UPPY_STATE_UPDATE', nextState) + } + }) + this.on('core:error', (error) => { this.setState({ error }) }) @@ -730,6 +752,10 @@ class Uppy { close () { this.reset() + if (this.withDevTools) { + this.devToolsUnsubscribe() + } + this.iteratePlugins((plugin) => { plugin.uninstall() }) From 431f815fc0be77cf1ec1a9528082630f4acd8087 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sat, 30 Sep 2017 00:27:37 -0400 Subject: [PATCH 10/19] =?UTF-8?q?Don=E2=80=99t=20store=20function=20refere?= =?UTF-8?q?nces=20in=20state=20to=20keep=20state=20serializable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of storing methods in state, find plugin and add methods to the object that we pass to `render`, when it’s needed. --- src/plugins/Dashboard/index.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index 6cbeac625..f3e676f65 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -93,7 +93,7 @@ module.exports = class DashboardUI extends Plugin { addTarget (plugin) { const callerPluginId = plugin.id || plugin.constructor.name const callerPluginName = plugin.title || callerPluginId - const callerPluginIcon = plugin.icon || this.opts.defaultTabIcon + // const callerPluginIcon = plugin.icon || this.opts.defaultTabIcon const callerPluginType = plugin.type if (callerPluginType !== 'acquirer' && @@ -107,9 +107,9 @@ module.exports = class DashboardUI extends Plugin { const target = { id: callerPluginId, name: callerPluginName, - icon: callerPluginIcon, + // icon: callerPluginIcon, type: callerPluginType, - render: plugin.render, + // render: plugin.render, isHidden: true } @@ -306,11 +306,17 @@ module.exports = class DashboardUI extends Plugin { totalSize = prettyBytes(totalSize) totalUploadedSize = prettyBytes(totalUploadedSize) - const acquirers = pluginState.targets.filter((target) => { + const acquirers = pluginState.targets.filter(target => { + const plugin = this.core.getPlugin(target.id) + target.icon = plugin.icon || this.opts.defaultTabIcon + target.render = plugin.render return target.type === 'acquirer' }) const progressindicators = pluginState.targets.filter((target) => { + const plugin = this.core.getPlugin(target.id) + target.icon = plugin.icon || this.opts.defaultTabIcon + target.render = plugin.render return target.type === 'progressindicator' }) From 239a6f1d1c7a634da388c41dfb3a29e375849e3b Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sat, 30 Sep 2017 17:52:00 -0400 Subject: [PATCH 11/19] move ReduxDevTools from Core to a separate plugin --- src/core/Core.js | 57 +++++++++++++++++------------- src/plugins/ReduxDevTools.js | 67 ++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 src/plugins/ReduxDevTools.js diff --git a/src/core/Core.js b/src/core/Core.js index 064ba7d62..df29e8e0f 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -65,10 +65,10 @@ class Uppy { // Container for different types of plugins this.plugins = {} - // @TODO maybe bindall this.translator = new Translator({locale: this.opts.locale}) this.i18n = this.translator.translate.bind(this.translator) this.getState = this.getState.bind(this) + this.getPlugin = this.getPlugin.bind(this) this.updateMeta = this.updateMeta.bind(this) this.initSocket = this.initSocket.bind(this) this.log = this.log.bind(this) @@ -106,21 +106,33 @@ class Uppy { } // for debugging and testing - - this.withDevTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ - - if (this.withDevTools) { - this.devTools = window.devToolsExtension.connect() - this.devToolsUnsubscribe = this.devTools.subscribe((message) => { - // Implement monitors actions. For example time traveling: - if (message.type === 'DISPATCH' && message.payload.type === 'JUMP_TO_STATE') { - const state = JSON.parse(message.state) - // this.setState(state) - this.state = Object.assign({}, this.state, state) - this.updateAll(this.state) - } - }) - } + // // Implement monitors actions. + // // See https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f + // // and https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js + // this.withDevTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ + // if (this.withDevTools) { + // this.devTools = window.devToolsExtension.connect() + // this.devToolsUnsubscribe = this.devTools.subscribe((message) => { + // if (message.type === 'DISPATCH') { + // console.log(message.payload.type) + // switch (message.payload.type) { + // case 'RESET': + // this.reset() + // return + // case 'IMPORT_STATE': + // const computedStates = message.payload.nextLiftedState.computedStates + // this.state = Object.assign({}, this.state, computedStates[computedStates.length - 1].state) + // this.updateAll(this.state) + // return + // case 'JUMP_TO_STATE': + // case 'JUMP_TO_ACTION': + // // this.setState(state) + // this.state = Object.assign({}, this.state, JSON.parse(message.state)) + // this.updateAll(this.state) + // } + // } + // }) + // } // this.updateNum = 0 if (this.opts.debug) { @@ -491,11 +503,11 @@ class Uppy { // this.setState({bla: 'bla'}) // }, 20) - this.on('core:state-update', (prevState, nextState, patch) => { - if (this.withDevTools) { - this.devTools.send('UPPY_STATE_UPDATE', nextState) - } - }) + // this.on('core:state-update', (prevState, nextState, patch) => { + // if (this.withDevTools) { + // this.devTools.send('UPPY_STATE_UPDATE', nextState) + // } + // }) this.on('core:error', (error) => { this.setState({ error }) @@ -555,7 +567,6 @@ class Uppy { const throttledCalculateProgress = throttle(this.calculateProgress, 100, {leading: true, trailing: false}) this.on('core:upload-progress', (data) => { - // this.calculateProgress(data) throttledCalculateProgress(data) }) @@ -564,8 +575,6 @@ class Uppy { const updatedFile = Object.assign({}, updatedFiles[fileID], { progress: Object.assign({}, updatedFiles[fileID].progress, { uploadComplete: true, - // good or bad idea? setting the percentage to 100 if upload is successful, - // so that if we lost some progress events on the way, its still marked “compete”? percentage: 100 }), uploadURL: uploadURL diff --git a/src/plugins/ReduxDevTools.js b/src/plugins/ReduxDevTools.js new file mode 100644 index 000000000..9f6e66c86 --- /dev/null +++ b/src/plugins/ReduxDevTools.js @@ -0,0 +1,67 @@ +const Plugin = require('./Plugin') + +/** + * + */ +module.exports = class ReduxDevTools extends Plugin { + constructor (core, opts) { + super(core, opts) + this.type = 'debugger' + this.id = 'ReduxDevTools' + this.title = 'Redux Dev Tools' + + // set default options + const defaultOptions = {} + + // merge default options with the ones set by user + this.opts = Object.assign({}, defaultOptions, opts) + + this.handleStateChange = this.handleStateChange.bind(this) + this.initDevTools = this.initDevTools.bind(this) + } + + handleStateChange (prevState, nextState, patch) { + this.devTools.send('UPPY_STATE_UPDATE', nextState) + } + + initDevTools () { + this.devTools = window.devToolsExtension.connect() + this.devToolsUnsubscribe = this.devTools.subscribe((message) => { + if (message.type === 'DISPATCH') { + console.log(message.payload.type) + switch (message.payload.type) { + case 'RESET': + this.core.reset() + return + case 'IMPORT_STATE': + const computedStates = message.payload.nextLiftedState.computedStates + this.core.state = Object.assign({}, this.core.state, computedStates[computedStates.length - 1].state) + this.core.updateAll(this.core.state) + return + case 'JUMP_TO_STATE': + case 'JUMP_TO_ACTION': + // this.setState(state) + this.core.state = Object.assign({}, this.core.state, JSON.parse(message.state)) + this.core.updateAll(this.core.state) + } + } + }) + } + + install () { + // Implement monitors actions. + // See https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f + // and https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js + this.withDevTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ + if (this.withDevTools) { + this.initDevTools() + this.core.on('core:state-update', this.handleStateChange) + } + } + + uninstall () { + if (this.withDevTools) { + this.core.emitter.off('core:state-update', this.handleStateUpdate) + } + } +} From 52d6ffe1573d0cf6fb5cd6617e03bd44e26147aa Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sat, 30 Sep 2017 17:52:36 -0400 Subject: [PATCH 12/19] to get to `render` of the plugin, find that plugin via `core.getPlugin()` --- src/plugins/Dashboard/Dashboard.js | 4 ++-- src/plugins/Dashboard/index.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/Dashboard/Dashboard.js b/src/plugins/Dashboard/Dashboard.js index 61e1483e7..90d6f7ae8 100644 --- a/src/plugins/Dashboard/Dashboard.js +++ b/src/plugins/Dashboard/Dashboard.js @@ -139,12 +139,12 @@ module.exports = function Dashboard (props) { type="button" onclick=${props.hideAllPanels}>${props.i18n('done')} - ${props.activePanel ? props.activePanel.render(props.state) : ''} + ${props.activePanel ? props.getPlugin(props.activePanel.id).render(props.state) : ''}
${props.progressindicators.map((target) => { - return target.render(props.state) + return props.getPlugin(target.id).render(props.state) })}
diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index f3e676f65..ec679be75 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -313,7 +313,7 @@ module.exports = class DashboardUI extends Plugin { return target.type === 'acquirer' }) - const progressindicators = pluginState.targets.filter((target) => { + const progressindicators = pluginState.targets.filter(target => { const plugin = this.core.getPlugin(target.id) target.icon = plugin.icon || this.opts.defaultTabIcon target.render = plugin.render @@ -354,6 +354,7 @@ module.exports = class DashboardUI extends Plugin { totalProgress: state.totalProgress, acquirers: acquirers, activePanel: pluginState.activePanel, + getPlugin: this.core.getPlugin, progressindicators: progressindicators, autoProceed: this.core.opts.autoProceed, hideUploadButton: this.opts.hideUploadButton, From f2b3988716fd9e0d253528e7fa4eb232a26e858d Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sat, 30 Sep 2017 21:26:30 -0400 Subject: [PATCH 13/19] comments and naming --- src/plugins/ReduxDevTools.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/ReduxDevTools.js b/src/plugins/ReduxDevTools.js index 9f6e66c86..9b8228936 100644 --- a/src/plugins/ReduxDevTools.js +++ b/src/plugins/ReduxDevTools.js @@ -1,14 +1,17 @@ const Plugin = require('./Plugin') /** + * Add Redux DevTools support to Uppy * + * See https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f + * and https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js */ module.exports = class ReduxDevTools extends Plugin { constructor (core, opts) { super(core, opts) this.type = 'debugger' this.id = 'ReduxDevTools' - this.title = 'Redux Dev Tools' + this.title = 'Redux DevTools' // set default options const defaultOptions = {} @@ -29,6 +32,8 @@ module.exports = class ReduxDevTools extends Plugin { this.devToolsUnsubscribe = this.devTools.subscribe((message) => { if (message.type === 'DISPATCH') { console.log(message.payload.type) + + // Implement monitors actions switch (message.payload.type) { case 'RESET': this.core.reset() @@ -49,9 +54,6 @@ module.exports = class ReduxDevTools extends Plugin { } install () { - // Implement monitors actions. - // See https://medium.com/@zalmoxis/redux-devtools-without-redux-or-how-to-have-a-predictable-state-with-any-architecture-61c5f5a7716f - // and https://github.com/zalmoxisus/mobx-remotedev/blob/master/src/monitorActions.js this.withDevTools = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__ if (this.withDevTools) { this.initDevTools() From be0ec9a15e2ef2d026fc676e4a7b570c59ae5778 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sun, 1 Oct 2017 00:17:49 -0400 Subject: [PATCH 14/19] remove 0 file warning --- src/core/Core.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/Core.js b/src/core/Core.js index 07826c911..04b45624c 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -947,10 +947,6 @@ class Uppy { this.log('No uploader type plugins are used', 'warning') } - if (Object.keys(this.state.files).length === 0) { - this.log('No files have been added', 'warning') - } - const isMinNumberOfFilesReached = this.checkMinNumberOfFiles() if (!isMinNumberOfFilesReached) { return Promise.reject(new Error('Minimum number of files has not been reached')) From a1c2271d0af26493fde76c8581f9dc2934f11d40 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Mon, 2 Oct 2017 10:30:15 -0400 Subject: [PATCH 15/19] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81276e540..0ecb5729b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -98,6 +98,7 @@ To be released: 2017-10-27 - [ ] core: return `{ successful, failed }` from `uppy.upload()` (@goto-bus-stop) - [ ] core: refactor `uppy-base` (@arturi) - [ ] uppy-server: look into storing tokens in user’s browser only (@ifedapoolarewaju) +- [ ] plugins: add tabindex="0" to buttons and tabs? # next From d16a7d8dbbe18fb4bf3b642e4c3156db3f40d6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 2 Oct 2017 17:37:19 +0200 Subject: [PATCH 16/19] xhrupload: add `fields` and `headers` to uppy-server request --- src/plugins/XHRUpload.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/plugins/XHRUpload.js b/src/plugins/XHRUpload.js index 3c34c6ad3..1f83abfda 100644 --- a/src/plugins/XHRUpload.js +++ b/src/plugins/XHRUpload.js @@ -150,6 +150,16 @@ module.exports = class XHRUpload extends Plugin { return new Promise((resolve, reject) => { this.core.emit('core:upload-started', file.id) + const fields = {} + const metaFields = Array.isArray(opts.metaFields) + ? opts.metaFields + // Send along all fields by default. + : Object.keys(file.meta) + + metaFields.forEach((name) => { + fields[name] = file.meta.name + }) + fetch(file.remote.url, { method: 'post', credentials: 'include', @@ -160,7 +170,9 @@ module.exports = class XHRUpload extends Plugin { body: JSON.stringify(Object.assign({}, file.remote.body, { endpoint: opts.endpoint, size: file.data.size, - fieldname: opts.fieldName + fieldname: opts.fieldName, + fields, + headers: opts.headers })) }) .then((res) => { From b430df0fdf5dfa3334ed10eb2540d7b5a3e7b074 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Mon, 2 Oct 2017 17:14:11 -0400 Subject: [PATCH 17/19] =?UTF-8?q?don=E2=80=99t=20do=20anything=20if=20`deb?= =?UTF-8?q?ug:=20false`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/Core.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/Core.js b/src/core/Core.js index 04b45624c..66eba1694 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -787,14 +787,14 @@ class Uppy { * @param {String} type optional `error` or `warning` */ log (msg, type) { - let message = `[Uppy] [${Utils.getTimeStamp()}] ${msg}` - - global.uppyLog = global.uppyLog + '\n' + 'DEBUG LOG: ' + msg - if (!this.opts.debug) { return } + let message = `[Uppy] [${Utils.getTimeStamp()}] ${msg}` + + global.uppyLog = global.uppyLog + '\n' + 'DEBUG LOG: ' + msg + if (type === 'error') { console.error(message) return From 72dc5a43cf99dc58ba8ab1a278d0559fd56f6b6a Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Tue, 3 Oct 2017 00:19:44 -0400 Subject: [PATCH 18/19] Update CHANGELOG.md --- CHANGELOG.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ecb5729b..9cd6f7c7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,7 +83,7 @@ What we need to do to release Uppy 1.0 To be released: 2017-10-27 -- [ ] webcam: look into simplifying / improving webcam plugin, only showing the tab when webcam is available (@arturi, @goto-bus-stop) +- [ ] webcam: look into simplifying / improving webcam plugin (probably good to do modern browsers only), only showing the tab when webcam is available (@arturi, @goto-bus-stop) - [ ] core: Redux PR (#216, #338 / @arturi, @goto-bus-stop, @richardwillars) - [ ] provider: improve UI, add icons for file types (@arturi) - [ ] core: css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop) @@ -99,6 +99,7 @@ To be released: 2017-10-27 - [ ] core: refactor `uppy-base` (@arturi) - [ ] uppy-server: look into storing tokens in user’s browser only (@ifedapoolarewaju) - [ ] plugins: add tabindex="0" to buttons and tabs? +- [ ] goldenretriever: add “ghost” files (@arturi) # next @@ -108,10 +109,13 @@ To be released: 2017-10-02. Theme: React and Retry - [ ] core: retry/error when upload can’t start or fails (offline, connection lost, wrong endpoint); add error in file progress state, UI, question mark button (#307 / @arturi) +- [ ] core: support for retry in Tus plugin (#307 / @arturi) +- [ ] core: support for retry in XHRUpload plugin (#307 / @arturi) +- [x] core: Add support for Redux DevTools via a plugin (#373 / @arturi) - [x] core: improve and merge the React PR (#170 / @goto-bus-stop, @arturi) -- [ ] goldenretriever: add “ghost” files (@arturi) +- [x] core: improve core.log method, add timestamps (#372 / @arturi) - [x] uploaders: upload resolution changes, followup to #323 (#347 / @goto-bus-stop) -- [ ] uploaders: issue warning when no uploading plugins are used (@arturi) +- [x] uploaders: issue warning when no uploading plugins are used (#372 / @arturi) - [x] core: fix `replaceTargetContent` and add tests for `Plugin` (#354 / @gavboulton) - [x] goldenretriever: Omit completed uploads from saved file state—previously, when an upload was finished and the user refreshed the page, all the finished files would still be there because we saved the entire list of files. Changed this to only store files that are part of an in-progress upload, or that have yet to be uploaded (#358, #324 / @goto-bus-stop) - [x] goldenretriever: Remove files from cache when upload finished—this uses the deleteBlobs function when core:success fires (#358, #324 / @goto-bus-stop) From 37a9ae2e5aa8098b00f1dbfa9ef24a3deddddbf5 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Tue, 3 Oct 2017 00:20:33 -0400 Subject: [PATCH 19/19] console.dir(msg) the original object followup to #372 --- src/core/Core.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Core.js b/src/core/Core.js index 6b3d85423..958188619 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -843,7 +843,9 @@ class Uppy { if (msg === `${msg}`) { console.log(message) } else { - console.dir(message) + message = `[Uppy] [${Utils.getTimeStamp()}]` + console.log(message) + console.dir(msg) } }