feat: replace our home-grown gantt implementation with ganttastic #2180
|
@ -52,7 +52,7 @@ import {parseKebabDate} from '@/helpers/time/parseKebabDate'
|
|||
|
||||
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
|
||||
import type {DateISO} from '@/types/DateISO'
|
||||
import type {GanttFilter} from '@/views/list/helpers/useGanttFilter'
|
||||
import type {GanttFilters} from '@/views/list/helpers/useGanttFilters'
|
||||
|
||||
import {
|
||||
extendDayjs,
|
||||
|
@ -66,7 +66,7 @@ import {MILLISECONDS_A_DAY} from '@/constants/date'
|
|||
|
||||
export interface GanttChartProps {
|
||||
isLoading: boolean,
|
||||
filters: GanttFilter,
|
||||
filters: GanttFilters,
|
||||
tasks: Map<ITask['id'], ITask>,
|
||||
defaultTaskStartDate: DateISO
|
||||
defaultTaskEndDate: DateISO
|
||||
|
|
|
@ -2,18 +2,18 @@ import {computed, ref, watch, type Ref} from 'vue'
|
|||
import {useRouter, type RouteLocationNormalized, type RouteLocationRaw} from 'vue-router'
|
||||
import cloneDeep from 'lodash.clonedeep'
|
||||
|
||||
export type Filter = Record<string, any>
|
||||
export type Filters = Record<string, any>
|
||||
|
||||
export function useRouteFilter<F extends Filter = Filter>(
|
||||
export function useRouteFilters<CurrentFilters extends Filters>(
|
||||
route: Ref<RouteLocationNormalized>,
|
||||
routeToFilter: (route: RouteLocationNormalized) => F,
|
||||
filterToRoute: (filter: F) => RouteLocationRaw,
|
||||
routeToFilters: (route: RouteLocationNormalized) => CurrentFilters,
|
||||
filtersToRoute: (filters: CurrentFilters) => RouteLocationRaw,
|
||||
) {
|
||||
const router = useRouter()
|
||||
|
||||
const filters = ref<F>(routeToFilter(route.value))
|
||||
const filters = ref<CurrentFilters>(routeToFilters(route.value))
|
||||
|
||||
const routeFromFiltersFullPath = computed(() => router.resolve(filterToRoute(filters.value)).fullPath)
|
||||
const routeFromFiltersFullPath = computed(() => router.resolve(filtersToRoute(filters.value)).fullPath)
|
||||
|
||||
watch(() => cloneDeep(route.value), (route, oldRoute) => {
|
||||
if (
|
||||
|
@ -23,7 +23,7 @@ export function useRouteFilter<F extends Filter = Filter>(
|
|||
return
|
||||
}
|
||||
|
||||
filters.value = routeToFilter(route)
|
||||
filters.value = routeToFilters(route)
|
||||
})
|
||||
|
||||
watch(
|
|
@ -56,7 +56,7 @@ import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
|||
import TaskForm from '@/components/tasks/TaskForm.vue'
|
||||
|
||||
import {createAsyncComponent} from '@/helpers/createAsyncComponent'
|
||||
import {useGanttFilter} from './helpers/useGanttFilter'
|
||||
import {useGanttFilters} from './helpers/useGanttFilters'
|
||||
import {RIGHTS} from '@/constants/rights'
|
||||
|
||||
import type {DateISO} from '@/types/DateISO'
|
||||
|
@ -78,7 +78,7 @@ const {
|
|||
isLoading,
|
||||
konrad marked this conversation as resolved
Outdated
|
||||
addTask,
|
||||
updateTask,
|
||||
} = useGanttFilter(route)
|
||||
} = useGanttFilters(route)
|
||||
|
||||
const today = new Date(new Date().setHours(0,0,0,0))
|
||||
dpschen
commented
Can you explain in a different way? Can you explain in a different way?
konrad
commented
The problem is the gantt chart already updates when only one date (the start or end date) is selected. Ideally, they would only update the prop when both of these dates are available to avoid these partial updates. The problem is the gantt chart already updates when only one date (the start or end date) is selected. Ideally, they would only update the prop when both of these dates are available to avoid these partial updates.
dpschen
commented
Maybe I'm still not getting this correctly, but can't we just update the value when both (start and end) are set? Maybe I'm still not getting this correctly, but can't we just update the value when both (start and end) are set?
konrad
commented
Currently the from and to dates get passed as individual props. That means if one changes, it changes directly in the chart. I think the way to go here would be to pass a single object with both dates instead? Currently the from and to dates get passed as individual props. That means if one changes, it changes directly in the chart.
I think the way to go here would be to pass a single object with both dates instead?
dpschen
commented
That seems like the right approach That seems like the right approach
dpschen
commented
Will check this out again. Shouldn't be too hard. Will check this out again. Shouldn't be too hard.
|
||||
const defaultTaskStartDate: DateISO = new Date(today).toISOString()
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 {useRouteFilter} from '@/composables/useRouteFilter'
|
||||
import {useRouteFilters} from '@/composables/useRouteFilters'
|
||||
import {useGanttTaskList} from './useGanttTaskList'
|
||||
|
||||
import type {IList} from '@/modelTypes/IList'
|
||||
|
@ -14,7 +14,7 @@ import type {DateISO} from '@/types/DateISO'
|
|||
import type {DateKebab} from '@/types/DateKebab'
|
||||
|
||||
// convenient internal filter object
|
||||
export interface GanttFilter {
|
||||
export interface GanttFilters {
|
||||
listId: IList['id']
|
||||
dateFrom: DateISO
|
||||
dateTo: DateISO
|
||||
|
@ -37,17 +37,18 @@ function getDefaultDateTo() {
|
|||
}
|
||||
|
||||
// FIXME: use zod for this
|
||||
function ganttRouteToFilter(route: RouteLocationNormalized): GanttFilter {
|
||||
function ganttRouteToFilters(route: Partial<RouteLocationNormalized>): GanttFilters {
|
||||
const ganttRoute = route
|
||||
return {
|
||||
listId: Number(route.params.listId as string),
|
||||
dateFrom: parseDateProp(route.query.dateFrom as DateKebab) || getDefaultDateFrom(),
|
||||
dateTo: parseDateProp(route.query.dateTo as DateKebab) || getDefaultDateTo(),
|
||||
showTasksWithoutDates: parseBooleanProp(route.query.showTasksWithoutDates as string) || DEFAULT_SHOW_TASKS_WITHOUT_DATES,
|
||||
listId: Number(ganttRoute.params?.listId),
|
||||
dateFrom: parseDateProp(ganttRoute.query?.dateFrom as DateKebab) || getDefaultDateFrom(),
|
||||
dateTo: parseDateProp(ganttRoute.query?.dateTo as DateKebab) || getDefaultDateTo(),
|
||||
showTasksWithoutDates: parseBooleanProp(ganttRoute.query?.showTasksWithoutDates as string) || DEFAULT_SHOW_TASKS_WITHOUT_DATES,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: use zod for this
|
||||
function ganttFilterToRoute(filters: GanttFilter): RouteLocationRaw {
|
||||
function ganttFiltersToRoute(filters: GanttFilters): RouteLocationRaw {
|
||||
let query: Record<string, string> = {}
|
||||
if (
|
||||
filters.dateFrom !== getDefaultDateFrom() ||
|
||||
|
@ -70,7 +71,7 @@ function ganttFilterToRoute(filters: GanttFilter): RouteLocationRaw {
|
|||
}
|
||||
}
|
||||
|
||||
function ganttFiltersToApiParams(filters: GanttFilter): GetAllTasksParams {
|
||||
function ganttFiltersToApiParams(filters: GanttFilters): GetAllTasksParams {
|
||||
return {
|
||||
sort_by: ['start_date', 'done', 'id'],
|
||||
order_by: ['asc', 'asc', 'desc'],
|
||||
|
@ -82,22 +83,31 @@ function ganttFiltersToApiParams(filters: GanttFilter): GetAllTasksParams {
|
|||
}
|
||||
}
|
||||
|
||||
export function useGanttFilter(route: Ref<RouteLocationNormalized>): ReturnType<typeof useRouteFilter> & ReturnType<typeof useGanttTaskList> {
|
||||
const {filters} = useRouteFilter<GanttFilter>(route, ganttRouteToFilter, ganttFilterToRoute)
|
||||
export type UseGanttFiltersReturn = ReturnType<typeof useRouteFilters> & ReturnType<typeof useGanttTaskList>
|
||||
|
||||
export function useGanttFilters(route: Ref<RouteLocationNormalized>): UseGanttFiltersReturn {
|
||||
const {
|
||||
filters,
|
||||
} = useRouteFilters<GanttFilters>(
|
||||
route,
|
||||
ganttRouteToFilters,
|
||||
ganttFiltersToRoute
|
||||
)
|
||||
|
||||
const {
|
||||
tasks,
|
||||
loadTasks,
|
||||
|
||||
isLoading,
|
||||
addTask,
|
||||
updateTask,
|
||||
} = useGanttTaskList<GanttFilter>(filters, ganttFiltersToApiParams)
|
||||
|
||||
} = useGanttTaskList<GanttFilters>(filters, ganttFiltersToApiParams)
|
||||
|
||||
return {
|
||||
filters,
|
||||
|
||||
tasks,
|
||||
loadTasks,
|
||||
|
||||
isLoading,
|
||||
addTask,
|
|
@ -1,7 +1,7 @@
|
|||
import {computed, ref, shallowReactive, watch, type Ref} from 'vue'
|
||||
import cloneDeep from 'lodash.clonedeep'
|
||||
|
||||
import type {Filter} from '@/composables/useRouteFilter'
|
||||
import type {Filters} from '@/composables/useRouteFilters'
|
||||
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
|
||||
|
||||
import TaskCollectionService, {type GetAllTasksParams} from '@/services/taskCollection'
|
||||
|
@ -11,7 +11,7 @@ import TaskModel from '@/models/task'
|
|||
import {error, success} from '@/message'
|
||||
|
||||
// FIXME: unify with general `useTaskList`
|
||||
export function useGanttTaskList<F extends Filter>(
|
||||
export function useGanttTaskList<F extends Filters>(
|
||||
filters: Ref<F>,
|
||||
filterToApiParams: (filters: F) => GetAllTasksParams,
|
||||
options: {
|
||||
|
|
Reference in New Issue
Block a user
Should this update?
No, doesn't even need to be ref.