fix(filters): always persist filter or search in query path and load it correctly into filter query input when loading the page
Some checks failed
continuous-integration/drone/push Build is failing

Previously, when using the filter query as a search input, it would load the search as requested but the filter query parameter in the url would be empty, which meant the search would not be loaded correctly when reloading (or otherwise newly accessing) the page. We're now persisting the filter and search in the task loading logic, to make sure they are always populated correctly.
This commit is contained in:
kolaente 2024-04-13 23:34:25 +02:00
parent 5756da412b
commit 6e5b31f1e0
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
3 changed files with 50 additions and 42 deletions

View File

@ -30,45 +30,27 @@ import {computed, ref, watch} from 'vue'
import Filters from '@/components/project/partials/filters.vue' import Filters from '@/components/project/partials/filters.vue'
import {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection' import {type TaskFilterParams} from '@/services/taskCollection'
import {useRouteQuery} from '@vueuse/router'
const modelValue = defineModel<TaskFilterParams>({}) const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const value = ref<TaskFilterParams>({}) const value = ref<TaskFilterParams>({})
const filter = useRouteQuery('filter')
watch( watch(
() => modelValue.value, () => props.modelValue,
(modelValue: TaskFilterParams) => { (modelValue: TaskFilterParams) => {
value.value = modelValue value.value = modelValue
if (value.value.filter !== '' && value.value.filter !== getDefaultTaskFilterParams().filter) {
filter.value = value.value.filter
}
},
{immediate: true},
)
watch(
() => filter.value,
val => {
if (modelValue.value?.filter === val || typeof val === 'undefined') {
return
}
modelValue.value.filter = val
}, },
{immediate: true}, {immediate: true},
) )
function emitChanges(newValue: TaskFilterParams) { function emitChanges(newValue: TaskFilterParams) {
filter.value = newValue.filter emit('update:modelValue', {
if (modelValue.value?.filter === newValue.filter && modelValue.value?.s === newValue.s) { ...value.value,
return filter: newValue.filter,
} s: newValue.s,
})
modelValue.value.filter = newValue.filter
modelValue.value.s = newValue.s
} }
const hasFilters = computed(() => { const hasFilters = computed(() => {

View File

@ -5,7 +5,7 @@
role="search" role="search"
> >
<FilterInput <FilterInput
v-model="params.filter" v-model="filterQuery"
:project-id="projectId" :project-id="projectId"
@blur="change()" @blur="change()"
/> />
@ -28,7 +28,7 @@
<x-button <x-button
variant="secondary" variant="secondary"
class="mr-2" class="mr-2"
:disabled="params.filter === ''" :disabled="filterQuery === ''"
@click.prevent.stop="clearFiltersAndEmit" @click.prevent.stop="clearFiltersAndEmit"
> >
{{ $t('filters.clear') }} {{ $t('filters.clear') }}
@ -87,6 +87,16 @@ const params = ref<TaskFilterParams>({
s: '', s: '',
}) })
const filterQuery = ref('')
watch(
() => [params.value.filter, params.value.s],
() => {
const filter = params.value.filter || ''
const s = params.value.s || ''
filterQuery.value = filter || s
},
)
// Using watchDebounced to prevent the filter re-triggering itself. // Using watchDebounced to prevent the filter re-triggering itself.
watch( watch(
() => modelValue, () => modelValue,
@ -107,7 +117,7 @@ const projectStore = useProjectStore()
function change() { function change() {
const filter = transformFilterStringForApi( const filter = transformFilterStringForApi(
params.value.filter, filterQuery.value,
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null, labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
projectTitle => { projectTitle => {
const found = projectStore.findProjectByExactname(projectTitle) const found = projectStore.findProjectByExactname(projectTitle)
@ -142,7 +152,7 @@ function changeAndEmitButton() {
} }
function clearFiltersAndEmit() { function clearFiltersAndEmit() {
params.value.filter = '' filterQuery.value = ''
changeAndEmitButton() changeAndEmitButton()
} }
</script> </script>

View File

@ -1,5 +1,5 @@
import {ref, shallowReactive, watch, computed, type ComputedGetter} from 'vue' import {ref, shallowReactive, watch, computed, type ComputedGetter} from 'vue'
import {useRoute} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useRouteQuery} from '@vueuse/router' import {useRouteQuery} from '@vueuse/router'
import TaskCollectionService, {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection' import TaskCollectionService, {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection'
@ -66,7 +66,6 @@ export function useTaskList(
const params = ref<TaskFilterParams>({...getDefaultTaskFilterParams()}) const params = ref<TaskFilterParams>({...getDefaultTaskFilterParams()})
const search = ref('')
const page = useRouteQuery('page', '1', { transform: Number }) const page = useRouteQuery('page', '1', { transform: Number })
const sortBy = ref({ ...sortByDefault }) const sortBy = ref({ ...sortByDefault })
@ -74,10 +73,6 @@ export function useTaskList(
const allParams = computed(() => { const allParams = computed(() => {
const loadParams = {...params.value} const loadParams = {...params.value}
if (search.value !== '') {
loadParams.s = search.value
}
return formatSortOrder(sortBy.value, loadParams) return formatSortOrder(sortBy.value, loadParams)
}) })
@ -122,16 +117,38 @@ export function useTaskList(
const route = useRoute() const route = useRoute()
watch(() => route.query, (query) => { watch(() => route.query, (query) => {
const { page: pageQueryValue, search: searchQuery } = query const {
if (searchQuery !== undefined) { page: pageQueryValue,
search.value = searchQuery as string s,
filter,
} = query
if (s !== undefined) {
params.value.s = s as string
} }
if (pageQueryValue !== undefined) { if (pageQueryValue !== undefined) {
page.value = Number(pageQueryValue) page.value = Number(pageQueryValue)
} }
if (filter !== undefined) {
params.value.filter = filter
}
}, { immediate: true }) }, { immediate: true })
const router = useRouter()
watch(
() => [page.value, params.value.filter, params.value.s],
() => {
router.replace({
name: route.name,
params: route.params,
query: {
page: page.value,
filter: params.value.filter || undefined,
s: params.value.s || undefined,
},
})
},
{ deep: true },
)
// Only listen for query path changes // Only listen for query path changes
watch(() => JSON.stringify(getAllTasksParams.value), (newParams, oldParams) => { watch(() => JSON.stringify(getAllTasksParams.value), (newParams, oldParams) => {
@ -148,7 +165,6 @@ export function useTaskList(
totalPages, totalPages,
currentPage: page, currentPage: page,
loadTasks, loadTasks,
searchTerm: search,
params, params,
sortByParam: sortBy, sortByParam: sortBy,
} }