Files
RenewCMS/web/src/lib/entryListQuery.ts
T

91 lines
2.6 KiB
TypeScript

import type { LocationQuery } from 'vue-router'
import { t } from '@/i18n'
import {
DEFAULT_PAGE_SIZE,
PAGE_SIZES,
firstQueryValue,
parsePositiveInteger,
} from '@/lib/pageQuery'
export const ENTRY_SORT_FIELDS = ['id', 'created_at', 'updated_at'] as const
export type EntrySortField = (typeof ENTRY_SORT_FIELDS)[number]
export type EntrySortDirection = 'asc' | 'desc'
export const DEFAULT_ENTRY_SORT = 'updated_at:desc'
export interface EntryListQuery {
page: number
size: number
q: string
sort: string
}
const SORT_PATTERN = new RegExp(`^(${ENTRY_SORT_FIELDS.join('|')}):(asc|desc)$`)
export function parseEntryQuery(query: LocationQuery): EntryListQuery {
const size = parsePositiveInteger(firstQueryValue(query.size))
const sort = firstQueryValue(query.sort)
return {
page: parsePositiveInteger(firstQueryValue(query.page)) ?? 1,
size: size !== null && PAGE_SIZES.includes(size) ? size : DEFAULT_PAGE_SIZE,
q: '',
sort: SORT_PATTERN.test(sort) ? sort : DEFAULT_ENTRY_SORT,
}
}
export function toEntryRouteQuery(query: EntryListQuery) {
const route: Record<string, string> = {}
if (query.size !== DEFAULT_PAGE_SIZE) {
route.size = String(query.size)
}
if (query.sort !== DEFAULT_ENTRY_SORT) {
route.sort = query.sort
}
if (query.page !== 1) {
route.page = String(query.page)
}
return route
}
export function sameEntryQuery(left: EntryListQuery, right: EntryListQuery) {
return left.page === right.page && left.size === right.size && left.sort === right.sort
}
export function sortParts(sort: string) {
const [field, direction] = sort.split(':') as [EntrySortField, EntrySortDirection]
return { field, direction }
}
export function withSortField(sort: string, field: EntrySortField) {
return `${field}:${sortParts(sort).direction}`
}
export function withOppositeDirection(sort: string) {
const { field, direction } = sortParts(sort)
return `${field}:${direction === 'asc' ? 'desc' : 'asc'}`
}
export function sortFieldLabel(field: EntrySortField) {
if (field === 'id') {
return t('ID')
}
return field === 'created_at' ? t('Created') : t('Last updated')
}
export function sortDirectionLabel(sort: string) {
return sortParts(sort).direction === 'asc' ? t('Sort descending') : t('Sort ascending')
}
export function entryCaption(name: string, sort: string) {
const { field, direction } = sortParts(sort)
if (sort === DEFAULT_ENTRY_SORT) {
return t('{0}, sorted by last updated, newest first', [name])
}
const column = { id: t('id'), created_at: t('created'), updated_at: t('updated') }[field]
return t('{0}, sorted by {1}, {2}', [
name,
column,
direction === 'desc' ? t('descending') : t('ascending'),
])
}