feat(frontend): improve route filter generics (#953)

This commit is contained in:
Dominik Pschenitschni 2025-06-16 22:40:09 +02:00 committed by GitHub
parent fc369fb558
commit b1c200c9aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 46 additions and 7 deletions

View File

@ -0,0 +1,11 @@
import {describe, it, expectTypeOf} from 'vitest'
import {useRouteFilters, type UseRouteFiltersReturn} from './useRouteFilters'
interface DummyFilters {foo: string}
describe('useRouteFilters type inference', () => {
it('should infer return types based on filter interface', () => {
type Result = ReturnType<typeof useRouteFilters<DummyFilters>>
expectTypeOf<Result>().toEqualTypeOf<UseRouteFiltersReturn<DummyFilters>>()
})
})

View File

@ -5,13 +5,19 @@ import equal from 'fast-deep-equal/es6'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Filters = Record<string, any>
export interface UseRouteFiltersReturn<CurrentFilters extends Filters> {
filters: Ref<CurrentFilters>
hasDefaultFilters: Ref<boolean>
setDefaultFilters: () => void
}
export function useRouteFilters<CurrentFilters extends Filters>(
route: Ref<RouteLocationNormalized>,
getDefaultFilters: (route: RouteLocationNormalized) => CurrentFilters,
routeToFilters: (route: RouteLocationNormalized) => CurrentFilters,
filtersToRoute: (filters: CurrentFilters) => RouteLocationRaw,
routeAllowList: RouteRecordName[] = [],
) {
) : UseRouteFiltersReturn<CurrentFilters> {
const router = useRouter()
const filters = ref<CurrentFilters>(routeToFilters(route.value))

View File

@ -4,8 +4,8 @@ import type {RouteLocationNormalized, RouteLocationRaw} from 'vue-router'
import {isoToKebabDate} from '@/helpers/time/isoToKebabDate'
import {parseDateProp} from '@/helpers/time/parseDateProp'
import {parseBooleanProp} from '@/helpers/time/parseBooleanProp'
import {useRouteFilters} from '@/composables/useRouteFilters'
import {useGanttTaskList} from './useGanttTaskList'
import {useRouteFilters, type UseRouteFiltersReturn} from '@/composables/useRouteFilters'
import {useGanttTaskList, type UseGanttTaskListReturn} from './useGanttTaskList'
import type {IProject} from '@/modelTypes/IProject'
import type {TaskFilterParams} from '@/services/taskCollection'
@ -94,8 +94,8 @@ function ganttFiltersToApiParams(filters: GanttFilters): TaskFilterParams {
}
export type UseGanttFiltersReturn =
ReturnType<typeof useRouteFilters<GanttFilters>> &
ReturnType<typeof useGanttTaskList<GanttFilters>>
UseRouteFiltersReturn<GanttFilters> &
UseGanttTaskListReturn
export function useGanttFilters(route: Ref<RouteLocationNormalized>, viewId: Ref<IProjectView['id']>): UseGanttFiltersReturn {
const {

View File

@ -0,0 +1,14 @@
import {describe, it, expectTypeOf} from 'vitest'
import {useGanttTaskList, type UseGanttTaskListReturn} from './useGanttTaskList'
import type {Filters} from '@/composables/useRouteFilters'
interface TestFilters extends Filters {
projectId: number
}
describe('useGanttTaskList return type', () => {
it('should match interface', () => {
type Result = ReturnType<typeof useGanttTaskList<TestFilters>>
expectTypeOf<Result>().toEqualTypeOf<UseGanttTaskListReturn>()
})
})

View File

@ -1,4 +1,4 @@
import {computed, ref, type Ref, shallowReactive, watch} from 'vue'
import {computed, ref, type Ref, shallowReactive, watch, type ComputedRef} from 'vue'
import {klona} from 'klona/lite'
import type {Filters} from '@/composables/useRouteFilters'
@ -12,13 +12,21 @@ import {error, success} from '@/message'
import {useAuthStore} from '@/stores/auth'
import type {IProjectView} from '@/modelTypes/IProjectView'
export interface UseGanttTaskListReturn {
tasks: Ref<Map<ITask['id'], ITask>>
isLoading: ComputedRef<boolean>
loadTasks: () => Promise<void>
addTask: (task: Partial<ITask>) => Promise<ITask>
updateTask: (task: ITaskPartialWithId) => Promise<void>
}
// FIXME: unify with general `useTaskList`
export function useGanttTaskList<F extends Filters>(
filters: Ref<F>,
filterToApiParams: (filters: F) => TaskFilterParams,
viewId: Ref<IProjectView['id']>,
loadAll: boolean = true,
) {
) : UseGanttTaskListReturn {
const taskCollectionService = shallowReactive(new TaskCollectionService())
const taskService = shallowReactive(new TaskService())
const authStore = useAuthStore()