Merge remote-tracking branch 'upstream/main' into feat/payment-system-v2
# Conflicts: # frontend/src/api/admin/settings.ts # frontend/src/stores/app.ts # frontend/src/types/index.ts # frontend/src/views/admin/SettingsView.vue
This commit is contained in:
74
frontend/src/utils/__tests__/tablePreferences.spec.ts
Normal file
74
frontend/src/utils/__tests__/tablePreferences.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
DEFAULT_TABLE_PAGE_SIZE,
|
||||
DEFAULT_TABLE_PAGE_SIZE_OPTIONS,
|
||||
getConfiguredTableDefaultPageSize,
|
||||
getConfiguredTablePageSizeOptions,
|
||||
normalizeTablePageSize
|
||||
} from '@/utils/tablePreferences'
|
||||
|
||||
describe('tablePreferences', () => {
|
||||
afterEach(() => {
|
||||
delete window.__APP_CONFIG__
|
||||
})
|
||||
|
||||
it('returns built-in defaults when app config is missing', () => {
|
||||
expect(getConfiguredTableDefaultPageSize()).toBe(DEFAULT_TABLE_PAGE_SIZE)
|
||||
expect(getConfiguredTablePageSizeOptions()).toEqual(DEFAULT_TABLE_PAGE_SIZE_OPTIONS)
|
||||
})
|
||||
|
||||
it('uses configured defaults when app config is valid', () => {
|
||||
window.__APP_CONFIG__ = {
|
||||
table_default_page_size: 50,
|
||||
table_page_size_options: [20, 50, 100]
|
||||
} as any
|
||||
|
||||
expect(getConfiguredTableDefaultPageSize()).toBe(50)
|
||||
expect(getConfiguredTablePageSizeOptions()).toEqual([20, 50, 100])
|
||||
})
|
||||
|
||||
it('allows default page size outside selectable options', () => {
|
||||
window.__APP_CONFIG__ = {
|
||||
table_default_page_size: 1000,
|
||||
table_page_size_options: [20, 50, 100]
|
||||
} as any
|
||||
|
||||
expect(getConfiguredTableDefaultPageSize()).toBe(1000)
|
||||
expect(getConfiguredTablePageSizeOptions()).toEqual([20, 50, 100])
|
||||
expect(normalizeTablePageSize(1000)).toBe(100)
|
||||
expect(normalizeTablePageSize(35)).toBe(50)
|
||||
})
|
||||
|
||||
it('normalizes invalid options without rewriting the configured default itself', () => {
|
||||
window.__APP_CONFIG__ = {
|
||||
table_default_page_size: 35,
|
||||
table_page_size_options: [1001, 50, 10, 10, 2, 0]
|
||||
} as any
|
||||
|
||||
expect(getConfiguredTableDefaultPageSize()).toBe(35)
|
||||
expect(getConfiguredTablePageSizeOptions()).toEqual([10, 50])
|
||||
expect(normalizeTablePageSize(undefined)).toBe(50)
|
||||
})
|
||||
|
||||
it('normalizes page size against configured options by rounding up', () => {
|
||||
window.__APP_CONFIG__ = {
|
||||
table_default_page_size: 20,
|
||||
table_page_size_options: [20, 50, 1000]
|
||||
} as any
|
||||
|
||||
expect(normalizeTablePageSize(20)).toBe(20)
|
||||
expect(normalizeTablePageSize(30)).toBe(50)
|
||||
expect(normalizeTablePageSize(100)).toBe(1000)
|
||||
expect(normalizeTablePageSize(1500)).toBe(1000)
|
||||
expect(normalizeTablePageSize(undefined)).toBe(20)
|
||||
})
|
||||
|
||||
it('keeps built-in selectable defaults at 10, 20, 50, 100', () => {
|
||||
window.__APP_CONFIG__ = {
|
||||
table_default_page_size: 1000
|
||||
} as any
|
||||
|
||||
expect(getConfiguredTablePageSizeOptions()).toEqual([10, 20, 50, 100])
|
||||
})
|
||||
})
|
||||
73
frontend/src/utils/tablePreferences.ts
Normal file
73
frontend/src/utils/tablePreferences.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
const MIN_TABLE_PAGE_SIZE = 5
|
||||
const MAX_TABLE_PAGE_SIZE = 1000
|
||||
|
||||
export const DEFAULT_TABLE_PAGE_SIZE = 20
|
||||
export const DEFAULT_TABLE_PAGE_SIZE_OPTIONS = [10, 20, 50, 100]
|
||||
|
||||
const sanitizePageSize = (value: unknown): number | null => {
|
||||
const size = Number(value)
|
||||
if (!Number.isInteger(size)) return null
|
||||
if (size < MIN_TABLE_PAGE_SIZE || size > MAX_TABLE_PAGE_SIZE) return null
|
||||
return size
|
||||
}
|
||||
|
||||
const parsePageSizeForSelection = (value: unknown): number | null => {
|
||||
const size = Number(value)
|
||||
if (!Number.isInteger(size)) return null
|
||||
if (size < MIN_TABLE_PAGE_SIZE) return null
|
||||
return size
|
||||
}
|
||||
|
||||
const getInjectedAppConfig = () => {
|
||||
if (typeof window === 'undefined') return null
|
||||
return window.__APP_CONFIG__ ?? null
|
||||
}
|
||||
|
||||
const getSanitizedConfiguredOptions = (): number[] => {
|
||||
const configured = getInjectedAppConfig()?.table_page_size_options
|
||||
if (!Array.isArray(configured)) return []
|
||||
|
||||
return Array.from(
|
||||
new Set(
|
||||
configured
|
||||
.map((value) => sanitizePageSize(value))
|
||||
.filter((value): value is number => value !== null)
|
||||
)
|
||||
).sort((a, b) => a - b)
|
||||
}
|
||||
|
||||
const normalizePageSizeToOptions = (value: number, options: number[]): number => {
|
||||
for (const option of options) {
|
||||
if (option >= value) {
|
||||
return option
|
||||
}
|
||||
}
|
||||
return options[options.length - 1]
|
||||
}
|
||||
|
||||
export const getConfiguredTableDefaultPageSize = (): number => {
|
||||
const configured = sanitizePageSize(getInjectedAppConfig()?.table_default_page_size)
|
||||
if (configured === null) {
|
||||
return DEFAULT_TABLE_PAGE_SIZE
|
||||
}
|
||||
return configured
|
||||
}
|
||||
|
||||
export const getConfiguredTablePageSizeOptions = (): number[] => {
|
||||
const unique = getSanitizedConfiguredOptions()
|
||||
if (unique.length === 0) {
|
||||
return [...DEFAULT_TABLE_PAGE_SIZE_OPTIONS]
|
||||
}
|
||||
|
||||
return unique.length > 0 ? unique : [...DEFAULT_TABLE_PAGE_SIZE_OPTIONS]
|
||||
}
|
||||
|
||||
export const normalizeTablePageSize = (value: unknown): number => {
|
||||
const normalized = parsePageSizeForSelection(value)
|
||||
const defaultSize = getConfiguredTableDefaultPageSize()
|
||||
const options = getConfiguredTablePageSizeOptions()
|
||||
if (normalized !== null) {
|
||||
return normalizePageSizeToOptions(normalized, options)
|
||||
}
|
||||
return normalizePageSizeToOptions(defaultSize, options)
|
||||
}
|
||||
Reference in New Issue
Block a user