feat: replace our home-grown gantt implementation with ganttastic #2180

Merged
konrad merged 78 commits from feature/ganttastic into main 2022-10-27 16:03:27 +00:00
5 changed files with 36 additions and 26 deletions
Showing only changes of commit 6bf6357cbd - Show all commits

View File

@ -52,7 +52,7 @@ import {parseKebabDate} from '@/helpers/time/parseKebabDate'
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask' import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
import type {DateISO} from '@/types/DateISO' import type {DateISO} from '@/types/DateISO'
import type {GanttFilter} from '@/views/list/helpers/useGanttFilter' import type {GanttFilters} from '@/views/list/helpers/useGanttFilters'
import { import {
extendDayjs, extendDayjs,
@ -66,7 +66,7 @@ import {MILLISECONDS_A_DAY} from '@/constants/date'
export interface GanttChartProps { export interface GanttChartProps {
isLoading: boolean, isLoading: boolean,
filters: GanttFilter, filters: GanttFilters,
tasks: Map<ITask['id'], ITask>, tasks: Map<ITask['id'], ITask>,
defaultTaskStartDate: DateISO defaultTaskStartDate: DateISO
defaultTaskEndDate: DateISO defaultTaskEndDate: DateISO

View File

@ -2,18 +2,18 @@ import {computed, ref, watch, type Ref} from 'vue'
import {useRouter, type RouteLocationNormalized, type RouteLocationRaw} from 'vue-router' import {useRouter, type RouteLocationNormalized, type RouteLocationRaw} from 'vue-router'
import cloneDeep from 'lodash.clonedeep' 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>, route: Ref<RouteLocationNormalized>,
routeToFilter: (route: RouteLocationNormalized) => F, routeToFilters: (route: RouteLocationNormalized) => CurrentFilters,
filterToRoute: (filter: F) => RouteLocationRaw, filtersToRoute: (filters: CurrentFilters) => RouteLocationRaw,
) { ) {
const router = useRouter() 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) => { watch(() => cloneDeep(route.value), (route, oldRoute) => {
if ( if (
@ -23,7 +23,7 @@ export function useRouteFilter<F extends Filter = Filter>(
return return
} }
filters.value = routeToFilter(route) filters.value = routeToFilters(route)
}) })
watch( watch(

View File

@ -56,7 +56,7 @@ import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import TaskForm from '@/components/tasks/TaskForm.vue' import TaskForm from '@/components/tasks/TaskForm.vue'
import {createAsyncComponent} from '@/helpers/createAsyncComponent' import {createAsyncComponent} from '@/helpers/createAsyncComponent'
import {useGanttFilter} from './helpers/useGanttFilter' import {useGanttFilters} from './helpers/useGanttFilters'
import {RIGHTS} from '@/constants/rights' import {RIGHTS} from '@/constants/rights'
import type {DateISO} from '@/types/DateISO' import type {DateISO} from '@/types/DateISO'
@ -78,7 +78,7 @@ const {
isLoading, isLoading,
addTask, addTask,
updateTask, updateTask,
} = useGanttFilter(route) } = useGanttFilters(route)
const today = new Date(new Date().setHours(0,0,0,0)) const today = new Date(new Date().setHours(0,0,0,0))
const defaultTaskStartDate: DateISO = new Date(today).toISOString() const defaultTaskStartDate: DateISO = new Date(today).toISOString()

View File

@ -4,7 +4,7 @@ import type {RouteLocationNormalized, RouteLocationRaw} from 'vue-router'
import {isoToKebabDate} from '@/helpers/time/isoToKebabDate' import {isoToKebabDate} from '@/helpers/time/isoToKebabDate'
import {parseDateProp} from '@/helpers/time/parseDateProp' import {parseDateProp} from '@/helpers/time/parseDateProp'
import {parseBooleanProp} from '@/helpers/time/parseBooleanProp' import {parseBooleanProp} from '@/helpers/time/parseBooleanProp'
import {useRouteFilter} from '@/composables/useRouteFilter' import {useRouteFilters} from '@/composables/useRouteFilters'
import {useGanttTaskList} from './useGanttTaskList' import {useGanttTaskList} from './useGanttTaskList'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
@ -14,7 +14,7 @@ import type {DateISO} from '@/types/DateISO'
import type {DateKebab} from '@/types/DateKebab' import type {DateKebab} from '@/types/DateKebab'
// convenient internal filter object // convenient internal filter object
export interface GanttFilter { export interface GanttFilters {
listId: IList['id'] listId: IList['id']
dateFrom: DateISO dateFrom: DateISO
dateTo: DateISO dateTo: DateISO
@ -37,17 +37,18 @@ function getDefaultDateTo() {
} }
// FIXME: use zod for this // FIXME: use zod for this
function ganttRouteToFilter(route: RouteLocationNormalized): GanttFilter { function ganttRouteToFilters(route: Partial<RouteLocationNormalized>): GanttFilters {
const ganttRoute = route
return { return {
listId: Number(route.params.listId as string), listId: Number(ganttRoute.params?.listId),
dateFrom: parseDateProp(route.query.dateFrom as DateKebab) || getDefaultDateFrom(), dateFrom: parseDateProp(ganttRoute.query?.dateFrom as DateKebab) || getDefaultDateFrom(),
dateTo: parseDateProp(route.query.dateTo as DateKebab) || getDefaultDateTo(), dateTo: parseDateProp(ganttRoute.query?.dateTo as DateKebab) || getDefaultDateTo(),
showTasksWithoutDates: parseBooleanProp(route.query.showTasksWithoutDates as string) || DEFAULT_SHOW_TASKS_WITHOUT_DATES, showTasksWithoutDates: parseBooleanProp(ganttRoute.query?.showTasksWithoutDates as string) || DEFAULT_SHOW_TASKS_WITHOUT_DATES,
} }
} }
// FIXME: use zod for this // FIXME: use zod for this
function ganttFilterToRoute(filters: GanttFilter): RouteLocationRaw { function ganttFiltersToRoute(filters: GanttFilters): RouteLocationRaw {
let query: Record<string, string> = {} let query: Record<string, string> = {}
if ( if (
filters.dateFrom !== getDefaultDateFrom() || filters.dateFrom !== getDefaultDateFrom() ||
@ -70,7 +71,7 @@ function ganttFilterToRoute(filters: GanttFilter): RouteLocationRaw {
} }
} }
function ganttFiltersToApiParams(filters: GanttFilter): GetAllTasksParams { function ganttFiltersToApiParams(filters: GanttFilters): GetAllTasksParams {
return { return {
sort_by: ['start_date', 'done', 'id'], sort_by: ['start_date', 'done', 'id'],
order_by: ['asc', 'asc', 'desc'], 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> { export type UseGanttFiltersReturn = ReturnType<typeof useRouteFilters> & ReturnType<typeof useGanttTaskList>
const {filters} = useRouteFilter<GanttFilter>(route, ganttRouteToFilter, ganttFilterToRoute)
export function useGanttFilters(route: Ref<RouteLocationNormalized>): UseGanttFiltersReturn {
const {
filters,
} = useRouteFilters<GanttFilters>(
route,
ganttRouteToFilters,
ganttFiltersToRoute
)
const { const {
tasks, tasks,
loadTasks,
isLoading, isLoading,
addTask, addTask,
updateTask, updateTask,
} = useGanttTaskList<GanttFilter>(filters, ganttFiltersToApiParams) } = useGanttTaskList<GanttFilters>(filters, ganttFiltersToApiParams)
return { return {
filters, filters,
tasks, tasks,
loadTasks,
isLoading, isLoading,
addTask, addTask,

View File

@ -1,7 +1,7 @@
import {computed, ref, shallowReactive, watch, type Ref} from 'vue' import {computed, ref, shallowReactive, watch, type Ref} from 'vue'
import cloneDeep from 'lodash.clonedeep' 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 type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
import TaskCollectionService, {type GetAllTasksParams} from '@/services/taskCollection' import TaskCollectionService, {type GetAllTasksParams} from '@/services/taskCollection'
@ -11,7 +11,7 @@ import TaskModel from '@/models/task'
import {error, success} from '@/message' import {error, success} from '@/message'
// FIXME: unify with general `useTaskList` // FIXME: unify with general `useTaskList`
export function useGanttTaskList<F extends Filter>( export function useGanttTaskList<F extends Filters>(
filters: Ref<F>, filters: Ref<F>,
filterToApiParams: (filters: F) => GetAllTasksParams, filterToApiParams: (filters: F) => GetAllTasksParams,
options: { options: {