Quellcode durchsuchen

statusbar: Pull the dashboard status bar into its own plugin.

Renée Kooi vor 7 Jahren
Ursprung
Commit
f7074e3f2e

+ 1 - 1
src/plugins/Dashboard/Dashboard.js

@@ -3,7 +3,7 @@ const FileList = require('./FileList')
 const Tabs = require('./Tabs')
 const Tabs = require('./Tabs')
 const FileCard = require('./FileCard')
 const FileCard = require('./FileCard')
 const UploadBtn = require('./UploadBtn')
 const UploadBtn = require('./UploadBtn')
-const StatusBar = require('./StatusBar')
+const StatusBar = require('../StatusBar/StatusBar')
 const { isTouchDevice, toArray } = require('../../core/Utils')
 const { isTouchDevice, toArray } = require('../../core/Utils')
 const { closeIcon } = require('./icons')
 const { closeIcon } = require('./icons')
 
 

+ 9 - 8
src/plugins/Dashboard/StatusBar.js → src/plugins/StatusBar/StatusBar.js

@@ -66,17 +66,18 @@ module.exports = (props) => {
   } else if (uploadState === STATE_UPLOADING) {
   } else if (uploadState === STATE_UPLOADING) {
     progressBarContent = ProgressBarUploading(props)
     progressBarContent = ProgressBarUploading(props)
   } else if (uploadState === STATE_ERROR) {
   } else if (uploadState === STATE_ERROR) {
+    progressValue = undefined
     progressBarContent = ProgressBarError(props)
     progressBarContent = ProgressBarError(props)
   }
   }
 
 
   const width = typeof progressValue === 'number' ? progressValue : 100
   const width = typeof progressValue === 'number' ? progressValue : 100
 
 
   return html`
   return html`
-    <div class="UppyDashboard-statusBar is-${uploadState}"
+    <div class="UppyStatusBar is-${uploadState}"
                 aria-hidden="${uploadState === STATE_WAITING}"
                 aria-hidden="${uploadState === STATE_WAITING}"
                 title="">
                 title="">
       <progress style="display: none;" min="0" max="100" value=${progressValue}></progress>
       <progress style="display: none;" min="0" max="100" value=${progressValue}></progress>
-      <div class="UppyDashboard-statusBarProgress ${progressMode ? `is-${progressMode}` : ''}"
+      <div class="UppyStatusBar-progress ${progressMode ? `is-${progressMode}` : ''}"
            style="width: ${width}%"></div>
            style="width: ${width}%"></div>
       ${progressBarContent}
       ${progressBarContent}
     </div>
     </div>
@@ -107,7 +108,7 @@ const ProgressBarProcessing = (props) => {
   }
   }
 
 
   return html`
   return html`
-    <div class="UppyDashboard-statusBarContent">
+    <div class="UppyStatusBar-content">
       ${mode === 'determinate' ? `${value * 100}%・` : ''}
       ${mode === 'determinate' ? `${value * 100}%・` : ''}
       ${message}
       ${message}
     </div>
     </div>
@@ -116,7 +117,7 @@ const ProgressBarProcessing = (props) => {
 
 
 const ProgressBarUploading = (props) => {
 const ProgressBarUploading = (props) => {
   return html`
   return html`
-    <div class="UppyDashboard-statusBarContent">
+    <div class="UppyStatusBar-content">
       ${props.isUploadStarted && !props.isAllComplete
       ${props.isUploadStarted && !props.isAllComplete
         ? !props.isAllPaused
         ? !props.isAllPaused
           ? html`<span title="Uploading">${pauseResumeButtons(props)} Uploading... ${throttledProgressDetails(props)}</span>`
           ? html`<span title="Uploading">${pauseResumeButtons(props)} Uploading... ${throttledProgressDetails(props)}</span>`
@@ -129,9 +130,9 @@ const ProgressBarUploading = (props) => {
 
 
 const ProgressBarComplete = ({ totalProgress }) => {
 const ProgressBarComplete = ({ totalProgress }) => {
   return html`
   return html`
-    <div class="UppyDashboard-statusBarContent">
+    <div class="UppyStatusBar-content">
       <span title="Complete">
       <span title="Complete">
-        <svg class="UppyDashboard-statusBarAction UppyIcon" width="18" height="17" viewBox="0 0 23 17">
+        <svg class="UppyStatusBar-action UppyIcon" width="18" height="17" viewBox="0 0 23 17">
           <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
           <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
         </svg>
         </svg>
         Upload complete・${totalProgress}%
         Upload complete・${totalProgress}%
@@ -142,7 +143,7 @@ const ProgressBarComplete = ({ totalProgress }) => {
 
 
 const ProgressBarError = ({ error }) => {
 const ProgressBarError = ({ error }) => {
   return html`
   return html`
-    <div class="UppyDashboard-statusBarContent">
+    <div class="UppyStatusBar-content">
       <span>
       <span>
         ${error.message}
         ${error.message}
       </span>
       </span>
@@ -157,7 +158,7 @@ const pauseResumeButtons = (props) => {
                   : 'pause upload'
                   : 'pause upload'
                 : 'cancel upload'
                 : 'cancel upload'
 
 
-  return html`<button title="${title}" class="UppyDashboard-statusBarAction" type="button" onclick=${() => togglePauseResume(props)}>
+  return html`<button title="${title}" class="UppyStatusBar-action" type="button" onclick=${() => togglePauseResume(props)}>
     ${props.resumableUploads
     ${props.resumableUploads
       ? props.isAllPaused
       ? props.isAllPaused
         ? html`<svg class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">
         ? html`<svg class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">

+ 141 - 0
src/plugins/StatusBar/index.js

@@ -0,0 +1,141 @@
+const Plugin = require('../Plugin')
+const StatusBar = require('./StatusBar')
+const { getSpeed } = require('../../core/Utils')
+const { getBytesRemaining } = require('../../core/Utils')
+const { prettyETA } = require('../../core/Utils')
+const prettyBytes = require('prettier-bytes')
+
+/**
+ * A status bar.
+ */
+module.exports = class StatusBarUI extends Plugin {
+  constructor (core, opts) {
+    super(core, opts)
+    this.id = 'StatusBarUI'
+    this.title = 'StatusBar UI'
+    this.type = 'progressindicator'
+
+    // set default options
+    const defaultOptions = {
+      target: 'body',
+      showProgressDetails: false
+    }
+
+    // merge default options with the ones set by user
+    this.opts = Object.assign({}, defaultOptions, opts)
+
+    this.pauseAll = this.pauseAll.bind(this)
+    this.resumeAll = this.resumeAll.bind(this)
+    this.cancelAll = this.cancelAll.bind(this)
+    this.render = this.render.bind(this)
+    this.install = this.install.bind(this)
+  }
+
+  cancelAll () {
+    this.core.bus.emit('core:cancel-all')
+  }
+
+  pauseAll () {
+    this.core.bus.emit('core:pause-all')
+  }
+
+  resumeAll () {
+    this.core.bus.emit('core:resume-all')
+  }
+
+  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
+  }
+
+  render (state) {
+    const files = state.files
+
+    const uploadStartedFiles = Object.keys(files).filter((file) => {
+      return files[file].progress.uploadStarted
+    })
+    const completeFiles = Object.keys(files).filter((file) => {
+      return files[file].progress.uploadComplete
+    })
+    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.forEach((file) => {
+      inProgressFilesArray.push(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 isAllComplete = state.totalProgress === 100 &&
+      completeFiles.length === Object.keys(files).length &&
+      processingFiles.length === 0
+    const isAllPaused = inProgressFiles.length === 0 && !isAllComplete && uploadStartedFiles.length > 0
+    const isUploadStarted = uploadStartedFiles.length > 0
+
+    const resumableUploads = this.core.getState().capabilities.resumableUploads || false
+
+    return StatusBar({
+      error: state.error,
+      totalProgress: state.totalProgress,
+      totalSize: totalSize,
+      totalUploadedSize: totalUploadedSize,
+      uploadStartedFiles: uploadStartedFiles,
+      isAllComplete: isAllComplete,
+      isAllPaused: isAllPaused,
+      isUploadStarted: isUploadStarted,
+      pauseAll: this.pauseAll,
+      resumeAll: this.resumeAll,
+      cancelAll: this.cancelAll,
+      complete: completeFiles.length,
+      inProgress: uploadStartedFiles.length,
+      totalSpeed: totalSpeed,
+      totalETA: totalETA,
+      files: state.files,
+      resumableUploads: resumableUploads
+    })
+  }
+
+  install () {
+    const target = this.opts.target
+    const plugin = this
+    this.target = this.mount(target, plugin)
+  }
+
+  uninstall () {
+    this.unmount()
+  }
+}

+ 0 - 88
src/scss/_dashboard.scss

@@ -1094,91 +1094,3 @@
     height: 30px;
     height: 30px;
   }
   }
 }
 }
-
-.UppyDashboard-statusBar {
-  position: relative;
-  height: 30px;
-  line-height: 30px;
-  font-size: 12px;
-  font-weight: 500;
-  color: $color-white;
-  background-color: rgba($color-asphalt-gray, 0.7);
-  box-shadow: 1px 1px 4px 0 rgba($color-asphalt-gray, 0.3);
-  overflow: hidden;
-  z-index: $zIndex-2;
-  transition: height .35s;
-
-  .UppyDashboard--wide & {
-    height: 40px;
-    line-height: 40px;
-    font-size: 14px;
-  }
-}
-
-.UppyDashboard-statusBar[aria-hidden=true] {
-  height: 0;
-}
-
-.UppyDashboard-statusBar.is-complete .UppyDashboard-statusBarProgress {
-  background-color: $color-green;
-}
-
-.UppyDashboard-statusBar.is-error .UppyDashboard-statusBarProgress {
-  background-color: $color-red;
-}
-
-.UppyDashboard-statusBar.is-complete .UppyDashboard-statusBarContent {
-  text-align: center;
-  padding-left: 0;
-}
-
-.UppyDashboard-statusBarProgress {
-  background-color: $color-cornflower-blue;
-  height: 100%;
-  position: absolute;
-  z-index: $zIndex-2;
-  transition: background-color, width .3s ease-out;
-
-  &.is-indeterminate {
-    $stripe-color: darken($color-cornflower-blue, 10%);
-    background-size: 64px 64px;
-    background-image: linear-gradient(45deg, $stripe-color 25%, transparent 25%, transparent 50%, $stripe-color 50%, $stripe-color 75%, transparent 75%, transparent);
-    animation: statusBarProgressStripes 1s linear infinite;
-  }
-}
-
-@keyframes statusBarProgressStripes {
-  from { background-position: 64px 0; }
-  to { background-position: 0 0; }
-}
-
-.UppyDashboard-statusBarContent {
-  font-weight: 600;
-  position: relative;
-  z-index: $zIndex-3;
-  padding-left: 15px;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  overflow: hidden;
-}
-
-.UppyDashboard-statusBarContent .UppyIcon {
-  width: 15px;
-  height: 15px;
-
-  .UppyDashboard--wide & {
-    width: 17px;
-    height: 17px;
-  }
-}
-
-.UppyDashboard-statusBarAction {
-  color: $color-white;
-  margin-right: 8px;
-}
-
-button.UppyDashboard-statusBarAction {
-  @include reset-button;
-  margin-right: 8px;
-  cursor: pointer;
-}

+ 81 - 0
src/scss/_statusbar.scss

@@ -0,0 +1,81 @@
+.UppyStatusBar {
+  position: relative;
+  height: 30px;
+  line-height: 30px;
+  font-size: 12px;
+  font-weight: 500;
+  color: $color-white;
+  background-color: rgba($color-asphalt-gray, 0.7);
+  box-shadow: 1px 1px 4px 0 rgba($color-asphalt-gray, 0.3);
+  overflow: hidden;
+  z-index: $zIndex-2;
+  transition: height .35s;
+}
+
+.UppyStatusBar[aria-hidden=true] {
+  height: 0;
+}
+
+.UppyStatusBar.is-complete .UppyStatusBar-progress {
+  background-color: $color-green;
+}
+
+.UppyStatusBar.is-error .UppyStatusBar-progress {
+  background-color: $color-red;
+}
+
+.UppyStatusBar.is-complete .UppyStatusBar-content {
+  text-align: center;
+  padding-left: 0;
+}
+
+.UppyStatusBar-progress {
+  background-color: $color-cornflower-blue;
+  height: 100%;
+  position: absolute;
+  z-index: $zIndex-2;
+  transition: background-color, width .3s ease-out;
+
+  &.is-indeterminate {
+    $stripe-color: darken($color-cornflower-blue, 10%);
+    background-size: 64px 64px;
+    background-image: linear-gradient(45deg, $stripe-color 25%, transparent 25%, transparent 50%, $stripe-color 50%, $stripe-color 75%, transparent 75%, transparent);
+    animation: statusBarProgressStripes 1s linear infinite;
+  }
+}
+
+@keyframes statusBarProgressStripes {
+  from { background-position: 64px 0; }
+  to { background-position: 0 0; }
+}
+
+.UppyStatusBar-content {
+  font-weight: 600;
+  position: relative;
+  z-index: $zIndex-3;
+  padding-left: 15px;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+.UppyStatusBar-content .UppyIcon {
+  width: 15px;
+  height: 15px;
+
+  .UppyDashboard--wide & {
+    width: 17px;
+    height: 17px;
+  }
+}
+
+.UppyStatusBar-action {
+  color: $color-white;
+  margin-right: 8px;
+}
+
+button.UppyStatusBar-action {
+  @include reset-button;
+  margin-right: 8px;
+  cursor: pointer;
+}

+ 1 - 0
src/scss/uppy.scss

@@ -14,4 +14,5 @@
 @import '_dragdrop.scss';
 @import '_dragdrop.scss';
 @import '_provider.scss';
 @import '_provider.scss';
 @import '_progressbar.scss';
 @import '_progressbar.scss';
+@import '_statusbar.scss';
 @import '_webcam.scss';
 @import '_webcam.scss';