diff --git a/changelog/unreleased/enhnacement-respect-max-quota b/changelog/unreleased/enhnacement-respect-max-quota new file mode 100644 index 00000000000..85784610127 --- /dev/null +++ b/changelog/unreleased/enhnacement-respect-max-quota @@ -0,0 +1,6 @@ +Enhancement: Respect max quota + +We've updated the quota-select component, so that values higher than max quota set on the server side won't be shown. + +https://github.com/owncloud/web/pull/8489 +https://github.com/owncloud/web/issues/8490 diff --git a/packages/web-app-admin-settings/src/components/Spaces/ContextActions.vue b/packages/web-app-admin-settings/src/components/Spaces/ContextActions.vue index 46a41919187..a07f9e6a50a 100644 --- a/packages/web-app-admin-settings/src/components/Spaces/ContextActions.vue +++ b/packages/web-app-admin-settings/src/components/Spaces/ContextActions.vue @@ -5,6 +5,7 @@ v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :spaces="items" + :max-quota="maxQuota" @space-quota-updated="spaceQuotaUpdated" /> @@ -22,6 +23,7 @@ import { computed, defineComponent, getCurrentInstance, PropType, unref } from ' import { Resource } from 'web-client' import ContextActionMenu from 'web-pkg/src/components/ContextActions/ContextActionMenu.vue' import QuotaModal from 'web-pkg/src/components/Spaces/QuotaModal.vue' +import { useCapabilitySpacesMaxQuota } from 'web-pkg/src/composables' export default defineComponent({ name: 'ContextActions', @@ -85,6 +87,7 @@ export default defineComponent({ instance.$data.$_editQuota_selectedSpace.spaceQuota = quota } return { + maxQuota: useCapabilitySpacesMaxQuota(), menuSections, quotaModalIsOpen, closeQuotaModal, diff --git a/packages/web-app-admin-settings/src/components/Spaces/SideBar/ActionsPanel.vue b/packages/web-app-admin-settings/src/components/Spaces/SideBar/ActionsPanel.vue index 7ec59c80152..f3320fcfdc2 100644 --- a/packages/web-app-admin-settings/src/components/Spaces/SideBar/ActionsPanel.vue +++ b/packages/web-app-admin-settings/src/components/Spaces/SideBar/ActionsPanel.vue @@ -4,6 +4,7 @@ v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :spaces="resources" + :max-quota="maxQuota" @space-quota-updated="spaceQuotaUpdated" /> @@ -29,6 +30,7 @@ import EditQuota from 'web-pkg/src/mixins/spaces/editQuota' import QuotaModal from 'web-pkg/src/components/Spaces/QuotaModal.vue' import { computed, defineComponent, getCurrentInstance, inject, unref } from 'vue' import { Resource } from 'web-client' +import { useCapabilitySpacesMaxQuota } from 'web-pkg/src/composables' export default defineComponent({ name: 'ActionsPanel', @@ -58,7 +60,14 @@ export default defineComponent({ const spaceQuotaUpdated = (quota) => { instance.$data.$_editQuota_selectedSpace.spaceQuota = quota } - return { actions, quotaModalIsOpen, closeQuotaModal, spaceQuotaUpdated, resources } + return { + actions, + maxQuota: useCapabilitySpacesMaxQuota(), + quotaModalIsOpen, + closeQuotaModal, + spaceQuotaUpdated, + resources + } } }) diff --git a/packages/web-app-admin-settings/src/components/Users/ContextActions.vue b/packages/web-app-admin-settings/src/components/Users/ContextActions.vue index 799e6184117..ea26dc37d73 100644 --- a/packages/web-app-admin-settings/src/components/Users/ContextActions.vue +++ b/packages/web-app-admin-settings/src/components/Users/ContextActions.vue @@ -5,6 +5,7 @@ v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :spaces="selectedPersonalDrives" + :max-quota="maxQuota" @space-quota-updated="spaceQuotaUpdated" /> @@ -30,6 +31,7 @@ import QuotaModal from 'web-pkg/src/components/Spaces/QuotaModal.vue' import EditQuota from 'web-pkg/src/mixins/spaces/editQuota' import { SpaceResource } from 'web-client/src' import { useGettext } from 'vue3-gettext' +import { useCapabilitySpacesMaxQuota } from 'web-pkg/src/composables' export default defineComponent({ name: 'ContextActions', @@ -111,6 +113,7 @@ export default defineComponent({ } return { + maxQuota: useCapabilitySpacesMaxQuota(), menuSections, quotaModalIsOpen, closeQuotaModal, diff --git a/packages/web-app-admin-settings/src/components/Users/SideBar/EditPanel.vue b/packages/web-app-admin-settings/src/components/Users/SideBar/EditPanel.vue index bacd873ba5e..b9796116197 100644 --- a/packages/web-app-admin-settings/src/components/Users/SideBar/EditPanel.vue +++ b/packages/web-app-admin-settings/src/components/Users/SideBar/EditPanel.vue @@ -74,6 +74,7 @@ class="oc-mb-s" :title="$gettext('Personal quota')" :total-quota="editUser.drive.quota.total || 0" + :max-quota="maxQuota" @selected-option-change="changeSelectedQuotaOption" />

{ const { memberOf: selectedGroups } = unref(editUser) return props.groups @@ -161,7 +162,14 @@ export default defineComponent({ const isLoginInputDisabled = computed(() => currentUser.uuid === (props.user as User).id) - return { isLoginInputDisabled, editUser, formData, groupOptions, ...useGraphClient() } + return { + maxQaxQuota: useCapabilitySpacesMaxQuota(), + isLoginInputDisabled, + editUser, + formData, + groupOptions, + ...useGraphClient() + } }, computed: { loginOptions() { diff --git a/packages/web-app-admin-settings/src/views/Spaces.vue b/packages/web-app-admin-settings/src/views/Spaces.vue index bd20db321b3..e70aa3f19ba 100644 --- a/packages/web-app-admin-settings/src/views/Spaces.vue +++ b/packages/web-app-admin-settings/src/views/Spaces.vue @@ -42,6 +42,7 @@ v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :spaces="selectedSpaces" + :max-quota="maxQuota" @space-quota-updated="spaceQuotaUpdated" /> import NoContentMessage from 'web-pkg/src/components/NoContentMessage.vue' -import { useAccessToken, useGraphClient, useStore } from 'web-pkg/src/composables' +import { + useAccessToken, + useCapabilitySpacesMaxQuota, + useGraphClient, + useStore +} from 'web-pkg/src/composables' import { computed, defineComponent, @@ -294,6 +300,7 @@ export default defineComponent({ } return { + maxQuota: useCapabilitySpacesMaxQuota(), sideBarOpen, sideBarActivePanel, spaces, diff --git a/packages/web-app-admin-settings/src/views/Users.vue b/packages/web-app-admin-settings/src/views/Users.vue index ddaeddb7eee..a6ad4662f9c 100644 --- a/packages/web-app-admin-settings/src/views/Users.vue +++ b/packages/web-app-admin-settings/src/views/Users.vue @@ -86,6 +86,7 @@ v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :spaces="selectedPersonalDrives" + :max-quota="maxQuota" @space-quota-updated="spaceQuotaUpdated" /> @@ -106,6 +107,7 @@ import Delete from '../mixins/users/delete' import { queryItemAsString, useAccessToken, + useCapabilitySpacesMaxQuota, useGraphClient, useRouteQuery, useStore @@ -294,6 +296,7 @@ export default defineComponent({ return { ...useSideBar(), + maxQuota: useCapabilitySpacesMaxQuota(), template, selectedUsers, loadedUser, diff --git a/packages/web-app-files/src/components/SideBar/Actions/SpaceActions.vue b/packages/web-app-files/src/components/SideBar/Actions/SpaceActions.vue index f5ba5036b3f..d913b519158 100644 --- a/packages/web-app-files/src/components/SideBar/Actions/SpaceActions.vue +++ b/packages/web-app-files/src/components/SideBar/Actions/SpaceActions.vue @@ -5,7 +5,12 @@ :cancel="closeReadmeContentModal" :space="resources[0]" > - + >('space'), resources } diff --git a/packages/web-app-files/src/components/Spaces/SpaceContextActions.vue b/packages/web-app-files/src/components/Spaces/SpaceContextActions.vue index 3332dce5d61..c81578ad5d6 100644 --- a/packages/web-app-files/src/components/Spaces/SpaceContextActions.vue +++ b/packages/web-app-files/src/components/Spaces/SpaceContextActions.vue @@ -5,6 +5,7 @@ v-if="quotaModalIsOpen" :cancel="closeQuotaModal" :spaces="quotaModalSelectedSpaces" + :max-quota="maxQuota" /> { + if (this.totalQuota === 0 && availableOption.value === 0) { + availableOption.selectable = false + return true + } + return availableOption.value !== 0 && availableOption.value <= this.maxQuota + }) + } + + const selectedQuotaInOptions = availableOptions.find( (option) => option.value === this.totalQuota ) + if (!selectedQuotaInOptions) { - const newOption = { + availableOptions.push({ displayValue: (this.totalQuota * Math.pow(10, -9)) .toFixed(2) .toString() .replace('.00', ''), displayUnit: 'GB', - value: this.totalQuota - } - computedOptions.push(newOption) - } - if (this.maxQuota) { - computedOptions.forEach((computedOption) => { - if (computedOption.value > this.maxQuota || computedOption.value === 0) { - computedOption.selectable = false - } + value: this.totalQuota, + selectable: !(this.maxQuota && this.totalQuota > this.maxQuota) }) } + // Sort options and make sure that unlimited is at the end - computedOptions = [ - ...computedOptions.filter((o) => o.value).sort((a, b) => a.value - b.value), - ...computedOptions.filter((o) => !o.value) + availableOptions = [ + ...availableOptions.filter((o) => o.value).sort((a, b) => a.value - b.value), + ...availableOptions.filter((o) => !o.value) ] - this.options = computedOptions + this.options = availableOptions } } } diff --git a/packages/web-pkg/src/components/Spaces/QuotaModal.vue b/packages/web-pkg/src/components/Spaces/QuotaModal.vue index ee0ccb7e925..e76d9cfc23d 100644 --- a/packages/web-pkg/src/components/Spaces/QuotaModal.vue +++ b/packages/web-pkg/src/components/Spaces/QuotaModal.vue @@ -12,6 +12,7 @@ @@ -40,6 +41,10 @@ export default defineComponent({ cancel: { type: Function, required: true + }, + maxQuota: { + type: Number, + default: 0 } }, emits: ['spaceQuotaUpdated'], diff --git a/packages/web-pkg/src/composables/capability/useCapability.ts b/packages/web-pkg/src/composables/capability/useCapability.ts index 9abc8fda9cf..63810441448 100644 --- a/packages/web-pkg/src/composables/capability/useCapability.ts +++ b/packages/web-pkg/src/composables/capability/useCapability.ts @@ -39,6 +39,7 @@ export const useCapabilityFilesSharingResharingDefault = createCapabilityComposa ) export const useCapabilitySpacesEnabled = createCapabilityComposable('spaces.enabled', false) +export const useCapabilitySpacesMaxQuota = createCapabilityComposable('spaces.max_quota', 0) export const useCapabilityProjectSpacesEnabled = createCapabilityComposable( 'spaces.projects', false diff --git a/packages/web-pkg/tests/unit/components/QuotaSelect.spec.ts b/packages/web-pkg/tests/unit/components/QuotaSelect.spec.ts index b885ccd63f4..5d9ebe6c969 100644 --- a/packages/web-pkg/tests/unit/components/QuotaSelect.spec.ts +++ b/packages/web-pkg/tests/unit/components/QuotaSelect.spec.ts @@ -18,14 +18,14 @@ describe('QuotaSelect', () => { describe('method "createOption"', () => { it('should create option', () => { const { wrapper } = getWrapper() - expect((wrapper.vm as any).createOption('11')).toEqual({ - displayValue: '11', + expect((wrapper.vm as any).createOption('3')).toEqual({ + displayValue: '3', displayUnit: 'GB', - value: 11 * Math.pow(10, 9) + value: 3 * Math.pow(10, 9) }) }) it('should contain error property while maxQuota will be exceeded', () => { - const { wrapper } = getWrapper() + const { wrapper } = getWrapper({ maxQuota: 3 * Math.pow(10, 9) }) expect((wrapper.vm as any).createOption('2000')).toHaveProperty('error') }) it('should contain error property while creating an invalid option', () => { @@ -50,7 +50,56 @@ describe('QuotaSelect', () => { { displayValue: '45', displayUnit: 'GB', - value: 45 * Math.pow(10, 9) + value: 45 * Math.pow(10, 9), + selectable: true + } + ]) + ) + }) + it('should only contain lower or equal options when max quota is set', () => { + const { wrapper } = getWrapper({ + totalQuota: 2 * Math.pow(10, 9), + maxQuota: 4 * Math.pow(10, 9) + }) + ;(wrapper.vm as any).setOptions() + expect((wrapper.vm as any).options).toEqual( + expect.arrayContaining([ + { + displayValue: '1', + displayUnit: 'GB', + value: Math.pow(10, 9) + }, + { + displayValue: '2', + displayUnit: 'GB', + value: 2 * Math.pow(10, 9) + } + ]) + ) + }) + it('should contain a non selectable option if preset quota is higher than max quota', () => { + const { wrapper } = getWrapper({ + totalQuota: 100 * Math.pow(10, 9), + maxQuota: 4 * Math.pow(10, 9) + }) + ;(wrapper.vm as any).setOptions() + expect((wrapper.vm as any).options).toEqual( + expect.arrayContaining([ + { + displayValue: '1', + displayUnit: 'GB', + value: Math.pow(10, 9) + }, + { + displayValue: '2', + displayUnit: 'GB', + value: 2 * Math.pow(10, 9) + }, + { + displayValue: '100', + displayUnit: 'GB', + value: 100 * Math.pow(10, 9), + selectable: false } ]) ) @@ -58,7 +107,7 @@ describe('QuotaSelect', () => { }) }) -function getWrapper({ totalQuota = 10000000000 } = {}) { +function getWrapper({ totalQuota = 10 * Math.pow(10, 9), maxQuota = 0 } = {}) { return { wrapper: shallowMount(QuotaSelect, { data: () => { @@ -73,7 +122,7 @@ function getWrapper({ totalQuota = 10000000000 } = {}) { }, props: { totalQuota, - maxQuota: 100 * Math.pow(10, 9), + maxQuota, title: 'Personal quota' }, global: {