瀏覽代碼

Merge branch 'master' into feature/tl-preset

Renée Kooi 6 年之前
父節點
當前提交
f56bd0e196

+ 1 - 1
packages/@uppy/companion/package.json

@@ -41,7 +41,7 @@
     "express-interceptor": "^1.2.0",
     "express-interceptor": "^1.2.0",
     "express-prom-bundle": "^3.1.0",
     "express-prom-bundle": "^3.1.0",
     "express-session": "1.15.6",
     "express-session": "1.15.6",
-    "grant-express": "^4.0.1",
+    "grant-express": "4.1.2",
     "helmet": "3.8.2",
     "helmet": "3.8.2",
     "isobject": "3.0.1",
     "isobject": "3.0.1",
     "jsonwebtoken": "^8.0.1",
     "jsonwebtoken": "^8.0.1",

+ 3 - 2
packages/@uppy/companion/src/server/controllers/callback.js

@@ -27,8 +27,9 @@ module.exports = function callback (req, res, next) {
   // add the token to cookies for thumbnail/image requests
   // add the token to cookies for thumbnail/image requests
   tokenService.addToCookies(res, uppyAuthToken, req.uppy.options)
   tokenService.addToCookies(res, uppyAuthToken, req.uppy.options)
 
 
-  if ((req.session.grant || {}).state) {
-    const origin = oAuthState.getFromState(req.session.grant.state, 'origin', req.uppy.options.secret)
+  const state = (req.session.grant || {}).state
+  if (state) {
+    const origin = oAuthState.getFromState(state, 'origin', req.uppy.options.secret)
     const allowedClients = req.uppy.options.clients
     const allowedClients = req.uppy.options.clients
     // if no preset clients then allow any client
     // if no preset clients then allow any client
     if (!allowedClients || hasMatch(origin, allowedClients) || hasMatch(parseUrl(origin).host, allowedClients)) {
     if (!allowedClients || hasMatch(origin, allowedClients) || hasMatch(parseUrl(origin).host, allowedClients)) {

+ 1 - 1
packages/@uppy/companion/src/uppy.js

@@ -117,7 +117,7 @@ module.exports.socket = (server) => {
     const fullPath = ws.upgradeReq.url
     const fullPath = ws.upgradeReq.url
     // the token identifies which ongoing upload's progress, the socket
     // the token identifies which ongoing upload's progress, the socket
     // connection wishes to listen to.
     // connection wishes to listen to.
-    const token = fullPath.replace(/\/api\//, '')
+    const token = fullPath.replace(/^.*\/api\//, '')
     logger.info(`connection received from ${token}`, 'socket.connect')
     logger.info(`connection received from ${token}`, 'socket.connect')
 
 
     /**
     /**

+ 56 - 21
packages/@uppy/core/src/index.js

@@ -639,22 +639,49 @@ class Uppy {
   _calculateTotalProgress () {
   _calculateTotalProgress () {
     // calculate total progress, using the number of files currently uploading,
     // calculate total progress, using the number of files currently uploading,
     // multiplied by 100 and the summ of individual progress of each file
     // multiplied by 100 and the summ of individual progress of each file
-    const files = Object.assign({}, this.getState().files)
+    const files = this.getFiles()
 
 
-    const inProgress = Object.keys(files).filter((file) => {
-      return files[file].progress.uploadStarted
-    })
-    const progressMax = inProgress.length * 100
-    let progressAll = 0
-    inProgress.forEach((file) => {
-      progressAll = progressAll + files[file].progress.percentage
+    const inProgress = files.filter((file) => {
+      return file.progress.uploadStarted
     })
     })
 
 
-    const totalProgress = progressMax === 0 ? 0 : Math.floor((progressAll * 100 / progressMax).toFixed(2))
+    if (inProgress.length === 0) {
+      this.setState({ totalProgress: 0 })
+      return
+    }
 
 
-    this.setState({
-      totalProgress: totalProgress
+    const sizedFiles = inProgress.filter((file) => file.progress.bytesTotal != null)
+    const unsizedFiles = inProgress.filter((file) => file.progress.bytesTotal == null)
+
+    if (sizedFiles.length === 0) {
+      const progressMax = inProgress.length
+      const currentProgress = unsizedFiles.reduce((acc, file) => {
+        return acc + file.progress.percentage
+      }, 0)
+      const totalProgress = Math.round(currentProgress / progressMax * 100)
+      this.setState({ totalProgress })
+      return
+    }
+
+    let totalSize = sizedFiles.reduce((acc, file) => {
+      return acc + file.progress.bytesTotal
+    }, 0)
+    const averageSize = totalSize / sizedFiles.length
+    totalSize += averageSize * unsizedFiles.length
+
+    let uploadedSize = 0
+    sizedFiles.forEach((file) => {
+      uploadedSize += file.progress.bytesUploaded
     })
     })
+    unsizedFiles.forEach((file) => {
+      uploadedSize += averageSize * (file.progress.percentage || 0)
+    })
+
+    const totalProgress = totalSize === 0
+      ? 0
+      : Math.round(uploadedSize / totalSize * 100)
+
+    this.setState({ totalProgress })
   }
   }
 
 
   /**
   /**
@@ -1103,7 +1130,6 @@ class Uppy {
    */
    */
   _runUpload (uploadID) {
   _runUpload (uploadID) {
     const uploadData = this.getState().currentUploads[uploadID]
     const uploadData = this.getState().currentUploads[uploadID]
-    const fileIDs = uploadData.fileIDs
     const restoreStep = uploadData.step
     const restoreStep = uploadData.step
 
 
     const steps = [
     const steps = [
@@ -1128,9 +1154,10 @@ class Uppy {
             [uploadID]: currentUpload
             [uploadID]: currentUpload
           })
           })
         })
         })
+
         // TODO give this the `currentUpload` object as its only parameter maybe?
         // TODO give this the `currentUpload` object as its only parameter maybe?
         // Otherwise when more metadata may be added to the upload this would keep getting more parameters
         // Otherwise when more metadata may be added to the upload this would keep getting more parameters
-        return fn(fileIDs, uploadID)
+        return fn(currentUpload.fileIDs, uploadID)
       }).then((result) => {
       }).then((result) => {
         return null
         return null
       })
       })
@@ -1140,23 +1167,31 @@ class Uppy {
     // promise from this method if the upload failed.
     // promise from this method if the upload failed.
     lastStep.catch((err) => {
     lastStep.catch((err) => {
       this.emit('error', err, uploadID)
       this.emit('error', err, uploadID)
-
       this._removeUpload(uploadID)
       this._removeUpload(uploadID)
     })
     })
 
 
     return lastStep.then(() => {
     return lastStep.then(() => {
-      const files = fileIDs.map((fileID) => this.getFile(fileID))
-      const successful = files.filter((file) => file && !file.error)
-      const failed = files.filter((file) => file && file.error)
-      this.addResultData(uploadID, { successful, failed, uploadID })
-
+      // Set result data.
       const { currentUploads } = this.getState()
       const { currentUploads } = this.getState()
-      if (!currentUploads[uploadID]) {
+      const currentUpload = currentUploads[uploadID]
+      if (!currentUpload) {
         this.log(`Not setting result for an upload that has been removed: ${uploadID}`)
         this.log(`Not setting result for an upload that has been removed: ${uploadID}`)
         return
         return
       }
       }
 
 
-      const result = currentUploads[uploadID].result
+      const files = currentUpload.fileIDs
+        .map((fileID) => this.getFile(fileID))
+      const successful = files.filter((file) => !file.error)
+      const failed = files.filter((file) => file.error)
+      this.addResultData(uploadID, { successful, failed, uploadID })
+    }).then(() => {
+      // Emit completion events.
+      // This is in a separate function so that the `currentUploads` variable
+      // always refers to the latest state. In the handler right above it refers
+      // to an outdated object without the `.result` property.
+      const { currentUploads } = this.getState()
+      const currentUpload = currentUploads[uploadID]
+      const result = currentUpload.result
       this.emit('complete', result)
       this.emit('complete', result)
 
 
       this._removeUpload(uploadID)
       this._removeUpload(uploadID)

+ 30 - 2
packages/@uppy/core/src/index.test.js

@@ -373,6 +373,34 @@ describe('src/Core', () => {
         })
         })
     })
     })
 
 
+    it('should not pass removed file IDs to next step', async () => {
+      const core = new Core()
+      const uploader = jest.fn()
+      core.addPreProcessor((fileIDs) => {
+        core.removeFile(fileIDs[0])
+      })
+      core.addUploader(uploader)
+
+      core.addFile({
+        source: 'jest',
+        name: 'rmd.jpg',
+        type: 'image/jpeg',
+        data: new File([sampleImage], { type: 'image/jpeg' })
+      })
+      core.addFile({
+        source: 'jest',
+        name: 'kept.jpg',
+        type: 'image/jpeg',
+        data: new File([sampleImage], { type: 'image/jpeg' })
+      })
+
+      await core.upload()
+
+      expect(uploader.mock.calls.length).toEqual(1)
+      expect(uploader.mock.calls[0][0].length).toEqual(1, 'Got 1 file ID')
+      expect(core.getFile(uploader.mock.calls[0][0][0]).name).toEqual('kept.jpg')
+    })
+
     it('should update the file progress state when preprocess-progress event is fired', () => {
     it('should update the file progress state when preprocess-progress event is fired', () => {
       const core = new Core()
       const core = new Core()
       core.addFile({
       core.addFile({
@@ -1020,7 +1048,7 @@ describe('src/Core', () => {
       })
       })
 
 
       core._calculateTotalProgress()
       core._calculateTotalProgress()
-      expect(core.getState().totalProgress).toEqual(65)
+      expect(core.getState().totalProgress).toEqual(66)
     })
     })
 
 
     it('should reset the progress', () => {
     it('should reset the progress', () => {
@@ -1057,7 +1085,7 @@ describe('src/Core', () => {
 
 
       core._calculateTotalProgress()
       core._calculateTotalProgress()
 
 
-      expect(core.getState().totalProgress).toEqual(65)
+      expect(core.getState().totalProgress).toEqual(66)
 
 
       core.resetProgress()
       core.resetProgress()
 
 

+ 9 - 4
packages/@uppy/status-bar/src/StatusBar.js

@@ -1,6 +1,8 @@
 const throttle = require('lodash.throttle')
 const throttle = require('lodash.throttle')
 const classNames = require('classnames')
 const classNames = require('classnames')
 const statusBarStates = require('./StatusBarStates')
 const statusBarStates = require('./StatusBarStates')
+const prettyBytes = require('prettier-bytes')
+const prettyETA = require('@uppy/utils/lib/prettyETA')
 const { h } = require('preact')
 const { h } = require('preact')
 
 
 function calculateProcessingProgress (files) {
 function calculateProcessingProgress (files) {
@@ -204,8 +206,11 @@ const ProgressBarProcessing = (props) => {
 const ProgressDetails = (props) => {
 const ProgressDetails = (props) => {
   return <div class="uppy-StatusBar-statusSecondary">
   return <div class="uppy-StatusBar-statusSecondary">
     { props.numUploads > 1 && props.i18n('filesUploadedOfTotal', { complete: props.complete, smart_count: props.numUploads }) + ' \u00B7 ' }
     { props.numUploads > 1 && props.i18n('filesUploadedOfTotal', { complete: props.complete, smart_count: props.numUploads }) + ' \u00B7 ' }
-    { props.i18n('dataUploadedOfTotal', { complete: props.totalUploadedSize, total: props.totalSize }) + ' \u00B7 ' }
-    { props.i18n('xTimeLeft', { time: props.totalETA }) }
+    { props.i18n('dataUploadedOfTotal', {
+      complete: prettyBytes(props.totalUploadedSize),
+      total: prettyBytes(props.totalSize)
+    }) + ' \u00B7 ' }
+    { props.i18n('xTimeLeft', { time: prettyETA(props.totalETA) }) }
   </div>
   </div>
 }
 }
 
 
@@ -269,9 +274,9 @@ const ProgressBarError = ({ error, retryAll, hideRetryButton, i18n }) => {
   return (
   return (
     <div class="uppy-StatusBar-content" role="alert">
     <div class="uppy-StatusBar-content" role="alert">
       <span class="uppy-StatusBar-contentPadding">{i18n('uploadFailed')}.</span>
       <span class="uppy-StatusBar-contentPadding">{i18n('uploadFailed')}.</span>
-      {!hideRetryButton &&
+      {/* {!hideRetryButton &&
         <span class="uppy-StatusBar-contentPadding">{i18n('pleasePressRetry')}</span>
         <span class="uppy-StatusBar-contentPadding">{i18n('pleasePressRetry')}</span>
-      }
+      } */}
       <span class="uppy-StatusBar-details"
       <span class="uppy-StatusBar-details"
         aria-label={error}
         aria-label={error}
         data-microtip-position="top"
         data-microtip-position="top"

+ 1 - 7
packages/@uppy/status-bar/src/index.js

@@ -4,8 +4,6 @@ const StatusBarUI = require('./StatusBar')
 const statusBarStates = require('./StatusBarStates')
 const statusBarStates = require('./StatusBarStates')
 const getSpeed = require('@uppy/utils/lib/getSpeed')
 const getSpeed = require('@uppy/utils/lib/getSpeed')
 const getBytesRemaining = require('@uppy/utils/lib/getBytesRemaining')
 const getBytesRemaining = require('@uppy/utils/lib/getBytesRemaining')
-const prettyETA = require('@uppy/utils/lib/prettyETA')
-const prettyBytes = require('prettier-bytes')
 
 
 /**
 /**
  * StatusBar: renders a status bar with upload/pause/resume/cancel/retry buttons,
  * StatusBar: renders a status bar with upload/pause/resume/cancel/retry buttons,
@@ -195,8 +193,7 @@ module.exports = class StatusBar extends Plugin {
       return files[file]
       return files[file]
     })
     })
 
 
-    const totalSpeed = prettyBytes(this.getTotalSpeed(inProgressNotPausedFilesArray))
-    const totalETA = prettyETA(this.getTotalETA(inProgressNotPausedFilesArray))
+    const totalETA = this.getTotalETA(inProgressNotPausedFilesArray)
 
 
     // total size and uploaded size
     // total size and uploaded size
     let totalSize = 0
     let totalSize = 0
@@ -205,8 +202,6 @@ module.exports = class StatusBar extends Plugin {
       totalSize = totalSize + (file.progress.bytesTotal || 0)
       totalSize = totalSize + (file.progress.bytesTotal || 0)
       totalUploadedSize = totalUploadedSize + (file.progress.bytesUploaded || 0)
       totalUploadedSize = totalUploadedSize + (file.progress.bytesUploaded || 0)
     })
     })
-    totalSize = prettyBytes(totalSize)
-    totalUploadedSize = prettyBytes(totalUploadedSize)
 
 
     const isUploadStarted = uploadStartedFiles.length > 0
     const isUploadStarted = uploadStartedFiles.length > 0
 
 
@@ -243,7 +238,6 @@ module.exports = class StatusBar extends Plugin {
       complete: completeFiles.length,
       complete: completeFiles.length,
       newFiles: newFiles.length,
       newFiles: newFiles.length,
       numUploads: startedFiles.length,
       numUploads: startedFiles.length,
-      totalSpeed,
       totalETA,
       totalETA,
       files,
       files,
       i18n: this.i18n,
       i18n: this.i18n,

+ 7 - 0
packages/@uppy/webcam/src/style.scss

@@ -16,6 +16,7 @@
   overflow: hidden;
   overflow: hidden;
   background-color: $color-black;
   background-color: $color-black;
   text-align: center;
   text-align: center;
+  position: relative;
 }
 }
 
 
   .uppy-size--md .uppy-Webcam-videoContainer {
   .uppy-size--md .uppy-Webcam-videoContainer {
@@ -27,6 +28,12 @@
   // height: 100%;
   // height: 100%;
   max-width: 100%;
   max-width: 100%;
   max-height: 100%;
   max-height: 100%;
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  margin: auto;
 }
 }
 
 
   .uppy-Webcam-video--mirrored {
   .uppy-Webcam-video--mirrored {

+ 6 - 2
packages/@uppy/xhr-upload/src/index.js

@@ -202,7 +202,9 @@ module.exports = class XHRUpload extends Plugin {
       })
       })
 
 
       const xhr = new XMLHttpRequest()
       const xhr = new XMLHttpRequest()
-      xhr.responseType = opts.responseType
+      if (opts.responseType !== '') {
+        xhr.responseType = opts.responseType
+      }
 
 
       const id = cuid()
       const id = cuid()
 
 
@@ -360,7 +362,9 @@ module.exports = class XHRUpload extends Plugin {
       })
       })
 
 
       const xhr = new XMLHttpRequest()
       const xhr = new XMLHttpRequest()
-      xhr.responseType = this.opts.responseType
+      if (this.opts.responseType !== '') {
+        xhr.responseType = this.opts.responseType
+      }
 
 
       const timer = this.createProgressTimeout(this.opts.timeout, (error) => {
       const timer = this.createProgressTimeout(this.opts.timeout, (error) => {
         xhr.abort()
         xhr.abort()

+ 7 - 1
test/endtoend/thumbnails/test.js

@@ -1,4 +1,4 @@
-/* global browser, expect, $, $$ */
+/* global browser, capabilities, expect, $, $$ */
 const path = require('path')
 const path = require('path')
 const fs = require('fs')
 const fs = require('fs')
 const { selectFakeFile, supportsChooseFile } = require('../utils')
 const { selectFakeFile, supportsChooseFile } = require('../utils')
@@ -21,6 +21,12 @@ describe('ThumbnailGenerator', () => {
   })
   })
 
 
   it('should generate thumbnails for images', function () {
   it('should generate thumbnails for images', function () {
+    // Does not work on IE right now
+    if (capabilities.browserName === 'internet explorer') {
+      this.skip()
+      return
+    }
+
     $('#uppyThumbnails .uppy-FileInput-input').waitForExist()
     $('#uppyThumbnails .uppy-FileInput-input').waitForExist()
 
 
     browser.execute(/* must be valid ES5 for IE */ function () {
     browser.execute(/* must be valid ES5 for IE */ function () {

+ 2 - 2
test/endtoend/transloadit/test.js

@@ -46,9 +46,9 @@ describe('Transloadit file processing', () => {
         `image/jpeg`, // type
         `image/jpeg`, // type
         fs.readFileSync(img, 'base64') // b64
         fs.readFileSync(img, 'base64') // b64
       )
       )
-      browser.execute(selectFakeFile, 'uppyTransloadit')
+      // browser.execute(selectFakeFile, 'uppyTransloadit')
     }
     }
-    $(resultPath).waitForExist(15000)
+    $(resultPath).waitForExist(25000)
     const text = browser.getText(resultPath)
     const text = browser.getText(resultPath)
     expect(text).to.be.equal('ok')
     expect(text).to.be.equal('ok')
   })
   })

+ 2 - 1
test/endtoend/wdio.base.conf.js

@@ -17,7 +17,8 @@ exports.config = {
   // directory is where your package.json resides, so `wdio` will be called from there.
   // directory is where your package.json resides, so `wdio` will be called from there.
   //
   //
   specs: [
   specs: [
-    'test/endtoend/*/test.js'
+    // 'test/endtoend/*/test.js',
+    'test/endtoend/transloadit/test.js'
   ],
   ],
 
 
   // Patterns to exclude.
   // Patterns to exclude.

+ 1 - 1
website/src/docs/dropbox.md

@@ -18,7 +18,7 @@ uppy.use(Dropbox, {
 })
 })
 ```
 ```
 
 
-[Try live!](/examples/dashboard/)
+<a class="TryButton" href="/examples/dashboard/">Try it live</a>
 
 
 ## Installation
 ## Installation
 
 

+ 1 - 1
website/src/docs/google-drive.md

@@ -18,7 +18,7 @@ uppy.use(GoogleDrive, {
 })
 })
 ```
 ```
 
 
-[Try live!](/examples/dashboard/)
+<a class="TryButton" href="/examples/dashboard/">Try it live</a>
 
 
 ## Installation
 ## Installation
 
 

+ 1 - 1
website/src/docs/instagram.md

@@ -18,7 +18,7 @@ uppy.use(Instagram, {
 })
 })
 ```
 ```
 
 
-[Try live!](/examples/dashboard/)
+<a class="TryButton" href="/examples/dashboard/">Try it live</a>
 
 
 ## Installation
 ## Installation
 
 

+ 1 - 1
website/src/docs/url.md

@@ -18,7 +18,7 @@ uppy.use(Url, {
 })
 })
 ```
 ```
 
 
-[Try live!](/examples/dashboard/)
+<a class="TryButton" href="/examples/dashboard/">Try it live</a>
 
 
 ## Installation
 ## Installation
 
 

+ 1 - 1
website/src/docs/webcam.md

@@ -18,7 +18,7 @@ uppy.use(Webcam, {
 })
 })
 ```
 ```
 
 
-[Try live!](/examples/dashboard/)
+<a class="TryButton" href="/examples/dashboard/">Try it live</a>
 
 
 ## Installation
 ## Installation