Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion packages/web-pkg/src/components/QuotaSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
:clearable="false"
:options="options"
:create-option="createOption"
:filter="filterOptions"
option-label="displayValue"
:label="$gettext('Quota')"
v-bind="$attrs"
Expand Down Expand Up @@ -66,6 +67,11 @@ function isValueValidNumber(value: string | number) {
return optionIsNumberRegex.test(value)
}

function isZeroInput(input: string) {
const normalizedInput = input.replace(',', '.')
return isValueValidNumber(normalizedInput) && parseFloat(normalizedInput) === 0
}

function getFormattedFileSize(value: number) {
const formattedFilesize = formatFileSize(value, unref(currentLanguage))
return !isValueValidNumber(value) ? value.toString() : formattedFilesize
Expand Down Expand Up @@ -114,7 +120,23 @@ function optionSelectable(option: Option) {
return option.selectable !== false
}

function filterOptions(items: Option[], search: string) {
// a typed 0 means "No restriction", so it must not match presets like "10 GB"
if (isZeroInput(search)) {
return items.filter((item) => item.value === 0)
}
const normalizedSearch = search.toLocaleLowerCase()
return items.filter((item) => item.displayValue.toLocaleLowerCase().includes(normalizedSearch))
}

function createOption(option: string) {
if (isZeroInput(option)) {
const unlimitedOption = unref(options).find((o) => o.value === 0)
if (unlimitedOption) {
return unlimitedOption
}
}

option = option.replace(',', '.')

if (!isValueValidNumber(option)) {
Expand All @@ -125,7 +147,16 @@ function createOption(option: string) {
selectable: false
}
}
const value = parseFloat(option) * Math.pow(10, 9)
const value = Math.round(parseFloat(option) * Math.pow(10, 9))

if (value < 1) {
return {
displayValue: option,
value: option,
error: $gettext('Please enter a value greater than 0'),
selectable: false
}
}

if (value > unref(quotaLimit)) {
return {
Expand Down
53 changes: 52 additions & 1 deletion packages/web-pkg/tests/unit/components/QuotaSelect.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import QuotaSelect from '../../../src/components/QuotaSelect.vue'
import { defaultPlugins, shallowMount } from '@opencloud-eu/web-test-helpers'
import { defaultPlugins, mount, shallowMount } from '@opencloud-eu/web-test-helpers'

describe('QuotaSelect', () => {
describe('method "optionSelectable"', () => {
Expand All @@ -25,6 +25,29 @@ describe('QuotaSelect', () => {
value: 3 * Math.pow(10, 9)
})
})
it('should round decimal values to whole bytes', () => {
const { wrapper } = getWrapper()
expect((wrapper.vm as any).createOption('4.1').value).toBe(4100000000)
expect((wrapper.vm as any).createOption('8,2').value).toBe(8200000000)
})
it('should contain error property for values below one byte', () => {
const { wrapper } = getWrapper()
expect((wrapper.vm as any).createOption('0.0000000001')).toHaveProperty('error')
})
it.each(['0', '0.0', '0,0'])('should map "%s" to the unlimited option', (input) => {
const { wrapper } = getWrapper()
expect((wrapper.vm as any).createOption(input)).toEqual({
displayValue: 'No restriction',
value: 0
})
})
it('should contain error property for 0 when unlimited is not available', () => {
const { wrapper } = getWrapper({
totalQuota: 2 * Math.pow(10, 9),
maxQuota: 4 * Math.pow(10, 9)
})
expect((wrapper.vm as any).createOption('0')).toHaveProperty('error')
})
it('should contain error property while maxQuota will be exceeded', () => {
const { wrapper } = getWrapper({ maxQuota: 3 * Math.pow(10, 9) })
expect((wrapper.vm as any).createOption('2000')).toHaveProperty('error')
Expand All @@ -36,6 +59,34 @@ describe('QuotaSelect', () => {
expect((wrapper.vm as any).createOption('1.')).toHaveProperty('error')
})
})
describe('typing a value and pressing Enter', () => {
it.each(['0', '0.0', '0,0'])('should select unlimited for "%s"', async (input) => {
const wrapper = mount(QuotaSelect, {
props: { totalQuota: 2 * Math.pow(10, 9) },
global: { plugins: [...defaultPlugins()] }
})
const search = wrapper.find('input.vs__search')
await search.trigger('click')
await search.setValue(input)
await search.trigger('keydown', { key: 'Enter', keyCode: 13 })
const emitted = wrapper.emitted('selectedOptionChange')
expect(emitted).toHaveLength(1)
expect(emitted[0][0]).toEqual({ displayValue: 'No restriction', value: 0 })
})
it('should select a custom value rounded to whole bytes', async () => {
const wrapper = mount(QuotaSelect, {
props: { totalQuota: 2 * Math.pow(10, 9) },
global: { plugins: [...defaultPlugins()] }
})
const search = wrapper.find('input.vs__search')
await search.trigger('click')
await search.setValue('4.1')
await search.trigger('keydown', { key: 'Enter', keyCode: 13 })
const emitted = wrapper.emitted('selectedOptionChange')
expect(emitted).toHaveLength(1)
expect((emitted[0][0] as { value: number }).value).toBe(4100000000)
})
})
describe('method "setOptions"', () => {
it('should set options to default options', () => {
const { wrapper } = getWrapper()
Expand Down
Loading