Browse Source

Merge pull request #363 from goto-bus-stop/feature/setpluginstate

Move `setPluginState` to Plugin class, add `getPluginState` to match
Renée Kooi 7 years ago
parent
commit
e8ea5b2e21

+ 1 - 1
CHANGELOG.md

@@ -90,7 +90,6 @@ To be released: 2017-10-27
 - [ ] test: add https://github.com/pa11y/pa11y for automated accessibility testing (@arturi)
 - [ ] test: add tests for `npm install uppy` and running in different browsers, the real world use case (@arturi)
 - [ ] core: allow setting custom `id` for plugins: https://github.com/transloadit/uppy/pull/328#issuecomment-328242214 (@arturi)
-- [ ] core: move `setPluginState` to Plugin class ? (@goto-bus-stop)
 - [ ] 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)
 - [ ] goldenretriever: Ability to clear upload history or set expiry date (#324 / @arturi)
@@ -117,6 +116,7 @@ Theme: React and Retry
 - [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] core: move `setPluginState` to Plugin class ? (@goto-bus-stop)
 
 ## 0.19.1
 

+ 1 - 0
src/core/Core.js

@@ -91,6 +91,7 @@ class Uppy {
     this.postProcessors = []
 
     this.state = {
+      plugins: {},
       files: {},
       capabilities: {
         resumableUploads: false

+ 6 - 0
src/core/Core.test.js

@@ -147,6 +147,7 @@ describe('src/Core', () => {
         foo: 'baar',
         info: { isHidden: true, message: '', type: 'info' },
         meta: {},
+        plugins: {},
         totalProgress: 0
       }
 
@@ -168,6 +169,7 @@ describe('src/Core', () => {
         foo: 'bar',
         info: { isHidden: true, message: '', type: 'info' },
         meta: {},
+        plugins: {},
         totalProgress: 0
       })
       // new state
@@ -178,6 +180,7 @@ describe('src/Core', () => {
         foo: 'baar',
         info: { isHidden: true, message: '', type: 'info' },
         meta: {},
+        plugins: {},
         totalProgress: 0
       })
     })
@@ -193,6 +196,7 @@ describe('src/Core', () => {
         foo: 'bar',
         info: { isHidden: true, message: '', type: 'info' },
         meta: {},
+        plugins: {},
         totalProgress: 0
       })
     })
@@ -219,6 +223,7 @@ describe('src/Core', () => {
       foo: 'bar',
       info: { isHidden: true, message: '', type: 'info' },
       meta: {},
+      plugins: {},
       totalProgress: 0
     })
   })
@@ -244,6 +249,7 @@ describe('src/Core', () => {
       files: {},
       info: { isHidden: true, message: '', type: 'info' },
       meta: {},
+      plugins: {},
       totalProgress: 0
     })
     expect(core.plugins.acquirer[0].mocks.uninstall.mock.calls.length).toEqual(

+ 29 - 47
src/plugins/Dashboard/index.js

@@ -113,37 +113,33 @@ module.exports = class DashboardUI extends Plugin {
       isHidden: true
     }
 
-    const modal = this.core.getState().modal
-    const newTargets = modal.targets.slice()
+    const state = this.getPluginState()
+    const newTargets = state.targets.slice()
     newTargets.push(target)
 
-    this.core.setState({
-      modal: Object.assign({}, modal, {
-        targets: newTargets
-      })
+    this.setPluginState({
+      targets: newTargets
     })
 
     return this.target
   }
 
   hideAllPanels () {
-    const modal = this.core.getState().modal
-
-    this.core.setState({modal: Object.assign({}, modal, {
+    this.setPluginState({
       activePanel: false
-    })})
+    })
   }
 
   showPanel (id) {
-    const modal = this.core.getState().modal
+    const { targets } = this.getPluginState()
 
-    const activePanel = modal.targets.filter((target) => {
+    const activePanel = targets.filter((target) => {
       return target.type === 'acquirer' && target.id === id
     })[0]
 
-    this.core.setState({modal: Object.assign({}, modal, {
+    this.setPluginState({
       activePanel: activePanel
-    })})
+    })
   }
 
   requestCloseModal () {
@@ -155,12 +151,8 @@ module.exports = class DashboardUI extends Plugin {
   }
 
   openModal () {
-    const modal = this.core.getState().modal
-
-    this.core.setState({
-      modal: Object.assign({}, modal, {
-        isHidden: false
-      })
+    this.setPluginState({
+      isHidden: false
     })
 
     // save scroll position
@@ -180,12 +172,8 @@ module.exports = class DashboardUI extends Plugin {
   }
 
   closeModal () {
-    const modal = this.core.getState().modal
-
-    this.core.setState({
-      modal: Object.assign({}, modal, {
-        isHidden: true
-      })
+    this.setPluginState({
+      isHidden: true
     })
 
     document.body.classList.remove('is-UppyDashboard-open')
@@ -194,7 +182,7 @@ module.exports = class DashboardUI extends Plugin {
   }
 
   isModalOpen () {
-    return !this.core.getState().modal.isHidden || false
+    return !this.getPluginState().isHidden || false
   }
 
   // Close the Modal on esc key press
@@ -255,21 +243,14 @@ module.exports = class DashboardUI extends Plugin {
     const dashboardEl = this.target.querySelector('.UppyDashboard-inner')
     this.core.log(`Dashboard width: ${dashboardEl.offsetWidth}`)
 
-    const modal = this.core.getState().modal
-    this.core.setState({
-      modal: Object.assign({}, modal, {
-        containerWidth: dashboardEl.offsetWidth
-      })
+    this.setPluginState({
+      containerWidth: dashboardEl.offsetWidth
     })
   }
 
   handleFileCard (fileId) {
-    const modal = this.core.state.modal
-
-    this.core.setState({
-      modal: Object.assign({}, modal, {
-        fileCardFor: fileId || false
-      })
+    this.setPluginState({
+      fileCardFor: fileId || false
     })
   }
 
@@ -299,6 +280,7 @@ module.exports = class DashboardUI extends Plugin {
   }
 
   render (state) {
+    const pluginState = this.getPluginState()
     const files = state.files
 
     const newFiles = Object.keys(files).filter((file) => {
@@ -324,11 +306,11 @@ module.exports = class DashboardUI extends Plugin {
     totalSize = prettyBytes(totalSize)
     totalUploadedSize = prettyBytes(totalUploadedSize)
 
-    const acquirers = state.modal.targets.filter((target) => {
+    const acquirers = pluginState.targets.filter((target) => {
       return target.type === 'acquirer'
     })
 
-    const progressindicators = state.modal.targets.filter((target) => {
+    const progressindicators = pluginState.targets.filter((target) => {
       return target.type === 'progressindicator'
     })
 
@@ -359,13 +341,13 @@ module.exports = class DashboardUI extends Plugin {
 
     return Dashboard({
       state: state,
-      modal: state.modal,
+      modal: pluginState,
       newFiles: newFiles,
       files: files,
       totalFileCount: Object.keys(files).length,
       totalProgress: state.totalProgress,
       acquirers: acquirers,
-      activePanel: state.modal.activePanel,
+      activePanel: pluginState.activePanel,
       progressindicators: progressindicators,
       autoProceed: this.core.opts.autoProceed,
       hideUploadButton: this.opts.hideUploadButton,
@@ -390,14 +372,14 @@ module.exports = class DashboardUI extends Plugin {
       startUpload: startUpload,
       pauseUpload: pauseUpload,
       cancelUpload: cancelUpload,
-      fileCardFor: state.modal.fileCardFor,
+      fileCardFor: pluginState.fileCardFor,
       showFileCard: showFileCard,
       fileCardDone: fileCardDone,
       updateDashboardElWidth: this.updateDashboardElWidth,
       maxWidth: this.opts.maxWidth,
       maxHeight: this.opts.maxHeight,
-      currentWidth: state.modal.containerWidth,
-      isWide: state.modal.containerWidth > 400
+      currentWidth: pluginState.containerWidth,
+      isWide: pluginState.containerWidth > 400
     })
   }
 
@@ -411,12 +393,12 @@ module.exports = class DashboardUI extends Plugin {
 
   install () {
     // Set default state for Modal
-    this.core.setState({modal: {
+    this.setPluginState({
       isHidden: true,
       showFileCard: false,
       activePanel: false,
       targets: []
-    }})
+    })
 
     const target = this.opts.target
 

+ 13 - 0
src/plugins/Plugin.js

@@ -26,6 +26,19 @@ module.exports = class Plugin {
     this.uninstall = this.uninstall.bind(this)
   }
 
+  getPluginState () {
+    return this.core.state.plugins[this.id]
+  }
+
+  setPluginState (update) {
+    const plugins = Object.assign({}, this.core.state.plugins)
+    plugins[this.id] = Object.assign({}, plugins[this.id], update)
+
+    this.core.setState({
+      plugins: plugins
+    })
+  }
+
   update (state) {
     if (typeof this.el === 'undefined') {
       return

+ 47 - 0
src/plugins/Plugin.test.js

@@ -37,6 +37,53 @@ describe('Plugin', () => {
     expect(typeof plugin.opts).toBe('object')
   })
 
+  describe('plugin state', () => {
+    class MockPlugin extends Plugin {
+      constructor (core, opts) {
+        super(core, opts)
+        this.id = 'MockPlugin'
+      }
+    }
+    it('returns plugin state from `getPluginState()`', () => {
+      const mockState = {}
+      plugin = new MockPlugin({
+        state: {
+          plugins: {
+            MockPlugin: mockState
+          }
+        }
+      })
+
+      expect(plugin.getPluginState()).toBe(mockState)
+    })
+
+    it('merges plugin state using `setPluginState()`', () => {
+      const initialState = {
+        plugins: {
+          MockPlugin: {
+            hello: 'world',
+            asdf: 'quux'
+          }
+        }
+      }
+
+      plugin = new MockPlugin({
+        setState (patch) {
+          this.state = Object.assign({}, this.state, patch)
+        },
+        state: initialState
+      })
+
+      plugin.setPluginState({ hello: 'friends' })
+
+      expect(plugin.core.state).not.toBe(initialState)
+      expect(plugin.getPluginState()).toEqual({
+        hello: 'friends',
+        asdf: 'quux'
+      })
+    })
+  })
+
   // it('sets `replaceTargetContent` based on options argument', () => {
   //   plugin = new Plugin(null, { replaceTargetContent: false })
   //   expect(plugin.opts.replaceTargetContent).toBe(false)

+ 9 - 15
src/plugins/Transloadit/index.js

@@ -125,7 +125,7 @@ module.exports = class Transloadit extends Plugin {
       signature: options.signature
     }).then((assembly) => {
       // Store the list of assemblies related to this upload.
-      const state = this.core.state.transloadit
+      const state = this.getPluginState()
       const assemblyList = state.uploadsAssemblies[uploadID]
       const uploadsAssemblies = Object.assign({}, state.uploadsAssemblies, {
         [uploadID]: assemblyList.concat([ assembly.assembly_id ])
@@ -213,7 +213,7 @@ module.exports = class Transloadit extends Plugin {
       return
     }
 
-    const state = this.core.state.transloadit
+    const state = this.getPluginState()
     const assembly = state.assemblies[file.transloadit.assembly]
 
     this.client.addFile(assembly, file).catch((err) => {
@@ -235,7 +235,7 @@ module.exports = class Transloadit extends Plugin {
   }
 
   onFileUploadComplete (assemblyId, uploadedFile) {
-    const state = this.core.state.transloadit
+    const state = this.getPluginState()
     const file = this.findFile(uploadedFile)
     this.setPluginState({
       files: Object.assign({}, state.files, {
@@ -249,7 +249,7 @@ module.exports = class Transloadit extends Plugin {
   }
 
   onResult (assemblyId, stepName, result) {
-    const state = this.core.state.transloadit
+    const state = this.getPluginState()
     const file = state.files[result.original_id]
     // The `file` may not exist if an import robot was used instead of a file upload.
     result.localId = file ? file.id : null
@@ -262,7 +262,7 @@ module.exports = class Transloadit extends Plugin {
 
   onAssemblyFinished (url) {
     this.client.getAssemblyStatus(url).then((assembly) => {
-      const state = this.core.state.transloadit
+      const state = this.getPluginState()
       this.setPluginState({
         assemblies: Object.assign({}, state.assemblies, {
           [assembly.assembly_id]: assembly
@@ -327,7 +327,7 @@ module.exports = class Transloadit extends Plugin {
       })
     }
 
-    const state = this.core.state.transloadit
+    const state = this.getPluginState()
     const uploadsAssemblies = Object.assign({},
       state.uploadsAssemblies,
       { [uploadID]: [] })
@@ -358,7 +358,7 @@ module.exports = class Transloadit extends Plugin {
   }
 
   afterUpload (fileIDs, uploadID) {
-    const state = this.core.state.transloadit
+    const state = this.getPluginState()
     const assemblyIDs = state.uploadsAssemblies[uploadID]
 
     // If we don't have to wait for encoding metadata or results, we can close
@@ -456,7 +456,7 @@ module.exports = class Transloadit extends Plugin {
       this.core.on('transloadit:import-error', onImportError)
     }).then(() => {
       // Clean up uploadID → assemblyIDs, they're no longer going to be used anywhere.
-      const state = this.core.state.transloadit
+      const state = this.getPluginState()
       const uploadsAssemblies = Object.assign({}, state.uploadsAssemblies)
       delete uploadsAssemblies[uploadID]
       this.setPluginState({ uploadsAssemblies })
@@ -493,7 +493,7 @@ module.exports = class Transloadit extends Plugin {
   }
 
   getAssembly (id) {
-    const state = this.core.state.transloadit
+    const state = this.getPluginState()
     return state.assemblies[id]
   }
 
@@ -505,10 +505,4 @@ module.exports = class Transloadit extends Plugin {
       return file && file.transloadit && file.transloadit.assembly === assemblyID
     })
   }
-
-  setPluginState (newState) {
-    const transloadit = Object.assign({}, this.core.state.transloadit, newState)
-
-    this.core.setState({ transloadit })
-  }
 }

+ 8 - 18
src/plugins/Webcam/index.js

@@ -100,16 +100,6 @@ module.exports = class Webcam extends Plugin {
     // }
   }
 
-  /**
-   * Little shorthand to update the state with my new state
-   */
-  setPluginState (newState) {
-    const {state} = this.core
-    const webcam = Object.assign({}, state.webcam, newState)
-
-    this.core.setState({webcam})
-  }
-
   start () {
     this.webcamActive = true
 
@@ -269,15 +259,17 @@ module.exports = class Webcam extends Plugin {
       this.start()
     }
 
-    if (!state.webcam.cameraReady && !state.webcam.useTheFlash) {
-      return PermissionsScreen(state.webcam)
+    const webcamState = this.getPluginState()
+
+    if (!webcamState.cameraReady && !webcamState.useTheFlash) {
+      return PermissionsScreen(webcamState)
     }
 
     if (!this.streamSrc) {
       this.streamSrc = this.stream ? URL.createObjectURL(this.stream) : null
     }
 
-    return CameraScreen(Object.assign({}, state.webcam, {
+    return CameraScreen(Object.assign({}, webcamState, {
       onSnapshot: this.takeSnapshot,
       onStartRecording: this.startRecording,
       onStopRecording: this.stopRecording,
@@ -285,7 +277,7 @@ module.exports = class Webcam extends Plugin {
       onStop: this.stop,
       modes: this.opts.modes,
       supportsRecording: supportsMediaRecorder(),
-      recording: state.webcam.isRecording,
+      recording: webcamState.isRecording,
       getSWFHTML: this.webcam.getSWFHTML,
       src: this.streamSrc
     }))
@@ -293,10 +285,8 @@ module.exports = class Webcam extends Plugin {
 
   install () {
     this.webcam.init()
-    this.core.setState({
-      webcam: {
-        cameraReady: false
-      }
+    this.setPluginState({
+      cameraReady: false
     })
 
     const target = this.opts.target