From 2f8ceb2931c4627310b9dc39a4260a90087d94fb Mon Sep 17 00:00:00 2001 From: DarkPhoenix2704 Date: Wed, 28 Feb 2024 10:11:39 +0000 Subject: [PATCH] feat(nc-gui): granularity in drag drop --- .../calendar/DayView/DateTimeField.vue | 57 +++++++-- .../smartsheet/calendar/RecordCard.vue | 10 +- .../smartsheet/calendar/VRecordCard.vue | 8 +- .../calendar/WeekView/DateTimeField.vue | 118 ++++++++++++------ 4 files changed, 137 insertions(+), 56 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue b/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue index fa079b2890..4c9f56c872 100644 --- a/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue +++ b/packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue @@ -56,7 +56,7 @@ const recordsAcrossAllRange = computed<{ record: Row[] count: { [key: string]: { - id: string + id: string[] overflow: boolean overflowCount: number } @@ -167,7 +167,7 @@ const recordsAcrossAllRange = computed<{ style.display = 'none' overlaps[timeKey].overflowCount += 1 } - _startDate = _startDate.add(15, 'minutes') + _startDate = _startDate.add(1, 'minutes') } // This property is used to determine which side the record should be rounded. It can be top, bottom, both or none @@ -205,16 +205,16 @@ const recordsAcrossAllRange = computed<{ const id = generateRandomNumber() const startDate = dayjs(record.row[fromCol.title!]) - const endDate = dayjs(record.row[fromCol.title!]).add(15, 'minutes') + const endDate = dayjs(record.row[fromCol.title!]).add(1, 'hour') const startHour = startDate.hour() let style: Partial = {} let _startDate = startDate.clone() - // We loop through every 15 minutes between the start and end date and keep track of the number of records that overlap at a given time + // We loop through every minute between the start and end date and keep track of the number of records that overlap at a given time while (_startDate.isBefore(endDate)) { - const timeKey = _startDate.startOf('hour').format('HH:mm') + const timeKey = _startDate.format('HH:mm') if (!overlaps[timeKey]) { overlaps[timeKey] = { @@ -234,15 +234,20 @@ const recordsAcrossAllRange = computed<{ display: 'none', } } - _startDate = _startDate.add(15, 'minutes') + _startDate = _startDate.add(1, 'minute') } - const topInPixels = (startDate.hour() + startDate.startOf('hour').minute() / 60) * 80 + // The top of the record is calculated based on the start hour + // Update such that it is also based on Minutes + + const minutes = startDate.minute() + startDate.hour() * 60 + + const updatedTopInPixels = (minutes * 80) / 60 // A minimum height of 80px is set for each record const heightInPixels = Math.max((endDate.diff(startDate, 'minute') / 60) * 80, perRecordHeight) - const finalTopInPixels = topInPixels + startHour * 2 + const finalTopInPixels = updatedTopInPixels + startHour * 2 style = { ...style, @@ -331,9 +336,10 @@ const calculateNewRow = (event: MouseEvent) => { // We calculate the hour based on the percentage of the mouse position in the scroll container // It can be between 0 and 23 (inclusive) const hour = Math.max(Math.floor(percentY * 23), 0) + const minutes = Math.floor(((percentY * 22 - hour) * 60) / 15) * 15 // We calculate the new startDate by adding the hour to the start of the selected date - const newStartDate = dayjs(selectedDate.value).startOf('day').add(hour, 'hour') + const newStartDate = dayjs(selectedDate.value).startOf('day').add(hour, 'hour').add(minutes, 'minute') if (!newStartDate || !fromCol) return { newRow: null, updateProperty: [] } let endDate @@ -570,6 +576,35 @@ const dragStart = (event: MouseEvent, record: Row) => { document.addEventListener('mouseup', onMouseUp) } +const isOverflowAcrossHourRange = (hour: dayjs.Dayjs) => { + let startOfHour = hour.startOf('hour') + const endOfHour = hour.endOf('hour') + + const ids: Array = [] + + let isOverflow = false + let overflowCount = 0 + + while (startOfHour.isBefore(endOfHour, 'minute')) { + const hourKey = startOfHour.format('HH:mm') + if (recordsAcrossAllRange.value?.count?.[hourKey]?.overflow) { + isOverflow = true + + recordsAcrossAllRange.value?.count?.[hourKey]?.id.forEach((id) => { + if (!ids.includes(id)) { + ids.push(id) + overflowCount += 1 + } + }) + } + startOfHour = startOfHour.add(1, 'minute') + } + + overflowCount = overflowCount > 8 ? overflowCount - 8 : 0 + + return { isOverflow, overflowCount } +} + const viewMore = (hour: dayjs.Dayjs) => { sideBarFilterOption.value = 'selectedHours' selectedTime.value = hour @@ -680,7 +715,7 @@ const viewMore = (hour: dayjs.Dayjs) => { { > + - {{ recordsAcrossAllRange?.count[hour.format('HH:mm')]?.overflowCount }} + {{ isOverflowAcrossHourRange(hour).overflowCount }} more diff --git a/packages/nc-gui/components/smartsheet/calendar/RecordCard.vue b/packages/nc-gui/components/smartsheet/calendar/RecordCard.vue index 8f28681bc5..fbeb7efcb2 100644 --- a/packages/nc-gui/components/smartsheet/calendar/RecordCard.vue +++ b/packages/nc-gui/components/smartsheet/calendar/RecordCard.vue @@ -28,8 +28,8 @@ const emit = defineEmits(['resize-start']) :class="{ 'min-h-9': size === 'small', 'h-full': size === 'auto', - 'rounded-l-lg ml-1': position === 'leftRounded', - 'rounded-r-lg mr-1': position === 'rightRounded', + 'rounded-l-lg': position === 'leftRounded', + 'rounded-r-lg': position === 'rightRounded', 'rounded-lg mx-1': position === 'rounded', 'rounded-none': position === 'none', 'bg-maroon-50': color === 'maroon', @@ -53,7 +53,7 @@ const emit = defineEmits(['resize-start']) 'bg-pink-500': color === 'pink', 'bg-purple-500': color === 'purple', }" - class="block h-full min-h-5 w-1 rounded" + class="w-1 min-h-5 bg-blue-500 rounded-x rounded-y-sm" >
@@ -70,13 +70,13 @@ const emit = defineEmits(['resize-start'])
-
+
.... diff --git a/packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue b/packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue index cb4d52d4d0..a9b3ca080a 100644 --- a/packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue +++ b/packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue @@ -51,9 +51,9 @@ const emit = defineEmits(['resize-start']) 'group-hover:(border-brand-500)': resize, '!border-brand-500 border-1': selected || hover, }" - class="relative h-full ml-0.25 border-1 border-gray-50" + class="relative flex items-center h-full ml-0.25 border-1 border-gray-50" > -
+
....
diff --git a/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue b/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue index cd6e73dea6..b2ee6aaf4e 100644 --- a/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue +++ b/packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue @@ -99,7 +99,7 @@ const recordsAcrossAllRange = computed<{ const scheduleStart = dayjs(selectedDateRange.value.start).startOf('day') const scheduleEnd = dayjs(selectedDateRange.value.end).endOf('day') - // We need to keep track of the overlaps for each day and hour in the week to calculate the width and left position of each record + // We need to keep track of the overlaps for each day and hour, minute in the week to calculate the width and left position of each record // The first key is the date, the second key is the hour, and the value is an object containing the ids of the records that overlap // The key is in the format YYYY-MM-DD and the hour is in the format HH:mm const overlaps: { @@ -137,48 +137,58 @@ const recordsAcrossAllRange = computed<{ sortedFormattedData.forEach((record: Row) => { if (!toCol && fromCol) { // If there is no toColumn chosen in the range - const startDate = record.row[fromCol.title!] ? dayjs(record.row[fromCol.title!]) : null - if (!startDate) return + const ogStartDate = record.row[fromCol.title!] ? dayjs(record.row[fromCol.title!]) : null + if (!ogStartDate) return - // Hour Key currently is set as start of the hour - // TODO: Need to work on the granularity of the hour - const dateKey = startDate?.format('YYYY-MM-DD') - const hourKey = startDate?.startOf('hour').format('HH:mm') + const endDate = ogStartDate.clone().add(1, 'hour') const id = record.rowMeta.id ?? generateRandomNumber() + let startDate = ogStartDate.clone() + let style: Partial = {} - // If the dateKey and hourKey are valid, we add the id to the overlaps object - if (dateKey && hourKey) { - if (!overlaps[dateKey]) { - overlaps[dateKey] = {} - } - if (!overlaps[dateKey][hourKey]) { - overlaps[dateKey][hourKey] = { - id: [], - overflow: false, - overflowCount: 0, + while (startDate.isBefore(endDate, 'minutes')) { + const dateKey = startDate?.format('YYYY-MM-DD') + const hourKey = startDate?.format('HH:mm') + + // If the dateKey and hourKey are valid, we add the id to the overlaps object + if (dateKey && hourKey) { + if (!overlaps[dateKey]) { + overlaps[dateKey] = {} } + if (!overlaps[dateKey][hourKey]) { + overlaps[dateKey][hourKey] = { + id: [], + overflow: false, + overflowCount: 0, + } + } + overlaps[dateKey][hourKey].id.push(id) } - overlaps[dateKey][hourKey].id.push(id) - } - // If the number of records that overlap in a single hour is more than 4, we hide the record and set the overflow flag to true - // We also keep track of the number of records that overflow - if (overlaps[dateKey][hourKey].id.length > 4) { - overlaps[dateKey][hourKey].overflow = true - style.display = 'none' - overlaps[dateKey][hourKey].overflowCount += 1 - } + // If the number of records that overlap in a single hour is more than 4, we hide the record and set the overflow flag to true + // We also keep track of the number of records that overflow + if (overlaps[dateKey][hourKey].id.length > 4) { + overlaps[dateKey][hourKey].overflow = true + style.display = 'none' + overlaps[dateKey][hourKey].overflowCount += 1 + } + + // TODO: dayIndex is not calculated perfectly + // Should revisit this part in next iteration + let dayIndex = dayjs(dateKey).day() - 1 + if (dayIndex === -1) { + dayIndex = 6 + } - // TODO: dayIndex is not calculated perfectly - // Should revisit this part in next iteration - let dayIndex = dayjs(dateKey).day() - 1 - if (dayIndex === -1) { - dayIndex = 6 + startDate = startDate.add(1, 'minute') } + const dayIndex = ogStartDate.day() - 1 + + const hourKey = ogStartDate.format('HH:mm') + // We calculate the index of the hour in the day and set the top and height of the record const hourIndex = Math.min( Math.max( @@ -188,10 +198,14 @@ const recordsAcrossAllRange = computed<{ 23, ) + const minutes = ogStartDate.minute() + ogStartDate.hour() * 60 + + const topPx = (minutes * perHeight) / 60 + style = { ...style, - top: `${hourIndex * perHeight - hourIndex - hourIndex * 0.15}px`, - height: `${perHeight - 2}px`, + top: `${topPx - hourIndex - hourIndex * 0.15}px`, + height: `${perHeight - 4}px`, } recordsToDisplay.push({ @@ -514,7 +528,9 @@ const calculateNewRow = ( const day = Math.max(0, Math.min(6, Math.floor(percentX * 7))) const hour = Math.max(0, Math.min(23, Math.floor(percentY * 24))) - const newStartDate = dayjs(selectedDateRange.value.start).add(day, 'day').add(hour, 'hour') + const minutes = Math.floor(((percentY * 22 - hour) * 60) / 15) * 15 + + const newStartDate = dayjs(selectedDateRange.value.start).add(day, 'day').add(hour, 'hour').add(minutes, 'minute') if (!newStartDate) return { newRow: null, updatedProperty: [] } let endDate @@ -678,6 +694,36 @@ const viewMore = (hour: dayjs.Dayjs) => { selectedTime.value = hour showSideMenu.value = true } + +const isOverflowAcrossHourRange = (hour: dayjs.Dayjs) => { + let startOfHour = hour.startOf('hour') + const endOfHour = hour.endOf('hour') + + const ids: Array = [] + + let isOverflow = false + let overflowCount = 0 + + while (startOfHour.isBefore(endOfHour, 'minute')) { + const dateKey = startOfHour.format('YYYY-MM-DD') + const hourKey = startOfHour.format('HH:mm') + if (recordsAcrossAllRange.value?.count?.[dateKey]?.[hourKey]?.overflow) { + isOverflow = true + + recordsAcrossAllRange.value?.count?.[dateKey]?.[hourKey]?.id.forEach((id) => { + if (!ids.includes(id)) { + ids.push(id) + overflowCount += 1 + } + }) + } + startOfHour = startOfHour.add(1, 'minute') + } + + overflowCount = overflowCount > 4 ? overflowCount - 4 : 0 + + return { isOverflow, overflowCount } +}