From ca7746b0b6636d80428b8664240526f3cc9fd8dc Mon Sep 17 00:00:00 2001 From: mup Date: Fri, 17 Oct 2025 13:26:04 +0200 Subject: [PATCH] Last found bug fixed --- src/common/calendar/gui/TimeView.ts | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/common/calendar/gui/TimeView.ts b/src/common/calendar/gui/TimeView.ts index deb51c6e5f..e56769a631 100644 --- a/src/common/calendar/gui/TimeView.ts +++ b/src/common/calendar/gui/TimeView.ts @@ -69,6 +69,7 @@ export class TimeView implements Component { private timeRowHeight?: number private blockingGroupsCache: Map>> = new Map() private expandabilityCache: Map = new Map() + private eventIdToOriginalColumnArrayIndex: Map = new Map() view({ attrs }: Vnode) { const { timeScale, timeRange, events, conflictRenderPolicy, dates, timeIndicator, hasAnyConflict } = attrs @@ -285,6 +286,7 @@ export class TimeView implements Component { for (const [columnIndex, columnData] of allColumns.entries()) { for (const [eventId, eventRowData] of columnData.events.entries()) { + this.eventIdToOriginalColumnArrayIndex.set(eventId, columnIndex) let currentEventCanExpand = false // Optimized: Check cache first before recalculating @@ -347,9 +349,87 @@ export class TimeView implements Component { } } + this.applyRetroactiveShifts(gridData, allColumns) + return gridData } + /** + * NEW: Apply retroactive shifts to earlier events when later events have shifted + * This ensures events that were blocked by shifted events can now expand properly + */ + private applyRetroactiveShifts(gridData: Map, allColumns: Array): void { + for (const [eventId, gridInfo] of gridData.entries()) { + const eventIndex = this.eventIdToOriginalColumnArrayIndex.get(eventId) + if (eventIndex == null) { + continue + } + + const expectedGridEnd = gridInfo.gridColumnStart + gridInfo.gridColumnEnd + + let conflict: + | { + distance: number + id: string + gridStart: number + } + | undefined + + for (let i = eventIndex + 1; i < allColumns.length; i++) { + const columnData = allColumns[i] + + const overlappingEvents = this.findOverlappingEvents( + { + rowStart: gridInfo.start, + rowEnd: gridInfo.end, + }, + columnData.events, + ) + + if (overlappingEvents.size === 0) { + continue + } + + for (const [conflictId, _] of overlappingEvents.entries()) { + const conflictInfo = gridData.get(conflictId) + + if (!conflictInfo) { + continue + } + const distance = conflictInfo.gridColumnStart - expectedGridEnd + if (conflict?.distance == null || distance < conflict?.distance) { + conflict = { + distance, + id: conflictId, + gridStart: conflictInfo.gridColumnStart, + } + } + } + } + + if (!conflict) { + // Maybe we should set to max here? + continue + } + + if (expectedGridEnd < conflict.gridStart) { + const newSize = gridInfo.gridColumnEnd + conflict.distance + gridData.set(eventId, { + ...gridInfo, + gridColumnEnd: + gridInfo.gridColumnStart + newSize > allColumns.length + 1 + ? Math.max(allColumns.length - gridInfo.gridColumnStart, BASE_EVENT_BUBBLE_SPAN_SIZE) + : newSize, + }) + } else if (expectedGridEnd > conflict.gridStart) { + gridData.set(eventId, { + ...gridInfo, + gridColumnEnd: conflict.gridStart - 1, + }) + } + } + } + /** * Optimized: Memoized and returns on first overlap found * O(e) instead of O(e²) in worst case