diff --git a/changelog/unreleased/bugfix-re-fetch-quota b/changelog/unreleased/bugfix-re-fetch-quota new file mode 100644 index 00000000000..442b03d8c48 --- /dev/null +++ b/changelog/unreleased/bugfix-re-fetch-quota @@ -0,0 +1,8 @@ +Bugfix: Re-fetch quota + +We've fixed a bug where uploading, deleting or restoring resources doesn't always re-fetch the quota and therefore +was falsy displayed. + +https://github.com/owncloud/web/pull/7415 +https://github.com/owncloud/web/issues/6930 +https://github.com/owncloud/web/issues/7389 diff --git a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue index 98c2040c9a3..0f0f615fcfd 100644 --- a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue +++ b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue @@ -122,9 +122,12 @@ import MixinFileActions, { EDITOR_MODE_CREATE } from '../../mixins/fileActions' import { buildResource, buildWebDavFilesPath, buildWebDavSpacesPath } from '../../helpers/resources' import { isLocationPublicActive, isLocationSpacesActive } from '../../router' import { useActiveLocation } from '../../composables' +import { useGraphClient } from 'web-client/src/composables' + import { useRequest, useCapabilityShareJailEnabled, + useCapabilitySpacesEnabled, useStore, usePublicLinkPassword, useUserContext @@ -151,7 +154,6 @@ export default defineComponent({ onMounted(() => { const filesSelectedSub = uppyService.subscribe('filesSelected', instance.onFilesSelected) - const uploadSuccessSub = uppyService.subscribe('uploadSuccess', instance.onFileSuccess) const uploadCompletedSub = uppyService.subscribe('uploadCompleted', instance.onUploadComplete) uppyService.useDropTarget({ @@ -161,7 +163,6 @@ export default defineComponent({ instance.$on('beforeDestroy', () => { uppyService.unsubscribe('filesSelected', filesSelectedSub) - uppyService.unsubscribe('uploadSuccess', uploadSuccessSub) uppyService.unsubscribe('uploadCompleted', uploadCompletedSub) uppyService.removeDropTarget() }) @@ -173,12 +174,14 @@ export default defineComponent({ }), ...useUploadHelpers(), ...useRequest(), + ...useGraphClient(), isPersonalLocation: useActiveLocation(isLocationSpacesActive, 'files-spaces-personal'), isPublicLocation: useActiveLocation(isLocationPublicActive, 'files-public-files'), isSpacesProjectsLocation: useActiveLocation(isLocationSpacesActive, 'files-spaces-projects'), isSpacesProjectLocation: useActiveLocation(isLocationSpacesActive, 'files-spaces-project'), isSpacesShareLocation: useActiveLocation(isLocationSpacesActive, 'files-spaces-share'), hasShareJail: useCapabilityShareJailEnabled(), + hasSpaces: useCapabilitySpacesEnabled(), publicLinkPassword: usePublicLinkPassword({ store }), isUserContext: useUserContext({ store }) } @@ -278,16 +281,10 @@ export default defineComponent({ 'setModalInputErrorMessage', 'hideModal' ]), - ...mapMutations('Files', ['UPSERT_RESOURCE']), + ...mapMutations('Files', ['UPSERT_RESOURCE', 'UPDATE_SPACE_FIELD']), ...mapMutations(['SET_QUOTA']), - onFileSuccess() { - if (this.user?.quota) { - this.SET_QUOTA(this.user.quota) - } - }, - - onUploadComplete(result) { + async onUploadComplete(result) { if (result.successful) { const file = result.successful[0] @@ -295,6 +292,20 @@ export default defineComponent({ return } + if (this.isSpacesProjectLocation || this.isPersonalLocation) { + if (this.hasSpaces) { + const driveResponse = await this.graphClient.drives.getDrive(file.meta.routeStorageId) + this.UPDATE_SPACE_FIELD({ + id: driveResponse.data.id, + field: 'spaceQuota', + value: driveResponse.data.quota + }) + } else { + const user = await this.$client.users.getUser(this.user.id) + this.SET_QUOTA(user.quota) + } + } + let pathFileWasUploadedTo = file.meta.currentFolder if (file.meta.relativeFolder) { pathFileWasUploadedTo += file.meta.relativeFolder diff --git a/packages/web-app-files/src/components/SpaceQuota.vue b/packages/web-app-files/src/components/SpaceQuota.vue index 63d98068789..51094ee35af 100644 --- a/packages/web-app-files/src/components/SpaceQuota.vue +++ b/packages/web-app-files/src/components/SpaceQuota.vue @@ -2,7 +2,7 @@

s.driveType === 'personal').id + const driveResponse = await graphClient.drives.getDrive(driveId) + this.UPDATE_SPACE_FIELD({ + id: driveResponse.data.id, + field: 'spaceQuota', + value: driveResponse.data.quota + }) + } else { + const user = await this.$client.users.getUser(this.user.id) + this.SET_QUOTA(user.quota) + } } } } diff --git a/packages/web-app-files/src/mixins/deleteResources.js b/packages/web-app-files/src/mixins/deleteResources.js index 8a9b8b5fea6..40762c4a174 100644 --- a/packages/web-app-files/src/mixins/deleteResources.js +++ b/packages/web-app-files/src/mixins/deleteResources.js @@ -3,7 +3,8 @@ import { cloneStateObject } from '../helpers/store' import { isSameResource } from '../helpers/resource' import { buildWebDavFilesTrashPath, buildWebDavSpacesTrashPath } from '../helpers/resources' import PQueue from 'p-queue' -import { isLocationTrashActive } from '../router' +import { isLocationTrashActive, isLocationSpacesActive } from '../router' +import { clientService } from 'web-pkg/src/services' export default { data: () => ({ @@ -14,8 +15,9 @@ export default { computed: { ...mapGetters('Files', ['selectedFiles']), - ...mapGetters(['user']), + ...mapGetters(['user', 'configuration', 'capabilities']), ...mapGetters('runtime/auth', { isPublicLinkContext: 'isPublicLinkContextReady' }), + ...mapGetters('runtime/auth', ['accessToken']), $_deleteResources_isInTrashbin() { return ( @@ -97,6 +99,7 @@ export default { methods: { ...mapActions('Files', ['pushResourcesToDeleteList', 'removeFilesFromTrashbin', 'deleteFiles']), ...mapActions(['showMessage', 'toggleModalConfirmButton', 'hideModal', 'createModal']), + ...mapMutations('Files', ['UPDATE_SPACE_FIELD']), ...mapMutations(['SET_QUOTA']), $_deleteResources_trashbin_deleteOp(resource) { @@ -160,9 +163,27 @@ export default { this.toggleModalConfirmButton() // Load quota - if (this.user?.id) { - const user = await this.$client.users.getUser(this.user.id) - this.SET_QUOTA(user.quota) + if ( + isLocationSpacesActive(this.$router, 'files-spaces-project') || + isLocationSpacesActive(this.$router, 'files-spaces-personal') + ) { + if (this.capabilities?.spaces?.enabled) { + const graphClient = clientService.graphAuthenticated( + this.configuration.server, + this.accessToken + ) + const driveResponse = await graphClient.drives.getDrive( + this.$_deleteResources_resources[0].storageId + ) + this.UPDATE_SPACE_FIELD({ + id: driveResponse.data.id, + field: 'spaceQuota', + value: driveResponse.data.quota + }) + } else { + const user = await this.$client.users.getUser(this.user.id) + this.SET_QUOTA(user.quota) + } } let parentFolderPath diff --git a/packages/web-app-files/src/services/folder/legacy/loaderPersonal.ts b/packages/web-app-files/src/services/folder/legacy/loaderPersonal.ts index e6159aa6a5b..1e13c0f5215 100644 --- a/packages/web-app-files/src/services/folder/legacy/loaderPersonal.ts +++ b/packages/web-app-files/src/services/folder/legacy/loaderPersonal.ts @@ -55,12 +55,6 @@ export class FolderLoaderLegacyPersonal implements FolderLoader { currentFolder, files: resources }) - - // fetch user quota - ;(async () => { - const user = await client.users.getUser(router.currentRoute.params.storageId) - store.commit('SET_QUOTA', user.quota) - })() } catch (error) { store.commit('Files/SET_CURRENT_FOLDER', null) console.error(error) diff --git a/packages/web-app-files/src/services/folder/spaces/loaderPersonal.ts b/packages/web-app-files/src/services/folder/spaces/loaderPersonal.ts index 3bd64974445..1062f4b9a24 100644 --- a/packages/web-app-files/src/services/folder/spaces/loaderPersonal.ts +++ b/packages/web-app-files/src/services/folder/spaces/loaderPersonal.ts @@ -51,12 +51,6 @@ export class FolderLoaderSpacesPersonal implements FolderLoader { currentFolder, files: resources }) - - // fetch user quota - ;(async () => { - const user = await clientService.owncloudSdk.users.getUser(ref.user.id) - store.commit('SET_QUOTA', user.quota) - })() } catch (error) { store.commit('Files/SET_CURRENT_FOLDER', null) console.error(error) diff --git a/packages/web-app-files/tests/unit/components/__snapshots__/SpaceQuota.spec.js.snap b/packages/web-app-files/tests/unit/components/__snapshots__/SpaceQuota.spec.js.snap index f6d007d7977..3351829570d 100644 --- a/packages/web-app-files/tests/unit/components/__snapshots__/SpaceQuota.spec.js.snap +++ b/packages/web-app-files/tests/unit/components/__snapshots__/SpaceQuota.spec.js.snap @@ -2,7 +2,7 @@ exports[`SpaceQuota component renders the space storage quota label 1`] = `

-

1 B of 10 B used (10.0% used)

+

1 B of 10 B used (10% used)

`; diff --git a/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js b/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js index 521a512cb1d..53a137942e9 100644 --- a/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js +++ b/packages/web-app-files/tests/unit/mixins/actions/restore.spec.js @@ -101,7 +101,8 @@ function getWrapper({ invalidLocation = false, resolveClearTrashBin: resolveRest getters: { configuration: () => ({ server: 'https://example.com' - }) + }), + capabilities: () => {} }, modules: { user: { @@ -119,6 +120,9 @@ function getWrapper({ invalidLocation = false, resolveClearTrashBin: resolveRest removeFilesFromTrashbin: jest.fn() } } + }, + mutations: { + SET_QUOTA: () => jest.fn() } }) }) diff --git a/packages/web-app-files/tests/unit/mixins/deleteResources.spec.js b/packages/web-app-files/tests/unit/mixins/deleteResources.spec.js index 6c9acb38c3e..549ec37e524 100644 --- a/packages/web-app-files/tests/unit/mixins/deleteResources.spec.js +++ b/packages/web-app-files/tests/unit/mixins/deleteResources.spec.js @@ -2,6 +2,7 @@ import Vuex from 'vuex' import { createStore } from 'vuex-extensions' import { mount, createLocalVue } from '@vue/test-utils' import deleteResources from '@files/src/mixins/deleteResources.js' +import { createLocationSpaces } from '../../../src/router' const localVue = createLocalVue() localVue.use(Vuex) @@ -27,9 +28,10 @@ describe('deleteResources', () => { const resourcesToDelete = [{ id: 2, path: '/' }] const wrapper = getWrapper(resourcesToDelete) const spyHideModalStub = jest.spyOn(wrapper.vm, 'hideModal') + const spyRouterPushStub = jest.spyOn(wrapper.vm.$router, 'push') await wrapper.vm.$_deleteResources_filesList_delete() await wrapper.vm.$nextTick() - expect(wrapper.vm.$router.length).toBeGreaterThanOrEqual(0) + expect(spyRouterPushStub).toHaveBeenCalledTimes(0) expect(spyHideModalStub).toHaveBeenCalledTimes(1) }) @@ -37,9 +39,10 @@ describe('deleteResources', () => { const resourcesToDelete = [currentFolder] const wrapper = getWrapper(resourcesToDelete) const spyHideModalStub = jest.spyOn(wrapper.vm, 'hideModal') + const spyRouterPushStub = jest.spyOn(wrapper.vm.$router, 'push') await wrapper.vm.$_deleteResources_filesList_delete() await wrapper.vm.$nextTick() - expect(wrapper.vm.$router.length).toBeGreaterThanOrEqual(1) + expect(spyRouterPushStub).toHaveBeenCalledTimes(1) expect(spyHideModalStub).toHaveBeenCalledTimes(1) }) }) @@ -52,7 +55,15 @@ function getWrapper(resourcesToDelete) { $route: { name: 'files-personal' }, - $router: [], + $router: { + currentRoute: createLocationSpaces('files-spaces-personal'), + resolve: (r) => { + return { + href: r.name + } + }, + push: jest.fn() + }, $client: { users: { getUser: jest.fn(() => user) @@ -67,7 +78,11 @@ function getWrapper(resourcesToDelete) { getters: { user: () => { return { id: 'marie' } - } + }, + configuration: () => ({ + server: 'https://example.com' + }), + capabilities: () => {} }, modules: { Files: { diff --git a/packages/web-runtime/src/components/Topbar/UserMenu.vue b/packages/web-runtime/src/components/Topbar/UserMenu.vue index ac5057d0d3d..458b8df59c5 100644 --- a/packages/web-runtime/src/components/Topbar/UserMenu.vue +++ b/packages/web-runtime/src/components/Topbar/UserMenu.vue @@ -64,7 +64,7 @@