From 00c0b9495215b220a72990c2849a2677a5f08311 Mon Sep 17 00:00:00 2001 From: Pascal Wengerter Date: Tue, 15 Feb 2022 12:54:50 +0000 Subject: [PATCH 1/4] Use resource-icon for All Files navItem --- packages/web-app-files/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web-app-files/src/index.js b/packages/web-app-files/src/index.js index eba4951c99c..4fca4d65819 100644 --- a/packages/web-app-files/src/index.js +++ b/packages/web-app-files/src/index.js @@ -30,7 +30,7 @@ function $gettext(msg) { const appInfo = { name: $gettext('Files'), id: 'files', - icon: 'folder', + icon: 'resource-type-folder', isFileEditor: false, extensions: [], fileSideBars From c35de98b6b49739451d917fcaffc051e8c9227cf Mon Sep 17 00:00:00 2001 From: Pascal Wengerter Date: Tue, 15 Feb 2022 12:55:32 +0000 Subject: [PATCH 2/4] Fix usage of external app icon/image in contextMenu --- packages/web-app-files/src/components/ActionMenuItem.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/web-app-files/src/components/ActionMenuItem.vue b/packages/web-app-files/src/components/ActionMenuItem.vue index 10076744df0..45964967ea1 100644 --- a/packages/web-app-files/src/components/ActionMenuItem.vue +++ b/packages/web-app-files/src/components/ActionMenuItem.vue @@ -14,6 +14,13 @@ alt="" class="oc-icon oc-icon-m" /> + Date: Tue, 15 Feb 2022 15:08:16 +0000 Subject: [PATCH 3/4] Separate 'create new file/folder' and 'upload files/folder' actions into two dropdowns Extract create/upload from appBar into new component --- ...enhancement-redesign-create-upload-buttons | 7 + packages/web-app-draw-io/src/index.js | 2 +- .../src/components/AppBar/AppBar.vue | 465 +------------- .../src/components/AppBar/CreateAndUpload.vue | 567 ++++++++++++++++++ .../components/AppBar/Upload/FileUpload.vue | 4 +- .../components/AppBar/Upload/FolderUpload.vue | 4 +- .../unit/components/AppBar/AppBar.spec.js | 39 +- .../AppBar/Upload/FolderUpload.spec.js | 1 + packages/web-app-markdown-editor/src/index.js | 4 +- tests/acceptance/pageObjects/personalPage.js | 7 +- tests/e2e/support/page/files/allFiles.ts | 2 +- 11 files changed, 629 insertions(+), 473 deletions(-) create mode 100644 changelog/unreleased/enhancement-redesign-create-upload-buttons create mode 100644 packages/web-app-files/src/components/AppBar/CreateAndUpload.vue diff --git a/changelog/unreleased/enhancement-redesign-create-upload-buttons b/changelog/unreleased/enhancement-redesign-create-upload-buttons new file mode 100644 index 00000000000..581e50dd641 --- /dev/null +++ b/changelog/unreleased/enhancement-redesign-create-upload-buttons @@ -0,0 +1,7 @@ +Enhancement: Redesign create and upload buttons + +We have separated the "Create new file/folder" and "Upload" actions above the files list into two separate buttons, +also using the new resource type icons for more consistency. + +https://github.com/owncloud/web/issues/6279 +https://github.com/owncloud/web/pull/6358 diff --git a/packages/web-app-draw-io/src/index.js b/packages/web-app-draw-io/src/index.js index 32f90039321..96e059c72db 100644 --- a/packages/web-app-draw-io/src/index.js +++ b/packages/web-app-draw-io/src/index.js @@ -24,7 +24,7 @@ const appInfo = { routeName: 'draw-io', newFileMenu: { menuTitle($gettext) { - return $gettext('New draw.io document…') + return $gettext('Draw.io document') } } }, diff --git a/packages/web-app-files/src/components/AppBar/AppBar.vue b/packages/web-app-files/src/components/AppBar/AppBar.vue index 75f359d0719..6ceecbd5f1b 100644 --- a/packages/web-app-files/src/components/AppBar/AppBar.vue +++ b/packages/web-app-files/src/components/AppBar/AppBar.vue @@ -30,98 +30,18 @@
- +
@@ -136,30 +56,28 @@ import { mapActions, mapGetters, mapState, mapMutations } from 'vuex' import pathUtil from 'path' import Mixins from '../../mixins' -import MixinFileActions, { EDITOR_MODE_CREATE } from '../../mixins/fileActions' +import MixinFileActions from '../../mixins/fileActions' import { buildResource, buildWebDavFilesPath, buildWebDavSpacesPath } from '../../helpers/resources' import { bus } from 'web-pkg/src/instance' -import { isLocationActive, isLocationPublicActive, isLocationSpacesActive } from '../../router' +import { DavProperties } from 'web-pkg/src/constants' +import { isLocationPublicActive, isLocationSpacesActive } from '../../router' import { useActiveLocation } from '../../composables' import BatchActions from './SelectedResources/BatchActions.vue' +import ContextActions from '../FilesList/ContextActions.vue' +import CreateAndUpload from './CreateAndUpload.vue' import FileDrop from './Upload/FileDrop.vue' -import FileUpload from './Upload/FileUpload.vue' -import FolderUpload from './Upload/FolderUpload.vue' import SizeInfo from './SelectedResources/SizeInfo.vue' import ViewOptions from './ViewOptions.vue' -import { DavProperties, DavProperty } from 'web-pkg/src/constants' -import ContextActions from '../FilesList/ContextActions.vue' export default { components: { BatchActions, + ContextActions, + CreateAndUpload, FileDrop, - FileUpload, - FolderUpload, SizeInfo, - ViewOptions, - ContextActions + ViewOptions }, mixins: [Mixins, MixinFileActions], setup() { @@ -187,31 +105,6 @@ export default { ...mapGetters('Files', ['files', 'currentFolder', 'selectedFiles', 'publicLinkPassword']), ...mapState('Files', ['areHiddenFilesShown']), - mimetypesAllowedForCreation() { - // we can't use `mapGetters` here because the External app doesn't exist in all deployments - const mimeTypes = this.$store.getters['External/mimeTypes'] - if (!mimeTypes) { - return [] - } - return mimeTypes.filter((mimetype) => mimetype.allow_creation) || [] - }, - newButtonTooltip() { - if (!this.canUpload) { - return this.$gettext('You have no permission to upload!') - } - if (!this.hasFreeSpace) { - return this.$gettext('You have not enough space left to upload!') - } - return null - }, - newButtonAriaLabel() { - const tooltip = this.newButtonTooltip - if (tooltip) { - return tooltip - } - return this.$gettext('Add files or folders') - }, - currentPath() { const path = this.$route.params.item || '' if (path.endsWith('/')) { @@ -332,10 +225,6 @@ export default { return this.selectedFiles.length < 1 }, - isNewBtnDisabled() { - return !this.canUpload || !this.hasFreeSpace - }, - selectedResourcesAnnouncement() { if (this.selectedFiles.length === 0) { return this.$gettext('No items selected.') @@ -346,12 +235,6 @@ export default { this.selectedFiles.length ) return this.$gettextInterpolate(translated, { amount: this.selectedFiles.length }) - }, - - newFileHandlersForRoute() { - return this.newFileHandlers.filter(({ routes = [] }) => - isLocationActive(this.$router, ...routes.map((name) => ({ name }))) - ) } }, @@ -367,318 +250,10 @@ export default { methods: { ...mapActions('Files', ['updateFileProgress', 'removeFilesFromTrashbin', 'loadIndicators']), - ...mapActions(['openFile', 'showMessage', 'createModal', 'setModalInputErrorMessage']), + ...mapActions(['openFile', 'showMessage']), ...mapMutations('Files', ['UPSERT_RESOURCE', 'SET_HIDDEN_FILES_VISIBILITY']), ...mapMutations(['SET_QUOTA']), - showCreateResourceModal( - isFolder = true, - ext = 'txt', - openAction = null, - addAppProviderFile = false - ) { - const defaultName = isFolder - ? this.$gettext('New folder') - : this.$gettext('New file') + '.' + ext - const checkInputValue = (value) => { - this.setModalInputErrorMessage( - isFolder ? this.checkNewFolderName(value) : this.checkNewFileName(value) - ) - } - - // Sets action to be executed after creation of the file - if (!isFolder) { - this.newFileAction = openAction - } - - const modal = { - variation: 'passive', - title: isFolder ? this.$gettext('Create a new folder') : this.$gettext('Create a new file'), - cancelText: this.$gettext('Cancel'), - confirmText: this.$gettext('Create'), - hasInput: true, - inputValue: defaultName, - inputLabel: isFolder ? this.$gettext('Folder name') : this.$gettext('File name'), - inputError: isFolder - ? this.checkNewFolderName(defaultName) - : this.checkNewFileName(defaultName), - onCancel: this.hideModal, - onConfirm: isFolder - ? this.addNewFolder - : addAppProviderFile - ? this.addAppProviderFile - : this.addNewFile, - onInput: checkInputValue - } - - this.createModal(modal) - }, - - async addNewFolder(folderName) { - if (folderName === '') { - return - } - - this.fileFolderCreationLoading = true - - try { - let path = pathUtil.join(this.currentPath, folderName) - let resource - - if (this.isPersonalLocation) { - path = buildWebDavFilesPath(this.user.id, path) - await this.$client.files.createFolder(path) - resource = await this.$client.files.fileInfo(path, DavProperties.Default) - } else if (this.isSpacesProjectLocation) { - path = buildWebDavSpacesPath(this.$route.params.spaceId, path) - await this.$client.files.createFolder(path) - resource = await this.$client.files.fileInfo(path, DavProperties.Default) - } else { - await this.$client.publicFiles.createFolder(path, null, this.publicLinkPassword) - resource = await this.$client.publicFiles.getFileInfo( - path, - this.publicLinkPassword, - DavProperties.PublicLink - ) - } - resource = buildResource(resource) - - this.UPSERT_RESOURCE(resource) - this.hideModal() - - if (this.isPersonalLocation) { - this.loadIndicators({ - client: this.$client, - currentFolder: this.currentFolder.path - }) - } - - this.showMessage({ - title: this.$gettextInterpolate( - this.$gettext('"%{folderName}" was created successfully'), - { - folderName - } - ) - }) - } catch (error) { - console.error(error) - this.showMessage({ - title: this.$gettext('Failed to create folder'), - status: 'danger' - }) - } - - this.fileFolderCreationLoading = false - }, - - checkNewFolderName(folderName) { - if (folderName === '') { - return this.$gettext('Folder name cannot be empty') - } - - if (/[/]/.test(folderName)) { - return this.$gettext('Folder name cannot contain "/"') - } - - if (folderName === '.') { - return this.$gettext('Folder name cannot be equal to "."') - } - - if (folderName === '..') { - return this.$gettext('Folder name cannot be equal to ".."') - } - - if (/\s+$/.test(folderName)) { - return this.$gettext('Folder name cannot end with whitespace') - } - - const exists = this.files.find((file) => file.name === folderName) - - if (exists) { - const translated = this.$gettext('%{name} already exists') - return this.$gettextInterpolate(translated, { name: folderName }, true) - } - - return null - }, - - async addNewFile(fileName) { - if (fileName === '') { - return - } - - this.fileFolderCreationLoading = true - - try { - let resource - let path = pathUtil.join(this.currentPath, fileName) - - if (this.isPersonalLocation) { - path = buildWebDavFilesPath(this.user.id, path) - await this.$client.files.putFileContents(path, '') - resource = await this.$client.files.fileInfo(path, DavProperties.Default) - } else if (this.isSpacesProjectLocation) { - path = buildWebDavSpacesPath(this.$route.params.spaceId, path) - await this.$client.files.putFileContents(path, '') - resource = await this.$client.files.fileInfo(path, DavProperties.Default) - } else { - await this.$client.publicFiles.putFileContents('', path, this.publicLinkPassword, '') - resource = await this.$client.publicFiles.getFileInfo( - path, - this.publicLinkPassword, - DavProperties.PublicLink - ) - } - - if (this.newFileAction) { - const fileId = resource.fileInfo[DavProperty.FileId] - - this.$_fileActions_openEditor(this.newFileAction, path, fileId, EDITOR_MODE_CREATE) - this.hideModal() - - return - } - - resource = buildResource(resource) - - this.UPSERT_RESOURCE(resource) - this.hideModal() - - if (this.isPersonalLocation) { - this.loadIndicators({ - client: this.$client, - currentFolder: this.currentFolder.path - }) - } - - this.showMessage({ - title: this.$gettextInterpolate(this.$gettext('"%{fileName}" was created successfully'), { - fileName - }) - }) - } catch (error) { - console.error(error) - this.showMessage({ - title: this.$gettext('Failed to create file'), - status: 'danger' - }) - } - - this.fileFolderCreationLoading = false - }, - async addAppProviderFile(fileName) { - // FIXME: this belongs in web-app-external, but the app provider handles file creation differently than other editor extensions. Needs more refactoring. - if (fileName === '') { - return - } - try { - const parent = this.currentFolder.fileId - const publicToken = (this.$router.currentRoute.params.item || '').split('/')[0] - - const configUrl = this.configuration.server - const appNewUrl = this.capabilities.files.app_providers[0].new_url.replace(/^\/+/, '') - const url = - configUrl + - appNewUrl + - `?parent_container_id=${parent}&filename=${encodeURIComponent(fileName)}` - - const headers = { - 'X-Requested-With': 'XMLHttpRequest', - ...(this.isPublicLocation && - publicToken && { - 'public-token': publicToken - }), - ...(this.isPublicLocation && - this.publicLinkPassword && { - Authorization: - 'Basic ' + - Buffer.from(['public', this.publicLinkPassword].join(':')).toString('base64') - }), - ...(this.getToken && { - Authorization: 'Bearer ' + this.getToken - }) - } - - const response = await fetch(url, { - method: 'POST', - headers - }) - - if (response.status !== 200) { - throw new Error(`An error has occurred: ${response.status}`) - } - - let resource - let path = pathUtil.join(this.currentPath, fileName) - - if (this.isPersonalLocation) { - path = buildWebDavFilesPath(this.user.id, path) - resource = await this.$client.files.fileInfo(path, DavProperties.Default) - } else if (this.isSpacesProjectLocation) { - path = buildWebDavSpacesPath(this.$route.params.spaceId, path) - resource = await this.$client.files.fileInfo(path, DavProperties.Default) - } else { - resource = await this.$client.publicFiles.getFileInfo( - path, - this.publicLinkPassword, - DavProperties.PublicLink - ) - } - resource = buildResource(resource) - this.$_fileActions_triggerDefaultAction(resource) - this.UPSERT_RESOURCE(resource) - this.hideModal() - - if (this.isPersonalLocation) { - this.loadIndicators({ - client: this.$client, - currentFolder: this.currentFolder.path - }) - } - this.showMessage({ - title: this.$gettextInterpolate(this.$gettext('"%{fileName}" was created successfully'), { - fileName - }) - }) - } catch (error) { - console.error(error) - this.showMessage({ - title: this.$gettext('Failed to create file'), - status: 'danger' - }) - } - }, - checkNewFileName(fileName) { - if (fileName === '') { - return this.$gettext('File name cannot be empty') - } - - if (/[/]/.test(fileName)) { - return this.$gettext('File name cannot contain "/"') - } - - if (fileName === '.') { - return this.$gettext('File name cannot be equal to "."') - } - - if (fileName === '..') { - return this.$gettext('File name cannot be equal to ".."') - } - - if (/\s+$/.test(fileName)) { - return this.$gettext('File name cannot end with whitespace') - } - - const exists = this.files.find((file) => file.name === fileName) - - if (exists) { - const translated = this.$gettext('%{name} already exists') - return this.$gettextInterpolate(translated, { name: fileName }, true) - } - - return null - }, async onFileSuccess(event, file) { try { if (file.name) { diff --git a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue new file mode 100644 index 00000000000..d95af1daff4 --- /dev/null +++ b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue @@ -0,0 +1,567 @@ + + + + diff --git a/packages/web-app-files/src/components/AppBar/Upload/FileUpload.vue b/packages/web-app-files/src/components/AppBar/Upload/FileUpload.vue index 271a9ad6fae..3303719fdf9 100644 --- a/packages/web-app-files/src/components/AppBar/Upload/FileUpload.vue +++ b/packages/web-app-files/src/components/AppBar/Upload/FileUpload.vue @@ -1,8 +1,8 @@ -
  • +
  • -
  • +
  • mimetype.allow_creation) || [] }, createFileActionsAvailable() { - return this.newFileHandlersForRoute.length > 0 || this.mimetypesAllowedForCreation.length > 0 + return this.newFileHandlers.length > 0 || this.mimetypesAllowedForCreation.length > 0 }, newButtonTooltip() { if (!this.canUpload) { @@ -214,12 +203,6 @@ export default { uploadOrFileCreationBlocked() { return !this.canUpload || !this.hasFreeSpace - }, - - newFileHandlersForRoute() { - return this.newFileHandlers.filter(({ routes = [] }) => - isLocationActive(this.$router, ...routes.map((name) => ({ name }))) - ) } }, methods: { @@ -227,14 +210,14 @@ export default { ...mapActions(['openFile', 'showMessage', 'createModal', 'setModalInputErrorMessage']), ...mapMutations('Files', ['UPSERT_RESOURCE']), - uploadSuccess() { - this.$emit('success') + uploadSuccess(args, file) { + this.$emit('success', args, file) }, - uploadError() { - this.$emit('error') + uploadError(error) { + this.$emit('error', error) }, - uploadProgress() { - this.$emit('progress') + uploadProgress(progress) { + this.$emit('progress', progress) }, showCreateResourceModal( @@ -397,6 +380,8 @@ export default { ) } + this.UPSERT_RESOURCE(buildResource(resource)) + if (this.newFileAction) { const fileId = resource.fileInfo[DavProperty.FileId] @@ -406,9 +391,6 @@ export default { return } - resource = buildResource(resource) - - this.UPSERT_RESOURCE(resource) this.hideModal() if (this.isPersonalLocation) { diff --git a/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js b/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js index d851b5e7415..7c95a9b04fc 100644 --- a/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js +++ b/packages/web-app-files/tests/unit/components/AppBar/AppBar.spec.js @@ -1,9 +1,8 @@ -import { shallowMount, mount, createLocalVue } from '@vue/test-utils' +import { shallowMount, createLocalVue } from '@vue/test-utils' import Vuex from 'vuex' import DesignSystem from 'owncloud-design-system' import GetTextPlugin from 'vue-gettext' -import stubs from '@/tests/unit/stubs' import AppBar from '@files/src/components/AppBar/AppBar' import { createLocationCommon, @@ -23,68 +22,15 @@ localVue.use(GetTextPlugin, { const elSelector = { batchActions: 'batch-actions-stub', sizeInfo: 'size-info-stub', - newFileButton: '#new-file-menu-btn', - newFileDrop: 'oc-drop-stub #new-file-menu-drop', - newFileMenuList: '#create-list > li', - uploadButton: '#upload-menu-btn', - uploadDrop: 'oc-drop-stub #upload-menu-drop', - uploadMenuList: '#upload-list > li', - fileUpload: 'file-upload-stub', - folderUpload: 'folder-upload-stub', - newFolderBtn: '#new-folder-btn', - newTextFileBtn: '.new-file-btn-txt', - newMdFileBtn: '.new-file-btn-md', - newDrawioFileBtn: '.new-file-btn-drawio' + createAndUpload: 'create-and-upload-stub' } -const spacesDefaultLocation = createLocationSpaces('files-spaces-personal-home') +const personalHomeLocation = createLocationSpaces('files-spaces-personal-home') const sharesWithMeLocation = createLocationShares('files-shares-with-me') const sharesWithOthersLocation = createLocationShares('files-shares-with-others') const publicFilesLocation = createLocationPublic('files-public-files') const favoritesLocation = createLocationCommon('files-common-favorites') -const routes = [ - spacesDefaultLocation.name, - favoritesLocation.name, - sharesWithOthersLocation.name, - sharesWithMeLocation.name, - publicFilesLocation.name -] - -const newFileHandlers = [ - { - ext: 'txt', - action: { - app: 'markdown-editor', - newTab: false, - extension: 'txt' - }, - routes, - menuTitle: () => 'Plain text file' - }, - { - ext: 'md', - action: { - app: 'markdown-editor', - newTab: false, - extension: 'md' - }, - routes, - menuTitle: () => 'Mark-down file' - }, - { - ext: 'drawio', - action: { - app: 'draw-io', - newTab: true, - routeName: 'draw-io-edit', - extension: 'drawio' - }, - routes, - menuTitle: () => 'Draw.io document' - } -] - const selectedFiles = [ { path: '/lorem.txt', @@ -104,7 +50,7 @@ describe('AppBar component', () => { jest.clearAllMocks() }) - describe.each([spacesDefaultLocation.name, publicFilesLocation.name])('%s route', (page) => { + describe.each([personalHomeLocation.name, publicFilesLocation.name])('%s route', (page) => { const route = { name: page, params: { @@ -118,89 +64,25 @@ describe('AppBar component', () => { } describe('when no items are selected', () => { - let wrapper - - const spyShowCreateResourceModal = jest - .spyOn(AppBar.methods, 'showCreateResourceModal') - .mockImplementation() - - beforeEach(() => { + it('should only show create and upload component', () => { const store = createStore({ selected: [], currentFolder }) - wrapper = getShallowWrapper(route, store) - }) - - it('should only show "New" and "Upload" button', () => { - const newFolderBtn = wrapper.find(elSelector.newFolderBtn) + const wrapper = getShallowWrapper(route, store) + const createAndUpload = wrapper.find(elSelector.createAndUpload) const sizeInfo = wrapper.find(elSelector.sizeInfo) - const newFileButton = wrapper.find(elSelector.newFileButton) - const uploadButton = wrapper.find(elSelector.uploadButton) + expect(createAndUpload.exists()).toBeTruthy() expect(sizeInfo.exists()).toBeFalsy() - expect(newFileButton.exists()).toBeFalsy() - expect(uploadButton.exists()).toBeTruthy() - expect(newFolderBtn.isVisible()).toBeTruthy() - expect(newFolderBtn.props('ariaLabel')).toEqual('Create a new folder') }) - it('should show default file menu items', () => { - const fileUpload = wrapper.find(elSelector.fileUpload) - const folderUpload = wrapper.find(elSelector.folderUpload) - const newFolderBtn = wrapper.find(elSelector.newFolderBtn) - - expect(fileUpload.isVisible()).toBeTruthy() - expect(folderUpload.isVisible()).toBeTruthy() - expect(newFolderBtn.isVisible()).toBeTruthy() - }) - it('should trigger "showCreateResourceModal" if new-folder button is clicked', async () => { - const store = createStore({ currentFolder, selected: [] }) - wrapper = getWrapper(route, store) - - const newFolderBtn = wrapper.find(elSelector.newFolderBtn) - await newFolderBtn.trigger('click') - - expect(spyShowCreateResourceModal).toHaveBeenCalled() - }) - it('should show extra file menu items', () => { - const store = createStore({ currentFolder, selected: [] }, newFileHandlers) - wrapper = getShallowWrapper(route, store) - const newTextFileBtn = wrapper.find(elSelector.newTextFileBtn) - const newMdFileBtn = wrapper.find(elSelector.newMdFileBtn) - const newDrawioFileBtn = wrapper.find(elSelector.newDrawioFileBtn) - const newFileMenuList = wrapper.findAll(elSelector.newFileMenuList) - - expect(newTextFileBtn.isVisible()).toBeTruthy() - expect(newMdFileBtn.isVisible()).toBeTruthy() - expect(newDrawioFileBtn.isVisible()).toBeTruthy() - expect(newFileMenuList.length).toBe(4) - }) - it.each(newFileHandlers)( - 'should trigger "showCreateResourceModal" if new file button is clicked', - async (fileHandler) => { - const store = createStore({ currentFolder, selected: [] }, newFileHandlers) - wrapper = getWrapper(route, store) - - const button = wrapper.find(getFileHandlerSelector(fileHandler.ext)) - await button.trigger('click') - - expect(spyShowCreateResourceModal).toHaveBeenCalled() - expect(spyShowCreateResourceModal).toHaveBeenCalledWith( - false, - fileHandler.ext, - fileHandler.action - ) - } - ) }) describe('when an item is selected', () => { - it('should hide "New" button but show size info', () => { + it('should hide create and upload component but show size info', () => { const store = createStore({ currentFolder, selected: selectedFiles }) const wrapper = getShallowWrapper(route, store) - const newButton = wrapper.find(elSelector.newFileButton) - const ocDrop = wrapper.find(elSelector.newFileDrop) + const createAndUpload = wrapper.find(elSelector.createAndUpload) const sizeInfo = wrapper.find(elSelector.sizeInfo) - expect(newButton.exists()).toBeFalsy() - expect(ocDrop.exists()).toBeFalsy() + expect(createAndUpload.exists()).toBeFalsy() expect(sizeInfo.isVisible()).toBeTruthy() }) }) @@ -222,21 +104,19 @@ describe('AppBar component', () => { wrapper = getShallowWrapper(route, store) }) - it('should not show "New" button and file menu list', () => { - const newButton = wrapper.find(elSelector.newFileButton) - const ocDrop = wrapper.find(elSelector.newFileDrop) - - expect(newButton.exists()).toBeFalsy() - expect(ocDrop.exists()).toBeFalsy() + it('should never show create and upload component', () => { + const createAndUpload = wrapper.find(elSelector.createAndUpload) + expect(createAndUpload.exists()).toBeFalsy() }) describe('when no items are selected', () => { - it('should show batch actions but not size-info', () => { - const batchActions = wrapper.find(elSelector.batchActions) + it('should not show size-info', () => { const sizeInfo = wrapper.find(elSelector.sizeInfo) - expect(sizeInfo.exists()).toBeFalsy() - expect(batchActions.isVisible()).toBeTruthy() + }) + it('should show batch actions', () => { + const batchActions = wrapper.find(elSelector.batchActions) + expect(batchActions.exists()).toBeTruthy() }) }) @@ -272,14 +152,12 @@ describe('AppBar component', () => { wrapper = getShallowWrapper(route, store) }) - describe('when no items are selected', () => { - it('should not show "New" button and file menu list', () => { - const newButton = wrapper.find(elSelector.newFileButton) - const ocDrop = wrapper.find(elSelector.newFileDrop) + it('should never show create and upload component', () => { + const createAndUpload = wrapper.find(elSelector.createAndUpload) + expect(createAndUpload.exists()).toBeFalsy() + }) - expect(newButton.exists()).toBeFalsy() - expect(ocDrop.exists()).toBeFalsy() - }) + describe('when no items are selected', () => { it('should not show size-info', () => { const sizeInfo = wrapper.find(elSelector.sizeInfo) expect(sizeInfo.exists()).toBeFalsy() @@ -306,46 +184,6 @@ describe('AppBar component', () => { ) }) -function getFileHandlerSelector(extension) { - const ext = extension.toLowerCase() - if (ext === 'txt') { - return elSelector.newTextFileBtn - } else if (ext === 'md') { - return elSelector.newMdFileBtn - } else if (ext === 'drawio') { - return elSelector.newDrawioFileBtn - } - return null -} - -function getWrapper(route = {}, store = {}) { - return mount(AppBar, { - localVue, - mocks: { - $route: route, - $router: { - currentRoute: route, - resolve: (r) => { - return { href: r.name } - } - }, - publicPage: jest.fn(() => false), - isIE11: jest.fn(() => false) - }, - stubs: { - ...stubs, - 'oc-button': false, - 'size-info': true, - 'batch-actions': true, - 'view-options': true, - 'file-drop': true, - 'file-upload': true, - 'folder-upload': true - }, - store - }) -} - function getShallowWrapper(route = {}, store = {}) { return shallowMount(AppBar, { localVue, @@ -368,7 +206,6 @@ function createStore(state = { selected: [], currentFolder: {} }, fileHandlers = return new Vuex.Store({ getters: { getToken: jest.fn(), - newFileHandlers: jest.fn(() => fileHandlers), quota: jest.fn() }, modules: { diff --git a/packages/web-app-files/tests/unit/components/AppBar/CreateAndUpload.spec.js b/packages/web-app-files/tests/unit/components/AppBar/CreateAndUpload.spec.js new file mode 100644 index 00000000000..5558d0fc914 --- /dev/null +++ b/packages/web-app-files/tests/unit/components/AppBar/CreateAndUpload.spec.js @@ -0,0 +1,253 @@ +import { shallowMount, mount, createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import DesignSystem from 'owncloud-design-system' +import GetTextPlugin from 'vue-gettext' + +import stubs from '@/tests/unit/stubs' +import CreateAndUpload from 'files/src/components/AppBar/CreateAndUpload' +import { createLocationSpaces } from '../../../../src/router' + +const localVue = createLocalVue() +localVue.use(Vuex) +localVue.use(DesignSystem) +localVue.use(GetTextPlugin, { + translations: 'does-not-matter.json', + silent: true +}) + +const elSelector = { + newFileButton: '#new-file-menu-btn', + newFileDrop: 'oc-drop-stub #new-file-menu-drop', + newFileMenuList: '#create-list > li', + uploadButton: '#upload-menu-btn', + uploadDrop: 'oc-drop-stub #upload-menu-drop', + uploadMenuList: '#upload-list > li', + fileUpload: 'file-upload-stub', + folderUpload: 'folder-upload-stub', + newFolderBtn: '#new-folder-btn', + newTextFileBtn: '.new-file-btn-txt', + newMdFileBtn: '.new-file-btn-md', + newDrawioFileBtn: '.new-file-btn-drawio' +} + +const personalHomeLocation = createLocationSpaces('files-spaces-personal-home') + +const newFileHandlers = [ + { + ext: 'txt', + action: { + app: 'markdown-editor', + newTab: false, + extension: 'txt' + }, + menuTitle: () => 'Plain text file' + }, + { + ext: 'md', + action: { + app: 'markdown-editor', + newTab: false, + extension: 'md' + }, + menuTitle: () => 'Mark-down file' + }, + { + ext: 'drawio', + action: { + app: 'draw-io', + newTab: true, + routeName: 'draw-io-edit', + extension: 'drawio' + }, + menuTitle: () => 'Draw.io document' + } +] + +const currentFolder = { + path: '/', + canUpload: jest.fn(() => true), + canCreate: jest.fn(() => true), + canBeDeleted: jest.fn(() => true) +} + +describe('CreateAndUpload component', () => { + afterEach(() => { + jest.clearAllMocks() + }) + + const route = { + name: personalHomeLocation.name, + params: { + item: '' + }, + meta: { + hasBulkActions: true, + hideFilelistActions: false + } + } + + let wrapper + + const spyShowCreateResourceModal = jest + .spyOn(CreateAndUpload.methods, 'showCreateResourceModal') + .mockImplementation() + + beforeEach(() => { + const store = createStore({ currentFolder }) + wrapper = getShallowWrapper(route, store) + }) + + it('should show default file menu items', () => { + const fileUpload = wrapper.find(elSelector.fileUpload) + const folderUpload = wrapper.find(elSelector.folderUpload) + const newFolderBtn = wrapper.find(elSelector.newFolderBtn) + + expect(fileUpload.exists()).toBeTruthy() + expect(folderUpload.exists()).toBeTruthy() + expect(newFolderBtn.exists()).toBeTruthy() + }) + + describe('no file handlers available', () => { + it('should show the create folder button standalone (no dropdown)', () => { + const newFileMenuList = wrapper.findAll(elSelector.newFileMenuList) + expect(newFileMenuList.exists()).toBeFalsy() + }) + }) + + describe('some file handlers available', () => { + it('should show the create folder button in a dropdown', () => { + const store = createStore({ currentFolder }, newFileHandlers) + wrapper = getShallowWrapper(route, store) + const newFileMenuList = wrapper.findAll(elSelector.newFileMenuList) + expect(newFileMenuList.exists()).toBeTruthy() + }) + + it('should show extra file menu items for file handlers', () => { + const store = createStore({ currentFolder }, newFileHandlers) + wrapper = getShallowWrapper(route, store) + const newTextFileBtn = wrapper.find(elSelector.newTextFileBtn) + const newMdFileBtn = wrapper.find(elSelector.newMdFileBtn) + const newDrawioFileBtn = wrapper.find(elSelector.newDrawioFileBtn) + const newFileMenuList = wrapper.findAll(elSelector.newFileMenuList) + + expect(newTextFileBtn.exists()).toBeTruthy() + expect(newMdFileBtn.exists()).toBeTruthy() + expect(newDrawioFileBtn.exists()).toBeTruthy() + expect(newFileMenuList.length).toBe(newFileHandlers.length + 1) // + 1 for "create folder" + }) + }) + + describe('button triggers', () => { + it('should trigger "showCreateResourceModal" if new-folder button is clicked', async () => { + const store = createStore({ currentFolder }, newFileHandlers) + wrapper = getWrapper(route, store) + + const newFolderBtn = wrapper.find(elSelector.newFolderBtn) + expect(newFolderBtn.exists()).toBeTruthy() + await newFolderBtn.trigger('click') + + expect(spyShowCreateResourceModal).toHaveBeenCalled() + }) + it.each(newFileHandlers)( + 'should trigger "showCreateResourceModal" if new file button is clicked', + async (fileHandler) => { + const store = createStore({ currentFolder }, newFileHandlers) + wrapper = getWrapper(route, store) + + const button = wrapper.find(getFileHandlerSelector(fileHandler.ext)) + expect(button.exists()).toBeTruthy() + await button.trigger('click') + + expect(spyShowCreateResourceModal).toHaveBeenCalled() + expect(spyShowCreateResourceModal).toHaveBeenCalledWith( + false, + fileHandler.ext, + fileHandler.action + ) + } + ) + }) +}) + +function getFileHandlerSelector(extension) { + const ext = extension.toLowerCase() + if (ext === 'txt') { + return elSelector.newTextFileBtn + } else if (ext === 'md') { + return elSelector.newMdFileBtn + } else if (ext === 'drawio') { + return elSelector.newDrawioFileBtn + } + return null +} + +function getWrapper(route = {}, store = {}) { + return mount(CreateAndUpload, { + localVue, + mocks: { + $route: route, + $router: { + currentRoute: route, + resolve: (r) => { + return { href: r.name } + } + }, + publicPage: jest.fn(() => false), + isIE11: jest.fn(() => false) + }, + propsData: { + currentPath: '' + }, + stubs: { + ...stubs, + 'oc-button': false, + 'file-upload': true, + 'folder-upload': true + }, + store + }) +} + +function getShallowWrapper(route = {}, store = {}) { + return shallowMount(CreateAndUpload, { + localVue, + mocks: { + $route: route, + $router: { + currentRoute: route, + resolve: (r) => { + return { href: r.name } + } + }, + publicPage: jest.fn(() => false), + isIE11: jest.fn(() => false) + }, + propsData: { + currentPath: '' + }, + store + }) +} + +function createStore(state = { currentFolder: {} }, fileHandlers = []) { + return new Vuex.Store({ + getters: { + getToken: jest.fn(), + newFileHandlers: jest.fn(() => fileHandlers) + }, + modules: { + Files: { + namespaced: true, + state: { + currentFolder: { + path: '/' + }, + ...state + }, + getters: { + currentFolder: () => state.currentFolder + } + } + } + }) +} diff --git a/packages/web-runtime/package.json b/packages/web-runtime/package.json index 350b2ba8440..181a9c308e9 100644 --- a/packages/web-runtime/package.json +++ b/packages/web-runtime/package.json @@ -28,7 +28,7 @@ "qs": "^6.10.3", "semver": "^7.3.5", "tippy.js": "^6.3.7", - "tus-js-client": "^2.3.0", + "tus-js-client": "^2.3.1", "utf8": "^3.0.0", "uuid": "^8.3.2", "v-calendar": "^2.3.2", diff --git a/tests/acceptance/features/webUIFilesSearch/search.feature b/tests/acceptance/features/webUIFilesSearch/search.feature index ff8d156fe28..6547701475c 100644 --- a/tests/acceptance/features/webUIFilesSearch/search.feature +++ b/tests/acceptance/features/webUIFilesSearch/search.feature @@ -128,7 +128,7 @@ Feature: Search Scenario: Search for a newly uploaded file When the user uploads file "simple.pdf" using the webUI - And the user opens folder "simple-folder" using the webUI + And the user opens folder "simple-folder" directly on the webUI And the user uploads file "simple.odt" using the webUI And the user browses to the files page And the user searches globally for "simple" using the webUI diff --git a/tests/acceptance/pageObjects/personalPage.js b/tests/acceptance/pageObjects/personalPage.js index 72a0eca6f5d..7097cacf1e1 100644 --- a/tests/acceptance/pageObjects/personalPage.js +++ b/tests/acceptance/pageObjects/personalPage.js @@ -182,8 +182,8 @@ module.exports = { * @param {string} folderName */ uploadFolder: function (folderName) { - return this.waitForElementVisible('@newFileMenuButton') - .click('@newFileMenuButton') + return this.waitForElementVisible('@uploadFilesButton') + .click('@uploadFilesButton') .waitForElementVisible('@fileUploadButton') .setValue('@folderUploadInput', folderName) .waitForElementVisible( @@ -193,7 +193,7 @@ module.exports = { false ) .waitForElementNotVisible('@fileUploadProgress') - .click('@newFileMenuButton') + .click('@uploadFilesButton') }, /** * Returns whether files or folders can be created in the current page. diff --git a/yarn.lock b/yarn.lock index 876f1c0ec84..3e24e967a11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,15 @@ __metadata: version: 5 cacheKey: 8 +"@ampproject/remapping@npm:^2.1.0": + version: 2.1.2 + resolution: "@ampproject/remapping@npm:2.1.2" + dependencies: + "@jridgewell/trace-mapping": ^0.3.0 + checksum: e023f92cdd9723f3042cde3b4d922adfeef0e198aa73486b0b6c034ad36af5f96e5c0cc72b335b30b2eb9852d907efc92af6bfcd3f4b4d286177ee32a189cf92 + languageName: node + linkType: hard + "@babel/code-frame@npm:7.12.11": version: 7.12.11 resolution: "@babel/code-frame@npm:7.12.11" @@ -30,26 +39,26 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.14.3, @babel/core@npm:^7.14.8, @babel/core@npm:^7.16.5, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": - version: 7.16.12 - resolution: "@babel/core@npm:7.16.12" +"@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.14.3, @babel/core@npm:^7.14.8, @babel/core@npm:^7.17.5, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": + version: 7.17.5 + resolution: "@babel/core@npm:7.17.5" dependencies: + "@ampproject/remapping": ^2.1.0 "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.16.8 + "@babel/generator": ^7.17.3 "@babel/helper-compilation-targets": ^7.16.7 "@babel/helper-module-transforms": ^7.16.7 - "@babel/helpers": ^7.16.7 - "@babel/parser": ^7.16.12 + "@babel/helpers": ^7.17.2 + "@babel/parser": ^7.17.3 "@babel/template": ^7.16.7 - "@babel/traverse": ^7.16.10 - "@babel/types": ^7.16.8 + "@babel/traverse": ^7.17.3 + "@babel/types": ^7.17.0 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.1.2 semver: ^6.3.0 - source-map: ^0.5.0 - checksum: 29b56f3cb7c329fc038a2efaccf64ac3025835676b3d90f57f2265b6acd477a970114d09021b38d019ac8f20b2bb1596a9e79ce1f820d6b8cf0e4a802891817c + checksum: c5e7dddb4feaacb91175d22a6edc8e93804242328a82b80732c6e84a0647bc0a9c9d5b05f3ce13138b8e59bf7aba4ff9f7b7446302f141f243ba51df02c318a5 languageName: node linkType: hard @@ -67,14 +76,14 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.16.8, @babel/generator@npm:^7.7.2": - version: 7.16.8 - resolution: "@babel/generator@npm:7.16.8" +"@babel/generator@npm:^7.17.3, @babel/generator@npm:^7.7.2": + version: 7.17.3 + resolution: "@babel/generator@npm:7.17.3" dependencies: - "@babel/types": ^7.16.8 + "@babel/types": ^7.17.0 jsesc: ^2.5.1 source-map: ^0.5.0 - checksum: 83af38b34735605c9d5f774c87a46c2cffaf666b28e9eeba883b2d7076412257e5c2264c26d9740ce44da6955fdaf857659391db02c012714a2a6dc19e403105 + checksum: ddf70e3489976018dfc2da8b9f43ec8c582cac2da681ed4a6227c53b26a9626223e4dca90098b3d3afe43bc67f20160856240e826c56b48e577f34a5a7e22b9f languageName: node linkType: hard @@ -350,14 +359,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.16.7": - version: 7.16.7 - resolution: "@babel/helpers@npm:7.16.7" +"@babel/helpers@npm:^7.17.2": + version: 7.17.2 + resolution: "@babel/helpers@npm:7.17.2" dependencies: "@babel/template": ^7.16.7 - "@babel/traverse": ^7.16.7 - "@babel/types": ^7.16.7 - checksum: 75504c76b66a29b91f954fcc0867dfe275a4cfba5b44df6d64405df74ea72f967fccfa63d62c31c423c5502d113290000c581e0e4858a214f0303d7ecf55c29f + "@babel/traverse": ^7.17.0 + "@babel/types": ^7.17.0 + checksum: 5fa06bbf59636314fb4098bb2e70cf488e0fb6989553438abab90356357b79976102ac129fb16fc8186893c79e0809de1d90e3304426d6fcdb1750da2b6dff9d languageName: node linkType: hard @@ -381,12 +390,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.0, @babel/parser@npm:^7.13.9, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.10, @babel/parser@npm:^7.16.12, @babel/parser@npm:^7.16.7, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": - version: 7.16.12 - resolution: "@babel/parser@npm:7.16.12" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.0, @babel/parser@npm:^7.13.9, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.16.7, @babel/parser@npm:^7.17.3, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": + version: 7.17.3 + resolution: "@babel/parser@npm:7.17.3" bin: parser: ./bin/babel-parser.js - checksum: af287f0f3dfa564958a7dddfeb62e08c0de9ce9bd8447fcde0997da26ec477bf19f37161b9d970e2c7e0d1f77e441258907d3347beddd0d42cae85ed46947703 + checksum: 311869baef97c7630ac3b3c4600da18229b95aa2785b2daab2044384745fe0653070916ade28749fb003f7369a081111ada53e37284ba48d6b5858cbb9e411d1 languageName: node linkType: hard @@ -1362,31 +1371,31 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.12.5, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.16.10, @babel/traverse@npm:^7.16.5, @babel/traverse@npm:^7.16.7, @babel/traverse@npm:^7.7.2": - version: 7.16.10 - resolution: "@babel/traverse@npm:7.16.10" +"@babel/traverse@npm:^7.12.5, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.16.5, @babel/traverse@npm:^7.16.7, @babel/traverse@npm:^7.17.0, @babel/traverse@npm:^7.17.3, @babel/traverse@npm:^7.7.2": + version: 7.17.3 + resolution: "@babel/traverse@npm:7.17.3" dependencies: "@babel/code-frame": ^7.16.7 - "@babel/generator": ^7.16.8 + "@babel/generator": ^7.17.3 "@babel/helper-environment-visitor": ^7.16.7 "@babel/helper-function-name": ^7.16.7 "@babel/helper-hoist-variables": ^7.16.7 "@babel/helper-split-export-declaration": ^7.16.7 - "@babel/parser": ^7.16.10 - "@babel/types": ^7.16.8 + "@babel/parser": ^7.17.3 + "@babel/types": ^7.17.0 debug: ^4.1.0 globals: ^11.1.0 - checksum: 58f52314f8a02157cd3004712e703e6b22dff57cee4bc1ab1954c511c6f885fd7763ea68d2d5f006891bc7b77b1f2e9c8c7cb0354f580c8343d5559ed971d087 + checksum: 780d7ecf711758174989794891af08d378f81febdb8932056c0d9979524bf0298e28f8e7708a872d7781151506c28f56c85c63ea3f1f654662c2fcb8a3eb9fdc languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.0, @babel/types@npm:^7.13.0, @babel/types@npm:^7.16.0, @babel/types@npm:^7.16.7, @babel/types@npm:^7.16.8, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": - version: 7.16.8 - resolution: "@babel/types@npm:7.16.8" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.0, @babel/types@npm:^7.13.0, @babel/types@npm:^7.16.0, @babel/types@npm:^7.16.7, @babel/types@npm:^7.17.0, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": + version: 7.17.0 + resolution: "@babel/types@npm:7.17.0" dependencies: "@babel/helper-validator-identifier": ^7.16.7 to-fast-properties: ^2.0.0 - checksum: 4f6a187b2924df70e21d6e6c0822f91b1b936fe060bc92bb477b93bd8a712c88fe41a73f85c0ec53b033353374fe33e773b04ffc340ad36afd8f647dd05c4ee1 + checksum: 12e5a287986fe557188e87b2c5202223f1dc83d9239a196ab936fdb9f8c1eb0be717ff19f934b5fad4e29a75586d5798f74bed209bccea1c20376b9952056f0e languageName: node linkType: hard @@ -1850,6 +1859,30 @@ __metadata: languageName: node linkType: hard +"@jridgewell/resolve-uri@npm:^3.0.3": + version: 3.0.5 + resolution: "@jridgewell/resolve-uri@npm:3.0.5" + checksum: 1ee652b693da7979ac4007926cc3f0a32b657ffeb913e111f44e5b67153d94a2f28a1d560101cc0cf8087625468293a69a00f634a2914e1a6d0817ba2039a913 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10": + version: 1.4.11 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.11" + checksum: 3b2afaf8400fb07a36db60e901fcce6a746cdec587310ee9035939d89878e57b2dec8173b0b8f63176f647efa352294049a53c49739098eb907ff81fec2547c8 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.0": + version: 0.3.4 + resolution: "@jridgewell/trace-mapping@npm:0.3.4" + dependencies: + "@jridgewell/resolve-uri": ^3.0.3 + "@jridgewell/sourcemap-codec": ^1.4.10 + checksum: ab8bce84bbbc8c34f3ba8325ed926f8f2d3098983c10442a80c55764c4eb6e47d5b92d8ff20a0dd868c3e76a3535651fd8a0138182c290dbfc8396195685c37b + languageName: node + linkType: hard + "@mdn/browser-compat-data@npm:^3.3.4": version: 3.3.7 resolution: "@mdn/browser-compat-data@npm:3.3.7" @@ -1991,12 +2024,12 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-html@npm:^0.2.0": - version: 0.2.3 - resolution: "@rollup/plugin-html@npm:0.2.3" +"@rollup/plugin-html@npm:^0.2.4": + version: 0.2.4 + resolution: "@rollup/plugin-html@npm:0.2.4" peerDependencies: rollup: ^1.20.0||^2.0.0 - checksum: 5218980230c9e3f6451964dc491d31e327ac1fc00cf16975244844b6e48d777cdaf7d04d0f023836a5b6c750c18e5733c140a1516897bc6b6c0730702d784499 + checksum: 63a644f13a855e1bd7bcc6a3aa12b894a2e50cc0ebd07f124e619987cc67483271d118f0875a945e531ece9dc92ab2166b223e2ea0cb3dd694b08987fbda911e languageName: node linkType: hard @@ -9142,13 +9175,27 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:2.6.1, node-fetch@npm:^2.6.1": +"node-fetch@npm:2.6.1": version: 2.6.1 resolution: "node-fetch@npm:2.6.1" checksum: 91075bedd57879117e310fbcc36983ad5d699e522edb1ebcdc4ee5294c982843982652925c3532729fdc86b2d64a8a827797a745f332040d91823c8752ee4d7c languageName: node linkType: hard +"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7": + version: 2.6.7 + resolution: "node-fetch@npm:2.6.7" + dependencies: + whatwg-url: ^5.0.0 + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 8d816ffd1ee22cab8301c7756ef04f3437f18dace86a1dae22cf81db8ef29c0bf6655f3215cb0cdb22b420b6fe141e64b26905e7f33f9377a7fa59135ea3e10b + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 8.2.0 resolution: "node-gyp@npm:8.2.0" @@ -11515,7 +11562,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: - "@babel/core": ^7.16.5 + "@babel/core": ^7.17.5 "@babel/eslint-parser": ^7.16.5 "@babel/polyfill": ^7.12.1 "@babel/preset-env": ^7.16.5 @@ -11527,7 +11574,7 @@ __metadata: "@playwright/test": ^1.17.2 "@rollup/plugin-alias": ^3.1.9 "@rollup/plugin-commonjs": ^17.0.0 - "@rollup/plugin-html": ^0.2.0 + "@rollup/plugin-html": ^0.2.4 "@rollup/plugin-inject": ^4.0.4 "@rollup/plugin-json": ^4.1.0 "@rollup/plugin-typescript": ^8.3.0 @@ -11571,7 +11618,7 @@ __metadata: jest-serializer-vue: ^2.0.2 join-path: ^1.1.1 lodash: ^4.17.21 - node-fetch: ^2.6.1 + node-fetch: ^2.6.7 pino: ^7.6.3 pino-pretty: ^7.3.0 playwright: ^1.17.1 @@ -12606,6 +12653,13 @@ __metadata: languageName: node linkType: hard +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 + languageName: node + linkType: hard + "traverse-chain@npm:~0.1.0": version: 0.1.0 resolution: "traverse-chain@npm:0.1.0" @@ -12761,9 +12815,9 @@ __metadata: languageName: node linkType: hard -"tus-js-client@npm:^2.3.0": - version: 2.3.0 - resolution: "tus-js-client@npm:2.3.0" +"tus-js-client@npm:^2.3.1": + version: 2.3.1 + resolution: "tus-js-client@npm:2.3.1" dependencies: buffer-from: ^0.1.1 combine-errors: ^3.0.3 @@ -12771,8 +12825,8 @@ __metadata: js-base64: ^2.6.1 lodash.throttle: ^4.1.1 proper-lockfile: ^2.0.1 - url-parse: ^1.4.3 - checksum: 7ae23e92a771418a8117440f56c143d10bbfb5236ab1ab2c37ba65122375008e72f930cee7b685254ca81dbc470daa542635dd861b7105ca9997e8b37b3c02ad + url-parse: ^1.5.7 + checksum: 684446bcc3c625e7aed5330f7b42de97ef515e07f7e7dcecd2eac056f9e93c6b0276ef02ac3662e439101f0ce0902ccb96a246262ee1d8e86f3d4027a7aed6dd languageName: node linkType: hard @@ -12993,13 +13047,13 @@ __metadata: languageName: node linkType: hard -"url-parse@npm:^1.4.3, url-parse@npm:^1.5.1": - version: 1.5.3 - resolution: "url-parse@npm:1.5.3" +"url-parse@npm:^1.5.1, url-parse@npm:^1.5.7": + version: 1.5.10 + resolution: "url-parse@npm:1.5.10" dependencies: querystringify: ^2.1.1 requires-port: ^1.0.0 - checksum: c6b32fff835e43f3b1b4150239f459744f0ab1a908841dbfecbfc79bf67f4d6c8d9af1841d0c6d814d45bfa08525cc29312a0bef31db7aa894306b3db07e4ee0 + checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf languageName: node linkType: hard @@ -13431,7 +13485,7 @@ __metadata: qs: ^6.10.3 semver: ^7.3.5 tippy.js: ^6.3.7 - tus-js-client: ^2.3.0 + tus-js-client: ^2.3.1 utf8: ^3.0.0 uuid: ^8.3.2 v-calendar: ^2.3.2 @@ -13485,6 +13539,13 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c + languageName: node + linkType: hard + "webidl-conversions@npm:^5.0.0": version: 5.0.0 resolution: "webidl-conversions@npm:5.0.0" @@ -13515,6 +13576,16 @@ __metadata: languageName: node linkType: hard +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: ~0.0.3 + webidl-conversions: ^3.0.0 + checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c + languageName: node + linkType: hard + "whatwg-url@npm:^8.0.0, whatwg-url@npm:^8.5.0": version: 8.6.0 resolution: "whatwg-url@npm:8.6.0"