From 2b91812f8da7023a2b52b8a8661914a5cb816a9f Mon Sep 17 00:00:00 2001 From: Pascal Wengerter Date: Wed, 27 Apr 2022 19:40:47 +0200 Subject: [PATCH] [full-ci] Switch upload logic to Uppy (#6202) * WIP * WIP uppy * Refactor uppy code * Update changelog item, move uppy dependencies to web-runtime package * Fix unit tests * Remove logs and unnecessary events * Minor fixes and improvements * Fix ocis e2e tests * Fix more e2e tests * Prevent form fields from being added to uploaded file contents * Properly encode file name for XHR uploads * update fileDrop acceptance tests * Remove Uppy drop target plugin on unmount * Fix issues when uploading nested folders * change rollup plugin order to apply injections for ts files also * Fix issue with missing slashes when uploading * Ensure that uppy uses only one upload plugin at a time * Fix issue when updating the store for newly created folders * Remove Uppy debug state * Small fixes and polishing * Fix tests, polishing * Undo change in sunday,monday.txt file * Bump owncloud-test-middleware docker image version to 1.5.0 Co-authored-by: Jannik Stehle Co-authored-by: saw-jan Co-authored-by: Florian Schade --- .drone.star | 2 +- .../unreleased/enhancement-resumeable-uploads | 12 + packages/web-app-files/package.json | 3 +- packages/web-app-files/src/App.vue | 16 +- .../src/components/AppBar/CreateAndUpload.vue | 217 ++++++---- .../src/components/AppBar/Upload/FileDrop.vue | 132 ------ .../components/AppBar/Upload/FileUpload.vue | 39 +- .../components/AppBar/Upload/FolderUpload.vue | 26 +- .../src/components/Upload/ProgressBar.vue | 7 +- .../src/composables/upload/index.ts | 1 + .../composables/upload/useUploadHelpers.ts | 174 ++++++++ .../web-app-files/src/helpers/user/types.ts | 1 + packages/web-app-files/src/mixins.js | 403 ------------------ packages/web-app-files/src/store/actions.js | 14 - packages/web-app-files/src/store/getters.js | 4 - packages/web-app-files/src/store/mutations.js | 48 --- packages/web-app-files/src/store/state.js | 2 - .../web-app-files/src/views/FilesDrop.vue | 174 +++----- .../components/AppBar/CreateAndUpload.spec.js | 3 +- .../components/AppBar/Upload/FileDrop.spec.js | 110 ----- .../AppBar/Upload/FileUpload.spec.js | 32 +- .../AppBar/Upload/FolderUpload.spec.js | 31 +- .../components/Upload/ProgressBar.spec.js | 3 +- .../web-app-files/tests/unit/mixins.spec.js | 37 -- .../tests/unit/views/FilesDrop.spec.js | 130 +----- .../__snapshots__/FilesDrop.spec.js.snap | 151 +------ .../tests/unit/views/views.setup.js | 1 - .../composables/capability/useCapability.ts | 8 + packages/web-runtime/package.json | 7 +- .../web-runtime/src/components/UploadInfo.vue | 223 ++++++++++ .../src/composables/upload/index.ts | 1 + .../upload/uppyPlugins/customDropTarget.ts | 39 ++ .../upload/uppyPlugins/customTus.ts | 14 + .../src/composables/upload/useUpload.ts | 151 +++++++ .../web-runtime/src/container/bootstrap.ts | 10 + packages/web-runtime/src/defaults/vue.js | 5 - packages/web-runtime/src/index.ts | 4 +- .../web-runtime/src/layouts/Application.vue | 5 +- packages/web-runtime/src/plugins/upload.js | 65 --- .../web-runtime/src/services/uppyService.ts | 240 +++++++++++ rollup.config.js | 10 +- .../shareByPublicLinkDifferentRoles.feature | 4 +- tests/acceptance/pageObjects/filesDropPage.js | 6 +- tests/acceptance/pageObjects/personalPage.js | 2 +- .../support/objects/app-files/page/public.ts | 2 +- .../objects/app-files/resource/actions.ts | 9 +- yarn.lock | 183 ++++++-- 47 files changed, 1331 insertions(+), 1430 deletions(-) create mode 100644 changelog/unreleased/enhancement-resumeable-uploads delete mode 100644 packages/web-app-files/src/components/AppBar/Upload/FileDrop.vue create mode 100644 packages/web-app-files/src/composables/upload/index.ts create mode 100644 packages/web-app-files/src/composables/upload/useUploadHelpers.ts delete mode 100644 packages/web-app-files/tests/unit/components/AppBar/Upload/FileDrop.spec.js delete mode 100644 packages/web-app-files/tests/unit/mixins.spec.js create mode 100644 packages/web-runtime/src/components/UploadInfo.vue create mode 100644 packages/web-runtime/src/composables/upload/index.ts create mode 100644 packages/web-runtime/src/composables/upload/uppyPlugins/customDropTarget.ts create mode 100644 packages/web-runtime/src/composables/upload/uppyPlugins/customTus.ts create mode 100644 packages/web-runtime/src/composables/upload/useUpload.ts delete mode 100644 packages/web-runtime/src/plugins/upload.js create mode 100644 packages/web-runtime/src/services/uppyService.ts diff --git a/.drone.star b/.drone.star index 2a54cdf6252..c343d151c5a 100644 --- a/.drone.star +++ b/.drone.star @@ -20,7 +20,7 @@ OC_CI_HUGO = "owncloudci/hugo:0.89.4" OC_CI_NODEJS = "owncloudci/nodejs:14" OC_CI_PHP = "owncloudci/php:7.4" OC_CI_WAIT_FOR = "owncloudci/wait-for:latest" -OC_TESTING_MIDDLEWARE = "owncloud/owncloud-test-middleware:1.4.2" +OC_TESTING_MIDDLEWARE = "owncloud/owncloud-test-middleware:1.5.0" OC_UBUNTU = "owncloud/ubuntu:20.04" PLUGINS_DOCKER = "plugins/docker:18.09" PLUGINS_DOWNSTREAM = "plugins/downstream" diff --git a/changelog/unreleased/enhancement-resumeable-uploads b/changelog/unreleased/enhancement-resumeable-uploads new file mode 100644 index 00000000000..df429090a42 --- /dev/null +++ b/changelog/unreleased/enhancement-resumeable-uploads @@ -0,0 +1,12 @@ +Enhancement: Resumable uploads + +We've implemented Uppy as a library for handling uploads. This concludes the following features and changes: + +- Resumable uploads when the backend supports the Tus-protocol +- A nice looking overview for all files that have been uploaded successfully or failed to upload +- Navigation across Web while uploads are in progress +- Improved rendering of uploadProgress-visualization +- Removed `vue2-dropzone` and `vue-drag-drop` libraries + +https://github.com/owncloud/web/pull/6202 +https://github.com/owncloud/web/issues/6268 diff --git a/packages/web-app-files/package.json b/packages/web-app-files/package.json index efc2da258ab..c8acbc83df6 100644 --- a/packages/web-app-files/package.json +++ b/packages/web-app-files/package.json @@ -4,7 +4,6 @@ "description": "ownCloud web files", "license": "AGPL-3.0", "dependencies": { - "copy-to-clipboard": "^3.3.1", - "vue2-dropzone": "^3.6.0" + "copy-to-clipboard": "^3.3.1" } } diff --git a/packages/web-app-files/src/App.vue b/packages/web-app-files/src/App.vue index fb8aae9e5fd..b9e1d445c57 100644 --- a/packages/web-app-files/src/App.vue +++ b/packages/web-app-files/src/App.vue @@ -1,11 +1,6 @@ @@ -26,6 +27,7 @@ import { mapActions, mapGetters } from 'vuex' import TopBar from '../components/Topbar/TopBar.vue' import MessageBar from '../components/MessageBar.vue' import SidebarNav from '../components/SidebarNav/SidebarNav.vue' +import UploadInfo from '../components/UploadInfo.vue' import { useActiveApp, useRoute } from 'web-pkg/src/composables' import { watch, defineComponent } from '@vue/composition-api' @@ -33,7 +35,8 @@ export default defineComponent({ components: { MessageBar, TopBar, - SidebarNav + SidebarNav, + UploadInfo }, setup() { // FIXME: we can convert to a single router-view without name (thus without the loop) and without this watcher when we release v6.0.0 diff --git a/packages/web-runtime/src/plugins/upload.js b/packages/web-runtime/src/plugins/upload.js deleted file mode 100644 index 4a6aa2c6a8e..00000000000 --- a/packages/web-runtime/src/plugins/upload.js +++ /dev/null @@ -1,65 +0,0 @@ -import { isSupported, Upload } from 'tus-js-client' - -export default { - install(Vue) { - Vue.mixin({ - computed: { - browserSupportsChunked() { - return isSupported - } - }, - methods: { - uploadChunkedFile(file, path, options) { - return new Promise((resolve, reject) => { - const headers = this.$client.helpers.buildHeaders() - delete headers['OCS-APIREQUEST'] - let mtime = null - if (file.lastModifiedDate) { - mtime = file.lastModifiedDate.getTime() / 1000 - } - if (file.lastModified) { - mtime = file.lastModified / 1000 - } - const upload = new Upload(file, { - endpoint: this.$client.files.getFileUrlV2(path), - headers: headers, - chunkSize: options.chunkSize || Infinity, - removeFingerprintOnSuccess: true, - overridePatchMethod: !!options.overridePatchMethod, - retryDelays: [0, 3000, 5000, 10000, 20000], - metadata: { - filename: file.name, - filetype: file.type, - size: file.size, - mtime: mtime - }, - - onError: (error) => { - console.error(`Error uploading file "${file}" to "${path}"`, error) - reject(error) - }, - - onProgress: (bytesUploaded, bytesTotal) => { - options.emitProgress({ loaded: bytesUploaded, total: bytesTotal }) - }, - - onSuccess: () => { - resolve(`File ${upload.file.name} was uploaded successfully`) - } - }) - - upload.findPreviousUploads().then((previousUploads) => { - if (previousUploads.length === 0) { - return - } - upload.resumeFromPreviousUpload(previousUploads[0]) - }) - - upload.start() - return upload - }) - } - } - }) - } -} diff --git a/packages/web-runtime/src/services/uppyService.ts b/packages/web-runtime/src/services/uppyService.ts new file mode 100644 index 00000000000..74e2f342571 --- /dev/null +++ b/packages/web-runtime/src/services/uppyService.ts @@ -0,0 +1,240 @@ +import Uppy from '@uppy/core' +import { CustomTus } from '../composables/upload/uppyPlugins/customTus' +import XHRUpload, { XHRUploadOptions } from '@uppy/xhr-upload' +import { CustomDropTarget } from '../composables/upload/uppyPlugins/customDropTarget' +import StatusBar from '@uppy/status-bar' +import { UppyResource } from '../composables/upload' +import Vue from 'vue' + +export class UppyService extends Vue { + uppy: Uppy + uploadInputs: HTMLInputElement[] = [] + + constructor() { + super() + this.uppy = new Uppy({ + autoProceed: true + }) + this.setUpEvents() + } + + useTus({ + tusMaxChunkSize, + uploadChunkSize, + tusHttpMethodOverride, + headers + }: { + tusMaxChunkSize: number + uploadChunkSize: number + tusHttpMethodOverride: boolean + headers: { [key: string]: string } + }) { + const chunkSize = + tusMaxChunkSize > 0 && uploadChunkSize !== Infinity + ? Math.max(tusMaxChunkSize, uploadChunkSize) + : uploadChunkSize + + const tusPluginOptions = { + headers: headers, + chunkSize: chunkSize, + removeFingerprintOnSuccess: true, + overridePatchMethod: !!tusHttpMethodOverride, + retryDelays: [0] + } + + const xhrPlugin = this.uppy.getPlugin('XHRUpload') + if (xhrPlugin) { + this.uppy.removePlugin(xhrPlugin) + } + + const tusPlugin = this.uppy.getPlugin('Tus') + if (tusPlugin) { + tusPlugin.setOptions(tusPluginOptions) + return + } + + this.uppy.use(CustomTus, tusPluginOptions) + } + + useXhr({ headers }: { headers: { [key: string]: string } }) { + const xhrPluginOptions: XHRUploadOptions = { + endpoint: '', + method: 'put', + headers, + formData: false, + getResponseData() { + return {} + } + } + + const tusPlugin = this.uppy.getPlugin('Tus') + if (tusPlugin) { + this.uppy.removePlugin(tusPlugin) + } + + const xhrPlugin = this.uppy.getPlugin('XHRUpload') + if (xhrPlugin) { + xhrPlugin.setOptions(xhrPluginOptions) + return + } + + this.uppy.use(XHRUpload, xhrPluginOptions) + } + + useDropTarget({ + targetSelector, + uppyService + }: { + targetSelector: string + uppyService: UppyService + }) { + if (this.uppy.getPlugin('DropTarget')) { + return + } + this.uppy.use(CustomDropTarget, { + target: targetSelector, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + uppyService + }) + } + + removeDropTarget() { + const dropTargetPlugin = this.uppy.getPlugin('DropTarget') + if (dropTargetPlugin) { + this.uppy.removePlugin(dropTargetPlugin) + } + } + + useStatusBar({ + targetSelector, + getText + }: { + targetSelector: string + getText: (msgid: string) => string + }) { + if (this.uppy.getPlugin('StatusBar')) { + return + } + + this.uppy.use(StatusBar, { + id: 'StatusBar', + target: targetSelector, + hideAfterFinish: true, + showProgressDetails: true, + hideUploadButton: false, + hideRetryButton: false, + hidePauseResumeButton: false, + hideCancelButton: false, + doneButtonHandler: null, + locale: { + strings: { + uploading: getText('Uploading'), + complete: getText('Complete'), + uploadFailed: getText('Upload failed'), + paused: getText('Paused'), + retry: getText('Retry'), + cancel: getText('Cancel'), + pause: getText('Pause'), + resume: getText('Resume'), + done: getText('Done'), + filesUploadedOfTotal: { + 0: getText('%{complete} of %{smart_count} file uploaded'), + 1: getText('%{complete} of %{smart_count} files uploaded') + }, + dataUploadedOfTotal: getText('%{complete} of %{total}'), + xTimeLeft: getText('%{time} left'), + uploadXFiles: { + 0: getText('Upload %{smart_count} file'), + 1: getText('Upload %{smart_count} files') + }, + uploadXNewFiles: { + 0: getText('Upload +%{smart_count} file'), + 1: getText('Upload +%{smart_count} files') + }, + upload: getText('Upload'), + retryUpload: getText('Retry upload'), + xMoreFilesAdded: { + 0: getText('%{smart_count} more file added'), + 1: getText('%{smart_count} more files added') + }, + showErrorDetails: getText('Show error details') + } + } + }) + } + + private setUpEvents() { + this.uppy.on('upload', () => { + this.$emit('uploadStarted') + }) + this.uppy.on('cancel-all', () => { + this.$emit('uploadCancelled') + }) + this.uppy.on('complete', (result) => { + this.$emit('uploadCompleted') + result.successful.forEach((file) => { + this.$emit('uploadSuccess', file) + this.uppy.removeFile(file.id) + }) + result.failed.forEach((file) => { + this.$emit('uploadError', file) + }) + this.uploadInputs.forEach((item) => { + item.value = null + }) + }) + this.uppy.on('file-removed', () => { + this.$emit('uploadRemoved') + this.uploadInputs.forEach((item) => { + item.value = null + }) + }) + this.uppy.on('file-added', (file) => { + this.$emit('fileAdded') + const addedFile = file as unknown as UppyResource + if (this.uppy.getPlugin('XHRUpload')) { + const escapedName = encodeURIComponent(addedFile.name) + this.uppy.setFileState(addedFile.id, { + xhrUpload: { + endpoint: `${addedFile.meta.tusEndpoint.replace(/\/+$/, '')}/${escapedName}` + } + }) + } + }) + } + + registerUploadInput(el: HTMLInputElement) { + const listenerRegistered = el.getAttribute('listener') + if (listenerRegistered !== 'true') { + el.setAttribute('listener', 'true') + el.addEventListener('change', (event) => { + const target = event.target as HTMLInputElement + const files = Array.from(target.files) + this.$emit('filesSelected', files) + }) + this.uploadInputs.push(el) + } + } + + removeUploadInput(el: HTMLInputElement) { + this.uploadInputs = this.uploadInputs.filter((input) => input !== el) + } + + uploadFiles(files: UppyResource[]) { + files.forEach((file) => { + try { + this.uppy.addFile(file) + } catch (err) { + console.error('error upload file:', file) + if (err.isRestriction) { + // handle restrictions + console.error('Restriction error:', err) + } else { + // handle other errors + console.error(err) + } + } + }) + } +} diff --git a/rollup.config.js b/rollup.config.js index 71eff617204..777e3fa9fe8 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -60,9 +60,6 @@ const plugins = [ css: false }), nodePolyfills(), - inject({ - Buffer: ['buffer', 'Buffer'] - }), resolve({ include: 'node_modules/**', dedupe: ['@vue/composition-api'], @@ -83,6 +80,9 @@ const plugins = [ ts({ browserslist: false }), + inject({ + Buffer: ['buffer', 'Buffer'] + }), json(), copy({ watch: !production && ['./config', './packages/web-runtime/themes'], @@ -150,7 +150,9 @@ const plugins = [ const fp = path.parse(f.fileName) const lastDash = fp.name.lastIndexOf('-') acc[c][ - production ? fp.name.slice(0, lastDash !== -1 ? lastDash : 0) || fp.name : fp.name + production + ? fp.name.slice(0, lastDash !== -1 ? lastDash : 0) || fp.name + : fp.name ] = c === 'js' ? fp.name : f.fileName }) diff --git a/tests/acceptance/features/webUISharingPublicDifferentRoles/shareByPublicLinkDifferentRoles.feature b/tests/acceptance/features/webUISharingPublicDifferentRoles/shareByPublicLinkDifferentRoles.feature index acf0005e7a2..f80efaa6dd3 100644 --- a/tests/acceptance/features/webUISharingPublicDifferentRoles/shareByPublicLinkDifferentRoles.feature +++ b/tests/acceptance/features/webUISharingPublicDifferentRoles/shareByPublicLinkDifferentRoles.feature @@ -71,7 +71,7 @@ Feature: Share by public link with different roles | name | Public link | And a link named "Public link" should be listed with role "Uploader" in the public link list of folder "simple-folder" on the webUI When the public uses the webUI to access the last public link created by user "Alice" in a new session - Then there should be no resources listed on the webUI + Then the user should be redirected to the files-drop page @skipOnOC10 @issue-ocis-reva-383 #after fixing the issue delete this scenario and use the one above by deleting the @skipOnOCIS tag there @@ -87,7 +87,7 @@ Feature: Share by public link with different roles | path | /simple-folder | And a public link with the last created link share token as name should be listed for resource "simple-folder" on the webUI When the public uses the webUI to access the last public link created by user "Alice" in a new session - Then there should be no resources listed on the webUI + Then the user should be redirected to the files-drop page @issue-4582 @disablePreviews Scenario: creating a public link with "Editor" role makes it possible to delete files via the link diff --git a/tests/acceptance/pageObjects/filesDropPage.js b/tests/acceptance/pageObjects/filesDropPage.js index 8f9bdd68a9f..707736792cf 100644 --- a/tests/acceptance/pageObjects/filesDropPage.js +++ b/tests/acceptance/pageObjects/filesDropPage.js @@ -44,7 +44,7 @@ module.exports = { const files = [] for (const { ELEMENT } of elements) { await this.api.elementIdText(ELEMENT, function (result) { - files.push(result.value) + files.push(result.value.replace('\n', '')) }) } return files @@ -56,11 +56,11 @@ module.exports = { locateStrategy: 'css selector' }, uploadedFiles: { - selector: 'table tr > td:first-child', + selector: '.upload-info-successful-uploads span.oc-resource-name', locateStrategy: 'css selector' }, fileDropzone: { - selector: '#oc-dropzone', + selector: '#files-drop-container', locateStrategy: 'css selector' } } diff --git a/tests/acceptance/pageObjects/personalPage.js b/tests/acceptance/pageObjects/personalPage.js index e3b566924c1..480dd78611c 100644 --- a/tests/acceptance/pageObjects/personalPage.js +++ b/tests/acceptance/pageObjects/personalPage.js @@ -168,7 +168,7 @@ module.exports = { false ) .waitForElementNotVisible('@fileUploadProgress') - .click('@newFileMenuButton') + .click('@uploadFilesButton') }, /** * This uploads a folder that is inside the selenium host, diff --git a/tests/e2e/support/objects/app-files/page/public.ts b/tests/e2e/support/objects/app-files/page/public.ts index 56198384fad..2f5e85a3338 100644 --- a/tests/e2e/support/objects/app-files/page/public.ts +++ b/tests/e2e/support/objects/app-files/page/public.ts @@ -23,7 +23,7 @@ export class Public { async upload({ resources }: { resources: File[] }): Promise { await this.#page - .locator('//input[@id="file_upload_start" or @class="dz-hidden-input"]') + .locator('//input[@id="fileUploadInput"]') .setInputFiles(resources.map((file) => file.path)) } } diff --git a/tests/e2e/support/objects/app-files/resource/actions.ts b/tests/e2e/support/objects/app-files/resource/actions.ts index e0b2cbd02a5..1299c624fe4 100644 --- a/tests/e2e/support/objects/app-files/resource/actions.ts +++ b/tests/e2e/support/objects/app-files/resource/actions.ts @@ -74,13 +74,12 @@ export const uploadResource = async (args: uploadResourceArgs): Promise => await page.locator('#fileUploadInput').setInputFiles(resources.map((file) => file.path)) if (createVersion) { - const fileName = resources.map((file) => path.basename(file.name)) - await Promise.all([ - page.waitForResponse((resp) => resp.url().endsWith(fileName[0]) && resp.status() === 204), - page.locator('.oc-modal-body-actions-confirm').click() - ]) + await page.locator('.oc-modal-body-actions-confirm').click() + // @TODO check if upload was successful } + await page.locator('#close-upload-info-btn').click() + await waitForResources({ page: page, names: resources.map((file) => path.basename(file.name)) diff --git a/yarn.lock b/yarn.lock index adf6a256120..39745305292 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2262,6 +2262,13 @@ __metadata: languageName: node linkType: hard +"@transloadit/prettier-bytes@npm:0.0.7": + version: 0.0.7 + resolution: "@transloadit/prettier-bytes@npm:0.0.7" + checksum: af075e1b2b045cac55d5ab854b5c94273ef7f4bd825f05fe578559465f206d2a1535343b50170252a9efb31ffdc2d6420e64eb32d2faeabeeb8b7d81d5d46ef0 + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.8 resolution: "@tsconfig/node10@npm:1.0.8" @@ -2739,6 +2746,100 @@ __metadata: languageName: node linkType: hard +"@uppy/companion-client@npm:^2.0.4, @uppy/companion-client@npm:^2.0.5": + version: 2.0.6 + resolution: "@uppy/companion-client@npm:2.0.6" + dependencies: + "@uppy/utils": ^4.0.6 + namespace-emitter: ^2.0.1 + checksum: 2a60c70a280b4c7d898d5c0b4b58b0088dc4dc2937b7cf426c6a29a9a404a9db218fa6b909f892eb8a886106882943e2ccfc05b309fa760d90bef76039bc7b52 + languageName: node + linkType: hard + +"@uppy/core@npm:^2.1.7": + version: 2.1.8 + resolution: "@uppy/core@npm:2.1.8" + dependencies: + "@transloadit/prettier-bytes": 0.0.7 + "@uppy/store-default": ^2.0.3 + "@uppy/utils": ^4.0.6 + lodash.throttle: ^4.1.1 + mime-match: ^1.0.2 + namespace-emitter: ^2.0.1 + nanoid: ^3.1.25 + preact: ^10.5.13 + checksum: 2c4e1febef1cd7ef841aa9634773fa7eccc9737b34412152964ff384a0ced32b85cadc3532de7de7c74ae7da8887d2e8accd7e5b9f1df40cdec72e65441f3aff + languageName: node + linkType: hard + +"@uppy/drop-target@npm:^1.1.1": + version: 1.1.2 + resolution: "@uppy/drop-target@npm:1.1.2" + dependencies: + "@uppy/utils": ^4.0.5 + peerDependencies: + "@uppy/core": ^2.1.6 + checksum: fc237303e0377182ec72288ade6fca9b3a6ee4344ff4930844efb460d3768b6273be3982c28726c8b134fc2966ea98d129e003ffaa96f1254d0f004d75726b2a + languageName: node + linkType: hard + +"@uppy/status-bar@npm:^2.1.3": + version: 2.1.3 + resolution: "@uppy/status-bar@npm:2.1.3" + dependencies: + "@transloadit/prettier-bytes": 0.0.7 + "@uppy/utils": ^4.0.5 + classnames: ^2.2.6 + lodash.throttle: ^4.1.1 + preact: ^10.5.13 + peerDependencies: + "@uppy/core": ^2.1.6 + checksum: 80df539fd4f8444ffdc824b102b248a039bd2519ce6940fa76d40723212dfd14642067410bce30f388ca64cd66152906fe5458d08e2d489ccb737e6d8c84e01a + languageName: node + linkType: hard + +"@uppy/store-default@npm:^2.0.3": + version: 2.0.3 + resolution: "@uppy/store-default@npm:2.0.3" + checksum: aa6a3f80611ce6efed2963a197e3592cf00b1dedeb7e6c5aa7282e4ef857c8a7c1b747f8943cf969cc0fb12daf4907b62f1041a3df177bff01feb403f7dc777e + languageName: node + linkType: hard + +"@uppy/tus@npm:^2.2.2": + version: 2.2.2 + resolution: "@uppy/tus@npm:2.2.2" + dependencies: + "@uppy/companion-client": ^2.0.5 + "@uppy/utils": ^4.0.5 + tus-js-client: ^2.1.1 + peerDependencies: + "@uppy/core": ^2.1.7 + checksum: 16073b4dfcd1a49d998ccaa37ff78707a80758dcebb92b5644042cb4601821e78690ed5e0ea3b829ed33129772c384bf8c9c60a69211e70447a956cef3225f57 + languageName: node + linkType: hard + +"@uppy/utils@npm:^4.0.4, @uppy/utils@npm:^4.0.5, @uppy/utils@npm:^4.0.6": + version: 4.0.6 + resolution: "@uppy/utils@npm:4.0.6" + dependencies: + lodash.throttle: ^4.1.1 + checksum: 8773c4b1d742d65237c48c0575f1a933a20ffdcd8da462141b19649c027b0b88e4aa5dcb26ead1e830c967b904e51315fb61ea72ee0273614b463122d2b63066 + languageName: node + linkType: hard + +"@uppy/xhr-upload@npm:^2.0.7": + version: 2.0.7 + resolution: "@uppy/xhr-upload@npm:2.0.7" + dependencies: + "@uppy/companion-client": ^2.0.4 + "@uppy/utils": ^4.0.4 + nanoid: ^3.1.25 + peerDependencies: + "@uppy/core": ^2.1.4 + checksum: 714bb27348816249feea9545da299b56e150830ecd2d5e7015a061f412b349287aa2db875465949b4c58836377dbb7634d8e176a87c0126cb92b0a54ab408049 + languageName: node + linkType: hard + "@vue/compiler-core@npm:3.1.1": version: 3.1.1 resolution: "@vue/compiler-core@npm:3.1.1" @@ -4221,6 +4322,13 @@ __metadata: languageName: node linkType: hard +"classnames@npm:^2.2.6": + version: 2.3.1 + resolution: "classnames@npm:2.3.1" + checksum: 14db8889d56c267a591f08b0834989fe542d47fac659af5a539e110cc4266694e8de86e4e3bbd271157dbd831361310a8293e0167141e80b0f03a0f175c80960 + languageName: node + linkType: hard + "clean-css@npm:^4.1.11": version: 4.2.3 resolution: "clean-css@npm:4.2.3" @@ -4570,7 +4678,7 @@ __metadata: languageName: node linkType: hard -"core-js@npm:^2.4.0, core-js@npm:^2.5.3, core-js@npm:^2.6.5": +"core-js@npm:^2.4.0, core-js@npm:^2.6.5": version: 2.6.12 resolution: "core-js@npm:2.6.12" checksum: 44fa9934a85f8c78d61e0c8b7b22436330471ffe59ec5076fe7f324d6e8cf7f824b14b1c81ca73608b13bdb0fef035bd820989bf059767ad6fa13123bb8bd016 @@ -5360,13 +5468,6 @@ __metadata: languageName: unknown linkType: soft -"dropzone@npm:^5.5.1": - version: 5.9.2 - resolution: "dropzone@npm:5.9.2" - checksum: 4c906f1e08421bbbb14f5e41ad37e5694317b6761f0a7e95d22c3037f6a05fe01ba48b722392187cccef367f18fdbaa18b1ae172c0b5cdb9a39ecba04ebb4f0a - languageName: node - linkType: hard - "duplexify@npm:^4.1.2": version: 4.1.2 resolution: "duplexify@npm:4.1.2" @@ -6324,7 +6425,6 @@ __metadata: resolution: "files@workspace:packages/web-app-files" dependencies: copy-to-clipboard: ^3.3.1 - vue2-dropzone: ^3.6.0 languageName: unknown linkType: soft @@ -9022,6 +9122,15 @@ __metadata: languageName: node linkType: hard +"mime-match@npm:^1.0.2": + version: 1.0.2 + resolution: "mime-match@npm:1.0.2" + dependencies: + wildcard: ^1.1.0 + checksum: 3e4afd6be98e20bfb421146a14147560941f471886e6d3534372b37d29bb7e35a7462e1f9cee98312f92e44969ae9deca2da7ad91ab5a738af55a7d5f03a6814 + languageName: node + linkType: hard + "mime-types@npm:^2.1.12": version: 2.1.31 resolution: "mime-types@npm:2.1.31" @@ -9257,12 +9366,19 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.32, nanoid@npm:^3.3.1": - version: 3.3.1 - resolution: "nanoid@npm:3.3.1" +"namespace-emitter@npm:^2.0.1": + version: 2.0.1 + resolution: "namespace-emitter@npm:2.0.1" + checksum: 49ae49674d5b83e18ad91c549ed264df1fcba02d039617e0932dab618f79e3749de6d878d54962b5cbf2611c0eafc91203a376980399c33c30edf542f19cb034 + languageName: node + linkType: hard + +"nanoid@npm:^3.1.25, nanoid@npm:^3.1.32, nanoid@npm:^3.3.1": + version: 3.3.2 + resolution: "nanoid@npm:3.3.2" bin: nanoid: bin/nanoid.cjs - checksum: 4ef0969e1bbe866fc223eb32276cbccb0961900bfe79104fa5abe34361979dead8d0e061410a5c03bc3d47455685adf32c09d6f27790f4a6898fb51f7df7ec86 + checksum: 376717f0685251fad77850bd84c6b8d57837c71eeb1c05be7c742140cc1835a5a2953562add05166d6dbc8fb65f3fdffa356213037b967a470e1691dc3e7b9cc languageName: node linkType: hard @@ -10739,6 +10855,13 @@ __metadata: languageName: node linkType: hard +"preact@npm:^10.5.13": + version: 10.7.1 + resolution: "preact@npm:10.7.1" + checksum: e99d08bd38372e78ce1c84e68685cad66adf076bd95069bc8bcd32c9903a4df09c01d5b04aad849527362b67cc2c09446b647f72de4e67d0578fdea0f904f28f + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -13151,7 +13274,7 @@ __metadata: languageName: node linkType: hard -"tus-js-client@npm:^2.3.1": +"tus-js-client@npm:^2.1.1": version: 2.3.1 resolution: "tus-js-client@npm:2.3.1" dependencies: @@ -13567,15 +13690,6 @@ __metadata: languageName: node linkType: hard -"vue-drag-drop@npm:^1.1.4": - version: 1.1.4 - resolution: "vue-drag-drop@npm:1.1.4" - dependencies: - core-js: ^2.5.3 - checksum: 8d4184ed35cb941745d42f9a925866f06fe9b7a71386792503efccc451fe6fed1c733d3f3d847a0eed2316ad861903b965fcb476153b233517609600dbb56695 - languageName: node - linkType: hard - "vue-eslint-parser@npm:^7.0.0, vue-eslint-parser@npm:^7.10.0": version: 7.11.0 resolution: "vue-eslint-parser@npm:7.11.0" @@ -13706,15 +13820,6 @@ __metadata: languageName: node linkType: hard -"vue2-dropzone@npm:^3.6.0": - version: 3.6.0 - resolution: "vue2-dropzone@npm:3.6.0" - dependencies: - dropzone: ^5.5.1 - checksum: 6aada15d09bc8d2a1a3d59b370927fade313726224048635aa896ed8e592b71d6b1eb22d74bb45062631adc63ddd19ebbcfa59d8eaaaea35cb1248fff3c80ca1 - languageName: node - linkType: hard - "vue@npm:^2.6.10": version: 2.6.14 resolution: "vue@npm:2.6.14" @@ -13818,6 +13923,11 @@ __metadata: "@popperjs/core": ^2.4.0 "@types/luxon": ^2.3.1 "@types/semver": ^7.3.8 + "@uppy/core": ^2.1.7 + "@uppy/drop-target": ^1.1.1 + "@uppy/status-bar": ^2.1.3 + "@uppy/tus": ^2.2.2 + "@uppy/xhr-upload": ^2.0.7 "@vue/composition-api": ^1.4.9 axios: ^0.26.1 cross-fetch: ^3.0.6 @@ -13842,14 +13952,12 @@ __metadata: sanitize-html: ^2.7.0 semver: ^7.3.5 tippy.js: ^6.3.7 - tus-js-client: ^2.3.1 utf8: ^3.0.0 uuid: ^8.3.2 v-calendar: ^2.3.2 vue: ^2.6.10 vue-async-computed: ^3.9.0 vue-concurrency: ^2.2.1 - vue-drag-drop: ^1.1.4 vue-events: ^3.1.0 vue-gettext: ^2.1.5 vue-inline-svg: ^2.0.0 @@ -13987,6 +14095,13 @@ __metadata: languageName: node linkType: hard +"wildcard@npm:^1.1.0": + version: 1.1.2 + resolution: "wildcard@npm:1.1.2" + checksum: f93bf48a23b7b776f7960fa7f252af55da265b4ce8127852e420f04a907b78073bc0412f74fc662f561667f3277473974f6553a260ece67f53b1975d128320ab + languageName: node + linkType: hard + "with@npm:^7.0.0": version: 7.0.2 resolution: "with@npm:7.0.2"