Skip to content

Commit b6dd3f2

Browse files
authored
Scheduler: Appointment Form — fix 'Save' button visibility in recurrence form for disabled appointment (#31923)
1 parent c073132 commit b6dd3f2

File tree

3 files changed

+141
-105
lines changed

3 files changed

+141
-105
lines changed
Loading

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

Lines changed: 88 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
} from '@jest/globals';
44
import $ from '@js/core/renderer';
55
import type { GroupItem, Item as FormItem } from '@js/ui/form';
6+
import type { ToolbarItem } from '@js/ui/popup';
67
import { toMilliseconds } from '@ts/utils/toMilliseconds';
78

89
import fx from '../../../common/core/animation/fx';
@@ -1957,44 +1958,6 @@ describe('Appointment Popup', () => {
19571958
});
19581959

19591960
describe('Toolbar', () => {
1960-
const toolbarWithSaveButton = [
1961-
{
1962-
toolbar: 'top',
1963-
location: 'before',
1964-
cssClass: 'dx-toolbar-label',
1965-
},
1966-
{
1967-
toolbar: 'top',
1968-
location: 'after',
1969-
options: {
1970-
onClick: expect.any(Function),
1971-
stylingMode: 'contained',
1972-
type: 'default',
1973-
text: 'Save',
1974-
},
1975-
shortcut: 'done',
1976-
},
1977-
{
1978-
toolbar: 'top',
1979-
location: 'after',
1980-
shortcut: 'cancel',
1981-
options: { stylingMode: 'outlined' },
1982-
},
1983-
];
1984-
const toolbarWithCancelButton = [
1985-
{
1986-
toolbar: 'top',
1987-
location: 'before',
1988-
cssClass: 'dx-toolbar-label',
1989-
},
1990-
{
1991-
toolbar: 'top',
1992-
location: 'after',
1993-
shortcut: 'cancel',
1994-
options: { stylingMode: 'outlined' },
1995-
},
1996-
];
1997-
19981961
describe('Popup Title', () => {
19991962
it('should display "New Appointment" when creating new appointment', async () => {
20001963
const { scheduler, POM } = await createScheduler({
@@ -2032,7 +1995,47 @@ describe('Appointment Popup', () => {
20321995
{ allowUpdating: false, disabled: true },
20331996
{ allowUpdating: true, disabled: false },
20341997
{ allowUpdating: true, disabled: true },
2035-
])('Buttons visibility when %p', async ({ allowUpdating, disabled }) => {
1998+
])('Buttons visibility in main form when %p', async ({ allowUpdating, disabled }) => {
1999+
const shouldHaveSaveButton = allowUpdating && !disabled;
2000+
2001+
const { scheduler, POM } = await createScheduler({
2002+
...getDefaultConfig(),
2003+
editing: { allowUpdating },
2004+
});
2005+
2006+
scheduler.showAppointmentPopup(disabled ? disabledAppointment : commonAppointment);
2007+
2008+
const toolbarItems = POM.popup.component.option('toolbarItems') ?? [];
2009+
2010+
expect(toolbarItems).toEqual(
2011+
expect.arrayContaining([
2012+
expect.objectContaining({
2013+
shortcut: 'cancel',
2014+
}),
2015+
]),
2016+
);
2017+
2018+
const doneButtonMatcher = expect.arrayContaining([
2019+
expect.objectContaining({
2020+
shortcut: 'done',
2021+
}),
2022+
]);
2023+
2024+
if (shouldHaveSaveButton) {
2025+
expect(toolbarItems).toEqual(doneButtonMatcher);
2026+
} else {
2027+
expect(toolbarItems).not.toEqual(doneButtonMatcher);
2028+
}
2029+
2030+
await POM.popup.component.hide();
2031+
});
2032+
2033+
it.each([
2034+
{ allowUpdating: false, disabled: false },
2035+
{ allowUpdating: false, disabled: true },
2036+
{ allowUpdating: true, disabled: false },
2037+
{ allowUpdating: true, disabled: true },
2038+
])('Buttons visibility in recurrence form when %p', async ({ allowUpdating, disabled }) => {
20362039
const shouldHaveSaveButton = allowUpdating && !disabled;
20372040

20382041
const { scheduler, POM } = await createScheduler({
@@ -2044,11 +2047,32 @@ describe('Appointment Popup', () => {
20442047
const appointment = disabled ? dataSource.items()[1] : dataSource.items()[0];
20452048

20462049
scheduler.showAppointmentPopup(appointment);
2050+
scheduler.showAppointmentPopup(disabled ? disabledAppointment : commonAppointment);
2051+
2052+
POM.popup.selectRepeatValue('daily');
2053+
2054+
await new Promise(process.nextTick);
2055+
2056+
const toolbarItems = POM.popup.component.option('toolbarItems') ?? [];
2057+
2058+
expect(toolbarItems).toEqual(
2059+
expect.arrayContaining([
2060+
expect.objectContaining({
2061+
shortcut: 'cancel',
2062+
}),
2063+
]),
2064+
);
2065+
2066+
const doneButtonMatcher = expect.arrayContaining([
2067+
expect.objectContaining({
2068+
shortcut: 'done',
2069+
}),
2070+
]);
20472071

20482072
if (shouldHaveSaveButton) {
2049-
expect(POM.popup.component.option('toolbarItems')).toMatchObject(toolbarWithSaveButton);
2073+
expect(toolbarItems).toEqual(doneButtonMatcher);
20502074
} else {
2051-
expect(POM.popup.component.option('toolbarItems')).toMatchObject(toolbarWithCancelButton);
2075+
expect(toolbarItems).not.toEqual(doneButtonMatcher);
20522076
}
20532077

20542078
await POM.popup.component.hide();
@@ -2063,22 +2087,35 @@ describe('Appointment Popup', () => {
20632087
},
20642088
});
20652089

2066-
const newAppointment = {
2067-
text: 'a',
2068-
startDate: new Date(2015, 5, 15, 10),
2069-
endDate: new Date(2015, 5, 15, 11),
2070-
};
2090+
const getToolbarItems = (): ToolbarItem [] => POM.popup.component.option('toolbarItems') ?? [];
20712091

2072-
scheduler.showAppointmentPopup(newAppointment);
2073-
expect(POM.popup.component.option('toolbarItems')).toMatchObject(toolbarWithSaveButton);
2092+
const doneButtonMatcher = expect.arrayContaining([
2093+
expect.objectContaining({
2094+
shortcut: 'done',
2095+
}),
2096+
]);
2097+
const cancelButtonMatcher = expect.arrayContaining([
2098+
expect.objectContaining({
2099+
shortcut: 'cancel',
2100+
}),
2101+
]);
2102+
2103+
scheduler.showAppointmentPopup();
2104+
2105+
expect(getToolbarItems()).toEqual(doneButtonMatcher);
2106+
expect(getToolbarItems()).toEqual(cancelButtonMatcher);
20742107

20752108
scheduler.option('editing', { allowUpdating: false, allowAdding: true });
2076-
scheduler.showAppointmentPopup(newAppointment);
2077-
expect(POM.popup.component.option('toolbarItems')).toMatchObject(toolbarWithCancelButton);
2109+
scheduler.showAppointmentPopup(commonAppointment);
2110+
2111+
expect(getToolbarItems()).not.toEqual(doneButtonMatcher);
2112+
expect(getToolbarItems()).toEqual(cancelButtonMatcher);
20782113

20792114
await POM.popup.component.hide();
20802115
scheduler.showAppointmentPopup();
2081-
expect(POM.popup.component.option('toolbarItems')).toMatchObject(toolbarWithSaveButton);
2116+
2117+
expect(getToolbarItems()).toEqual(doneButtonMatcher);
2118+
expect(getToolbarItems()).toEqual(cancelButtonMatcher);
20822119
});
20832120
});
20842121

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

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,50 @@ export class AppointmentPopup {
401401
return false;
402402
}
403403

404+
updateToolbarForMainGroup(): void {
405+
if (this.tryApplyCustomToolbarItems()) {
406+
return;
407+
}
408+
409+
const isCreating = this.state.action === ACTION_TO_APPOINTMENT.CREATE;
410+
const formTitleKey = isCreating ? 'dxScheduler-newPopupTitle' : 'dxScheduler-editPopupTitle';
411+
412+
const toolbarItems: ToolbarItem[] = [{
413+
toolbar: 'top',
414+
location: 'before',
415+
text: messageLocalization.format(formTitleKey),
416+
cssClass: 'dx-toolbar-label',
417+
}];
418+
419+
const canSave = !this.form.readOnly;
420+
if (canSave) {
421+
toolbarItems.push(
422+
{
423+
toolbar: 'top',
424+
location: 'after',
425+
options: {
426+
onClick: (e) => this._saveButtonClickHandler(e),
427+
stylingMode: 'contained',
428+
type: 'default',
429+
text: messageLocalization.format('dxScheduler-editPopupSaveButtonText'),
430+
},
431+
shortcut: 'done',
432+
} as ToolbarItem,
433+
);
434+
}
435+
436+
toolbarItems.push({
437+
toolbar: 'top',
438+
location: 'after',
439+
shortcut: 'cancel',
440+
options: {
441+
stylingMode: 'outlined',
442+
},
443+
} as ToolbarItem);
444+
445+
this.popup.option('toolbarItems', toolbarItems);
446+
}
447+
404448
updateToolbarForRecurrenceGroup(): void {
405449
if (this.tryApplyCustomToolbarItems()) {
406450
return;
@@ -426,66 +470,21 @@ export class AppointmentPopup {
426470
text: messageLocalization.format('dxScheduler-editorLabelRecurrence'),
427471
cssClass: 'dx-toolbar-label',
428472
},
429-
{
473+
];
474+
475+
const canSave = !this.form.readOnly;
476+
if (canSave) {
477+
toolbarItems.push({
430478
toolbar: 'top',
431479
location: 'after',
432-
widget: 'dxButton',
433480
options: {
434-
text: messageLocalization.format('dxScheduler-editPopupSaveButtonText'),
481+
onClick: (e) => this._saveButtonClickHandler(e),
435482
stylingMode: 'contained',
436483
type: 'default',
437-
onClick: (e): void => {
438-
this._saveButtonClickHandler(e);
439-
},
440-
},
441-
},
442-
{
443-
toolbar: 'top',
444-
location: 'after',
445-
widget: 'dxButton',
446-
options: {
447-
text: messageLocalization.format('Cancel'),
448-
stylingMode: 'outlined',
449-
onClick: (): void => {
450-
this.hide();
451-
},
484+
text: messageLocalization.format('dxScheduler-editPopupSaveButtonText'),
452485
},
453-
},
454-
];
455-
456-
this.popup.option('toolbarItems', toolbarItems);
457-
}
458-
459-
updateToolbarForMainGroup(): void {
460-
if (this.tryApplyCustomToolbarItems()) {
461-
return;
462-
}
463-
464-
const isCreating = this.state.action === ACTION_TO_APPOINTMENT.CREATE;
465-
const formTitleKey = isCreating ? 'dxScheduler-newPopupTitle' : 'dxScheduler-editPopupTitle';
466-
467-
const toolbarItems: ToolbarItem[] = [{
468-
toolbar: 'top',
469-
location: 'before',
470-
text: messageLocalization.format(formTitleKey),
471-
cssClass: 'dx-toolbar-label',
472-
}];
473-
474-
const canSave = !this.form.readOnly;
475-
if (canSave) {
476-
toolbarItems.push(
477-
{
478-
toolbar: 'top',
479-
location: 'after',
480-
options: {
481-
onClick: (e) => this._saveButtonClickHandler(e),
482-
stylingMode: 'contained',
483-
type: 'default',
484-
text: messageLocalization.format('dxScheduler-editPopupSaveButtonText'),
485-
},
486-
shortcut: 'done',
487-
} as ToolbarItem,
488-
);
486+
shortcut: 'done',
487+
} as ToolbarItem);
489488
}
490489

491490
toolbarItems.push({

0 commit comments

Comments
 (0)