-
Notifications
You must be signed in to change notification settings - Fork 663
Scheduler: T1310544 — scrollTo does not take offset into account #32073
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
base: 26_1
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes a bug where the Scheduler's scrollTo method did not properly account for the viewOffset option, which shifts the displayed time range. The fix ensures that when an offset is applied, hours are not incorrectly clamped to the startDayHour/endDayHour range, and the valid scroll date range is extended appropriately.
Key changes:
- Modified
_getScrollCoordinatesto skip hour clamping whenviewOffsetis non-zero, allowing natural hour values to be used with the offset - Enhanced
_isValidScrollDateto extend the valid date range by theviewOffseton both ends - Consolidated test files by merging
workspace.base.test.tsandworkspace.recalculation.test.tsinto a single organizedworkspace.test.tswith a new test case for the offset scrolling behavior
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts |
Fixed _getScrollCoordinates to conditionally apply hour clamping only when viewOffset === 0, and updated _isValidScrollDate to extend the valid date range by the offset value |
packages/devextreme/js/__internal/scheduler/__tests__/workspace.test.ts |
New consolidated test file containing all workspace tests including base functionality, async template recalculation, and a new test for scrollTo with offset (T1310544) |
packages/devextreme/js/__internal/scheduler/__tests__/workspace.base.test.ts |
Deleted - tests moved to workspace.test.ts |
packages/devextreme/js/__internal/scheduler/__tests__/workspace.recalculation.test.ts |
Deleted - tests moved to workspace.test.ts |
aleksei-semikozov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see two remote test files.
How I see them:
workspace.base.test.ts - unit test.
workspace.recalculation.test.ts - integration test where we create the scheduler
I don't think this test should be in one file
I would rename workspace.recalculation.test.ts -> workspace.test.ts and write your test case in this file
|
@aleksei-semikozov applied changes you asked |
| const extendedMin = new Date(min.getTime() - viewOffset); | ||
| const extendedMax = new Date(max.getTime() + viewOffset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: shouldn't min and max dates be offseted in the same direction?
| if (hours < startDayHour) { | ||
| hours = startDayHour; | ||
| } | ||
|
|
||
| if (hours >= endDayHour) { | ||
| hours = endDayHour - 1; | ||
| if (hours >= endDayHour) { | ||
| hours = endDayHour - 1; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I notice that we validate scrollTo date here before calculating scrollTo coordinates.
I suspect that this normalization may be redundant now, since we will throw a warning if scrollTo date is out of range. But I am not fully sure.
Can you investigate it please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got it. We need this normalization for views larger than day, e.g. timelineWeek, timelineMonth, etc.
However we should not just ignore this normalization if viewOffset is set. We need to adjust this normalization to include viewOffset into it.
For example this case (I have changed currentView and viewOffset). The scheduler is scrolled to 5 PM, however it should scroll to the last cell of the day (7 PM).
Please adjust the normalization and write a test for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts
Outdated
Show resolved
Hide resolved
packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts
Outdated
Show resolved
Hide resolved
packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts
Outdated
Show resolved
Hide resolved
packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| // If adjustedEndDayHour is 0, it means the range is [adjustedStartDayHour, 24), not crossing midnight | ||
| // Only consider it crossing midnight if adjustedEndDayHour > 0 and adjustedStartDayHour >= adjustedEndDayHour | ||
| const crossesMidnight = adjustedEndDayHour > 0 && adjustedStartDayHour >= adjustedEndDayHour; | ||
|
|
||
| // If adjustedEndDayHour is 0, treat it as 24 for range comparison |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "If adjustedEndDayHour is 0, it means the range is [adjustedStartDayHour, 24), not crossing midnight" may be misleading. When adjustedEndDayHour equals 0 after modulo 24, it actually means the end hour wraps to midnight (hour 24 becomes hour 0). This is not the same as saying "not crossing midnight" - it still represents a range that extends to exactly midnight. The condition for crossing midnight on line 1431 correctly excludes the case where adjustedEndDayHour is 0, but the comment explanation could be clearer about why this edge case needs special handling.
| // If adjustedEndDayHour is 0, it means the range is [adjustedStartDayHour, 24), not crossing midnight | |
| // Only consider it crossing midnight if adjustedEndDayHour > 0 and adjustedStartDayHour >= adjustedEndDayHour | |
| const crossesMidnight = adjustedEndDayHour > 0 && adjustedStartDayHour >= adjustedEndDayHour; | |
| // If adjustedEndDayHour is 0, treat it as 24 for range comparison | |
| // adjustedStartDayHour/adjustedEndDayHour are modulo 24. When endDayHour + viewOffset reaches 24, | |
| // adjustedEndDayHour becomes 0, which represents an end exactly at midnight (hour 24 → 0). | |
| // We treat the range as "crossing midnight" only when adjustedEndDayHour > 0 and | |
| // adjustedStartDayHour >= adjustedEndDayHour; the wrapped-to-0 case is handled separately below. | |
| const crossesMidnight = adjustedEndDayHour > 0 && adjustedStartDayHour >= adjustedEndDayHour; | |
| // If adjustedEndDayHour is 0 (wrapped midnight), treat it as 24 for range comparison |
| const currentDate = date || new Date(this.option('currentDate')); | ||
| const startDayHour = this.option('startDayHour'); | ||
| const endDayHour = this.option('endDayHour'); | ||
| const viewOffset = this.option('viewOffset') as number; |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type assertion assumes viewOffset is always a number, but if the option could be undefined or null in some edge cases, this could cause runtime errors. Consider adding a null check or using a fallback value like: const viewOffset = (this.option('viewOffset') as number) ?? 0;
| const viewOffset = this.option('viewOffset') as number; | |
| const rawViewOffset = this.option('viewOffset'); | |
| const viewOffset = typeof rawViewOffset === 'number' ? rawViewOffset : 0; |
| } | ||
|
|
||
| _isValidScrollDate(date, throwWarning = true) { | ||
| const viewOffset = this.option('viewOffset') as number; |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type assertion assumes viewOffset is always a number, but if the option could be undefined or null in some edge cases, this could cause runtime errors. Consider adding a null check or using a fallback value like: const viewOffset = (this.option('viewOffset') as number) ?? 0;
| const viewOffset = this.option('viewOffset') as number; | |
| const viewOffset = (this.option('viewOffset') as number | undefined | null) ?? 0; |
No description provided.