diff --git a/src/components/tasks/GanttChart.vue b/src/components/tasks/GanttChart.vue
index d536c6467..a49eaf788 100644
--- a/src/components/tasks/GanttChart.vue
+++ b/src/components/tasks/GanttChart.vue
@@ -5,10 +5,9 @@
/>
import {computed, ref, watch, toRefs, onActivated} from 'vue'
import {useRouter} from 'vue-router'
-
import {getHexColor} from '@/models/task'
-
import {colorIsDark} from '@/helpers/color/colorIsDark'
-import {isoToKebabDate} from '@/helpers/time/isoToKebabDate'
-import {parseKebabDate} from '@/helpers/time/parseKebabDate'
-
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask'
-import type {DateISO} from '@/types/DateISO'
import type {GanttFilters} from '@/views/project/helpers/useGanttFilters'
import {
@@ -66,12 +59,10 @@ export interface GanttChartProps {
isLoading: boolean,
filters: GanttFilters,
tasks: Map,
- defaultTaskStartDate: DateISO
- defaultTaskEndDate: DateISO
+ defaultTaskStartDate: Date
+ defaultTaskEndDate: Date
}
-const DAYJS_ISO_DATE_FORMAT = 'YYYY-MM-DD'
-
const props = defineProps()
const emit = defineEmits<{
@@ -93,16 +84,28 @@ const dateFromDate = computed(() => new Date(new Date(filters.value.dateFrom).se
const dateToDate = computed(() => new Date(new Date(filters.value.dateTo).setHours(23,59,0,0)))
const DAY_WIDTH_PIXELS = 30
+const DAY_HOUR_PRECISION_THRESHOLD = 5
+
const ganttChartWidth = computed(() => {
const ganttContainerReference = ganttContainer?.value
const ganttContainerWidth = ganttContainerReference ? (ganttContainerReference['clientWidth'] ?? 0) : 0
const dateDiff = Math.floor((dateToDate.value.valueOf() - dateFromDate.value.valueOf()) / MILLISECONDS_A_DAY)
- const calculatedWidth = dateDiff * DAY_WIDTH_PIXELS
+
+ let calculatedWidth = dateDiff * DAY_WIDTH_PIXELS
+
+ if(dateDiff < DAY_HOUR_PRECISION_THRESHOLD) {
+ calculatedWidth *= 24
+ }
return (calculatedWidth > ganttContainerWidth) ? calculatedWidth + 'px' : '100%'
+})
+const ganttChartPrecision = computed(() => {
+ const dateDiff = Math.floor((dateToDate.value.valueOf() - dateFromDate.value.valueOf()) / MILLISECONDS_A_DAY)
+
+ return dateDiff < DAY_HOUR_PRECISION_THRESHOLD ? 'hour' : 'day'
})
const ganttBars = ref([])
@@ -121,9 +124,10 @@ watch(
function transformTaskToGanttBar(t: ITask) {
const black = 'var(--grey-800)'
+
return [{
- startDate: isoToKebabDate(t.startDate ? t.startDate.toISOString() : props.defaultTaskStartDate),
- endDate: isoToKebabDate(t.endDate ? t.endDate.toISOString() : props.defaultTaskEndDate),
+ startDate: t.startDate ?? props.defaultTaskStartDate,
+ endDate: t.endDate ?? props.defaultTaskEndDate,
ganttBarConfig: {
id: String(t.id),
label: t.title,
@@ -143,10 +147,32 @@ async function updateGanttTask(e: {
e: MouseEvent;
datetime?: string | undefined;
}) {
+
+ const taskId = Number(e.bar.ganttBarConfig.id)
+ const task = tasks.value.get(taskId)
+
+ const startDate: Date = new Date(e.bar.startDate)
+ const endDate: Date = new Date(e.bar.endDate)
+
+ if(task && ganttChartPrecision.value == 'day') {
+
+ if(task.startDate) {
+ startDate.setHours(task.startDate.getHours(), task.startDate.getMinutes(), task.startDate.getSeconds())
+ } else {
+ startDate.setHours(0,0,0)
+ }
+
+ if(task.endDate) {
+ endDate.setHours(task.endDate.getHours(), task.endDate.getMinutes(), task.endDate.getSeconds())
+ } else {
+ endDate.setHours(23,59,59)
+ }
+ }
+
emit('update:task', {
- id: Number(e.bar.ganttBarConfig.id),
- startDate: new Date(parseKebabDate(e.bar.startDate).setHours(0,0,0,0)),
- endDate: new Date(parseKebabDate(e.bar.endDate).setHours(23,59,0,0)),
+ id: Number(taskId),
+ startDate: startDate,
+ endDate: endDate,
})
}
diff --git a/src/constants/date.ts b/src/constants/date.ts
index 835f2c4da..b0224f26f 100644
--- a/src/constants/date.ts
+++ b/src/constants/date.ts
@@ -1,4 +1,5 @@
export const DATEFNS_DATE_FORMAT_KEBAB = 'yyyy-LL-dd'
+export const DATEFNS_DATETIME_FORMAT_KEBAB = 'yyyy-LL-dd HH:mm'
export const SECONDS_A_MINUTE = 60
export const SECONDS_A_HOUR = SECONDS_A_MINUTE * 60
diff --git a/src/helpers/time/isoToKebabDate.ts b/src/helpers/time/isoToKebabDate.ts
index 54290a035..532c7c581 100644
--- a/src/helpers/time/isoToKebabDate.ts
+++ b/src/helpers/time/isoToKebabDate.ts
@@ -1,5 +1,5 @@
import type {DateISO} from '@/types/DateISO'
-import type {DateKebab} from '@/types/DateKebab'
+import type {DateKebab, TimeKebab} from '@/types/DateKebab'
// ✅ Format a date to YYYY-MM-DD (or any other format)
function padTo2Digits(num: number) {
@@ -13,4 +13,16 @@ export function isoToKebabDate(isoDate: DateISO) {
padTo2Digits(date.getMonth() + 1), // January is 0, but we want it to be 1
padTo2Digits(date.getDate()),
].join('-') as DateKebab
+}
+
+export function isoToKebabTime(isoDate: DateISO) {
+ 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('-') + ' ' + [
+ padTo2Digits(date.getHours()), // January is 0, but we want it to be 1
+ padTo2Digits(date.getMinutes()),
+ ].join(':') as TimeKebab
}
\ No newline at end of file
diff --git a/src/helpers/time/parseKebabDate.ts b/src/helpers/time/parseKebabDate.ts
index f1643aa48..68bcc3b6f 100644
--- a/src/helpers/time/parseKebabDate.ts
+++ b/src/helpers/time/parseKebabDate.ts
@@ -1,7 +1,11 @@
import {parse} from 'date-fns'
-import {DATEFNS_DATE_FORMAT_KEBAB} from '@/constants/date'
-import type {DateKebab} from '@/types/DateKebab'
+import {DATEFNS_DATE_FORMAT_KEBAB, DATEFNS_DATETIME_FORMAT_KEBAB} from '@/constants/date'
+import type {DateKebab, TimeKebab} from '@/types/DateKebab'
export function parseKebabDate(date: DateKebab): Date {
return parse(date, DATEFNS_DATE_FORMAT_KEBAB, new Date())
+}
+
+export function parseKebabDateTime(date: TimeKebab): Date {
+ return parse(date, DATEFNS_DATETIME_FORMAT_KEBAB, new Date())
}
\ No newline at end of file
diff --git a/src/types/DateKebab.ts b/src/types/DateKebab.ts
index bdc1808df..2c5f15909 100644
--- a/src/types/DateKebab.ts
+++ b/src/types/DateKebab.ts
@@ -2,3 +2,8 @@
* Date in Format 2022-12-10
*/
export type DateKebab = `${string}-${string}-${string}`
+
+/**
+* Date in Format 2022-12-10 00:00
+*/
+export type TimeKebab = `${string}-${string}-${string} ${string}:${string}`
diff --git a/src/views/project/ProjectGantt.vue b/src/views/project/ProjectGantt.vue
index ef270a6ed..026510419 100644
--- a/src/views/project/ProjectGantt.vue
+++ b/src/views/project/ProjectGantt.vue
@@ -65,7 +65,6 @@ import {createAsyncComponent} from '@/helpers/createAsyncComponent'
import {useGanttFilters} from './helpers/useGanttFilters'
import {RIGHTS} from '@/constants/rights'
-import type {DateISO} from '@/types/DateISO'
import type {ITask} from '@/modelTypes/ITask'
type Options = Flatpickr.Options.Options
@@ -91,12 +90,12 @@ const {
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(
+const defaultTaskStartDate: Date = new Date(today.setHours(0, 0, 0, 0))
+const defaultTaskEndDate: Date = new Date(new Date(
today.getFullYear(),
today.getMonth(),
today.getDate() + DEFAULT_DATE_RANGE_DAYS,
-).setHours(23, 59, 0, 0)).toISOString()
+).setHours(23, 59, 0, 0))
async function addGanttTask(title: ITask['title']) {
return await addTask({