From 326427a24282a769e28b357ebb8c071096fc0844 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 6 Apr 2026 02:41:44 +0200 Subject: [PATCH] feat(sort): persist sort selection to URL query parameter Syncs the sort choice to a ?sort=field:order URL parameter so it survives page refreshes and can be shared. The default position sort is omitted from the URL to keep links clean. --- frontend/src/composables/useTaskList.ts | 41 +++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/frontend/src/composables/useTaskList.ts b/frontend/src/composables/useTaskList.ts index dff757d9e..b595e5e09 100644 --- a/frontend/src/composables/useTaskList.ts +++ b/frontend/src/composables/useTaskList.ts @@ -27,6 +27,32 @@ export interface SortBy { created?: Order updated?: Order done_at?: Order, + position?: Order, +} + +const VALID_SORT_FIELDS = new Set( + ['id', 'index', 'done', 'title', 'priority', 'due_date', 'start_date', + 'end_date', 'percent_done', 'created', 'updated', 'done_at', 'position'], +) + +function parseSortQuery(raw: string, fallback: SortBy): SortBy { + const result: Record = {} + for (const part of raw.split(',')) { + const [field, order] = part.split(':') + if (!VALID_SORT_FIELDS.has(field)) continue + if (order !== 'asc' && order !== 'desc') continue + result[field] = order + } + return Object.keys(result).length > 0 ? result as SortBy : {...fallback} +} + +function serializeSortBy(sortBy: SortBy, defaultSort: SortBy): string | undefined { + const keys = Object.keys(sortBy) as (keyof SortBy)[] + const defaultKeys = Object.keys(defaultSort) as (keyof SortBy)[] + const isDefault = keys.length === defaultKeys.length && + keys.every(k => sortBy[k] === defaultSort[k]) + if (isDefault) return undefined + return keys.map(k => `${k}:${sortBy[k]}`).join(',') } const SORT_BY_DEFAULT: SortBy = { @@ -80,8 +106,19 @@ export function useTaskList( watch(() => params.value.filter, v => { filter.value = v || undefined }) watch(() => params.value.s, v => { s.value = v || undefined }) - const sortBy = ref({ ...sortByDefault }) - + const sortQuery = useRouteQuery('sort') + + const sortBy = computed({ + get() { + const raw = sortQuery.value as string | undefined + if (!raw) return {...sortByDefault} + return parseSortQuery(raw, sortByDefault) + }, + set(val: SortBy) { + sortQuery.value = serializeSortBy(val, sortByDefault) || undefined + }, + }) + const allParams = computed(() => { const loadParams = {...params.value}