From 7ec2b6c0d28a1ae1799b1ed7a781efbf4c4542d7 Mon Sep 17 00:00:00 2001 From: Dominik Pschenitschni Date: Wed, 9 Nov 2022 18:33:06 +0100 Subject: [PATCH 1/4] fix: gantt route sync --- src/composables/useRouteFilters.ts | 44 ++++++++++++++++------- src/helpers/time/isoToKebabDate.ts | 14 ++++++-- src/helpers/time/parseDateProp.ts | 2 +- src/views/list/ListGantt.vue | 12 +++++-- src/views/list/helpers/useGanttFilters.ts | 2 +- 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/composables/useRouteFilters.ts b/src/composables/useRouteFilters.ts index 5d9bb891a..75d0903f3 100644 --- a/src/composables/useRouteFilters.ts +++ b/src/composables/useRouteFilters.ts @@ -16,16 +16,23 @@ export function useRouteFilters( const routeFromFiltersFullPath = computed(() => router.resolve(filtersToRoute(filters.value)).fullPath) - watch(() => route.value, (route, oldRoute) => { - if ( - (route && oldRoute && typeof route.name !== 'undefined' && typeof oldRoute.name !== 'undefined' && route.name !== oldRoute.name) || - routeFromFiltersFullPath.value === route.fullPath - ) { - return - } + watch( + route, + (route, oldRoute) => { + if ( + route?.name !== oldRoute?.name || + routeFromFiltersFullPath.value === route.fullPath + ) { + return + } - filters.value = routeToFilters(route) - }) + filters.value = routeToFilters(route) + }, + { + deep: true, + immediate: true, // set the filter from the initial route + }, + ) watch( filters, @@ -35,12 +42,23 @@ export function useRouteFilters( } }, // only apply new route after all filters have changed in component cycle - {flush: 'post'}, + { + deep: true, + flush: 'post', + }, ) - const hasDefaultFilters = computed(() => { - return equal(filters.value, getDefaultFilters(route.value)) - }) + const hasDefaultFilters = ref(false) + watch( + [filters, route], + ([filters, route]) => { + hasDefaultFilters.value = equal(filters, getDefaultFilters(route)) + }, + { + deep: true, + immediate: true, + }, + ) function setDefaultFilters() { filters.value = getDefaultFilters(route.value) diff --git a/src/helpers/time/isoToKebabDate.ts b/src/helpers/time/isoToKebabDate.ts index b9ec26c52..54290a035 100644 --- a/src/helpers/time/isoToKebabDate.ts +++ b/src/helpers/time/isoToKebabDate.ts @@ -1,8 +1,16 @@ -import {format} from 'date-fns' -import {DATEFNS_DATE_FORMAT_KEBAB} from '@/constants/date' import type {DateISO} from '@/types/DateISO' import type {DateKebab} from '@/types/DateKebab' +// ✅ Format a date to YYYY-MM-DD (or any other format) +function padTo2Digits(num: number) { + return num.toString().padStart(2, '0') +} + export function isoToKebabDate(isoDate: DateISO) { - return format(new Date(isoDate), DATEFNS_DATE_FORMAT_KEBAB) as DateKebab + const date = new Date(isoDate) + return [ + date.getFullYear(), + padTo2Digits(date.getMonth() + 1), // January is 0, but we want it to be 1 + padTo2Digits(date.getDate()), + ].join('-') as DateKebab } \ No newline at end of file diff --git a/src/helpers/time/parseDateProp.ts b/src/helpers/time/parseDateProp.ts index 9e426df25..bf3be0984 100644 --- a/src/helpers/time/parseDateProp.ts +++ b/src/helpers/time/parseDateProp.ts @@ -22,7 +22,7 @@ export function parseDateProp(kebabDate: DateKebab | undefined): string | undefi if (!dateValuesAreValid) { throw new Error('Invalid date values') } - return new Date(year, month, date).toISOString() as DateISO + return new Date(year, month - 1, date).toISOString() as DateISO } catch(e) { // ignore nonsense route queries return diff --git a/src/views/list/ListGantt.vue b/src/views/list/ListGantt.vue index b46b42819..5ffa9a255 100644 --- a/src/views/list/ListGantt.vue +++ b/src/views/list/ListGantt.vue @@ -88,9 +88,15 @@ const { updateTask, } = useGanttFilters(route) -const today = new Date(new Date().setHours(0,0,0,0)) -const defaultTaskStartDate: DateISO = new Date(today).toISOString() -const defaultTaskEndDate: DateISO = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 7, 23,59,0,0).toISOString() +const DEFAULT_DATE_RANGE_DAYS = 7 + +const today = new Date() +const defaultTaskStartDate: DateISO = new Date(today.setHours(0, 0, 0, 0)).toISOString() +const defaultTaskEndDate: DateISO = new Date(new Date( + today.getFullYear(), + today.getMonth(), + today.getDate() + DEFAULT_DATE_RANGE_DAYS, +).setHours(23, 59, 0, 0)).toISOString() async function addGanttTask(title: ITask['title']) { return await addTask({ diff --git a/src/views/list/helpers/useGanttFilters.ts b/src/views/list/helpers/useGanttFilters.ts index ef65621b7..91d6db77d 100644 --- a/src/views/list/helpers/useGanttFilters.ts +++ b/src/views/list/helpers/useGanttFilters.ts @@ -98,8 +98,8 @@ export function useGanttFilters(route: Ref): UseGanttFi setDefaultFilters, } = useRouteFilters( route, - ganttRouteToFilters, ganttGetDefaultFilters, + ganttRouteToFilters, ganttFiltersToRoute, ) -- 2.40.1 From 6055fecc5d94da03a1e555e2e3d7489cb2d88605 Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 9 Nov 2022 19:54:53 +0100 Subject: [PATCH 2/4] fix(gantt): don't try to load list NaN when opening a task from the gantt chart --- src/composables/useRouteFilters.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/composables/useRouteFilters.ts b/src/composables/useRouteFilters.ts index 75d0903f3..2fdbb71d5 100644 --- a/src/composables/useRouteFilters.ts +++ b/src/composables/useRouteFilters.ts @@ -29,7 +29,6 @@ export function useRouteFilters( filters.value = routeToFilters(route) }, { - deep: true, immediate: true, // set the filter from the initial route }, ) -- 2.40.1 From 2952a0155fbea1a01d9b0d47d4a970034266e9ab Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 9 Nov 2022 20:10:18 +0100 Subject: [PATCH 3/4] feat(tests): add tests for gantt chart time range --- cypress/e2e/list/list-view-gantt.spec.ts | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cypress/e2e/list/list-view-gantt.spec.ts b/cypress/e2e/list/list-view-gantt.spec.ts index 6763c359b..4b5372c40 100644 --- a/cypress/e2e/list/list-view-gantt.spec.ts +++ b/cypress/e2e/list/list-view-gantt.spec.ts @@ -77,4 +77,34 @@ describe('List View Gantt', () => { .trigger('mouseup', {force: true}) cy.wait('@taskUpdate') }) + + it('Should change the query parameters when selecting a date range', () => { + const now = Date.UTC(2022, 10, 9) + cy.clock(now, ['Date']) + + cy.visit('/lists/1/gantt') + + cy.get('.list-gantt .gantt-options .field .control input.input.form-control') + .click() + cy.get('.flatpickr-calendar .flatpickr-innerContainer .dayContainer .flatpickr-day') + .first() + .click() + cy.get('.flatpickr-calendar .flatpickr-innerContainer .dayContainer .flatpickr-day') + .last() + .click() + + cy.url().should('contain', 'dateFrom=2022-09-25') + cy.url().should('contain', 'dateTo=2022-11-05') + }) + + it('Should change the date range based on date query parameters', () => { + cy.visit('/lists/1/gantt?dateFrom=2022-09-25&dateTo=2022-11-05') + + cy.get('.g-timeunits-container') + .should('contain', 'September 2022') + .should('contain', 'October 2022') + .should('contain', 'November 2022') + cy.get('.list-gantt .gantt-options .field .control input.input.form-control') + .should('have.value', '25 Sep 2022 to 5 Nov 2022') + }) }) \ No newline at end of file -- 2.40.1 From bd0c4d03555a0df7c7ff47f7eda233d58ed949db Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 9 Nov 2022 20:16:30 +0100 Subject: [PATCH 4/4] feat(tests): add tests for gantt chart task detail open --- cypress/e2e/list/list-view-gantt.spec.ts | 29 ++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/cypress/e2e/list/list-view-gantt.spec.ts b/cypress/e2e/list/list-view-gantt.spec.ts index 4b5372c40..f5ce93fb1 100644 --- a/cypress/e2e/list/list-view-gantt.spec.ts +++ b/cypress/e2e/list/list-view-gantt.spec.ts @@ -62,7 +62,7 @@ describe('List View Gantt', () => { it('Drags a task around', () => { cy.intercept('**/api/v1/tasks/*') .as('taskUpdate') - + const now = new Date() TaskFactory.create(1, { start_date: formatISO(now), @@ -77,13 +77,13 @@ describe('List View Gantt', () => { .trigger('mouseup', {force: true}) cy.wait('@taskUpdate') }) - + it('Should change the query parameters when selecting a date range', () => { const now = Date.UTC(2022, 10, 9) cy.clock(now, ['Date']) - + cy.visit('/lists/1/gantt') - + cy.get('.list-gantt .gantt-options .field .control input.input.form-control') .click() cy.get('.flatpickr-calendar .flatpickr-innerContainer .dayContainer .flatpickr-day') @@ -92,14 +92,14 @@ describe('List View Gantt', () => { cy.get('.flatpickr-calendar .flatpickr-innerContainer .dayContainer .flatpickr-day') .last() .click() - + cy.url().should('contain', 'dateFrom=2022-09-25') cy.url().should('contain', 'dateTo=2022-11-05') }) - + it('Should change the date range based on date query parameters', () => { cy.visit('/lists/1/gantt?dateFrom=2022-09-25&dateTo=2022-11-05') - + cy.get('.g-timeunits-container') .should('contain', 'September 2022') .should('contain', 'October 2022') @@ -107,4 +107,19 @@ describe('List View Gantt', () => { cy.get('.list-gantt .gantt-options .field .control input.input.form-control') .should('have.value', '25 Sep 2022 to 5 Nov 2022') }) + + it('Should open a task when double clicked on it', () => { + const now = new Date() + const tasks = TaskFactory.create(1, { + start_date: formatISO(now), + end_date: formatISO(now.setDate(now.getDate() + 4)), + }) + cy.visit('/lists/1/gantt') + + cy.get('.gantt-container .g-gantt-chart .g-gantt-row-bars-container .g-gantt-bar') + .dblclick() + + cy.url() + .should('contain', `/tasks/${tasks[0].id}`) + }) }) \ No newline at end of file -- 2.40.1