mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-18 00:55:35 +00:00
234 lines
7.5 KiB
JavaScript
234 lines
7.5 KiB
JavaScript
const Plugin = require('../../core/Plugin')
|
|
const Translator = require('../../core/Translator')
|
|
const StatusBarUI = require('./StatusBar')
|
|
const statusBarStates = require('./StatusBarStates')
|
|
const { getSpeed } = require('../../core/Utils')
|
|
const { getBytesRemaining } = require('../../core/Utils')
|
|
const { prettyETA } = require('../../core/Utils')
|
|
const prettyBytes = require('prettier-bytes')
|
|
|
|
/**
|
|
* StatusBar: renders a status bar with upload/pause/resume/cancel/retry buttons,
|
|
* progress percentage and time remaining.
|
|
*/
|
|
module.exports = class StatusBar extends Plugin {
|
|
constructor (uppy, opts) {
|
|
super(uppy, opts)
|
|
this.id = this.opts.id || 'StatusBar'
|
|
this.title = 'StatusBar'
|
|
this.type = 'progressindicator'
|
|
|
|
const defaultLocale = {
|
|
strings: {
|
|
uploading: 'Uploading',
|
|
complete: 'Complete',
|
|
uploadFailed: 'Upload failed',
|
|
pleasePressRetry: 'Please press Retry to upload again',
|
|
paused: 'Paused',
|
|
error: 'Error',
|
|
retry: 'Retry',
|
|
cancel: 'Cancel',
|
|
pressToRetry: 'Press to retry',
|
|
retryUpload: 'Retry upload',
|
|
resumeUpload: 'Resume upload',
|
|
cancelUpload: 'Cancel upload',
|
|
pauseUpload: 'Pause upload',
|
|
filesUploadedOfTotal: {
|
|
0: '%{complete} of %{smart_count} file uploaded',
|
|
1: '%{complete} of %{smart_count} files uploaded'
|
|
},
|
|
dataUploadedOfTotal: '%{complete} of %{total}',
|
|
xTimeLeft: '%{time} left',
|
|
uploadXFiles: {
|
|
0: 'Upload %{smart_count} file',
|
|
1: 'Upload %{smart_count} files'
|
|
},
|
|
uploadXNewFiles: {
|
|
0: 'Upload +%{smart_count} file',
|
|
1: 'Upload +%{smart_count} files'
|
|
}
|
|
}
|
|
}
|
|
|
|
// set default options
|
|
const defaultOptions = {
|
|
target: 'body',
|
|
hideUploadButton: false,
|
|
showProgressDetails: false,
|
|
locale: defaultLocale,
|
|
hideAfterFinish: true
|
|
}
|
|
|
|
// merge default options with the ones set by user
|
|
this.opts = Object.assign({}, defaultOptions, opts)
|
|
|
|
this.locale = Object.assign({}, defaultLocale, this.opts.locale)
|
|
this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)
|
|
|
|
this.translator = new Translator({locale: this.locale})
|
|
this.i18n = this.translator.translate.bind(this.translator)
|
|
|
|
this.startUpload = this.startUpload.bind(this)
|
|
this.render = this.render.bind(this)
|
|
this.install = this.install.bind(this)
|
|
}
|
|
|
|
getTotalSpeed (files) {
|
|
let totalSpeed = 0
|
|
files.forEach((file) => {
|
|
totalSpeed = totalSpeed + getSpeed(file.progress)
|
|
})
|
|
return totalSpeed
|
|
}
|
|
|
|
getTotalETA (files) {
|
|
const totalSpeed = this.getTotalSpeed(files)
|
|
if (totalSpeed === 0) {
|
|
return 0
|
|
}
|
|
|
|
const totalBytesRemaining = files.reduce((total, file) => {
|
|
return total + getBytesRemaining(file.progress)
|
|
}, 0)
|
|
|
|
return Math.round(totalBytesRemaining / totalSpeed * 10) / 10
|
|
}
|
|
|
|
startUpload () {
|
|
return this.uppy.upload().catch((err) => {
|
|
this.uppy.log(err.stack || err.message || err)
|
|
// Ignore
|
|
})
|
|
}
|
|
|
|
getUploadingState (isAllErrored, isAllComplete, files) {
|
|
if (isAllErrored) {
|
|
return statusBarStates.STATE_ERROR
|
|
}
|
|
|
|
if (isAllComplete) {
|
|
return statusBarStates.STATE_COMPLETE
|
|
}
|
|
|
|
let state = statusBarStates.STATE_WAITING
|
|
const fileIDs = Object.keys(files)
|
|
for (let i = 0; i < fileIDs.length; i++) {
|
|
const progress = files[fileIDs[i]].progress
|
|
// If ANY files are being uploaded right now, show the uploading state.
|
|
if (progress.uploadStarted && !progress.uploadComplete) {
|
|
return statusBarStates.STATE_UPLOADING
|
|
}
|
|
// If files are being preprocessed AND postprocessed at this time, we show the
|
|
// preprocess state. If any files are being uploaded we show uploading.
|
|
if (progress.preprocess && state !== statusBarStates.STATE_UPLOADING) {
|
|
state = statusBarStates.STATE_PREPROCESSING
|
|
}
|
|
// If NO files are being preprocessed or uploaded right now, but some files are
|
|
// being postprocessed, show the postprocess state.
|
|
if (progress.postprocess && state !== statusBarStates.STATE_UPLOADING && state !== statusBarStates.STATE_PREPROCESSING) {
|
|
state = statusBarStates.STATE_POSTPROCESSING
|
|
}
|
|
}
|
|
return state
|
|
}
|
|
|
|
render (state) {
|
|
const files = state.files
|
|
|
|
const uploadStartedFiles = Object.keys(files).filter((file) => {
|
|
return files[file].progress.uploadStarted
|
|
})
|
|
const newFiles = Object.keys(files).filter((file) => {
|
|
return !files[file].progress.uploadStarted &&
|
|
!files[file].progress.preprocess &&
|
|
!files[file].progress.postprocess
|
|
})
|
|
const completeFiles = Object.keys(files).filter((file) => {
|
|
return files[file].progress.uploadComplete
|
|
})
|
|
const erroredFiles = Object.keys(files).filter((file) => {
|
|
return files[file].error
|
|
})
|
|
const inProgressFiles = Object.keys(files).filter((file) => {
|
|
return !files[file].progress.uploadComplete &&
|
|
files[file].progress.uploadStarted &&
|
|
!files[file].isPaused
|
|
})
|
|
const processingFiles = Object.keys(files).filter((file) => {
|
|
return files[file].progress.preprocess || files[file].progress.postprocess
|
|
})
|
|
|
|
let inProgressFilesArray = inProgressFiles.map((file) => {
|
|
return files[file]
|
|
})
|
|
|
|
const totalSpeed = prettyBytes(this.getTotalSpeed(inProgressFilesArray))
|
|
const totalETA = prettyETA(this.getTotalETA(inProgressFilesArray))
|
|
|
|
// total size and uploaded size
|
|
let totalSize = 0
|
|
let totalUploadedSize = 0
|
|
inProgressFilesArray.forEach((file) => {
|
|
totalSize = totalSize + (file.progress.bytesTotal || 0)
|
|
totalUploadedSize = totalUploadedSize + (file.progress.bytesUploaded || 0)
|
|
})
|
|
totalSize = prettyBytes(totalSize)
|
|
totalUploadedSize = prettyBytes(totalUploadedSize)
|
|
|
|
const isUploadStarted = uploadStartedFiles.length > 0
|
|
|
|
const isAllComplete = state.totalProgress === 100 &&
|
|
completeFiles.length === Object.keys(files).length &&
|
|
processingFiles.length === 0
|
|
|
|
const isAllErrored = isUploadStarted &&
|
|
erroredFiles.length === uploadStartedFiles.length
|
|
|
|
const isAllPaused = inProgressFiles.length === 0 &&
|
|
!isAllComplete &&
|
|
!isAllErrored &&
|
|
uploadStartedFiles.length > 0
|
|
|
|
const resumableUploads = state.capabilities.resumableUploads || false
|
|
|
|
return StatusBarUI({
|
|
error: state.error,
|
|
uploadState: this.getUploadingState(isAllErrored, isAllComplete, state.files || {}),
|
|
totalProgress: state.totalProgress,
|
|
totalSize: totalSize,
|
|
totalUploadedSize: totalUploadedSize,
|
|
uploadStarted: uploadStartedFiles.length,
|
|
isAllComplete: isAllComplete,
|
|
isAllPaused: isAllPaused,
|
|
isAllErrored: isAllErrored,
|
|
isUploadStarted: isUploadStarted,
|
|
complete: completeFiles.length,
|
|
newFiles: newFiles.length,
|
|
inProgress: inProgressFiles.length,
|
|
totalSpeed: totalSpeed,
|
|
totalETA: totalETA,
|
|
files: state.files,
|
|
i18n: this.i18n,
|
|
pauseAll: this.uppy.pauseAll,
|
|
resumeAll: this.uppy.resumeAll,
|
|
retryAll: this.uppy.retryAll,
|
|
cancelAll: this.uppy.cancelAll,
|
|
startUpload: this.startUpload,
|
|
resumableUploads: resumableUploads,
|
|
showProgressDetails: this.opts.showProgressDetails,
|
|
hideUploadButton: this.opts.hideUploadButton,
|
|
hideAfterFinish: this.opts.hideAfterFinish
|
|
})
|
|
}
|
|
|
|
install () {
|
|
const target = this.opts.target
|
|
if (target) {
|
|
this.mount(target, this)
|
|
}
|
|
}
|
|
|
|
uninstall () {
|
|
this.unmount()
|
|
}
|
|
}
|