Skip to content

Commit 1bad8e1

Browse files
Merge branch '26_1' into chore/migrate-devextreme-to-nx-part-9
2 parents 97b9dda + eb60337 commit 1bad8e1

6 files changed

Lines changed: 137 additions & 74 deletions

File tree

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,23 +114,21 @@ export const createAppointmentPopup = async (
114114
const onSave = options.onSave
115115
?? jest.fn<(appointment: Record<string, unknown>) => PromiseLike<unknown>>(resolvedDeferred);
116116

117-
const formSchedulerProxy = {
118-
getResourceById: (): Record<string, unknown> => resourceManager.resourceById,
119-
getDataAccessors: (): AppointmentDataAccessor => dataAccessors,
117+
const formConfig = {
118+
dataAccessors,
119+
editing,
120+
resourceManager,
121+
firstDayOfWeek: options.firstDayOfWeek ?? 0,
122+
startDayHour: options.startDayHour ?? 0,
120123
createComponent,
121-
getEditingConfig: (): typeof editing => editing,
122-
getResourceManager: (): ResourceManager => resourceManager,
123-
getFirstDayOfWeek: (): number => options.firstDayOfWeek ?? 0,
124-
getStartDayHour: (): number => options.startDayHour ?? 0,
125124
getCalculatedEndDate: (startDate: Date): Date => {
126125
const endDate = new Date(startDate);
127126
endDate.setHours(endDate.getHours() + 1);
128127
return endDate;
129128
},
130-
getTimeZoneCalculator: (): typeof timeZoneCalculator => timeZoneCalculator,
131129
};
132130

133-
const form = new AppointmentForm(formSchedulerProxy);
131+
const form = new AppointmentForm(formConfig);
134132

135133
const noop = (): void => {};
136134

packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,27 @@ describe('Appointment Form', () => {
11791179
expect(loadSpy).toHaveBeenCalledTimes(1);
11801180
expect(byKeySpy).toHaveBeenCalledTimes(0);
11811181
});
1182+
1183+
it('should recreate appointment form synchronously when resources option changes', async () => {
1184+
const { scheduler } = await createScheduler({
1185+
...getDefaultConfig(),
1186+
resources: [{
1187+
fieldExpr: 'roomId',
1188+
dataSource: [{ id: 1, text: 'Room 1' }],
1189+
}],
1190+
});
1191+
const formBefore = (scheduler as any).appointmentForm;
1192+
1193+
scheduler.option('resources', [{
1194+
fieldExpr: 'ownerId',
1195+
dataSource: [{ id: 1, text: 'Owner 1' }],
1196+
}]);
1197+
1198+
const formAfter = (scheduler as any).appointmentForm;
1199+
expect(formAfter).not.toBe(formBefore);
1200+
expect(formAfter.config.resourceManager)
1201+
.toBe((scheduler as any).resourceManager);
1202+
});
11821203
});
11831204

11841205
describe('Recurrence Form', () => {
@@ -1755,6 +1776,19 @@ describe('Appointment Form', () => {
17551776
expect(endDateEditorAfter).toBeDefined();
17561777
expect(endDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0);
17571778
});
1779+
1780+
it('should pass undefined firstDayOfWeek to calendars when option is not set', async () => {
1781+
const { POM, scheduler } = await createScheduler({
1782+
...getDefaultConfig(),
1783+
firstDayOfWeek: undefined,
1784+
});
1785+
1786+
scheduler.showAppointmentPopup(commonAppointment);
1787+
1788+
const startDateEditor = POM.popup.dxForm.getEditor('startDateEditor');
1789+
expect(startDateEditor).toBeDefined();
1790+
expect(startDateEditor?.option('calendarOptions.firstDayOfWeek')).toBeUndefined();
1791+
});
17581792
});
17591793

17601794
describe('Icons', () => {

packages/devextreme/js/__internal/scheduler/appointment_popup/m_form.ts

Lines changed: 66 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type Popup from '@ts/ui/popup/m_popup';
2828

2929
import timeZoneUtils from '../m_utils_time_zone';
3030
import type { SafeAppointment } from '../types';
31+
import type { AppointmentDataAccessor } from '../utils/data_accessor/appointment_data_accessor';
3132
import type { ResourceLoader } from '../utils/loader/resource_loader';
3233
import { DEFAULT_ICONS_SHOW_MODE } from '../utils/options/constants';
3334
import { getAppointmentGroupIndex, getRawAppointmentGroupValues, getSafeGroupValues } from '../utils/resource_manager/appointment_groups_utils';
@@ -37,6 +38,24 @@ import { customizeFormItems } from './m_customize_form_items';
3738
import { RecurrenceForm } from './m_recurrence_form';
3839
import { createFormIconTemplate, getStartDateCommonConfig, RecurrenceRule } from './utils';
3940

41+
type SchedulerEditingObject = Exclude<NonNullable<SchedulerProperties['editing']>, boolean>;
42+
43+
export type CreateComponentFn = (
44+
element: string | HTMLElement | dxElementWrapper | Element,
45+
Component: any,
46+
options: any,
47+
) => any;
48+
49+
export interface AppointmentFormConfig {
50+
dataAccessors: AppointmentDataAccessor;
51+
editing: SchedulerProperties['editing'];
52+
resourceManager: ResourceManager;
53+
firstDayOfWeek: number | undefined;
54+
startDayHour: number;
55+
createComponent: CreateComponentFn;
56+
getCalculatedEndDate: (startDate: Date) => Date;
57+
}
58+
4059
const CLASSES = {
4160
form: 'dx-scheduler-form',
4261
icon: 'dx-icon',
@@ -118,9 +137,7 @@ const RESOURCES_GROUP_ICON_NAME = 'resourcesGroupIcon';
118137
const DESCRIPTION_ICON_NAME = 'descriptionIcon';
119138

120139
export class AppointmentForm {
121-
private readonly scheduler: any;
122-
123-
private readonly resourceManager!: ResourceManager;
140+
private readonly config: AppointmentFormConfig;
124141

125142
private dxFormInstance?: dxForm;
126143

@@ -132,6 +149,10 @@ export class AppointmentForm {
132149

133150
private $recurrenceGroup?: dxElementWrapper;
134151

152+
private get resourceManager(): ResourceManager {
153+
return this.config.resourceManager;
154+
}
155+
135156
get dxForm(): dxForm {
136157
return this.dxFormInstance as dxForm;
137158
}
@@ -158,29 +179,28 @@ export class AppointmentForm {
158179
}
159180

160181
get startDate(): Date | null {
161-
const { startDateExpr } = this.scheduler.getDataAccessors().expr;
182+
const { startDateExpr } = this.config.dataAccessors.expr;
162183
const value = this.getFormDataField(startDateExpr);
163184

164185
return value ? new Date(dateSerialization.deserializeDate(value)) : null;
165186
}
166187

167188
get endDate(): Date | null {
168-
const { endDateExpr } = this.scheduler.getDataAccessors().expr;
189+
const { endDateExpr } = this.config.dataAccessors.expr;
169190
const value = this.getFormDataField(endDateExpr);
170191

171192
return value ? new Date(dateSerialization.deserializeDate(value)) : null;
172193
}
173194

174195
get recurrenceRuleRaw(): string | null {
175-
const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr;
196+
const { recurrenceRuleExpr } = this.config.dataAccessors.expr;
176197
const value = this.getFormDataField(recurrenceRuleExpr) as string | undefined;
177198

178199
return value ?? null;
179200
}
180201

181-
constructor(scheduler: any) {
182-
this.scheduler = scheduler;
183-
this.resourceManager = scheduler.getResourceManager();
202+
constructor(config: AppointmentFormConfig) {
203+
this.config = config;
184204
}
185205

186206
private getFormDataField(field: string): any {
@@ -200,7 +220,10 @@ export class AppointmentForm {
200220

201221
const mainGroup = this.createMainFormGroup();
202222

203-
this.recurrenceForm = new RecurrenceForm(this.scheduler);
223+
this.recurrenceForm = new RecurrenceForm({
224+
firstDayOfWeek: this.config.firstDayOfWeek,
225+
createComponent: this.config.createComponent,
226+
});
204227
const recurrenceGroup = this.recurrenceForm.createRecurrenceFormGroup();
205228

206229
const items = [mainGroup, recurrenceGroup];
@@ -212,28 +235,33 @@ export class AppointmentForm {
212235
this.applyFormItemDefaults(mainGroup, showMainGroupIcons);
213236
this.applyFormItemDefaults(recurrenceGroup, showRecurrenceGroupIcons);
214237

215-
const editingConfig = this.scheduler.getEditingConfig();
216-
const customizedItems = customizeFormItems(items, editingConfig?.form?.items);
238+
const customizedItems = customizeFormItems(items, this.getEditingForm()?.items);
217239

218240
this.createForm(customizedItems);
219241
}
220242

221-
private getIconsShowMode(): AppointmentFormIconsShowMode {
222-
const editingConfig = this.scheduler.getEditingConfig() as SchedulerProperties['editing'];
243+
private getEditingForm(): SchedulerEditingObject['form'] {
244+
const editing = this.getEditingObject();
245+
return editing?.form;
246+
}
223247

224-
if (isBoolean(editingConfig)) {
225-
return DEFAULT_ICONS_SHOW_MODE;
248+
private getEditingObject(): SchedulerEditingObject | undefined {
249+
const { editing } = this.config;
250+
if (isBoolean(editing) || !editing) {
251+
return undefined;
226252
}
253+
return editing;
254+
}
227255

228-
return editingConfig?.form?.iconsShowMode ?? DEFAULT_ICONS_SHOW_MODE;
256+
private getIconsShowMode(): AppointmentFormIconsShowMode {
257+
return this.getEditingForm()?.iconsShowMode ?? DEFAULT_ICONS_SHOW_MODE;
229258
}
230259

231260
private createForm(items: FormProperties['items']): dxForm {
232261
const element = $('<div>');
233-
const editingConfig = this.scheduler.getEditingConfig();
234262
const {
235263
items: formItems, onContentReady, onInitialized, ...customFormOptions
236-
} = editingConfig?.form ?? {};
264+
} = this.getEditingForm() ?? {};
237265

238266
const defaultOptions: FormProperties = {
239267
items,
@@ -251,7 +279,7 @@ export class AppointmentForm {
251279
onFieldDataChanged: (e) => {
252280
const {
253281
startDateExpr, endDateExpr, recurrenceRuleExpr,
254-
} = this.scheduler.getDataAccessors().expr;
282+
} = this.config.dataAccessors.expr;
255283

256284
const { dataField } = e;
257285

@@ -261,7 +289,7 @@ export class AppointmentForm {
261289

262290
const isDateRangeChanged = [startDateExpr, endDateExpr].includes(dataField);
263291
const isRecurrenceRuleChanged = dataField === recurrenceRuleExpr;
264-
const isResourceChanged = Object.keys(this.scheduler.getResourceById()).includes(dataField);
292+
const isResourceChanged = Object.keys(this.config.resourceManager.resourceById).includes(dataField);
265293

266294
if (isDateRangeChanged) {
267295
this.updateDateEditorsValues();
@@ -300,7 +328,7 @@ export class AppointmentForm {
300328
} as FormProperties;
301329

302330
const formOptions = extend(true, defaultOptions, customFormOptions);
303-
return this.scheduler.createComponent(element, dxForm, formOptions) as dxForm;
331+
return this.config.createComponent(element, dxForm, formOptions) as dxForm;
304332
}
305333

306334
private createMainFormGroup(): GroupItem {
@@ -320,7 +348,7 @@ export class AppointmentForm {
320348
}
321349

322350
private createSubjectGroup(): GroupItem {
323-
const { textExpr } = this.scheduler.getDataAccessors().expr;
351+
const { textExpr } = this.config.dataAccessors.expr;
324352

325353
return {
326354
name: SUBJECT_GROUP_NAME,
@@ -375,7 +403,7 @@ export class AppointmentForm {
375403
}
376404

377405
private createAllDaySwitch(): SimpleItem {
378-
const { allDayExpr, startDateExpr, endDateExpr } = this.scheduler.getDataAccessors().expr;
406+
const { allDayExpr, startDateExpr, endDateExpr } = this.config.dataAccessors.expr;
379407

380408
return {
381409
name: ALL_DAY_EDITOR_NAME,
@@ -403,10 +431,9 @@ export class AppointmentForm {
403431
this.dxForm.updateData(startDateExpr, allDayStartDate);
404432
this.dxForm.updateData(endDateExpr, allDayStartDate);
405433
} else {
406-
const startHour = this.scheduler.getStartDayHour();
407-
startDate.setHours(startHour);
434+
startDate.setHours(this.config.startDayHour);
408435

409-
const calculatedEndDate = this.scheduler.getCalculatedEndDate(startDate);
436+
const calculatedEndDate = this.config.getCalculatedEndDate(startDate);
410437

411438
this.dxForm.updateData(startDateExpr, startDate);
412439
this.dxForm.updateData(endDateExpr, calculatedEndDate);
@@ -419,7 +446,7 @@ export class AppointmentForm {
419446
private createStartDateGroup(): GroupItem {
420447
const {
421448
startDateExpr, startDateTimeZoneExpr, endDateTimeZoneExpr,
422-
} = this.scheduler.getDataAccessors().expr;
449+
} = this.config.dataAccessors.expr;
423450

424451
return this.createDateGroup(
425452
startDateExpr,
@@ -459,7 +486,7 @@ export class AppointmentForm {
459486
}
460487

461488
private createEndDateGroup(): GroupItem {
462-
const { endDateExpr, endDateTimeZoneExpr } = this.scheduler.getDataAccessors().expr;
489+
const { endDateExpr, endDateTimeZoneExpr } = this.config.dataAccessors.expr;
463490

464491
return this.createDateGroup(
465492
endDateExpr,
@@ -498,8 +525,8 @@ export class AppointmentForm {
498525
timeItemOptions?: SimpleItem,
499526
timezoneItemOptions?: SimpleItem,
500527
): GroupItem {
501-
const { allowTimeZoneEditing } = this.scheduler.getEditingConfig();
502-
const { startDateExpr, endDateExpr } = this.scheduler.getDataAccessors().expr;
528+
const allowTimeZoneEditing = this.getEditingObject()?.allowTimeZoneEditing;
529+
const { startDateExpr, endDateExpr } = this.config.dataAccessors.expr;
503530
const isStartDateEditor = dateExpr === startDateExpr;
504531

505532
const getEditorsDate = (): Date | null => (isStartDateEditor ? this.startDate : this.endDate);
@@ -567,7 +594,7 @@ export class AppointmentForm {
567594
items: [
568595
extend(
569596
true,
570-
getStartDateCommonConfig(this.scheduler.getFirstDayOfWeek()),
597+
getStartDateCommonConfig(this.config.firstDayOfWeek),
571598
{
572599
editorOptions: {
573600
onValueChanged: (e) => {
@@ -593,7 +620,7 @@ export class AppointmentForm {
593620
type: 'time',
594621
useMaskBehavior: true,
595622
calendarOptions: {
596-
firstDayOfWeek: this.scheduler.getFirstDayOfWeek(),
623+
firstDayOfWeek: this.config.firstDayOfWeek,
597624
},
598625
onValueChanged: (e) => {
599626
dateValueChanged(e, (date: Date): void => {
@@ -625,7 +652,7 @@ export class AppointmentForm {
625652
}
626653

627654
private createRepeatGroup(): GroupItem {
628-
const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr;
655+
const { recurrenceRuleExpr } = this.config.dataAccessors.expr;
629656

630657
return {
631658
name: REPEAT_GROUP_NAME,
@@ -677,7 +704,7 @@ export class AppointmentForm {
677704
}
678705

679706
private createDescriptionGroup(): GroupItem {
680-
const { descriptionExpr } = this.scheduler.getDataAccessors().expr;
707+
const { descriptionExpr } = this.config.dataAccessors.expr;
681708

682709
return {
683710
name: DESCRIPTION_GROUP_NAME,
@@ -709,7 +736,7 @@ export class AppointmentForm {
709736
}
710737

711738
private createResourcesGroup(): GroupItem {
712-
const resourcesLoaders: ResourceLoader[] = Object.values(this.scheduler.getResourceById());
739+
const resourcesLoaders: ResourceLoader[] = Object.values(this.config.resourceManager.resourceById);
713740

714741
let resourcesItems: FormItem[] = resourcesLoaders.map((resourceLoader) => {
715742
const { dataSource, dataAccessor } = resourceLoader;
@@ -854,8 +881,7 @@ export class AppointmentForm {
854881

855882
showMainGroup(): void {
856883
const currentHeight = this.dxPopup.option('height') as string | number | undefined;
857-
const editingConfig = this.scheduler.getEditingConfig();
858-
const configuredHeight = editingConfig?.popup?.height ?? 'auto';
884+
const configuredHeight = this.getEditingObject()?.popup?.height ?? 'auto';
859885

860886
if (typeof currentHeight === 'number') {
861887
this.dxPopup.option('height', configuredHeight);
@@ -908,7 +934,7 @@ export class AppointmentForm {
908934

909935
saveRecurrenceValue(): void {
910936
const { recurrenceRule } = this.recurrenceForm;
911-
const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr;
937+
const { recurrenceRuleExpr } = this.config.dataAccessors.expr;
912938

913939
const recurrenceRuleSerialized = recurrenceRule.toString() ?? '';
914940

@@ -1003,7 +1029,7 @@ export class AppointmentForm {
10031029
}
10041030

10051031
private updateDateTimeEditorsVisibility(): void {
1006-
const { allDayExpr } = this.scheduler.getDataAccessors().expr;
1032+
const { allDayExpr } = this.config.dataAccessors.expr;
10071033
const visible = !this.getFormDataField(allDayExpr);
10081034

10091035
const dateOptionsGroupPath = `${MAIN_GROUP_NAME}.${DATE_GROUP_NAME}.${DATE_OPTIONS_GROUP_NAME}`;

0 commit comments

Comments
 (0)