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.
171 lines
3.9 KiB
TypeScript
171 lines
3.9 KiB
TypeScript
import {ref, shallowReactive, watch, computed, type ComputedGetter} from 'vue'
|
|
import {useRoute, useRouter} from 'vue-router'
|
|
import {useRouteQuery} from '@vueuse/router'
|
|
|
|
import TaskCollectionService, {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection'
|
|
import type {ITask} from '@/modelTypes/ITask'
|
|
import {error} from '@/message'
|
|
import type {IProject} from '@/modelTypes/IProject'
|
|
import {useAuthStore} from '@/stores/auth'
|
|
import type {IProjectView} from '@/modelTypes/IProjectView'
|
|
|
|
export type Order = 'asc' | 'desc' | 'none'
|
|
|
|
export interface SortBy {
|
|
id?: Order
|
|
index?: Order
|
|
done?: Order
|
|
title?: Order
|
|
priority?: Order
|
|
due_date?: Order
|
|
start_date?: Order
|
|
end_date?: Order
|
|
percent_done?: Order
|
|
created?: Order
|
|
updated?: Order
|
|
done_at?: Order,
|
|
}
|
|
|
|
const SORT_BY_DEFAULT: SortBy = {
|
|
id: 'desc',
|
|
}
|
|
|
|
// This makes sure an id sort order is always sorted last.
|
|
// When tasks would be sorted first by id and then by whatever else was specified, the id sort takes
|
|
// precedence over everything else, making any other sort columns pretty useless.
|
|
function formatSortOrder(sortBy, params) {
|
|
let hasIdFilter = false
|
|
const sortKeys = Object.keys(sortBy)
|
|
for (const s of sortKeys) {
|
|
if (s === 'id') {
|
|
sortKeys.splice(s, 1)
|
|
hasIdFilter = true
|
|
break
|
|
}
|
|
}
|
|
if (hasIdFilter) {
|
|
sortKeys.push('id')
|
|
}
|
|
params.sort_by = sortKeys
|
|
params.order_by = sortKeys.map(s => sortBy[s])
|
|
|
|
return params
|
|
}
|
|
|
|
/**
|
|
* This mixin provides a base set of methods and properties to get tasks.
|
|
*/
|
|
export function useTaskList(
|
|
projectIdGetter: ComputedGetter<IProject['id']>,
|
|
projectViewIdGetter: ComputedGetter<IProjectView['id']>,
|
|
sortByDefault: SortBy = SORT_BY_DEFAULT,
|
|
) {
|
|
|
|
const projectId = computed(() => projectIdGetter())
|
|
const projectViewId = computed(() => projectViewIdGetter())
|
|
|
|
const params = ref<TaskFilterParams>({...getDefaultTaskFilterParams()})
|
|
|
|
const page = useRouteQuery('page', '1', { transform: Number })
|
|
|
|
const sortBy = ref({ ...sortByDefault })
|
|
|
|
const allParams = computed(() => {
|
|
const loadParams = {...params.value}
|
|
|
|
return formatSortOrder(sortBy.value, loadParams)
|
|
})
|
|
|
|
watch(
|
|
() => allParams.value,
|
|
() => {
|
|
// When parameters change, the page should always be the first
|
|
page.value = 1
|
|
},
|
|
)
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
const getAllTasksParams = computed(() => {
|
|
return [
|
|
{
|
|
projectId: projectId.value,
|
|
viewId: projectViewId.value,
|
|
},
|
|
{
|
|
...allParams.value,
|
|
filter_timezone: authStore.settings.timezone,
|
|
},
|
|
page.value,
|
|
]
|
|
})
|
|
|
|
const taskCollectionService = shallowReactive(new TaskCollectionService())
|
|
const loading = computed(() => taskCollectionService.loading)
|
|
const totalPages = computed(() => taskCollectionService.totalPages)
|
|
|
|
const tasks = ref<ITask[]>([])
|
|
async function loadTasks() {
|
|
tasks.value = []
|
|
try {
|
|
tasks.value = await taskCollectionService.getAll(...getAllTasksParams.value)
|
|
} catch (e) {
|
|
error(e)
|
|
}
|
|
return tasks.value
|
|
}
|
|
|
|
const route = useRoute()
|
|
watch(() => route.query, (query) => {
|
|
const {
|
|
page: pageQueryValue,
|
|
s,
|
|
filter,
|
|
} = query
|
|
if (s !== undefined) {
|
|
params.value.s = s as string
|
|
}
|
|
if (pageQueryValue !== undefined) {
|
|
page.value = Number(pageQueryValue)
|
|
}
|
|
if (filter !== undefined) {
|
|
params.value.filter = filter
|
|
}
|
|
}, { 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
|
|
watch(() => JSON.stringify(getAllTasksParams.value), (newParams, oldParams) => {
|
|
if (oldParams === newParams) {
|
|
return
|
|
}
|
|
|
|
loadTasks()
|
|
}, { immediate: true })
|
|
|
|
return {
|
|
tasks,
|
|
loading,
|
|
totalPages,
|
|
currentPage: page,
|
|
loadTasks,
|
|
params,
|
|
sortByParam: sortBy,
|
|
}
|
|
} |