Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(nc-gui): calendar drag-drop granularity #7731

Merged
merged 8 commits into from
Feb 28, 2024
2 changes: 1 addition & 1 deletion packages/nc-gui/components/nc/DateWeekSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ const paginate = (action: 'next' | 'prev') => {
'text-gray-400': !isDateInCurrentMonth(date),
'nc-selected-week-start': isSameDate(date, selectedWeek?.start),
'nc-selected-week-end': isSameDate(date, selectedWeek?.end),
'rounded-md bg-brand-50 text-brand-500': isSameDate(date, dayjs()) && isDateInCurrentMonth(date),
'rounded-md bg-brand-50 nc-calendar-today text-brand-500': isSameDate(date, dayjs()) && isDateInCurrentMonth(date),
}"
class="h-9 w-9 px-1 py-2 relative font-medium flex items-center cursor-pointer justify-center"
data-testid="nc-calendar-date"
Expand Down
1 change: 0 additions & 1 deletion packages/nc-gui/components/smartsheet/calendar/Cell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ const getLookupValue = (modelValue: string | null | number | Array<any>, col: Co
}

const getAttachmentValue = (modelValue: string | null | number | Array<any>) => {
console.log(modelValue)
if (Array.isArray(modelValue)) {
return modelValue.map((v) => `${v.title} (${getPossibleAttachmentSrc(v).join(', ')})`).join(', ')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const recordsAcrossAllRange = computed<{
record: Row[]
count: {
[key: string]: {
id: string
id: string[]
overflow: boolean
overflowCount: number
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -205,16 +205,21 @@ const recordsAcrossAllRange = computed<{
const id = generateRandomNumber()

const startDate = dayjs(record.row[fromCol.title!])
const endDate = dayjs(record.row[fromCol.title!]).add(15, 'minutes')

let endDate = dayjs(record.row[fromCol.title!]).add(1, 'hour')

if (endDate.isAfter(scheduleEnd, 'minutes')) {
endDate = scheduleEnd
}

const startHour = startDate.hour()

let style: Partial<CSSStyleDeclaration> = {}
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] = {
Expand All @@ -234,15 +239,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,
Expand Down Expand Up @@ -332,8 +342,9 @@ const calculateNewRow = (event: MouseEvent) => {
// It can be between 0 and 23 (inclusive)
const hour = Math.max(Math.floor(percentY * 23), 0)

const minutes = Math.min(Math.max(Math.round(Math.floor((percentY * 23 - hour) * 60) / 15) * 15, 0), 60)
// 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
Expand Down Expand Up @@ -570,6 +581,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<string> = []

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
Expand Down Expand Up @@ -680,15 +720,15 @@ const viewMore = (hour: dayjs.Dayjs) => {
</NcButton>

<NcButton
v-if="recordsAcrossAllRange?.count?.[hour.format('HH:mm')]?.overflow"
v-if="isOverflowAcrossHourRange(hour).isOverflow"
class="!absolute bottom-2 text-center w-15 mx-auto inset-x-0 z-3 text-gray-500"
size="xxsmall"
type="secondary"
@click="viewMore(hour)"
>
<span class="text-xs">
+
{{ recordsAcrossAllRange?.count[hour.format('HH:mm')]?.overflowCount }}
{{ isOverflowAcrossHourRange(hour).overflowCount }}
more
</span>
</NcButton>
Expand All @@ -709,7 +749,6 @@ const viewMore = (hour: dayjs.Dayjs) => {
>
<LazySmartsheetRow :row="record">
<LazySmartsheetCalendarVRecordCard
:view="activeCalendarView"
:hover="hoverRecord === record.rowMeta.id"
:position="record.rowMeta!.position"
:record="record"
Expand Down
13 changes: 4 additions & 9 deletions packages/nc-gui/components/smartsheet/calendar/MonthView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ const onResizeEnd = () => {
const onResizeStart = (direction: 'right' | 'left', event: MouseEvent, record: Row) => {
if (!isUIAllowed('dataEdit') || draggingId.value) return

selectedDate.value = null
// selectedDate.value = null
resizeInProgress.value = true
resizeDirection.value = direction
resizeRecord.value = record
Expand All @@ -508,12 +508,8 @@ const onResizeStart = (direction: 'right' | 'left', event: MouseEvent, record: R

const stopDrag = (event: MouseEvent) => {
clearTimeout(dragTimeout.value)

console.log('stopDrag')
console.log('stopDrag', dragRecord.value, isDragging.value)
if (!isUIAllowed('dataEdit') || !dragRecord.value || !isDragging.value) return

console.log('stopDrag')
event.preventDefault()
dragElement.value!.style.boxShadow = 'none'

Expand Down Expand Up @@ -560,7 +556,7 @@ const dragStart = (event: MouseEvent, record: Row) => {
})

dragRecord.value = record
selectedDate.value = null
// selectedDate.value = null

isDragging.value = true
dragElement.value = target
Expand Down Expand Up @@ -633,7 +629,7 @@ const isDateSelected = (date: dayjs.Dayjs) => {
<div
v-for="(day, index) in days"
:key="index"
class="text-center bg-gray-50 py-1 text-sm border-b-1 border-r-1 last:border-r-0 border-gray-200 font-semibold text-gray-500"
class="text-center bg-gray-50 py-1 text-sm border-b-1 border-r-1 last:border-r-0 border-gray-100 font-semibold text-gray-500"
>
{{ day }}
</div>
Expand All @@ -657,7 +653,7 @@ const isDateSelected = (date: dayjs.Dayjs) => {
isDateSelected(day) || (focusedDate && dayjs(day).isSame(focusedDate, 'day')),
'!text-gray-400': !isDayInPagedMonth(day),
}"
class="text-right relative group last:border-r-0 text-sm h-full border-r-1 border-b-1 border-gray-200 font-medium hover:bg-gray-50 text-gray-800 bg-white"
class="text-right relative group last:border-r-0 text-sm h-full border-r-1 border-b-1 border-gray-100 font-medium hover:bg-gray-50 text-gray-800 bg-white"
data-testid="nc-calendar-month-day"
@click="selectDate(day)"
>
Expand Down Expand Up @@ -793,7 +789,6 @@ const isDateSelected = (date: dayjs.Dayjs) => {
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
Expand Down
10 changes: 5 additions & 5 deletions packages/nc-gui/components/smartsheet/calendar/RecordCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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"
></div>

<div v-if="(position === 'leftRounded' || position === 'rounded') && resize" class="mt-0.7 h-7.1 absolute -left-4 resize">
Expand All @@ -70,13 +70,13 @@ const emit = defineEmits(['resize-start'])
</NcButton>
</div>

<div class="overflow-hidden flex w-full ml-2 h-8 absolute">
<div class="overflow-hidden items-center flex w-full ml-2 h-8">
<span v-if="position === 'rightRounded' || position === 'none'" class="mr-1"> .... </span>
<span
:class="{
'pr-7': position === 'leftRounded',
}"
class="text-sm pt-1.5 pr-3 mr-3 break-word space-x-2 whitespace-nowrap gap-2 overflow-hidden text-ellipsis w-full truncate text-gray-800"
class="text-sm pr-3 mr-3 break-word space-x-2 whitespace-nowrap gap-2 overflow-hidden text-ellipsis w-full truncate text-gray-800"
>
<slot />
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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-transparent"
>
<div class="h-full absolute py-2">
<div class="h-full py-1">
<div
:class="{
'bg-maroon-500': color === 'maroon',
Expand All @@ -63,14 +63,14 @@ const emit = defineEmits(['resize-start'])
'bg-pink-500': color === 'pink',
'bg-purple-500': color === 'purple',
}"
class="block h-full min-h-5 ml-1 w-1 rounded mr-2"
class="block h-full min-h-5 ml-1 w-1 rounded"
></div>
</div>

<div v-if="position === 'bottomRounded' || position === 'none'" class="ml-3">....</div>

<span
class="mt-1.5 pl-4 pr-1 text-sm h-[80%] text-gray-800 leading-7 space-x-2 break-all whitespace-normal truncate w-full overflow-y-hidden absolute"
class="pl-1 pr-1 text-sm h-[80%] text-gray-800 leading-7 space-x-2 break-all whitespace-normal truncate w-full overflow-y-hidden"
>
<slot />
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,6 @@ const dropEvent = (event: DragEvent) => {
>
<template v-if="!isRowEmpty(record, displayField)">
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
Expand Down