Skip to content

Commit 54d747e

Browse files
authored
Scheduler: fix options updating on view change (T1297019, T1301345) (#30506)
Co-authored-by: Vladimir Bushmanov <[email protected]>
1 parent 2f2cb57 commit 54d747e

File tree

8 files changed

+195
-31
lines changed

8 files changed

+195
-31
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Scheduler from '@ts/scheduler/m_scheduler';
2+
3+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4+
type Config = any;
5+
6+
export const createScheduler = async (config: Config): Promise<{
7+
container: HTMLDivElement;
8+
scheduler: Scheduler;
9+
}> => {
10+
const container = document.createElement('div');
11+
const scheduler = new Scheduler(container, config);
12+
await new Promise(process.nextTick);
13+
14+
return {
15+
container,
16+
scheduler,
17+
};
18+
};

packages/devextreme/js/__internal/scheduler/__tests__/__mock__/m_mock_scheduler.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ import DOMComponent from '@ts/core/widget/dom_component';
33

44
import SchedulerWorkSpace from '../../workspaces/m_work_space';
55

6-
export const setupSchedulerTestEnvironment = ({
7-
cellWidth,
8-
cellHeight,
9-
} = {
10-
cellWidth: 250,
11-
cellHeight: 80,
12-
}): void => {
6+
export const setupSchedulerTestEnvironment = (
7+
isTimelineView = false,
8+
): void => {
9+
const cellWidth = 250;
10+
const cellHeight = isTimelineView ? 450 : 80;
11+
1312
(DOMComponent.prototype as any)._isVisible = jest.fn().mockReturnValue(true);
1413
SchedulerWorkSpace.prototype._createCrossScrollingConfig = () => ({
1514
direction: 'both',
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import {
2+
describe, expect, it,
3+
} from '@jest/globals';
4+
import { DataSource } from '@ts/data/data_source/m_data_source';
5+
import CustomStore from '@ts/data/m_custom_store';
6+
import { createScheduler } from '@ts/scheduler/__tests__/__mock__/create_scheduler';
7+
8+
import { setupSchedulerTestEnvironment } from './__mock__/m_mock_scheduler';
9+
10+
const dataSource = [
11+
{
12+
startDate: new Date(2024, 8, 7, 0, 0),
13+
endDate: new Date(2024, 8, 7, 8, 0),
14+
roomId: 1,
15+
priorityId: 1,
16+
text: 'Install New Database',
17+
},
18+
];
19+
const rooms = [
20+
{ id: 1, text: 'Room 2', color: 'rgb(142, 205, 60)' },
21+
];
22+
const rooms2 = [
23+
{ id: 1, text: 'Room 2', color: 'rgb(60, 154, 205)' },
24+
];
25+
const getAppointmentColor = (container: HTMLDivElement): string => {
26+
const appointment = container.querySelector('.dx-scheduler-appointment') as HTMLDivElement;
27+
return appointment.style.backgroundColor;
28+
};
29+
const getAgendaAppointmentColor = (container: HTMLDivElement): string => {
30+
const appointment = container.querySelector('.dx-scheduler-agenda-appointment-marker') as HTMLDivElement;
31+
return appointment.style.backgroundColor;
32+
};
33+
34+
describe('Resources', () => {
35+
describe.each([
36+
'month',
37+
'agenda',
38+
])('%s view', (view) => {
39+
const getColor = view === 'agenda'
40+
? getAgendaAppointmentColor
41+
: getAppointmentColor;
42+
43+
it('should render correct appointment color for remote datasource (T1300252)', async () => {
44+
setupSchedulerTestEnvironment();
45+
46+
const dataPromise = new Promise((resolve) => {
47+
setTimeout(resolve, 100, rooms);
48+
});
49+
const { container } = await createScheduler({
50+
views: [view],
51+
currentView: view,
52+
currentDate: new Date(2024, 8, 7),
53+
dataSource,
54+
resources: [{
55+
fieldExpr: 'roomId',
56+
label: 'Room',
57+
dataSource: new DataSource({
58+
store: new CustomStore({
59+
load: () => dataPromise,
60+
}),
61+
paginate: false,
62+
}),
63+
}],
64+
});
65+
await dataPromise;
66+
await new Promise(process.nextTick);
67+
68+
expect(getColor(container)).toBe(rooms[0].color);
69+
});
70+
71+
it('should render correct appointment color for local datasource (T1300252)', async () => {
72+
setupSchedulerTestEnvironment();
73+
74+
const { container } = await createScheduler({
75+
views: [view],
76+
currentView: view,
77+
currentDate: new Date(2024, 8, 7),
78+
dataSource,
79+
resources: [{
80+
fieldExpr: 'roomId',
81+
label: 'Room',
82+
dataSource: rooms,
83+
}],
84+
});
85+
86+
expect(getColor(container)).toBe(rooms[0].color);
87+
});
88+
89+
it('should render appointments after resources update (T1301345)', async () => {
90+
setupSchedulerTestEnvironment();
91+
92+
const { container, scheduler } = await createScheduler({
93+
views: [view],
94+
currentView: view,
95+
currentDate: new Date(2024, 8, 7),
96+
dataSource,
97+
resources: [{
98+
fieldExpr: 'roomId',
99+
label: 'Room',
100+
dataSource: rooms,
101+
}],
102+
});
103+
scheduler.option('resources', [{
104+
fieldExpr: 'roomId',
105+
label: 'Room',
106+
dataSource: rooms2,
107+
}]);
108+
await new Promise(process.nextTick);
109+
110+
expect(getColor(container)).toBe(rooms2[0].color);
111+
});
112+
});
113+
});

packages/devextreme/js/__internal/scheduler/__tests__/santiago_timezone.test.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
/**
22
* @timezone America/Santiago
33
*/
4-
/* eslint-disable @typescript-eslint/no-unused-vars */
54

65
import {
76
describe, expect, it,
87
} from '@jest/globals';
98

10-
import Scheduler from '../m_scheduler';
9+
import { createScheduler } from './__mock__/create_scheduler';
1110
import { setupSchedulerTestEnvironment } from './__mock__/m_mock_scheduler';
1211

1312
const dataSource = [
@@ -104,22 +103,17 @@ const getTexts = (
104103

105104
describe('scheduler', () => {
106105
it.each(views)('should render correct workspace in Santiago DST for view: $view.name', async ({ view, result }) => {
107-
setupSchedulerTestEnvironment({
108-
cellWidth: 250,
109-
cellHeight: view.name.includes('Timeline') ? 450 : 80,
110-
});
106+
setupSchedulerTestEnvironment(true);
111107

112-
const container = document.createElement('div');
113-
const scheduler = new Scheduler(container, {
108+
const { container } = await createScheduler({
114109
views: [view],
115110
currentView: view.name,
116111
currentDate: new Date(2024, 8, 8),
117112
height: 600,
118113
cellDuration: 60,
119114
firstDayOfWeek: 1,
120115
dataSource,
121-
} as any);
122-
await new Promise(process.nextTick);
116+
});
123117

124118
if (result.hasCellContent) {
125119
const cells = container.querySelectorAll('.dx-scheduler-date-table-cell');
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {
2+
describe, expect, it,
3+
} from '@jest/globals';
4+
5+
import { createScheduler } from './__mock__/create_scheduler';
6+
import { setupSchedulerTestEnvironment } from './__mock__/m_mock_scheduler';
7+
8+
describe('views', () => {
9+
it('should render appointment after view change (T1297019)', async () => {
10+
setupSchedulerTestEnvironment();
11+
const { container, scheduler } = await createScheduler({
12+
timeZone: 'Etc/UTC',
13+
dataSource: [{
14+
text: 'Appointment',
15+
startDate: new Date('2021-02-02T08:00:00.000Z'),
16+
endDate: new Date('2021-02-02T20:00:00.000Z'),
17+
allDay: true,
18+
}],
19+
views: [{
20+
type: 'day',
21+
allDayPanelMode: 'hidden',
22+
}, {
23+
allDayPanelMode: 'all',
24+
type: 'timelineDay',
25+
}],
26+
currentView: 'timelineDay',
27+
currentDate: new Date('2021-02-02T10:00:00.000Z'),
28+
startDayHour: 8,
29+
endDayHour: 20,
30+
showAllDayPanel: false,
31+
height: 730,
32+
});
33+
34+
scheduler.option('currentView', 'day');
35+
await new Promise(process.nextTick);
36+
37+
const appointment = container.querySelector('.dx-scheduler-appointment');
38+
expect(appointment !== null).toBe(true);
39+
});
40+
});

packages/devextreme/js/__internal/scheduler/appointments/data_provider/m_appointment_filter.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ export class AppointmentFilterBaseStrategy {
3939

4040
get timeZoneCalculator() { return this.options.timeZoneCalculator; }
4141

42-
get viewStartDayHour() { return this.options.startDayHour; }
42+
get viewStartDayHour() { return this._resolveOption('startDayHour'); }
4343

44-
get viewEndDayHour() { return this.options.endDayHour; }
44+
get viewEndDayHour() { return this._resolveOption('endDayHour'); }
4545

46-
get timezone() { return this.options.timezone; }
46+
get timezone() { return this._resolveOption('timezone'); }
4747

48-
get firstDayOfWeek() { return this.options.firstDayOfWeek; }
48+
get firstDayOfWeek() { return this._resolveOption('firstDayOfWeek'); }
4949

50-
get showAllDayPanel() { return this.options.showAllDayPanel; }
50+
get showAllDayPanel() { return this._resolveOption('showAllDayPanel'); }
5151

5252
get loadedResources() { return this._resolveOption('loadedResources'); }
5353

@@ -74,7 +74,7 @@ export class AppointmentFilterBaseStrategy {
7474

7575
filter(preparedItems: AppointmentDataItem[]): SafeAppointment[] {
7676
const [min, max] = this.dateRange;
77-
const { viewOffset } = this.options;
77+
const viewOffset = this._resolveOption('viewOffset');
7878
const allDay = !this.showAllDayPanel && this.supportAllDayRow
7979
? false
8080
: undefined;
@@ -285,7 +285,7 @@ export class AppointmentFilterBaseStrategy {
285285
}
286286

287287
if (result && recurrenceProcessor.isValidRecurrenceRule(recurrenceRule)) {
288-
const { viewOffset } = this.options;
288+
const viewOffset = this._resolveOption('viewOffset');
289289
result = recurrenceProcessor.hasRecurrence({
290290
rule: recurrenceRule,
291291
exception: recurrenceException,

packages/devextreme/js/__internal/scheduler/appointments/data_provider/m_appointment_filter_virtual.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class AppointmentFilterVirtualStrategy extends AppointmentFilterBaseStrat
1919
get resources() { return this.options.resources; }
2020

2121
filter(preparedItems: AppointmentDataItem[]): SafeAppointment[] {
22-
const { viewOffset } = this.options;
22+
const viewOffset = this._resolveOption('viewOffset');
2323
const hourMs = toMs('hour');
2424
const isCalculateStartAndEndDayHour = isDateAndTimeView(this.viewType);
2525
const checkIntersectViewport = isCalculateStartAndEndDayHour && this.viewDirection === 'horizontal';

packages/devextreme/js/__internal/scheduler/m_scheduler.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,12 +1049,12 @@ class Scheduler extends Widget<any> {
10491049
timeZoneCalculator: this.timeZoneCalculator,
10501050
dateSerializationFormat: this.option('dateSerializationFormat'),
10511051
resources: this.option('resources'),
1052-
startDayHour: this._getCurrentViewOption('startDayHour'),
1053-
endDayHour: this._getCurrentViewOption('endDayHour'),
1054-
viewOffset: this.getViewOffsetMs(),
1055-
appointmentDuration: this._getCurrentViewOption('cellDuration'),
1056-
allDayPanelMode: this._getCurrentViewOption('allDayPanelMode'),
1057-
showAllDayPanel: this.option('showAllDayPanel'),
1052+
startDayHour: () => this._getCurrentViewOption('startDayHour'),
1053+
endDayHour: () => this._getCurrentViewOption('endDayHour'),
1054+
viewOffset: () => this.getViewOffsetMs(),
1055+
appointmentDuration: () => this._getCurrentViewOption('cellDuration'),
1056+
allDayPanelMode: () => this._getCurrentViewOption('allDayPanelMode'),
1057+
showAllDayPanel: () => this.option('showAllDayPanel'),
10581058
getLoadedResources: () => this.option('loadedResources'),
10591059
getIsVirtualScrolling: () => this.isVirtualScrolling(),
10601060
getSupportAllDayRow: () => this._workSpace.supportAllDayRow(),

0 commit comments

Comments
 (0)