Skip to content

Commit 5e903b6

Browse files
Scheduler: fix customization for non-unique items in appointment form (#31857)
1 parent e4be44f commit 5e903b6

File tree

3 files changed

+150
-31
lines changed

3 files changed

+150
-31
lines changed

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

Lines changed: 119 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,115 @@ describe('Appointment Form', () => {
947947
POM.openPopupByDblClick('Resource test app');
948948
expect(POM.popup.getInputValue('roomId')).toBe('Room 2');
949949
});
950+
951+
it('should create resourceEditorsGroup when resources have no custom icons', async () => {
952+
const { POM } = await createScheduler({
953+
...getDefaultConfig(),
954+
dataSource: [{
955+
text: 'Resource test app',
956+
startDate: new Date(2017, 4, 9, 9, 30),
957+
endDate: new Date(2017, 4, 9, 11),
958+
roomId: 1,
959+
ownerId: 2,
960+
}],
961+
resources: [{
962+
fieldExpr: 'roomId',
963+
dataSource: [{ text: 'Room 1', id: 1 }, { text: 'Room 2', id: 2 }],
964+
}, {
965+
fieldExpr: 'ownerId',
966+
dataSource: [{ text: 'Owner 1', id: 1 }, { text: 'Owner 2', id: 2 }],
967+
}],
968+
});
969+
970+
POM.openPopupByDblClick('Resource test app');
971+
972+
const formItems = POM.popup.form.option('items') as FormItem[];
973+
const mainGroup = formItems.find((item) => item.name === 'mainGroup') as GroupItem;
974+
const resourcesGroup = mainGroup?.items?.find((item) => item.name === 'resourcesGroup') as GroupItem;
975+
976+
expect(resourcesGroup).toBeDefined();
977+
expect(resourcesGroup?.items?.length).toBe(2);
978+
979+
expect(resourcesGroup?.items).toEqual(
980+
expect.arrayContaining([
981+
expect.objectContaining({
982+
name: 'resourcesGroupContent',
983+
itemType: 'group',
984+
items: expect.arrayContaining([
985+
expect.objectContaining({
986+
name: 'roomId',
987+
}),
988+
expect.objectContaining({
989+
name: 'ownerId',
990+
}),
991+
]),
992+
}),
993+
]),
994+
);
995+
});
996+
997+
it('should create individual resource groups when resources have custom icons', async () => {
998+
const { POM } = await createScheduler({
999+
...getDefaultConfig(),
1000+
dataSource: [{
1001+
text: 'Resource test app',
1002+
startDate: new Date(2017, 4, 9, 9, 30),
1003+
endDate: new Date(2017, 4, 9, 11),
1004+
roomId: 1,
1005+
ownerId: 2,
1006+
}],
1007+
resources: [
1008+
{
1009+
fieldExpr: 'roomId',
1010+
icon: 'home',
1011+
dataSource: [{ text: 'Room 1', id: 1 }, { text: 'Room 2', id: 2 }],
1012+
},
1013+
{
1014+
fieldExpr: 'ownerId',
1015+
icon: 'user',
1016+
dataSource: [{ text: 'Owner 1', id: 1 }, { text: 'Owner 2', id: 2 }],
1017+
},
1018+
],
1019+
});
1020+
1021+
POM.openPopupByDblClick('Resource test app');
1022+
1023+
const formItems = POM.popup.form.option('items') as FormItem[];
1024+
const mainGroup = formItems.find((item) => item.name === 'mainGroup') as GroupItem;
1025+
const resourcesGroup = mainGroup?.items?.find((item) => item.name === 'resourcesGroup') as GroupItem;
1026+
1027+
expect(resourcesGroup).toBeDefined();
1028+
expect(resourcesGroup?.items?.length).toBe(2);
1029+
1030+
expect(resourcesGroup?.items).toEqual(
1031+
expect.arrayContaining([
1032+
expect.objectContaining({
1033+
name: 'roomIdGroup',
1034+
itemType: 'group',
1035+
items: expect.arrayContaining([
1036+
expect.objectContaining({
1037+
name: 'roomId',
1038+
}),
1039+
expect.objectContaining({
1040+
name: 'roomIdIcon',
1041+
}),
1042+
]),
1043+
}),
1044+
expect.objectContaining({
1045+
name: 'ownerIdGroup',
1046+
itemType: 'group',
1047+
items: expect.arrayContaining([
1048+
expect.objectContaining({
1049+
name: 'ownerId',
1050+
}),
1051+
expect.objectContaining({
1052+
name: 'ownerIdIcon',
1053+
}),
1054+
]),
1055+
}),
1056+
]),
1057+
);
1058+
});
9501059
});
9511060

9521061
describe('Recurrence Form', () => {
@@ -1041,7 +1150,7 @@ describe('Appointment Form', () => {
10411150
expect(POM.popup.getInputValue('recurrenceStartDateEditor')).toBe('5/1/2017');
10421151
expect(POM.popup.getInputValue('recurrenceCountEditor')).toBe('2');
10431152
expect(POM.popup.getInputValue('recurrencePeriodEditor')).toBe('Hour(s)');
1044-
expect(POM.popup.getInputValue('countEditor')).toBe('10 occurrence(s)');
1153+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('10 occurrence(s)');
10451154
});
10461155

10471156
it('should have correct input values for appointment with daily frequency', async () => {
@@ -1063,7 +1172,7 @@ describe('Appointment Form', () => {
10631172
expect(POM.popup.getInputValue('recurrenceStartDateEditor')).toBe('5/1/2017');
10641173
expect(POM.popup.getInputValue('recurrenceCountEditor')).toBe('2');
10651174
expect(POM.popup.getInputValue('recurrencePeriodEditor')).toBe('Day(s)');
1066-
expect(POM.popup.getInputValue('countEditor')).toBe('10 occurrence(s)');
1175+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('10 occurrence(s)');
10671176
});
10681177

10691178
it('should have correct input values for appointment with week frequency', async () => {
@@ -1089,7 +1198,7 @@ describe('Appointment Form', () => {
10891198
const expectedWeekDaysSelection = [true, false, true, false, true, false, false];
10901199
expect(POM.popup.getWeekDaysSelection()).toEqual(expectedWeekDaysSelection);
10911200

1092-
expect(POM.popup.getInputValue('countEditor')).toBe('10 occurrence(s)');
1201+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('10 occurrence(s)');
10931202
});
10941203

10951204
it('should have correct input values for appointment with monthly frequency', async () => {
@@ -1112,7 +1221,7 @@ describe('Appointment Form', () => {
11121221
expect(POM.popup.getInputValue('recurrenceCountEditor')).toBe('2');
11131222
expect(POM.popup.getInputValue('recurrencePeriodEditor')).toBe('Month(s)');
11141223
expect(POM.popup.getInputValue('recurrenceDayOfMonthEditor')).toBe('1');
1115-
expect(POM.popup.getInputValue('countEditor')).toBe('10 occurrence(s)');
1224+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('10 occurrence(s)');
11161225
});
11171226

11181227
it('should have correct input values for appointment with yearly frequency', async () => {
@@ -1136,7 +1245,7 @@ describe('Appointment Form', () => {
11361245
expect(POM.popup.getInputValue('recurrencePeriodEditor')).toBe('Year(s)');
11371246
expect(POM.popup.getInputValue('recurrenceDayOfYearDayEditor')).toBe('1');
11381247
expect(POM.popup.getInputValue('recurrenceDayOfYearMonthEditor')).toBe('May');
1139-
expect(POM.popup.getInputValue('countEditor')).toBe('10 occurrence(s)');
1248+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('10 occurrence(s)');
11401249
});
11411250

11421251
it('should have correct input values for appointment with no end', async () => {
@@ -1152,7 +1261,7 @@ describe('Appointment Form', () => {
11521261
POM.popup.getEditSeriesButton().click();
11531262
POM.popup.openRecurrenceSettings();
11541263

1155-
expect(POM.popup.getInputValue('repeatEndEditor')).toBe('never');
1264+
expect(POM.popup.getInputValue('recurrenceRepeatEndEditor')).toBe('never');
11561265
});
11571266

11581267
it('should have correct input values for appointment with end by date', async () => {
@@ -1168,8 +1277,8 @@ describe('Appointment Form', () => {
11681277
POM.popup.getEditSeriesButton().click();
11691278
POM.popup.openRecurrenceSettings();
11701279

1171-
expect(POM.popup.getInputValue('repeatEndEditor')).toBe('until');
1172-
expect(POM.popup.getInputValue('untilEditor')).toBe('6/1/2017');
1280+
expect(POM.popup.getInputValue('recurrenceRepeatEndEditor')).toBe('until');
1281+
expect(POM.popup.getInputValue('recurrenceEndUntilEditor')).toBe('6/1/2017');
11731282
});
11741283

11751284
it('should have correct input values for appointment with end by count', async () => {
@@ -1185,8 +1294,8 @@ describe('Appointment Form', () => {
11851294
POM.popup.getEditSeriesButton().click();
11861295
POM.popup.openRecurrenceSettings();
11871296

1188-
expect(POM.popup.getInputValue('repeatEndEditor')).toBe('count');
1189-
expect(POM.popup.getInputValue('countEditor')).toBe('10 occurrence(s)');
1297+
expect(POM.popup.getInputValue('recurrenceRepeatEndEditor')).toBe('count');
1298+
expect(POM.popup.getInputValue('recurrenceEndCountEditor')).toBe('10 occurrence(s)');
11901299
});
11911300
});
11921301
});

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ const createTimeZoneDataSource = (): DataSource => new DataSource({
104104

105105
const MAIN_GROUP_NAME = 'mainGroup';
106106
const DATE_GROUP_NAME = 'dateGroup';
107+
const DATE_OPTIONS_GROUP_NAME = 'dateOptionsGroup';
107108
const START_DATE_GROUP_NAME = 'startDateGroup';
108109
const END_DATE_GROUP_NAME = 'endDateGroup';
109110
const RESOURCES_GROUP_NAME = 'resourcesGroup';
@@ -373,6 +374,7 @@ export class AppointmentForm {
373374
},
374375
{
375376
colSpan: 1,
377+
name: DATE_OPTIONS_GROUP_NAME,
376378
itemType: 'group',
377379
items: [
378380
this.createAllDaySwitch(),
@@ -720,6 +722,7 @@ export class AppointmentForm {
720722

721723
return {
722724
itemType: 'simple',
725+
name: dataField,
723726
dataField,
724727
label: { text: label },
725728
colSpan: 1,
@@ -746,11 +749,13 @@ export class AppointmentForm {
746749
cssClass: `${CLASSES.resourcesGroup} ${CLASSES.groupWithIcon}`,
747750
items: [
748751
{
752+
name: `${RESOURCES_GROUP_NAME}Icon`,
749753
colSpan: 1,
750754
cssClass: `${CLASSES.formIcon} ${CLASSES.defaultResourceIcon}`,
751755
template: createFormIconTemplate('addcircleoutline'),
752756
},
753757
{
758+
name: `${RESOURCES_GROUP_NAME}Content`,
754759
itemType: 'group',
755760
colSpan: 1,
756761
items: resourcesItems,
@@ -761,11 +766,11 @@ export class AppointmentForm {
761766

762767
resourcesItems = resourcesItems.map((item, index) => {
763768
const icon = resourcesLoaders[index].icon ?? '';
764-
const name = resourcesLoaders[index].resourceName ?? `resource_${index}`;
769+
const dataField = resourcesLoaders[index].resourceIndex;
765770

766771
return {
767772
itemType: 'group',
768-
name: `${name}Group`,
773+
name: `${dataField}Group`,
769774
colCount: 2,
770775
colCountByScreen: {
771776
xs: 2,
@@ -774,11 +779,11 @@ export class AppointmentForm {
774779
items: [
775780
{
776781
colSpan: 1,
777-
name: `${name}Icon`,
782+
name: `${dataField}Icon`,
778783
cssClass: CLASSES.formIcon,
779784
template: createFormIconTemplate(icon),
780785
},
781-
{ ...item, name },
786+
item,
782787
],
783788
} as GroupItem;
784789
});
@@ -975,8 +980,9 @@ export class AppointmentForm {
975980
const { allDayExpr } = this.scheduler.getDataAccessors().expr;
976981
const visible = !this.getFormDataField(allDayExpr);
977982

978-
const startDateGroupPath = `${MAIN_GROUP_NAME}.${DATE_GROUP_NAME}.${START_DATE_GROUP_NAME}.${START_DATE_TIME_GROUP_NAME}`;
979-
const endDateGroupPath = `${MAIN_GROUP_NAME}.${DATE_GROUP_NAME}.${END_DATE_GROUP_NAME}.${END_DATE_TIME_GROUP_NAME}`;
983+
const dateOptionsGroupPath = `${MAIN_GROUP_NAME}.${DATE_GROUP_NAME}.${DATE_OPTIONS_GROUP_NAME}`;
984+
const startDateGroupPath = `${dateOptionsGroupPath}.${START_DATE_GROUP_NAME}.${START_DATE_TIME_GROUP_NAME}`;
985+
const endDateGroupPath = `${dateOptionsGroupPath}.${END_DATE_GROUP_NAME}.${END_DATE_TIME_GROUP_NAME}`;
980986

981987
const startDateItemName = `${startDateGroupPath}.${START_DATE_EDITOR_NAME}`;
982988
const startTimeItemName = `${startDateGroupPath}.${START_TIME_EDITOR_NAME}`;

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,17 @@ const FREQ = {
7272
} as const;
7373

7474
const EDITOR_NAMES = {
75-
recurrenceStartDateEditor: 'recurrenceStartDateEditor',
75+
recurrenceStartDate: 'recurrenceStartDateEditor',
7676
recurrenceCountEditor: 'recurrenceCountEditor',
7777
recurrencePeriodEditor: 'recurrencePeriodEditor',
78+
recurrenceDayOfYearMonthEditor: 'recurrenceDayOfYearMonthEditor',
7879
recurrenceDayOfMonthEditor: 'recurrenceDayOfMonthEditor',
7980
recurrenceDayOfYearDayEditor: 'recurrenceDayOfYearDayEditor',
80-
recurrenceDayOfYearMonthEditor: 'recurrenceDayOfYearMonthEditor',
8181
recurrenceEndEditor: 'recurrenceEndEditor',
82-
repeatEndEditor: 'repeatEndEditor',
83-
untilEditor: 'untilEditor',
84-
countEditor: 'countEditor',
82+
repeatEnd: 'recurrenceRepeatEndEditor',
83+
until: 'recurrenceEndUntilEditor',
84+
count: 'recurrenceEndCountEditor',
85+
recurrenceEndSpacer: 'recurrenceEndSpacer',
8586
};
8687

8788
const GROUP_NAMES = {
@@ -92,6 +93,7 @@ const GROUP_NAMES = {
9293
recurrenceEndGroup: 'recurrenceEndGroup',
9394
recurrenceDaysOfWeekEditor: 'recurrenceDaysOfWeekEditor',
9495
recurrenceDayOfYearGroup: 'recurrenceDayOfYearGroup',
96+
recurrenceEndEditorsGroup: 'recurrenceEndEditorsGroup',
9597
};
9698

9799
const ICON_NAMES = {
@@ -221,7 +223,7 @@ export class RecurrenceForm {
221223
true,
222224
getStartDateCommonConfig(this.scheduler.getFirstDayOfWeek()),
223225
{
224-
name: EDITOR_NAMES.recurrenceStartDateEditor,
226+
name: EDITOR_NAMES.recurrenceStartDate,
225227
label: {
226228
text: messageLocalization.format('dxScheduler-editorLabelStartDate'),
227229
},
@@ -457,7 +459,7 @@ export class RecurrenceForm {
457459
private createRecurrenceEndRadioGroup(): SimpleItem {
458460
return {
459461
itemType: 'simple',
460-
name: EDITOR_NAMES.repeatEndEditor,
462+
name: EDITOR_NAMES.repeatEnd,
461463
colSpan: 1,
462464
editorType: 'dxRadioGroup',
463465
cssClass: CLASSES.recurrenceEndEditors,
@@ -486,15 +488,17 @@ export class RecurrenceForm {
486488
private createRecurrenceEndEditors(): GroupItem {
487489
return {
488490
itemType: 'group',
491+
name: GROUP_NAMES.recurrenceEndEditorsGroup,
489492
cssClass: CLASSES.recurrenceEndEditors,
490493
colSpan: 1,
491494
items: [
492495
{
493496
itemType: 'empty',
497+
name: EDITOR_NAMES.recurrenceEndSpacer,
494498
},
495499
{
496500
itemType: 'simple',
497-
name: EDITOR_NAMES.untilEditor,
501+
name: EDITOR_NAMES.until,
498502
label: {
499503
visible: false,
500504
},
@@ -515,7 +519,7 @@ export class RecurrenceForm {
515519
},
516520
{
517521
itemType: 'simple',
518-
name: EDITOR_NAMES.countEditor,
522+
name: EDITOR_NAMES.count,
519523
cssClass: CLASSES.countEditor,
520524
label: {
521525
visible: false,
@@ -549,12 +553,12 @@ export class RecurrenceForm {
549553
startDate,
550554
);
551555

552-
this.dxForm.getEditor(EDITOR_NAMES.recurrenceStartDateEditor)?.option('value', this.recurrenceRule.startDate);
556+
this.dxForm.getEditor(EDITOR_NAMES.recurrenceStartDate)?.option('value', this.recurrenceRule.startDate);
553557
this.dxForm.getEditor(EDITOR_NAMES.recurrencePeriodEditor)?.option('value', repeatEditorValue);
554558
this.dxForm.getEditor(EDITOR_NAMES.recurrenceCountEditor)?.option('value', this.recurrenceRule.interval);
555-
this.dxForm.getEditor(EDITOR_NAMES.repeatEndEditor)?.option('value', this.recurrenceRule.repeatEnd);
556-
this.dxForm.getEditor(EDITOR_NAMES.untilEditor)?.option('value', this.recurrenceRule.until);
557-
this.dxForm.getEditor(EDITOR_NAMES.countEditor)?.option('value', this.recurrenceRule.count);
559+
this.dxForm.getEditor(EDITOR_NAMES.repeatEnd)?.option('value', this.recurrenceRule.repeatEnd);
560+
this.dxForm.getEditor(EDITOR_NAMES.until)?.option('value', this.recurrenceRule.until);
561+
this.dxForm.getEditor(EDITOR_NAMES.count)?.option('value', this.recurrenceRule.count);
558562

559563
this.updateRepeatEndEditors();
560564
this.updateDayEditorsVisibility();
@@ -585,8 +589,8 @@ export class RecurrenceForm {
585589
private updateRepeatEndEditors(): void {
586590
const repeatEndValue = this.recurrenceRule.repeatEnd;
587591

588-
const untilEditor = this.dxForm.getEditor(EDITOR_NAMES.untilEditor);
589-
const countEditor = this.dxForm.getEditor(EDITOR_NAMES.countEditor);
592+
const untilEditor = this.dxForm.getEditor(EDITOR_NAMES.until);
593+
const countEditor = this.dxForm.getEditor(EDITOR_NAMES.count);
590594

591595
untilEditor?.option('disabled', repeatEndValue !== 'until');
592596
countEditor?.option('disabled', repeatEndValue !== 'count');

0 commit comments

Comments
 (0)