Przeglądaj źródła

Merge stable branch

Antoine du Hamel 10 miesięcy temu
rodzic
commit
ae2ffb88cd

+ 6 - 0
.github/CONTRIBUTING.md

@@ -297,6 +297,12 @@ Now let’s create the version & tag:
 mkdir -p .git && npm version --workspaces-update=false --tag-version-prefix='@uppy/companion@' patch
 ```
 
+**Important:** Build Companion lib folder
+
+```bash
+yarn run build
+```
+
 Run a “dry-run” first:
 
 ```bash

+ 20 - 0
CHANGELOG.md

@@ -350,6 +350,26 @@ Released: 2024-03-28
 - @uppy/vue: [v4.x] remove manual types (Antoine du Hamel / #4803)
 - meta: prepare release workflow for beta versions (Antoine du Hamel)
 
+## 3.26.0
+
+Released: 2024-06-04
+
+| Package                | Version | Package                | Version |
+| ---------------------- | ------- | ---------------------- | ------- |
+| @uppy/aws-s3-multipart |  3.12.0 | @uppy/webcam           |   3.4.2 |
+| @uppy/core             |  3.12.0 | uppy                   |  3.26.0 |
+| @uppy/transloadit      |   3.7.0 |                        |         |
+
+- meta: remove Companion's `prepublishOnly` (Mikael Finstad / #5220)
+- docs: document clearUploadedFiles (Merlijn Vos / #5204)
+- @uppy/webcam: add missing types for `recordedVideo` (Antoine du Hamel / #5208)
+- @uppy/core: check capabilities in clearUploadedFiles (Merlijn Vos / #5201)
+- @uppy/core: PartialTree - change the `maxTotalFileSize` error (Evgenia Karunus / #5203)
+- @uppy/transloadit: remove `updateNumberOfFilesInAssembly` (Merlijn Vos / #5202)
+- @uppy/aws-s3: resolve all headers on response (Merlijn Vos / #5195)
+- docs: Improve provider docs: OneDrive (Evgenia Karunus / #5196)
+
+
 ## 3.25.5
 
 Released: 2024-05-23

+ 9 - 1
docs/sources/companion-plugins/onedrive.mdx

@@ -100,7 +100,15 @@ If you are using Transloadit hosted Companion:
 https://api2.transloadit.com/companion/onedrive/redirect
 ```
 
-Microsoft will give you an OAuth client ID and client secret.
+Go to the “Manifest” tab, and find the `"signInAudience"` key.  
+Change it to `"signInAudience": "AzureADandPersonalMicrosoftAccount"`, and click
+“Save”.
+
+Go to the “Overview” tab.  
+Copy the `Application (client) ID` field - this will be your Oauth client ID.
+
+Go to the “Certificates & secrets” tab, and click “+ New client secret”.  
+Copy the `Value` field - this will be your OAuth client secret.
 
 Configure the OneDrive key and secret in Companion. With the standalone
 Companion server, specify environment variables:

+ 7 - 0
docs/uppy-core.mdx

@@ -701,6 +701,13 @@ that upload.
 uppy.removeFile('uppyteamkongjpg1501851828779');
 ```
 
+#### `clear()`
+
+Clear the state. Can be useful for manually resetting Uppy after a successful
+upload.
+
+Upload plugins may choose to throw an error if called during an upload.
+
 #### `getFile(fileID)`
 
 Get a specific [Uppy file](#working-with-uppy-files) by its ID.

+ 0 - 52
e2e/cypress/integration/dashboard-transloadit.spec.ts

@@ -209,58 +209,6 @@ describe('Dashboard with Transloadit', () => {
     })
   })
 
-  // Not working, the upstream changes have not landed yet.
-  it.skip('should create assembly if there is still one file to upload', () => {
-    cy.get('@file-input').selectFile(
-      [
-        'cypress/fixtures/images/cat.jpg',
-        'cypress/fixtures/images/traffic.jpg',
-      ],
-      { force: true },
-    )
-    cy.get('.uppy-StatusBar-actionBtn--upload').click()
-
-    cy.window().then(({ uppy }) => {
-      // eslint-disable-next-line
-      // @ts-ignore fix me
-      expect(
-        Object.values(uppy.getPlugin('Transloadit').activeAssemblies).length,
-      ).to.equal(0)
-
-      const { files } = uppy.getState()
-      const [fileID] = Object.keys(files)
-      uppy.removeFile(fileID)
-
-      cy.wait('@createAssemblies').then(() => {
-        cy.wait('@resumable')
-        cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete')
-      })
-    })
-  })
-
-  // Not working, the upstream changes have not landed yet.
-  it.skip('should complete upload if one gets cancelled mid-flight', () => {
-    cy.get('@file-input').selectFile(
-      [
-        'cypress/fixtures/images/cat.jpg',
-        'cypress/fixtures/images/traffic.jpg',
-      ],
-      { force: true },
-    )
-    cy.get('.uppy-StatusBar-actionBtn--upload').click()
-
-    cy.wait('@createAssemblies')
-    cy.wait('@resumable')
-
-    cy.window().then(({ uppy }) => {
-      const { files } = uppy.getState()
-      const [fileID] = Object.keys(files)
-      uppy.removeFile(fileID)
-
-      cy.get('.uppy-StatusBar-statusPrimary').should('contain', 'Complete')
-    })
-  })
-
   it('should not emit error if upload is cancelled right away', () => {
     cy.get('@file-input').selectFile('cypress/fixtures/images/cat.jpg', {
       force: true,

+ 16 - 5
packages/@uppy/aws-s3/src/index.ts

@@ -689,9 +689,20 @@ export default class AwsS3Multipart<
 
         onProgress?.({ loaded: size, lengthComputable: true })
 
-        // NOTE This must be allowed by CORS.
-        const etag = xhr.getResponseHeader('ETag')
-        const location = xhr.getResponseHeader('Location')
+        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#examples
+        const arr = xhr
+          .getAllResponseHeaders()
+          .trim()
+          .split(/[\r\n]+/)
+        // @ts-expect-error null is allowed to avoid inherited properties
+        const headersMap: Record<string, string> = { __proto__: null }
+        for (const line of arr) {
+          const parts = line.split(': ')
+          const header = parts.shift()!
+          const value = parts.join(': ')
+          headersMap[header] = value
+        }
+        const { etag, location } = headersMap
 
         if (method.toUpperCase() === 'POST' && location === null) {
           // Not being able to read the Location header is not a fatal error.
@@ -711,8 +722,8 @@ export default class AwsS3Multipart<
 
         onComplete?.(etag)
         resolve({
-          ETag: etag,
-          ...(location ? { location } : undefined),
+          ...headersMap,
+          ETag: etag, // keep capitalised ETag for backwards compatiblity
         })
       })
 

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

@@ -103,7 +103,6 @@
   "scripts": {
     "build": "tsc -p .",
     "deploy": "kubectl apply -f infra/kube/companion-kube.yml",
-    "prepublishOnly": "yarn run build",
     "start": "node ./lib/standalone/start-server.js",
     "test": "NODE_OPTIONS=--experimental-vm-modules jest --runInBand"
   },

+ 8 - 0
packages/@uppy/core/CHANGELOG.md

@@ -56,6 +56,14 @@ Included in: Uppy v4.0.0-beta.1
 - @uppy/core: various type fixes (Antoine du Hamel / #4995)
 - @uppy/core,@uppy/provider-views: Fix breadcrumbs (Evgenia Karunus / #4986)
 
+## 3.12.0
+
+Released: 2024-06-04
+Included in: Uppy v3.26.0
+
+- @uppy/core: check capabilities in clearUploadedFiles (Merlijn Vos / #5201)
+- @uppy/core: PartialTree - change the `maxTotalFileSize` error (Evgenia Karunus / #5203)
+
 ## 3.11.3
 
 Released: 2024-05-14

+ 9 - 17
packages/@uppy/core/src/Restricter.ts

@@ -98,25 +98,17 @@ class Restricter<M extends Meta, B extends Body> {
     }
 
     if (maxTotalFileSize) {
-      let totalFilesSize = existingFiles.reduce(
-        (total, f) => (total + (f.size ?? 0)) as number,
+      const totalFilesSize = [...existingFiles, ...addingFiles].reduce(
+        (total, f) => total + (f.size ?? 0),
         0,
       )
-
-      for (const addingFile of addingFiles) {
-        if (addingFile.size != null) {
-          // We can't check maxTotalFileSize if the size is unknown.
-          totalFilesSize += addingFile.size
-
-          if (totalFilesSize > maxTotalFileSize) {
-            throw new RestrictionError(
-              this.getI18n()('exceedsSize', {
-                size: prettierBytes(maxTotalFileSize),
-                file: addingFile.name,
-              }),
-            )
-          }
-        }
+      if (totalFilesSize > maxTotalFileSize) {
+        throw new RestrictionError(
+          this.getI18n()('aggregateExceedsSize', {
+            sizeAllowed: prettierBytes(maxTotalFileSize),
+            size: prettierBytes(totalFilesSize),
+          }),
+        )
       }
     }
   }

+ 5 - 3
packages/@uppy/core/src/Uppy.test.ts

@@ -492,7 +492,7 @@ describe('src/Core', () => {
 
     assert.throws(
       () => core.removeFile(fileIDs[0]),
-      /individualCancellation is disabled/,
+      /The installed uploader plugin does not allow removing files during an upload/,
     )
 
     expect(core.getState().currentUploads[id]).toBeDefined()
@@ -2135,7 +2135,7 @@ describe('src/Core', () => {
     it('should enforce the maxTotalFileSize rule', () => {
       const core = new Core({
         restrictions: {
-          maxTotalFileSize: 34000,
+          maxTotalFileSize: 20000,
         },
       })
 
@@ -2154,7 +2154,9 @@ describe('src/Core', () => {
           data: testImage,
         })
       }).toThrowError(
-        new Error('foo1.jpg exceeds maximum allowed size of 33 KB'),
+        new Error(
+          'You selected 34 KB of files, but maximum allowed size is 20 KB',
+        ),
       )
     })
 

+ 13 - 1
packages/@uppy/core/src/Uppy.ts

@@ -557,6 +557,16 @@ export class Uppy<M extends Meta, B extends Body> {
   }
 
   clear(): void {
+    const { capabilities, currentUploads } = this.getState()
+    if (
+      Object.keys(currentUploads).length > 0 &&
+      !capabilities.individualCancellation
+    ) {
+      throw new Error(
+        'The installed uploader plugin does not allow removing files during an upload.',
+      )
+    }
+
     this.setState({ ...defaultUploadState, files: {} })
   }
 
@@ -1130,7 +1140,9 @@ export class Uppy<M extends Meta, B extends Body> {
         newFileIDs.length !== currentUploads[uploadID].fileIDs.length &&
         !capabilities.individualCancellation
       ) {
-        throw new Error('individualCancellation is disabled')
+        throw new Error(
+          'The installed uploader plugin does not allow removing files during an upload.',
+        )
       }
 
       updatedUploads[uploadID] = {

+ 2 - 0
packages/@uppy/core/src/locale.ts

@@ -12,6 +12,8 @@ export default {
       0: 'You have to select at least %{smart_count} file',
       1: 'You have to select at least %{smart_count} files',
     },
+    aggregateExceedsSize:
+      'You selected %{size} of files, but maximum allowed size is %{sizeAllowed}',
     exceedsSize: '%{file} exceeds maximum allowed size of %{size}',
     missingRequiredMetaField: 'Missing required meta fields',
     missingRequiredMetaFieldOnFile:

+ 8 - 0
packages/@uppy/transloadit/CHANGELOG.md

@@ -20,6 +20,14 @@ Released: 2024-03-28
 Included in: Uppy v4.0.0-beta.1
 
 - @uppy/transloadit: migrate to TS (Merlijn Vos / #4987)
+
+## 3.7.0
+
+Released: 2024-06-04
+Included in: Uppy v3.26.0
+
+- @uppy/transloadit: remove `updateNumberOfFilesInAssembly` (Merlijn Vos / #5202)
+
 ## 3.6.2
 
 Released: 2024-05-23

+ 0 - 24
packages/@uppy/transloadit/src/Client.ts

@@ -170,30 +170,6 @@ export default class Client<M extends Meta, B extends Body> {
     )
   }
 
-  /**
-   * Update the number of expected files in an already created assembly.
-   */
-  async updateNumberOfFilesInAssembly(
-    assembly: AssemblyResponse,
-    num_expected_upload_files: number,
-  ): Promise<AssemblyResponse> {
-    const url = new URL(assembly.assembly_ssl_url)
-    url.pathname = '/update_assemblies'
-    const body = JSON.stringify({
-      assembly_updates: [
-        {
-          assembly_id: assembly.assembly_id,
-          num_expected_upload_files,
-        },
-      ],
-    })
-    return this.#fetchJSON(url, {
-      method: 'POST',
-      headers: this.#headers,
-      body,
-    }).catch((err) => this.#reportError(err, { url, type: 'API_ERROR' }))
-  }
-
   /**
    * Cancel a running Assembly.
    */

+ 5 - 23
packages/@uppy/transloadit/src/index.ts

@@ -395,17 +395,10 @@ export default class Transloadit<
         const files = this.uppy
           .getFiles()
           .filter(({ id }) => fileIDs.includes(id))
-        if (files.length !== fileIDs.length) {
-          if (files.length === 0) {
-            // All files have been removed, cancelling.
-            await this.client.cancelAssembly(newAssembly)
-            return null
-          }
-          // At least one file has been removed.
-          await this.client.updateNumberOfFilesInAssembly(
-            newAssembly,
-            files.length,
-          )
+        if (files.length === 0) {
+          // All files have been removed, cancelling.
+          await this.client.cancelAssembly(newAssembly)
+          return null
         }
 
         const assembly = new Assembly(newAssembly, this.#rateLimitedQueue)
@@ -441,22 +434,11 @@ export default class Transloadit<
         // TODO: this should not live inside a `file-removed` event but somewhere more deterministic.
         // Such as inside the function where the assembly has succeeded or cancelled.
         // For the use case of cancelling the assembly when needed, we should try to do that with just `cancel-all`.
-        const fileRemovedHandler = (fileRemoved: UppyFile<M, B>) => {
+        const fileRemovedHandler = () => {
           // If the assembly has successfully completed, we do not need these checks.
           // Otherwise we may cancel an assembly after it already succeeded
           if (assembly.status?.ok === 'ASSEMBLY_COMPLETED') {
             this.uppy.off('file-removed', fileRemovedHandler)
-            return
-          }
-          if (fileRemoved.id in updatedFiles) {
-            delete updatedFiles[fileRemoved.id]
-            const nbOfRemainingFiles = Object.keys(updatedFiles).length
-
-            this.client
-              .updateNumberOfFilesInAssembly(newAssembly, nbOfRemainingFiles)
-              .catch(() => {
-                /* ignore potential errors */
-              })
           }
         }
         this.uppy.on('file-removed', fileRemovedHandler)

+ 7 - 0
packages/@uppy/webcam/CHANGELOG.md

@@ -15,6 +15,13 @@ Included in: Uppy v4.0.0-beta.1
 - @uppy/audio,@uppy/dashboard,@uppy/drop-target,@uppy/webcam: add missing exports (Antoine du Hamel / #5014)
 - @uppy/webcam: refactor to TypeScript (Antoine du Hamel / #4870)
 
+## 3.4.2
+
+Released: 2024-06-04
+Included in: Uppy v3.26.0
+
+- @uppy/webcam: add missing types for `recordedVideo` (Antoine du Hamel / #5208)
+
 ## 3.4.0
 
 Released: 2024-03-27

+ 1 - 1
packages/@uppy/webcam/src/CameraScreen.tsx

@@ -21,6 +21,7 @@ interface CameraScreenProps extends VideoSourceSelectProps {
 
   src: MediaStream | null
   recording: boolean
+  recordedVideo: string | null
   modes: string[]
   supportsRecording: boolean
   showVideoSourceDropdown: boolean
@@ -53,7 +54,6 @@ class CameraScreen extends Component<CameraScreenProps> {
   render(): ComponentChild {
     const {
       src,
-      // @ts-expect-error TODO: remove unused
       recordedVideo,
       recording,
       modes,

+ 1 - 0
packages/@uppy/webcam/src/Webcam.tsx

@@ -81,6 +81,7 @@ interface WebcamState {
   recordingLengthSeconds: number
   videoSources: MediaDeviceInfo[]
   currentDeviceId: string | MediaStreamTrack | null | undefined
+  recordedVideo: null | string
   isRecording: boolean
   [key: string]: unknown
 }