diff --git a/apps/react-storybook/stories/scheduler/SchedulerAppointmentForm.stories.tsx b/apps/react-storybook/stories/scheduler/SchedulerAppointmentForm.stories.tsx new file mode 100644 index 000000000000..a5c229fe82a6 --- /dev/null +++ b/apps/react-storybook/stories/scheduler/SchedulerAppointmentForm.stories.tsx @@ -0,0 +1,53 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import dxScheduler from "devextreme/ui/scheduler"; +import { wrapDxWithReact } from "../utils"; +import { data, resources } from "./data"; + +const Scheduler = wrapDxWithReact(dxScheduler); + +const meta: Meta = { + title: 'Components/Scheduler/AppointmentForm', + component: Scheduler, + parameters: { + layout: 'padded', + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Overview: Story = { + args: { + 'editing.allowAdding': true, + 'editing.allowUpdating': true, + 'editing.allowDeleting': true, + 'editing.allowDragging': true, + 'editing.allowResizing': true, + 'editing.allowTimeZoneEditing': false, + resources, + height: 600, + views: ['day', 'week', 'workWeek', 'month'], + currentView: 'workWeek', + currentDate: new Date(2021, 3, 29), + dataSource: data + }, + argTypes: { + 'editing.allowAdding': { + control: 'boolean', + }, + 'editing.allowUpdating': { + control: 'boolean', + }, + 'editing.allowTimeZoneEditing': { + control: 'boolean', + }, + 'showResources': { + control: 'boolean', + }, + 'resources': { + control: 'boolean', + mapping: { true: resources, false: [] }, + } + }, +} diff --git a/apps/react-storybook/stories/scheduler/data.ts b/apps/react-storybook/stories/scheduler/data.ts index a27fabba697c..e1eba0ec5aae 100644 --- a/apps/react-storybook/stories/scheduler/data.ts +++ b/apps/react-storybook/stories/scheduler/data.ts @@ -17,3 +17,175 @@ export const assignees = [ color: '#7b49d3', }, ]; + +export const rooms = [ + { + text: 'Room 1', + id: 1, + color: '#00af2c', + }, { + text: 'Room 2', + id: 2, + color: '#56ca85', + }, { + text: 'Room 3', + id: 3, + color: '#8ecd3c', + }, +]; + +export const priorities = [ + { + text: 'High', + id: 1, + color: '#cc5c53', + }, { + text: 'Low', + id: 2, + color: '#ff9747', + }, +]; + +export const resources = [ + { + fieldExpr: 'roomId', + dataSource: rooms, + label: 'Room', + }, { + fieldExpr: 'priorityId', + dataSource: priorities, + label: 'Priority', + }, { + fieldExpr: 'assigneeId', + allowMultiple: true, + dataSource: assignees, + label: 'Assignee', + } +]; + +export const data = [ + { + text: 'Watercolor Landscape', + assigneeId: [4], + roomId: 1, + priorityId: 2, + startDate: new Date('2021-04-26T17:30:00.000Z'), + endDate: new Date('2021-04-26T19:00:00.000Z'), + recurrenceRule: 'FREQ=WEEKLY;BYDAY=MO,TH;COUNT=10', + }, + { + text: 'Website Re-Design Plan', + assigneeId: [4], + roomId: 1, + priorityId: 2, + startDate: new Date('2021-04-26T16:30:00.000Z'), + endDate: new Date('2021-04-26T18:30:00.000Z'), + }, { + text: 'Book Flights to San Fran for Sales Trip', + assigneeId: [2], + roomId: 2, + priorityId: 1, + startDate: new Date('2021-04-26T19:00:00.000Z'), + endDate: new Date('2021-04-26T20:00:00.000Z'), + allDay: true, + }, { + text: 'Install New Router in Dev Room', + assigneeId: [1], + roomId: 1, + priorityId: 2, + startDate: new Date('2021-04-26T21:30:00.000Z'), + endDate: new Date('2021-04-26T22:30:00.000Z'), + }, { + text: 'Approve Personal Computer Upgrade Plan', + assigneeId: [3], + roomId: 2, + priorityId: 2, + startDate: new Date('2021-04-27T17:00:00.000Z'), + endDate: new Date('2021-04-27T18:00:00.000Z'), + }, { + text: 'Final Budget Review', + assigneeId: [1], + roomId: 1, + priorityId: 1, + startDate: new Date('2021-04-27T19:00:00.000Z'), + endDate: new Date('2021-04-27T20:35:00.000Z'), + }, { + text: 'New Brochures', + assigneeId: [4], + roomId: 3, + priorityId: 2, + startDate: new Date('2021-04-27T21:30:00.000Z'), + endDate: new Date('2021-04-27T22:45:00.000Z'), + }, { + text: 'Install New Database', + assigneeId: [2], + roomId: 3, + priorityId: 1, + startDate: new Date('2021-04-28T16:45:00.000Z'), + endDate: new Date('2021-04-28T18:15:00.000Z'), + }, { + text: 'Approve New Online Marketing Strategy', + assigneeId: [4], + roomId: 2, + priorityId: 1, + startDate: new Date('2021-04-28T19:00:00.000Z'), + endDate: new Date('2021-04-28T21:00:00.000Z'), + }, { + text: 'Upgrade Personal Computers', + assigneeId: [2], + roomId: 2, + priorityId: 2, + startDate: new Date('2021-04-28T22:15:00.000Z'), + endDate: new Date('2021-04-28T23:30:00.000Z'), + }, { + text: 'Customer Workshop', + assigneeId: [3], + roomId: 3, + priorityId: 1, + startDate: new Date('2021-04-29T18:00:00.000Z'), + endDate: new Date('2021-04-29T19:00:00.000Z'), + allDay: true, + }, { + text: 'Prepare 2021 Marketing Plan', + assigneeId: [1], + roomId: 1, + priorityId: 2, + startDate: new Date('2021-04-29T18:00:00.000Z'), + endDate: new Date('2021-04-29T20:30:00.000Z'), + }, { + text: 'Brochure Design Review', + assigneeId: [4], + roomId: 1, + priorityId: 1, + startDate: new Date('2021-04-29T21:00:00.000Z'), + endDate: new Date('2021-04-29T22:30:00.000Z'), + }, { + text: 'Create Icons for Website', + assigneeId: [3], + roomId: 3, + priorityId: 1, + startDate: new Date('2021-04-30T17:00:00.000Z'), + endDate: new Date('2021-04-30T18:30:00.000Z'), + }, { + text: 'Upgrade Server Hardware', + assigneeId: [4], + roomId: 2, + priorityId: 2, + startDate: new Date('2021-04-30T21:30:00.000Z'), + endDate: new Date('2021-04-30T23:00:00.000Z'), + }, { + text: 'Submit New Website Design', + assigneeId: [1], + roomId: 1, + priorityId: 2, + startDate: new Date('2021-04-30T23:30:00.000Z'), + endDate: new Date('2021-05-01T01:00:00.000Z'), + }, { + text: 'Launch New Website', + assigneeId: [2], + roomId: 3, + priorityId: 1, + startDate: new Date('2021-04-30T19:20:00.000Z'), + endDate: new Date('2021-04-30T21:00:00.000Z'), + }, +]; diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/a11y/popup.ts b/e2e/testcafe-devextreme/tests/scheduler/common/a11y/legacyPopup.ts similarity index 87% rename from e2e/testcafe-devextreme/tests/scheduler/common/a11y/popup.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/a11y/legacyPopup.ts index 593c2366ac78..bef7d5c156e8 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/a11y/popup.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/a11y/legacyPopup.ts @@ -16,7 +16,7 @@ test('Scheduler edit appointment is accessible', async (t) => { const scheduler = new Scheduler('#container'); await t.doubleClick(scheduler.getAppointmentByIndex(0).element()); - await t.expect(scheduler.appointmentPopup.isVisible()).ok(); + await t.expect(scheduler.legacyAppointmentPopup.isVisible()).ok(); await a11yCheck(t, checkOptions, '#container'); }).before(async () => { @@ -28,6 +28,7 @@ test('Scheduler edit appointment is accessible', async (t) => { endDate: new Date('2021-03-29T22:30:00.000Z'), recurrenceRule: 'FREQ=DAILY', }], + editing: { legacyForm: true }, recurrenceEditMode: 'series', currentView: 'week', currentDate: new Date(2021, 2, 28), @@ -37,20 +38,20 @@ test('Scheduler edit appointment is accessible', async (t) => { test('Scheduler recurrence editor repeat end accessible', async (t) => { const scheduler = new Scheduler('#container'); const getItem = (index: number) => scheduler - .appointmentPopup + .legacyAppointmentPopup .getEndRepeatRadioButton(index); const getAriaLabel = (index: number) => getItem(index) .getAttribute('aria-label'); await t.doubleClick(scheduler.getAppointmentByIndex(0).element()); - await t.expect(scheduler.appointmentPopup.isVisible()).ok(); + await t.expect(scheduler.legacyAppointmentPopup.isVisible()).ok(); await t .expect(getAriaLabel(1)) .eql('On 22 May 2025') .expect(getAriaLabel(2)) .eql('After') - .typeText(scheduler.appointmentPopup.repeatUntilElement, '2026') + .typeText(scheduler.legacyAppointmentPopup.repeatUntilElement, '2026') .click(getItem(1)) // unfocus input .expect(getAriaLabel(1)) .eql('On 22 May 2026') @@ -68,7 +69,7 @@ test('Scheduler recurrence editor repeat end accessible', async (t) => { .eql('On') .expect(getAriaLabel(2)) .eql('After 1 occurrence(s)') - .typeText(scheduler.appointmentPopup.repeatCountElement, '3') + .typeText(scheduler.legacyAppointmentPopup.repeatCountElement, '3') .click(getItem(2)) // unfocus input .expect(getAriaLabel(1)) .eql('On') @@ -77,6 +78,7 @@ test('Scheduler recurrence editor repeat end accessible', async (t) => { }).before(async () => { await createWidget('dxScheduler', { timeZone: 'America/Los_Angeles', + editing: { legacyForm: true }, dataSource: [{ text: 'Install New Router in Dev Room', startDate: new Date('2021-03-29T21:30:00.000Z'), diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/agenda/keyField.ts b/e2e/testcafe-devextreme/tests/scheduler/common/agenda/keyField.ts index fc4be6d6507a..787c5399299a 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/agenda/keyField.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/agenda/keyField.ts @@ -120,8 +120,8 @@ test('Wrong behavior: editing recurrence appointment does not affect to appointm await t.doubleClick(scheduler.getAppointment('Test').element); await t - .typeText(scheduler.appointmentPopup.subjectElement, 'Updated', { replace: true }) - .click(scheduler.appointmentPopup.doneButton); + .typeText(scheduler.appointmentPopup.textEditor.element, 'Updated', { replace: true }) + .click(scheduler.appointmentPopup.saveButton.element); await t.expect(scheduler.getAppointment('Updated').element.exists).ok(); }).before(async () => { diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=fluent.blue.light).png new file mode 100644 index 000000000000..58a32cf4435d Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..8b4ef5ed9f5a Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=generic.light).png new file mode 100644 index 000000000000..00e291aa0fad Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=generic.light.compact).png new file mode 100644 index 000000000000..9ba22f071e96 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=material.blue.light).png new file mode 100644 index 000000000000..203b08fdffd2 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..2bf943a6f8e7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=false,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=fluent.blue.light).png new file mode 100644 index 000000000000..95f4e05eb884 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..d2b97be7ab24 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=generic.light).png new file mode 100644 index 000000000000..42981c3254c3 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=generic.light.compact).png new file mode 100644 index 000000000000..8ff235d1a139 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=material.blue.light).png new file mode 100644 index 000000000000..8c0d79ba6ab8 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..2c180dabdced Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=false,allDay=true,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=fluent.blue.light).png new file mode 100644 index 000000000000..fa875541c5bc Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..6de0bdef0fc1 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=generic.light).png new file mode 100644 index 000000000000..a19cad4e4f94 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=generic.light.compact).png new file mode 100644 index 000000000000..f4e485d6b96c Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=material.blue.light).png new file mode 100644 index 000000000000..dde5c0049c2a Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..54a31193a101 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=false,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=fluent.blue.light).png new file mode 100644 index 000000000000..fe8dcd53c1f8 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..010f88ef5190 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=generic.light).png new file mode 100644 index 000000000000..f0e0f83d4ab7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=generic.light.compact).png new file mode 100644 index 000000000000..91a192240e3f Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=material.blue.light).png new file mode 100644 index 000000000000..5037aba395e3 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..780e10e776af Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form.png (recurring=true,allDay=true,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=fluent.blue.light).png new file mode 100644 index 000000000000..6b2b3c0aadd7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..1cccdc832f4c Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=generic.light).png new file mode 100644 index 000000000000..49e09ec91c7c Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=generic.light.compact).png new file mode 100644 index 000000000000..fda564ad4498 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=material.blue.light).png new file mode 100644 index 000000000000..f0ae126873da Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..cb7006156481 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=false,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=fluent.blue.light).png new file mode 100644 index 000000000000..10a69a00bf64 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..e7d60a0ef718 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=generic.light).png new file mode 100644 index 000000000000..e97e6296d620 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=generic.light.compact).png new file mode 100644 index 000000000000..6ca3246a8831 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=material.blue.light).png new file mode 100644 index 000000000000..e5767357061e Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..d3490729d833 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=false,allDay=true,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=fluent.blue.light).png new file mode 100644 index 000000000000..8c7e18479c2b Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..e9829cfefc07 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=generic.light).png new file mode 100644 index 000000000000..0f0bbfa295b4 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=generic.light.compact).png new file mode 100644 index 000000000000..6c52039945e2 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=material.blue.light).png new file mode 100644 index 000000000000..e2527a40bb56 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..9dd7f8b20364 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=false,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=fluent.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=fluent.blue.light).png new file mode 100644 index 000000000000..8ff8d8de4228 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=fluent.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=fluent.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=fluent.blue.light.compact).png new file mode 100644 index 000000000000..0d1bcde378a2 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=fluent.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=generic.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=generic.light).png new file mode 100644 index 000000000000..078092cdc09b Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=generic.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=generic.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=generic.light.compact).png new file mode 100644 index 000000000000..71799928570d Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=generic.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=material.blue.light).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=material.blue.light).png new file mode 100644 index 000000000000..6a7132eec34e Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=material.blue.light).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=material.blue.light.compact).png b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=material.blue.light.compact).png new file mode 100644 index 000000000000..7a5c40afa279 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=true,allDay=true,theme=material.blue.light.compact).png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/form.visual.ts b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/form.visual.ts new file mode 100644 index 000000000000..e21fda7331e0 --- /dev/null +++ b/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/form.visual.ts @@ -0,0 +1,141 @@ +import Scheduler from 'devextreme-testcafe-models/scheduler'; +import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; +import AppointmentPopup from 'devextreme-testcafe-models/scheduler/appointment/popup'; +import { ClientFunction } from 'testcafe'; +import { createWidget } from '../../../../helpers/createWidget'; +import url from '../../../../helpers/getPageUrl'; +import { changeTheme } from '../../../../helpers/changeTheme'; +import { safeSizeTest } from '../../../../helpers/safeSizeTest'; + +fixture.disablePageReloads`Appointment Form: Main Form` + .page(url(__dirname, '../../../container.html')); + +const SCHEDULER_SELECTOR = '#container'; + +const openAppointmentPopup = async ( + t: TestController, + appointment: any, + isRecurringAppointment: boolean, +): Promise => { + await ClientFunction((appointmentData) => { + const instance = ($('#container') as any).dxScheduler('instance'); + instance.showAppointmentPopup(appointmentData); + })(appointment); + + const scheduler = new Scheduler(SCHEDULER_SELECTOR); + + if (isRecurringAppointment) { + await t.click(Scheduler.getEditRecurrenceDialog().series); + } + + return scheduler.appointmentPopup; +}; + +const getResources = () => ([ + { + fieldExpr: 'assigneeId', + allowMultiple: true, + label: 'Assignee', + dataSource: [ + { text: 'Samantha Bright', id: 1, color: '#727bd2' }, + { text: 'John Heart', id: 2, color: '#32c9ed' }, + ], + }, + { + fieldExpr: 'roomId', + label: 'Room', + dataSource: [ + { text: 'Room 1', id: 1, color: '#00af2c' }, + ], + }, + { + fieldExpr: 'priorityId', + label: 'Priority', + dataSource: [ + { text: 'High', id: 1, color: '#cc5c53' }, + ], + }, +]); + +const windowSize: [number, number] = [1500, 1500]; + +[ + 'generic.light', + 'generic.light.compact', + 'material.blue.light', + 'material.blue.light.compact', + 'fluent.blue.light', + 'fluent.blue.light.compact', +].forEach((theme) => { + [ + { isRecurringAppointment: false, isAllDay: true }, + { isRecurringAppointment: false, isAllDay: false }, + { isRecurringAppointment: true, isAllDay: true }, + { isRecurringAppointment: true, isAllDay: false }, + ].forEach(({ isRecurringAppointment, isAllDay }) => { + const appointment = { + text: 'Appointment', + startDate: new Date('2021-04-26T16:30:00.000Z'), + endDate: new Date('2021-04-26T18:30:00.000Z'), + allDay: isAllDay, + recurrenceRule: isRecurringAppointment ? 'FREQ=WEEKLY;BYDAY=MO,TH;COUNT=10' : undefined, + assigneeId: [1, 2], + roomId: 1, + priorityId: 1, + }; + + safeSizeTest(`appointment main form (${theme})`, async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + const appointmentPopup = await openAppointmentPopup(t, appointment, isRecurringAppointment); + + await takeScreenshot( + `scheduler__appointment__main-form.png (recurring=${isRecurringAppointment},allDay=${isAllDay},theme=${theme})`, + appointmentPopup.contentElement, + ); + + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); + }).before(async () => { + await changeTheme(theme); + await createWidget('dxScheduler', { + dataSource: [appointment], + views: ['week'], + currentView: 'week', + currentDate: new Date(2021, 2, 25), + }); + }).after(async () => { + await changeTheme('generic.light'); + }); + + safeSizeTest(`appointment main form with resources and timezones (${theme})`, async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + const appointmentPopup = await openAppointmentPopup(t, appointment, isRecurringAppointment); + + await takeScreenshot( + `scheduler__appointment__main-form__with-resources-and-timezones.png (recurring=${isRecurringAppointment},allDay=${isAllDay},theme=${theme})`, + appointmentPopup.contentElement, + ); + + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); + }, windowSize).before(async () => { + await changeTheme(theme); + await createWidget('dxScheduler', { + dataSource: [appointment], + views: ['week'], + currentView: 'week', + currentDate: new Date(2021, 2, 25), + resources: getResources(), + editing: { + allowTimeZoneEditing: true, + }, + }); + }).after(async () => { + await changeTheme('generic.light'); + }); + }); +}); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointments/displayArguments.ts b/e2e/testcafe-devextreme/tests/scheduler/common/appointments/displayArguments.ts index 4d74a698aa7d..be815b9278ce 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointments/displayArguments.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/appointments/displayArguments.ts @@ -14,8 +14,8 @@ fixture.disablePageReloads`Display* arguments in appointment templates and event await t.doubleClick(scheduler.getDateTableCell(1, 0), { speed: 0.5 }); await t - .typeText(scheduler.appointmentPopup.subjectElement, 'text') - .click(scheduler.appointmentPopup.doneButton); + .typeText(scheduler.appointmentPopup.textEditor.element, 'text') + .click(scheduler.appointmentPopup.saveButton.element); await t .expect(scheduler.getAppointmentByIndex(0).element.innerText) diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointments/editing.ts b/e2e/testcafe-devextreme/tests/scheduler/common/appointments/legacyEditing.ts similarity index 93% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointments/editing.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/appointments/legacyEditing.ts index 77a00069511d..a4c611036be5 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointments/editing.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/appointments/legacyEditing.ts @@ -17,7 +17,7 @@ test('Should correctly update appointment if dataSource is a simple array', asyn const scheduler = new Scheduler(SCHEDULER_SELECTOR); const appointment = scheduler.getAppointment(INITIAL_APPOINTMENT_TITLE); const updatedAppointment = scheduler.getAppointment(UPDATED_APPOINTMENT_TITLE); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(appointment.element, CLICK_OPTIONS) @@ -41,13 +41,14 @@ test('Should correctly update appointment if dataSource is a simple array', asyn startDayHour: 9, endDayHour: 14, height: 600, + editing: { legacyForm: true }, })); test('Should correctly update appointment if dataSource is a Store with key array', async (t) => { const scheduler = new Scheduler(SCHEDULER_SELECTOR); const appointment = scheduler.getAppointment(INITIAL_APPOINTMENT_TITLE); const updatedAppointment = scheduler.getAppointment(UPDATED_APPOINTMENT_TITLE); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(appointment.element, CLICK_OPTIONS) @@ -82,6 +83,7 @@ test('Should correctly update appointment if dataSource is a Store with key arra startDayHour: 9, endDayHour: 14, height: 600, + editing: { legacyForm: true }, }).dxScheduler('instance'); devExpress.fx.off = true; }, { dependencies: { SCHEDULER_SELECTOR, INITIAL_APPOINTMENT_TITLE } }); @@ -100,7 +102,7 @@ test('Appointment EditForm screenshot', async (t) => { .expect(await takeScreenshot('appointment-popup-screenshot.png', appointment.element)) .ok() // assert - .expect(scheduler.appointmentPopup.element.exists) + .expect(scheduler.legacyAppointmentPopup.element.exists) .ok() .expect(compareResults.isValid()) .ok(compareResults.errorMessages()); @@ -111,6 +113,7 @@ test('Appointment EditForm screenshot', async (t) => { startDate: new Date(2021, 2, 29, 9, 30), endDate: new Date(2021, 2, 29, 11, 30), }], + editing: { legacyForm: true }, views: ['day'], currentView: 'day', currentDate: new Date(2021, 2, 29), diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointments/resources.ts b/e2e/testcafe-devextreme/tests/scheduler/common/appointments/resources.ts index 8b4e58967fdf..971459fe5b30 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointments/resources.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/appointments/resources.ts @@ -106,11 +106,10 @@ test('Scheduler should renders correctly if resource dataSource is not set', asy test('Resource with allowMultiple should be set correctly for new the appointment (T1075028)', async (t) => { const scheduler = new Scheduler('#container'); const cell = scheduler.getDateTableCell(2, 0); - const popup = scheduler.appointmentPopup; await t .doubleClick(cell) - .expect(popup.element.exists) + .expect(scheduler.appointmentPopup.popup.isVisible()) .ok(); const resourceTagBox = new TagBox('.dx-tagbox'); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/etalons/save-appointment-loading-panel-screenshot.png b/e2e/testcafe-devextreme/tests/scheduler/common/etalons/save-appointment-loading-panel-screenshot.png index e5e161949cb7..c9caaf871486 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/etalons/save-appointment-loading-panel-screenshot.png and b/e2e/testcafe-devextreme/tests/scheduler/common/etalons/save-appointment-loading-panel-screenshot.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/hotkeysBehaviour/hotkeysBehaviour.ts b/e2e/testcafe-devextreme/tests/scheduler/common/hotkeysBehaviour/hotkeysBehaviour.ts index c7443b700eb8..900bf2801a5c 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/hotkeysBehaviour/hotkeysBehaviour.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/hotkeysBehaviour/hotkeysBehaviour.ts @@ -57,7 +57,7 @@ fixture.disablePageReloads`Hotkeys for appointments update and navigation` .click(appointment.element) .expect(appointment.isFocused).ok() .pressKey('enter') - .expect(appointmentPopup.isVisible()) + .expect(appointmentPopup.popup.isVisible()) .ok(); }).before(async () => createScheduler({ views: [view], @@ -68,8 +68,7 @@ fixture.disablePageReloads`Hotkeys for appointments update and navigation` test(`Navigate between tooltip appointments in the "${view}" view (Up/Down)`, async (t) => { const scheduler = new Scheduler('#container'); const collector = scheduler.collectors.find('3'); - const { appointmentPopup } = scheduler; - const { appointmentTooltip } = scheduler; + const { appointmentPopup, appointmentTooltip } = scheduler; await t .click(collector.element) @@ -83,7 +82,7 @@ fixture.disablePageReloads`Hotkeys for appointments update and navigation` .pressKey('enter') .expect(appointmentTooltip.isVisible()) .notOk() - .expect(appointmentPopup.isVisible()) + .expect(appointmentPopup.popup.isVisible()) .ok(); }).before(async () => createScheduler({ views: [view], diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/dataSource.ts b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/dataSource.ts index f240ee3c79d7..bb701f76daf1 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/dataSource.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/dataSource.ts @@ -13,7 +13,7 @@ test('Appointment key should be deleted when removing an appointment from series await t .doubleClick(scheduler.getAppointmentByIndex(1).element) - .click(scheduler.appointmentPopup.doneButton) + .click(scheduler.appointmentPopup.saveButton.element) .expect(await takeScreenshot('exclude-appointment-from-series-via-form-editing.png', scheduler.workSpace)) .ok() diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/disable.ts b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/disable.ts index ae3c92aba17c..0d430175fa7d 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/disable.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/disable.ts @@ -9,32 +9,33 @@ fixture.disablePageReloads`Layout:Appointments:disable` test('Appointment popup should be readOnly if appointment is disabled', async (t) => { const scheduler = new Scheduler('#container'); const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const { appointmentPopup } = scheduler; await t.expect(await takeScreenshot('disabled-appointments-in-grid.png')).ok(); await t.click(scheduler.getAppointment('A', 0).element) .click(scheduler.appointmentTooltip.getListItem('A').element) - .expect(await takeScreenshot('disabled-appointment.png', scheduler.appointmentPopup.content)).ok(); + .expect(await takeScreenshot('disabled-appointment.png', appointmentPopup.contentElement)).ok(); - await t.click(scheduler.appointmentPopup.cancelButton); + await t.click(appointmentPopup.cancelButton.element); await t.click(scheduler.getAppointment('B').element) .click(scheduler.appointmentTooltip.getListItem('B').element) - .expect(await takeScreenshot('enabled-appointment.png', scheduler.appointmentPopup.content)).ok(); + .expect(await takeScreenshot('enabled-appointment.png', appointmentPopup.contentElement)).ok(); - await t.click(scheduler.appointmentPopup.cancelButton); + await t.click(appointmentPopup.cancelButton.element); await t.click(scheduler.getAppointment('C').element) .click(scheduler.appointmentTooltip.getListItem('C').element) - .expect(await takeScreenshot('disabled-by-function-appointment.png', scheduler.appointmentPopup.content)).ok(); + .expect(await takeScreenshot('disabled-by-function-appointment.png', appointmentPopup.contentElement)).ok(); - await t.click(scheduler.appointmentPopup.cancelButton); + await t.click(appointmentPopup.cancelButton.element); await t.click(scheduler.getAppointment('D').element) .click(scheduler.appointmentTooltip.getListItem('D').element) - .expect(await takeScreenshot('enabled-by-function-appointment.png', scheduler.appointmentPopup.content)).ok(); + .expect(await takeScreenshot('enabled-by-function-appointment.png', appointmentPopup.contentElement)).ok(); - await t.click(scheduler.appointmentPopup.cancelButton); + await t.click(appointmentPopup.cancelButton.element); await t.expect(compareResults.isValid()) .ok(compareResults.errorMessages()); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-appointment.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-appointment.png index 55f85c2a01b9..d5cde95e0f6d 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-appointment.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-appointment.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-by-function-appointment.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-by-function-appointment.png index 29f27812d83e..578e65b6f8b6 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-by-function-appointment.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/disabled-by-function-appointment.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-appointment.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-appointment.png index 35db8ffc3109..e62d543eba15 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-appointment.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-appointment.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-by-function-appointment.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-by-function-appointment.png index 6c2ad41d165a..b06524df9b1b 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-by-function-appointment.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointments/etalons/enabled-by-function-appointment.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/allDay.ts b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/allDay.ts similarity index 87% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/allDay.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/allDay.ts index f46d07f6027b..a7fd203d890f 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/allDay.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/allDay.ts @@ -9,6 +9,7 @@ fixture.disablePageReloads`Layout:AppointmentForm:AllDay` test('Start and end dates should be reflect the current day(appointment is already available case)', async (t) => { const scheduler = new Scheduler('#container'); const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .click(scheduler.getAppointment('Text').element) @@ -18,12 +19,12 @@ test('Start and end dates should be reflect the current day(appointment is alrea .ok(); await t - .click(scheduler.appointmentPopup.allDayElement) + .click(appointmentPopup.allDayElement) .expect(await takeScreenshot('appointment-form-after-click-all-day.png')) .ok(); await t - .click(scheduler.appointmentPopup.doneButton) + .click(appointmentPopup.doneButton) .expect(await takeScreenshot('all-day-appointment-on-tables.png')) .ok(); @@ -35,7 +36,7 @@ test('Start and end dates should be reflect the current day(appointment is alrea .ok(); await t - .click(scheduler.appointmentPopup.allDayElement) + .click(appointmentPopup.allDayElement) .expect(await takeScreenshot('appointment-form-after-switch-off-all-day.png')) .ok(); @@ -48,6 +49,7 @@ test('Start and end dates should be reflect the current day(appointment is alrea startDate: new Date(2021, 3, 28, 10), endDate: new Date(2021, 3, 28, 12), }], + editing: { legacyForm: true }, views: ['week'], currentView: 'week', currentDate: new Date(2021, 3, 29), @@ -59,6 +61,7 @@ test('Start and end dates should be reflect the current day(appointment is alrea test('Start and end dates should be reflect the current day(create new appointment case)', async (t) => { const scheduler = new Scheduler('#container'); const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(scheduler.getDateTableCell(2, 3)) @@ -66,12 +69,12 @@ test('Start and end dates should be reflect the current day(create new appointme .ok(); await t - .click(scheduler.appointmentPopup.allDayElement) + .click(appointmentPopup.allDayElement) .expect(await takeScreenshot('new-appointment-form-after-click-all-day.png')) .ok(); await t - .click(scheduler.appointmentPopup.doneButton) + .click(appointmentPopup.doneButton) .expect(await takeScreenshot('new-all-day-appointment-on-tables.png')) .ok(); @@ -83,7 +86,7 @@ test('Start and end dates should be reflect the current day(create new appointme .ok(); await t - .click(scheduler.appointmentPopup.allDayElement) + .click(appointmentPopup.allDayElement) .expect(await takeScreenshot('new-appointment-form-after-switch-off-all-day.png')) .ok(); @@ -93,6 +96,7 @@ test('Start and end dates should be reflect the current day(create new appointme await createWidget('dxScheduler', { dataSource: [], views: ['week'], + editing: { legacyForm: true }, currentView: 'week', currentDate: new Date(2021, 3, 29), startDayHour: 9, @@ -102,7 +106,7 @@ test('Start and end dates should be reflect the current day(create new appointme test('StartDate and endDate should have correct type after "allDay" and "repeat" option are changed (T1002864)', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; const { takeScreenshot, compareResults } = createScreenshotsComparer(t); @@ -121,4 +125,5 @@ test('StartDate and endDate should have correct type after "allDay" and "repeat" .ok(compareResults.errorMessages()); }).before(async () => createWidget('dxScheduler', { currentDate: new Date(2021, 1, 1), + editing: { legacyForm: true }, })); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/common.ts b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/common.ts similarity index 88% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/common.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/common.ts index d7111726eaee..2252ea25ba5e 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/common.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/common.ts @@ -10,19 +10,19 @@ fixture`AppointmentForm screenshot tests` ['generic.light', 'material.blue.light', 'fluent.blue.light'].forEach((theme) => { test('Appointemt form tests', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; const { takeScreenshot, compareResults } = createScreenshotsComparer(t); await t .doubleClick(scheduler.getDateTableCell(0, 0)) - .expect(await takeScreenshot(`initial-form_${theme}.png`, scheduler.appointmentPopup.content)) + .expect(await takeScreenshot(`initial-form_${theme}.png`, appointmentPopup.content)) .ok() .click(appointmentPopup.allDayElement) .click(appointmentPopup.recurrenceElement) - .expect(await takeScreenshot(`allday-and-reccurence-form_${theme}.png`, scheduler.appointmentPopup.content)) + .expect(await takeScreenshot(`allday-and-reccurence-form_${theme}.png`, appointmentPopup.content)) .ok() .expect(compareResults.isValid()) @@ -31,6 +31,7 @@ fixture`AppointmentForm screenshot tests` await changeTheme(theme); await createWidget('dxScheduler', { currentDate: new Date(2021, 1, 1), + editing: { legacyForm: true }, }); }).after(async () => { await changeTheme('generic.light'); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/all-day-appointment-on-tables.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/all-day-appointment-on-tables.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/all-day-appointment-on-tables.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/all-day-appointment-on-tables.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/allday-and-reccurence-form_fluent.blue.light.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/allday-and-reccurence-form_fluent.blue.light.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/allday-and-reccurence-form_fluent.blue.light.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/allday-and-reccurence-form_fluent.blue.light.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/allday-and-reccurence-form_generic.light.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/allday-and-reccurence-form_generic.light.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/allday-and-reccurence-form_generic.light.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/allday-and-reccurence-form_generic.light.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/allday-and-reccurence-form_material.blue.light.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/allday-and-reccurence-form_material.blue.light.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/allday-and-reccurence-form_material.blue.light.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/allday-and-reccurence-form_material.blue.light.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-after-click-all-day.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-after-click-all-day.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-after-click-all-day.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-after-click-all-day.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-after-render-on-table.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-after-render-on-table.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-after-render-on-table.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-after-render-on-table.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-after-switch-off-all-day.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-after-switch-off-all-day.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-after-switch-off-all-day.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-after-switch-off-all-day.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-before-click-all-day.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-before-click-all-day.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-before-click-all-day.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-before-click-all-day.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-in-mobile-environment.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-in-mobile-environment.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/appointment-form-in-mobile-environment.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/appointment-form-in-mobile-environment.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/dx-number-boxes-not-integer-chars.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/dx-number-boxes-not-integer-chars.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/dx-number-boxes-not-integer-chars.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/dx-number-boxes-not-integer-chars.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/form-after-change-allday-and-reccurence-options.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/form-after-change-allday-and-reccurence-options.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/form-after-change-allday-and-reccurence-options.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/form-after-change-allday-and-reccurence-options.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/form-before-change-allday-and-reccurence-options.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/form-before-change-allday-and-reccurence-options.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/form-before-change-allday-and-reccurence-options.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/form-before-change-allday-and-reccurence-options.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/initial-form_fluent.blue.light.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/initial-form_fluent.blue.light.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/initial-form_fluent.blue.light.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/initial-form_fluent.blue.light.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/initial-form_generic.light.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/initial-form_generic.light.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/initial-form_generic.light.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/initial-form_generic.light.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/initial-form_material.blue.light.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/initial-form_material.blue.light.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/initial-form_material.blue.light.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/initial-form_material.blue.light.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-all-day-appointment-on-tables.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-all-day-appointment-on-tables.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-all-day-appointment-on-tables.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-all-day-appointment-on-tables.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-after-click-all-day.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-after-click-all-day.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-after-click-all-day.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-after-click-all-day.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-after-render-on-table.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-after-render-on-table.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-after-render-on-table.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-after-render-on-table.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-after-switch-off-all-day.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-after-switch-off-all-day.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-after-switch-off-all-day.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-after-switch-off-all-day.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-before-click-all-day.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-before-click-all-day.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/etalons/new-appointment-form-before-click-all-day.png rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/etalons/new-appointment-form-before-click-all-day.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/integerFormatNumberBox.ts b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/integerFormatNumberBox.ts similarity index 91% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/integerFormatNumberBox.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/integerFormatNumberBox.ts index 928ccfc3013a..91f73fa7b1df 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/integerFormatNumberBox.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/integerFormatNumberBox.ts @@ -8,7 +8,7 @@ fixture.disablePageReloads`Layout:AppointmentForm:IntegerFormatNumberBox` test('dxNumberBox should not allow to enter not integer chars(T1002864)', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; const { takeScreenshot, compareResults } = createScreenshotsComparer(t); @@ -19,7 +19,7 @@ test('dxNumberBox should not allow to enter not integer chars(T1002864)', async .typeText(appointmentPopup.repeatEveryElement, '.,2', { speed: 0.5 }); await t - .expect(await takeScreenshot('dx-number-boxes-not-integer-chars.png', scheduler.appointmentPopup.content)) + .expect(await takeScreenshot('dx-number-boxes-not-integer-chars.png', appointmentPopup.content)) .ok(); await t @@ -32,6 +32,7 @@ test('dxNumberBox should not allow to enter not integer chars(T1002864)', async endDate: new Date(2021, 3, 26, 11), recurrenceRule: 'FREQ=WEEKLY;BYDAY=MO,TH;UNTIL=20220114T205959Z', }], + editing: { legacyForm: true }, views: ['day', 'week', 'workWeek', 'month'], currentView: 'week', currentDate: new Date(2021, 3, 29), diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/mobileEnvironment.ts b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/mobileEnvironment.ts similarity index 97% rename from e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/mobileEnvironment.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/mobileEnvironment.ts index 95ab5547927e..a87022fc79a6 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/layout/appointmentForm/mobileEnvironment.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/layout/legacyAppointmentForm/mobileEnvironment.ts @@ -30,5 +30,6 @@ safeSizeTest('Appointment form should be display valid layout', async (t) => { currentDate: new Date(2021, 3, 29), startDayHour: 9, height: 600, + editing: { legacyForm: true }, }); }); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-month-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-month-with-form.png index 45ec421b53f3..9f8578d56b20 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-month-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-month-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineDay-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineDay-with-form.png index f6d2c56cfa76..be04e0f541e9 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineDay-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineDay-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineMonth-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineMonth-with-form.png index 1875162c2a66..9db36d677a21 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineMonth-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineMonth-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWeek-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWeek-with-form.png index 8c96634002b3..2ecbf0e8662c 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWeek-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWeek-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWorkWeek-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWorkWeek-with-form.png index e1387d8aa92e..4e01b0b1b289 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWorkWeek-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-timelineWorkWeek-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-week-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-week-with-form.png index cc28dbda7212..7506916d7b10 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-week-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-week-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-workWeek-with-form.png b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-workWeek-with-form.png index bb869e45ddf1..0eeef827aeb3 100644 Binary files a/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-workWeek-with-form.png and b/e2e/testcafe-devextreme/tests/scheduler/common/layout/views/intervalCount/etalons/start-date-in-workWeek-with-form.png differ diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm.ts similarity index 91% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm.ts index 2e97f0c2809e..d95c1992c010 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm.ts @@ -3,14 +3,14 @@ import Scheduler from 'devextreme-testcafe-models/scheduler'; import { createWidget } from '../../../helpers/createWidget'; import url from '../../../helpers/getPageUrl'; -fixture.disablePageReloads`Appointment popup form` +fixture.disablePageReloads`Legacy appointment popup form` .page(url(__dirname, '../../container.html')); test('Subject and description fields should be empty after showing popup on empty cell', async (t) => { const APPOINTMENT_TEXT = 'Website Re-Design Plan'; const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t.doubleClick(scheduler.getAppointment(APPOINTMENT_TEXT).element) .expect(appointmentPopup.subjectElement.value) @@ -32,6 +32,7 @@ test('Subject and description fields should be empty after showing popup on empt currentDate: new Date(2017, 4, 22), height: 600, width: 600, + editing: { legacyForm: true }, dataSource: [ { text: 'Website Re-Design Plan', @@ -57,7 +58,7 @@ test('Custom form shouldn\'t throw exception, after second show appointment form .expect(Selector(TEXT_EDITOR_CLASS).value) .eql(APPOINTMENT_TEXT) - .click(scheduler.appointmentPopup.cancelButton) + .click(scheduler.legacyAppointmentPopup.cancelButton) .click(scheduler.getAppointment(APPOINTMENT_TEXT).element) .click(scheduler.appointmentTooltip.getListItem(APPOINTMENT_TEXT).element) @@ -70,6 +71,7 @@ test('Custom form shouldn\'t throw exception, after second show appointment form currentDate: new Date(2017, 4, 22), height: 600, width: 600, + editing: { legacyForm: true }, onAppointmentFormOpening: (e) => { const items = [{ name: 'show1', @@ -102,7 +104,7 @@ test('Appointment should have correct form data on consecutive shows (T832711)', const APPOINTMENT_TEXT = 'Google AdWords Strategy'; const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(scheduler.getAppointment(APPOINTMENT_TEXT).element) @@ -130,6 +132,7 @@ test('Appointment should have correct form data on consecutive shows (T832711)', currentView: 'month', currentDate: new Date(2017, 4, 25), endDayHour: 20, + editing: { legacyForm: true }, dataSource: [{ text: 'Google AdWords Strategy', startDate: new Date(2017, 4, 1), @@ -142,7 +145,7 @@ test('Appointment should have correct form data on consecutive shows (T832711)', test('From elements for disabled appointments should be read only (T835731)', async (t) => { const APPOINTMENT_TEXT = 'Install New Router in Dev Room'; const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t.doubleClick(scheduler.getAppointment(APPOINTMENT_TEXT).element) .expect(appointmentPopup.freqElement.hasClass('dx-state-readonly')).ok() @@ -169,6 +172,7 @@ test('From elements for disabled appointments should be read only (T835731)', as disabled: true, recurrenceRule: 'FREQ=DAILY', }], + editing: { legacyForm: true }, currentView: 'week', recurrenceEditMode: 'series', currentDate: new Date(2017, 4, 25), @@ -178,7 +182,7 @@ test('From elements for disabled appointments should be read only (T835731)', as test('AppointmentForm should display correct dates in work-week when firstDayOfWeek is used', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(scheduler.getDateTableCell(2, 4)) @@ -191,6 +195,7 @@ test('AppointmentForm should display correct dates in work-week when firstDayOfW }).before(async () => createWidget('dxScheduler', { views: ['workWeek'], currentView: 'workWeek', + editing: { legacyForm: true }, currentDate: new Date(2021, 5, 28), startDayHour: 5, height: 600, diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/appointmentPopupErrors.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/appointmentPopupErrors.ts similarity index 96% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/appointmentPopupErrors.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/appointmentPopupErrors.ts index cbd0851bb062..4096577f7ce2 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/appointmentPopupErrors.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/appointmentPopupErrors.ts @@ -28,5 +28,8 @@ test('Appointment popup shouldn\'t raise error if appointment is recursive', asy currentView: 'month', currentDate: new Date(2020, 10, 25), height: 600, + editing: { + legacyForm: true, + }, }); }); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/dataEditors.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/dataEditors.ts similarity index 92% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/dataEditors.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/dataEditors.ts index 4db3ccb5e1e2..56eb1ac4553d 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/dataEditors.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/dataEditors.ts @@ -7,7 +7,7 @@ fixture.disablePageReloads`Appointment popup form:date editors` test('Form date editors should be pass numeric chars according by date mask', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(scheduler.getAppointment('Website Re-Design Plan').element); @@ -51,11 +51,14 @@ test('Form date editors should be pass numeric chars according by date mask', as currentDate: new Date(2021, 2, 28), startDayHour: 9, height: 600, + editing: { + legacyForm: true, + }, })); test('Form date editors should not be pass chars according by date mask', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(scheduler.getAppointment('Website Re-Design Plan').element); @@ -99,11 +102,14 @@ test('Form date editors should not be pass chars according by date mask', async currentDate: new Date(2021, 2, 28), startDayHour: 9, height: 600, + editing: { + legacyForm: true, + }, })); test('Form date editors should not be pass chars after remove all characters according by date mask', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t .doubleClick(scheduler.getAppointment('Website Re-Design Plan').element); @@ -123,7 +129,7 @@ test('Form date editors should not be pass chars after remove all characters acc await t .click(appointmentPopup.endDateElement) - .selectText(scheduler.appointmentPopup.endDateElement) + .selectText(appointmentPopup.endDateElement) .pressKey('backspace') .typeText(appointmentPopup.endDateElement, 'TEXT') @@ -159,4 +165,7 @@ test('Form date editors should not be pass chars after remove all characters acc currentDate: new Date(2021, 2, 28), startDayHour: 9, height: 600, + editing: { + legacyForm: true, + }, })); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/form_recurrence-editor-first-opening_nested-expr.png b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/etalons/form_recurrence-editor-first-opening_nested-expr.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/form_recurrence-editor-first-opening_nested-expr.png rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/etalons/form_recurrence-editor-first-opening_nested-expr.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/recurrence-editor_after-hide.png b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/etalons/recurrence-editor_after-hide.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/recurrence-editor_after-hide.png rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/etalons/recurrence-editor_after-hide.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/recurrence-editor_after-popup-reopen.png b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/etalons/recurrence-editor_after-popup-reopen.png similarity index 100% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/etalons/recurrence-editor_after-popup-reopen.png rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/etalons/recurrence-editor_after-popup-reopen.png diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/expressions.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/expressions.ts similarity index 90% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/expressions.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/expressions.ts index 6b2c1febf3d4..e7bd3e761570 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/expressions.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/expressions.ts @@ -20,9 +20,9 @@ const getDataSourceValues = ClientFunction(() => ($(SCHEDULER_SELECTOR) as any) const TEXT_TEST_CASES = { editor: 'text', errorMessage: 'appointment\'s text incorrect', - getValue: async (scheduler: Scheduler) => scheduler.appointmentPopup.subjectElement().value, + getValue: async (scheduler: Scheduler) => scheduler.legacyAppointmentPopup.subjectElement().value, setValue: async (t: TestController, scheduler: Scheduler, value: string) => t - .typeText(scheduler.appointmentPopup.subjectElement, value, { replace: true }), + .typeText(scheduler.legacyAppointmentPopup.subjectElement, value, { replace: true }), setTestValue: '???', expectedValue: TEST_TITLE, cases: [ @@ -72,9 +72,10 @@ const TEXT_TEST_CASES = { const DESCRIPTION_TEST_CASES = { editor: 'description', errorMessage: 'appointment\'s description incorrect', - getValue: async (scheduler: Scheduler) => scheduler.appointmentPopup.descriptionElement().value, + getValue: async (scheduler: Scheduler) => scheduler + .legacyAppointmentPopup.descriptionElement().value, setValue: async (t: TestController, scheduler: Scheduler, value: string) => t - .typeText(scheduler.appointmentPopup.descriptionElement, value, { replace: true }), + .typeText(scheduler.legacyAppointmentPopup.descriptionElement, value, { replace: true }), setTestValue: '???', expectedValue: TEST_DESCRIPTION, cases: [ @@ -127,9 +128,10 @@ const DESCRIPTION_TEST_CASES = { const START_DATE_TEST_CASES = { editor: 'startDate', errorMessage: 'appointment\'s startDate incorrect', - getValue: async (scheduler: Scheduler) => scheduler.appointmentPopup.startDateElement().value, + getValue: async (scheduler: Scheduler) => scheduler + .legacyAppointmentPopup.startDateElement().value, setValue: async (t: TestController, scheduler: Scheduler, value: string) => t - .typeText(scheduler.appointmentPopup.startDateElement, value, { replace: true }), + .typeText(scheduler.legacyAppointmentPopup.startDateElement, value, { replace: true }), setTestValue: '10/10/2020, 01:00 AM', expectedValue: '12/10/2023, 10:00 AM', cases: [ @@ -179,9 +181,9 @@ const START_DATE_TEST_CASES = { const END_DATE_TEST_CASES = { editor: 'endDate', errorMessage: 'appointment\'s endDate incorrect', - getValue: async (scheduler: Scheduler) => scheduler.appointmentPopup.endDateElement().value, + getValue: async (scheduler: Scheduler) => scheduler.legacyAppointmentPopup.endDateElement().value, setValue: async (t: TestController, scheduler: Scheduler, value: string) => t - .typeText(scheduler.appointmentPopup.endDateElement, value, { replace: true }), + .typeText(scheduler.legacyAppointmentPopup.endDateElement, value, { replace: true }), setTestValue: '10/10/2020, 01:00 AM', expectedValue: '12/10/2023, 2:00 PM', cases: [ @@ -232,12 +234,12 @@ const ALL_DAY_TEST_CASES = { editor: 'allDay', errorMessage: 'appointment\'s allDay incorrect', getValue: async (scheduler: Scheduler) => scheduler - .appointmentPopup.getAllDaySwitchValue(), + .legacyAppointmentPopup.getAllDaySwitchValue(), setValue: async (t: TestController, scheduler: Scheduler, value: string) => { - const currentValue = await scheduler.appointmentPopup.getAllDaySwitchValue(); + const currentValue = await scheduler.legacyAppointmentPopup.getAllDaySwitchValue(); if (currentValue !== value) { - await t.click(scheduler.appointmentPopup.allDayElement); + await t.click(scheduler.legacyAppointmentPopup.allDayElement); } }, setTestValue: 'false', @@ -294,8 +296,8 @@ const ALL_DAY_TEST_CASES = { const START_DATE_TIME_ZONE_TEST_CASES = { editor: 'startDateTimeZone', errorMessage: 'appointment\'s startDateTimeZone incorrect', - getValue: async (scheduler: Scheduler) => scheduler - .appointmentPopup.startDateTimeZoneElement().value, + // eslint-disable-next-line @stylistic/max-len + getValue: async (scheduler: Scheduler) => scheduler.legacyAppointmentPopup.startDateTimeZoneElement().value, expectedValue: '(GMT -01:00) Etc - GMT+1', cases: [ { @@ -357,7 +359,7 @@ const END_DATE_TIME_ZONE_TEST_CASES = { editor: 'endDateTimeZone', errorMessage: 'appointment\'s endDateTimeZone incorrect', getValue: async (scheduler: Scheduler) => scheduler - .appointmentPopup.endDateTimeZoneElement().value, + .legacyAppointmentPopup.endDateTimeZoneElement().value, expectedValue: '(GMT -02:00) Etc - GMT+2', cases: [ { @@ -419,7 +421,7 @@ const RECURRENCE_RULE_TEST_CASES = { editor: 'recurrenceRule', errorMessage: 'appointment\'s recurrenceRule incorrect', getValue: async (scheduler: Scheduler) => scheduler - .appointmentPopup.getRecurrenceRuleSwitchValue(), + .legacyAppointmentPopup.getRecurrenceRuleSwitchValue(), expectedValue: 'true', cases: [ { @@ -508,6 +510,10 @@ const RECURRENCE_RULE_TEST_CASES = { currentDate: '2023-12-10', cellDuration: 240, ...options, + editing: { + legacyForm: true, + ...options.editing, + }, }); }); }); @@ -539,7 +545,7 @@ const RECURRENCE_RULE_TEST_CASES = { await t.doubleClick(appointment.element); await setValue(t, scheduler, setTestValue); - await t.click(scheduler.appointmentPopup.cancelButton); + await t.click(scheduler.legacyAppointmentPopup.cancelButton); const dataSource = await getDataSourceValues(); @@ -549,6 +555,10 @@ const RECURRENCE_RULE_TEST_CASES = { currentDate: '2023-12-10', cellDuration: 240, ...options, + editing: { + legacyForm: true, + ...options.editing, + }, }); }); }); @@ -562,11 +572,11 @@ test( const appointment = scheduler.getAppointment(TEST_TITLE); await t.doubleClick(appointment.element); - await t.expect(scheduler.appointmentPopup.form.exists).ok(); + await t.expect(scheduler.legacyAppointmentPopup.form.exists).ok(); await takeScreenshot( 'form_recurrence-editor-first-opening_nested-expr.png', - scheduler.appointmentPopup.content, + scheduler.legacyAppointmentPopup.content, ); await t.expect(compareResults.isValid()) @@ -592,5 +602,8 @@ test( cellDuration: 240, recurrenceEditMode: 'series', recurrenceRuleExpr: 'nestedA.nestedB.nestedC.recurrenceRuleCustom', + editing: { + legacyForm: true, + }, }); }); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/recurrenceEditor.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/recurrenceEditor.ts similarity index 85% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/recurrenceEditor.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/recurrenceEditor.ts index 0f4f97fe0e3e..99b34d329a0e 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/recurrenceEditor.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/recurrenceEditor.ts @@ -1,6 +1,6 @@ import Scheduler from 'devextreme-testcafe-models/scheduler'; import { createScreenshotsComparer } from 'devextreme-screenshot-comparer'; -import AppointmentPopup from 'devextreme-testcafe-models/scheduler/appointment/popup'; +import LegacyAppointmentPopup from 'devextreme-testcafe-models/scheduler/appointment/legacyPopup'; import { createWidget } from '../../../../helpers/createWidget'; import url from '../../../../helpers/getPageUrl'; @@ -9,7 +9,10 @@ fixture.disablePageReloads`Appointment Form: recurrence editor` const SCHEDULER_SELECTOR = '#container'; -const fillRecurrenceForm = async (t: TestController, popup: AppointmentPopup): Promise => { +const fillRecurrenceForm = async ( + t: TestController, + popup: LegacyAppointmentPopup, +): Promise => { await t.click(popup.recurrenceTypeElement); await t.click(popup.getRecurrenceTypeSelectItem(2)); await t.typeText(popup.repeatEveryElement, '10', { replace: true }); @@ -20,7 +23,7 @@ const fillRecurrenceForm = async (t: TestController, popup: AppointmentPopup): P test('Should not reset the recurrence editor value after the repeat toggling', async (t) => { const { takeScreenshot, compareResults } = createScreenshotsComparer(t); const scheduler = new Scheduler(SCHEDULER_SELECTOR); - const popup = scheduler.appointmentPopup; + const popup = scheduler.legacyAppointmentPopup; const cell = scheduler.getDateTableCell(0, 0); await t.doubleClick(cell); @@ -39,13 +42,16 @@ test('Should not reset the recurrence editor value after the repeat toggling', a views: ['week'], currentView: 'week', currentDate: '2024-01-01T10:00:00', + editing: { + legacyForm: true, + }, }); }); test('Should reset the recurrence editor value after the popup reopening', async (t) => { const { takeScreenshot, compareResults } = createScreenshotsComparer(t); const scheduler = new Scheduler(SCHEDULER_SELECTOR); - const popup = scheduler.appointmentPopup; + const popup = scheduler.legacyAppointmentPopup; const cell = scheduler.getDateTableCell(0, 0); await t.doubleClick(cell); @@ -65,12 +71,15 @@ test('Should reset the recurrence editor value after the popup reopening', async views: ['week'], currentView: 'week', currentDate: '2024-01-01T10:00:00', + editing: { + legacyForm: true, + }, }); }); test('Should correctly create usual appointment after repeat toggling', async (t) => { const scheduler = new Scheduler(SCHEDULER_SELECTOR); - const popup = scheduler.appointmentPopup; + const popup = scheduler.legacyAppointmentPopup; const cell = scheduler.getDateTableCell(0, 0); await t.doubleClick(cell); @@ -85,12 +94,15 @@ test('Should correctly create usual appointment after repeat toggling', async (t views: ['week'], currentView: 'week', currentDate: '2024-01-01T10:00:00', + editing: { + legacyForm: true, + }, }); }); test('Should correctly create recurrent appointment', async (t) => { const scheduler = new Scheduler(SCHEDULER_SELECTOR); - const popup = scheduler.appointmentPopup; + const popup = scheduler.legacyAppointmentPopup; const cell = scheduler.getDateTableCell(0, 0); await t.doubleClick(cell); @@ -104,12 +116,15 @@ test('Should correctly create recurrent appointment', async (t) => { views: ['week'], currentView: 'week', currentDate: '2024-01-01T10:00:00', + editing: { + legacyForm: true, + }, }); }); test('Should correctly create recurrent appointment after repeat toggle', async (t) => { const scheduler = new Scheduler(SCHEDULER_SELECTOR); - const popup = scheduler.appointmentPopup; + const popup = scheduler.legacyAppointmentPopup; const cell = scheduler.getDateTableCell(0, 0); await t.doubleClick(cell); @@ -125,5 +140,8 @@ test('Should correctly create recurrent appointment after repeat toggle', async views: ['week'], currentView: 'week', currentDate: '2024-01-01T10:00:00', + editing: { + legacyForm: true, + }, }); }); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/showAppointmentPopup.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/showAppointmentPopup.ts similarity index 85% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/showAppointmentPopup.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/showAppointmentPopup.ts index 85e1a040911d..68fb3c8cd2b5 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/showAppointmentPopup.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/showAppointmentPopup.ts @@ -16,10 +16,10 @@ test('Invoke showAppointmentPopup method shouldn\'t raise error if value of curr await showAppointmentPopup(); - await t.expect(scheduler.appointmentPopup.startDateElement.value) + await t.expect(scheduler.legacyAppointmentPopup.startDateElement.value) .eql('3/25/2021, 12:00 AM'); - await t.expect(scheduler.appointmentPopup.endDateElement.value) + await t.expect(scheduler.legacyAppointmentPopup.endDateElement.value) .eql('3/25/2021, 12:30 AM'); }).before(async () => createWidget('dxScheduler', { dataSource: [], @@ -27,6 +27,9 @@ test('Invoke showAppointmentPopup method shouldn\'t raise error if value of curr currentView: 'week', currentDate: new Date(2021, 2, 25).toISOString(), height: 600, + editing: { + legacyForm: true, + }, })); test('Show appointment popup if deffereRendering is false (T1069753)', async (t) => { @@ -35,7 +38,7 @@ test('Show appointment popup if deffereRendering is false (T1069753)', async (t) await t .doubleClick(appointment.element) - .expect(scheduler.appointmentPopup.isVisible) + .expect(scheduler.legacyAppointmentPopup.isVisible) .ok(); }).before(async () => { await ClientFunction(() => { @@ -58,5 +61,8 @@ test('Show appointment popup if deffereRendering is false (T1069753)', async (t) startDayHour: 9, endDayHour: 12, width: 400, + editing: { + legacyForm: true, + }, }); }); diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/timezoneEditors.ts b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/timezoneEditors.ts similarity index 93% rename from e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/timezoneEditors.ts rename to e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/timezoneEditors.ts index 16909448b1d1..dc05d93e7c32 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/appointmentForm/timezoneEditors.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/legacyAppointmentForm/timezoneEditors.ts @@ -20,7 +20,7 @@ const endDateTimeZoneValue = '(GMT -08:00) US - Alaska'; test('TimeZone editors should be have data after hide forms data(T1080932)', async (t) => { const scheduler = new Scheduler('#container'); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t.doubleClick(scheduler.getAppointmentByIndex(0).element); @@ -37,6 +37,7 @@ test('TimeZone editors should be have data after hide forms data(T1080932)', asy }, editing: { allowTimeZoneEditing: true, + legacyForm: true, }, recurrenceEditMode: 'series', views: ['month'], @@ -52,7 +53,7 @@ test('TimeZone editors should be have data in default case(T1080932)', async (t) await t.doubleClick(scheduler.getAppointmentByIndex(0).element); - const { appointmentPopup } = scheduler; + const { legacyAppointmentPopup: appointmentPopup } = scheduler; await t.doubleClick(scheduler.getAppointmentByIndex(0).element); @@ -66,6 +67,7 @@ test('TimeZone editors should be have data in default case(T1080932)', async (t) dataSource, editing: { allowTimeZoneEditing: true, + legacyForm: true, }, recurrenceEditMode: 'series', views: ['month'], diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/loadingPanel.ts b/e2e/testcafe-devextreme/tests/scheduler/common/loadingPanel.ts index 684b165affa8..6c1b92ea4789 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/loadingPanel.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/loadingPanel.ts @@ -18,9 +18,9 @@ test('Save appointment loading panel screenshot', async (t) => { await t .doubleClick(appointment.element) - .click(appointmentPopup.subjectElement) - .typeText(appointmentPopup.subjectElement, ADDITIONAL_TITLE_TEXT) - .click(appointmentPopup.doneButton) + .click(appointmentPopup.textEditor.element) + .typeText(appointmentPopup.textEditor.element, ADDITIONAL_TITLE_TEXT) + .click(appointmentPopup.saveButton.element) // act .expect(await takeScreenshot('save-appointment-loading-panel-screenshot.png', scheduler.element)) .ok() diff --git a/e2e/testcafe-devextreme/tests/scheduler/common/timezone/T1102713/recurrenceAppointmentInDstTimeEditing.ts b/e2e/testcafe-devextreme/tests/scheduler/common/timezone/T1102713/recurrenceAppointmentInDstTimeEditing.ts index 43aace58d1f7..75257f47adc1 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/common/timezone/T1102713/recurrenceAppointmentInDstTimeEditing.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/common/timezone/T1102713/recurrenceAppointmentInDstTimeEditing.ts @@ -44,7 +44,7 @@ async function editingPopupTestFunction(t: TestController, screenshotName: strin await t.click(appointmentDialog.series); const { appointmentPopup } = scheduler; - await t.click(appointmentPopup.doneButton); + await t.click(appointmentPopup.saveButton.element); await takeScreenshot(`${SCREENSHOT_BASE_NAME}__${screenshotName}.png`, screenshotZone); diff --git a/e2e/testcafe-devextreme/tests/scheduler/viewOffset/common/apiCallbacks.ts b/e2e/testcafe-devextreme/tests/scheduler/viewOffset/common/apiCallbacks.ts index c1582f942976..51a725c8d0dc 100644 --- a/e2e/testcafe-devextreme/tests/scheduler/viewOffset/common/apiCallbacks.ts +++ b/e2e/testcafe-devextreme/tests/scheduler/viewOffset/common/apiCallbacks.ts @@ -129,7 +129,6 @@ const EXPECTED = { test(`onAppointmentAdding and onAppointmentAdded (offset: ${offset})`, async (t) => { const scheduler = new Scheduler(SCHEDULER_SELECTOR); const cell = scheduler.getDateTableCell(1, 2); - const popupDoneButton = scheduler.appointmentPopup.doneButton; const expectedAppointmentData = { allDay: false, @@ -139,7 +138,7 @@ const EXPECTED = { }; await t.doubleClick(cell); - await t.click(popupDoneButton); + await t.click(scheduler.appointmentPopup.saveButton.element); const [appointmentAddingData] = await CallbackTestHelper .getClientResults(API_CALLBACKS.appointmentAdding); diff --git a/packages/devextreme-scss/scss/widgets/base/scheduler/_common.scss b/packages/devextreme-scss/scss/widgets/base/scheduler/_common.scss index 2112c0eb101c..b34a4ed89777 100644 --- a/packages/devextreme-scss/scss/widgets/base/scheduler/_common.scss +++ b/packages/devextreme-scss/scss/widgets/base/scheduler/_common.scss @@ -16,7 +16,7 @@ $scheduler-popup-scrollable-content-padding: 20px; clip-path: polygon(0 0); } -.dx-scheduler-appointment-popup { +.dx-scheduler-legacy-appointment-popup { .dx-popup-content { padding-top: 0; padding-bottom: 0; diff --git a/packages/devextreme-scss/scss/widgets/base/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/base/scheduler/_index.scss index dc742b5cc42b..a317a8fea672 100644 --- a/packages/devextreme-scss/scss/widgets/base/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/base/scheduler/_index.scss @@ -462,6 +462,73 @@ $scheduler-appointment-form-label-padding: 20px; } .dx-scheduler-appointment-popup { + .dx-popup-content { + overflow-x: hidden; + } + + .dx-form { + /* Icons alignment */ + .dx-scheduler-form-group-with-icon .dx-box-item:has(.dx-scheduler-form-icon) { + flex: 0 1 auto !important; // stylelint-disable-line declaration-no-important + align-items: end; + } + + .dx-scheduler-form-date-range-group .dx-box-item:has(.dx-scheduler-form-icon), + .dx-scheduler-form-description-group .dx-box-item:has(.dx-scheduler-form-icon), + .dx-scheduler-form-resources-group .dx-box-item:has(.dx-scheduler-default-resources-icon) { + align-items: start; + } + + .dx-scheduler-form-icon { + display: flex; + align-items: center; + + > .dx-field-item-content { + line-height: 1; + } + } + + /* Editors alignment */ + .dx-scheduler-form-all-day-switch.dx-field-item.dx-label-h-align { + align-items: center; + + .dx-field-item-content { + text-align: end; + + .dx-switch.dx-widget { + margin: 0; + } + } + } + + .dx-scheduler-form-start-date-group .dx-item, + .dx-scheduler-form-end-date-group .dx-item { + align-items: end; + + .dx-datebox input.dx-texteditor-input { + padding-inline-end: 0; + } + } + + /* Repeat editor separator */ + .dx-scheduler-form-repeat-editor .dx-scheduler-form-recurrence-settings-button { + overflow: visible; + position: relative; + + &::after { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 1px; + height: 100%; + background-color: $scheduler-base-border-color; + } + } + } + } + + .dx-scheduler-legacy-appointment-popup { .dx-form .dx-field-item.dx-appointment-form-switch > div { flex-grow: 0; width: auto; diff --git a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_colors.scss b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_colors.scss index 0261e33f85f2..86a2f56cad12 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_colors.scss @@ -64,6 +64,8 @@ $scheduler-workspace-accent-color: $base-accent !default; $scheduler-current-time-cell-color: $base-accent !default; $scheduler-time-indicator-color: #eb5757 !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; +$scheduler-form-subject-icon-color: null !default; +$scheduler-form-icon-color: $base-text-color !default; $scheduler-popup-title-bg: $scheduler-workspace-background-color !default; $scheduler-workspace-month-text-color: color.change($base-text-color, $alpha: 0.54) !default; $scheduler-dropdown-appointment-date-color: color.change($base-text-color, $alpha: 0.54) !default; @@ -88,6 +90,7 @@ $agenda-appointment-text-color: $base-text-color !default; $header-panel-cell-date: null !default; @if $mode == "light" { + $scheduler-form-subject-icon-color: lighten(saturate(adjust-hue($base-accent, 3), 2.21), 44.31) !default; $scheduler-workspace-month-text-color: #707070; $scheduler-appointment-text-color: #000 !default; $scheduler-panel-text-color: #707070; @@ -109,6 +112,7 @@ $header-panel-cell-date: null !default; } @if $mode == "dark" { + $scheduler-form-subject-icon-color: darken(desaturate(adjust-hue($base-accent, -3), 11.06), 36.27); $scheduler-workspace-month-text-color: #999; $scheduler-appointment-base-color: darken($base-accent, 48%) !default; $scheduler-appointment-text-color: #fff !default; diff --git a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss index 4a28ddaf26d3..a4af1c5068b4 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_index.scss @@ -604,6 +604,52 @@ $fluent-scheduler-agenda-time-panel-cell-padding: 8px; } .dx-scheduler-appointment-popup { + > .dx-overlay-content > .dx-toolbar.dx-widget { + > .dx-toolbar-items-container { + height: $fluent-scheduler-appointment-popup-toolbar-height; + } + } + + .dx-form { + .dx-scheduler-form-icon { + color: $scheduler-form-icon-color; + + &.dx-field-item.dx-flex-layout { + height: $fluent-scheduler-appointment-popup-icon-container-height; + padding-inline-end: $fluent-scheduler-appointment-popup-icon-padding-right; + } + } + + .dx-scheduler-form-subject-group .dx-scheduler-form-icon { + color: $scheduler-form-subject-icon-color; + } + + .dx-scheduler-form-description-group .dx-scheduler-form-icon, + .dx-scheduler-form-resources-group .dx-scheduler-default-resources-icon { + margin-top: $fluent-scheduler-appointment-popup-description-icon-margin-top; + } + + .dx-field-item:not(.dx-first-col) { + padding-inline-start: $fluent-scheduler-appointment-popup-item-padding-horizontal; + } + + .dx-field-item:not(.dx-last-col) { + padding-inline-end: $fluent-scheduler-appointment-popup-item-padding-horizontal; + } + + .dx-scheduler-form-all-day-switch.dx-field-item.dx-label-h-align { + height: $fluent-scheduler-appointment-popup-all-day-item-height; + + .dx-field-item-content { + .dx-switch.dx-widget { + margin-bottom: 3px; + } + } + } + } +} + +.dx-scheduler-legacy-appointment-popup { .dx-form { padding: 0 10px 0 10px; } @@ -628,7 +674,7 @@ $fluent-scheduler-agenda-time-panel-cell-padding: 8px; } } -.dx-scheduler-appointment-popup .dx-form-validation-summary { +.dx-scheduler-legacy-appointment-popup .dx-form-validation-summary { padding: 10px 20px; } diff --git a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_sizes.scss b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_sizes.scss index baf319519f76..fe9bcd03e715 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/scheduler/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/scheduler/_sizes.scss @@ -25,6 +25,13 @@ $fluent-tooltip-marker-dimension: null !default; $fluent-scheduler-appointment-tooltip-title-margin-top: null !default; $fluent-scheduler-appointment-tooltip-remove-padding-top: null !default; +$fluent-scheduler-appointment-popup-toolbar-height: null !default; +$fluent-scheduler-appointment-popup-icon-container-height: null !default; +$fluent-scheduler-appointment-popup-icon-padding-right: null !default; +$fluent-scheduler-appointment-popup-description-icon-margin-top: null !default; +$fluent-scheduler-appointment-popup-item-padding-horizontal: null !default; +$fluent-scheduler-appointment-popup-all-day-item-height: null !default; + $scheduler-left-column-width: 65px !default; $fluent-scheduler-timeline-date-table-cell-height: 50px !default; @@ -94,6 +101,13 @@ $header-panel-time-cell-padding: null !default; $fluent-scheduler-appointment-tooltip-title-margin-top: 0 !default; $fluent-scheduler-appointment-tooltip-remove-padding-top: 1px !default; + $fluent-scheduler-appointment-popup-toolbar-height: 56px !default; + $fluent-scheduler-appointment-popup-icon-container-height: 32px !default; + $fluent-scheduler-appointment-popup-icon-padding-right: 10px !default; + $fluent-scheduler-appointment-popup-description-icon-margin-top: 24px !default; + $fluent-scheduler-appointment-popup-item-padding-horizontal: 6px !default; + $fluent-scheduler-appointment-popup-all-day-item-height: 40px !default; + $agenda-appointment-title-font-size: 14px; } @@ -130,5 +144,12 @@ $header-panel-time-cell-padding: null !default; $fluent-scheduler-appointment-tooltip-title-margin-top: 3px !default; $fluent-scheduler-appointment-tooltip-remove-padding-top: 2px !default; + $fluent-scheduler-appointment-popup-toolbar-height: 48px !default; + $fluent-scheduler-appointment-popup-icon-container-height: 24px !default; + $fluent-scheduler-appointment-popup-icon-padding-right: 8px !default; + $fluent-scheduler-appointment-popup-description-icon-margin-top: 18px !default; + $fluent-scheduler-appointment-popup-item-padding-horizontal: 4px !default; + $fluent-scheduler-appointment-popup-all-day-item-height: 30px !default; + $agenda-appointment-title-font-size: 13px; } diff --git a/packages/devextreme-scss/scss/widgets/generic/scheduler/_colors.scss b/packages/devextreme-scss/scss/widgets/generic/scheduler/_colors.scss index 50c9cf9dcb4f..a0393fe1ebb9 100644 --- a/packages/devextreme-scss/scss/widgets/generic/scheduler/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/generic/scheduler/_colors.scss @@ -67,6 +67,8 @@ $scheduler-current-time-cell-color: $base-accent !default; */ $scheduler-time-indicator-color: null !default; $scheduler-dd-appointment-hover-text-color: null !default; +$scheduler-form-icon-color: $base-text-color !default; +$scheduler-form-subject-icon-color: null !default; $scheduler-popup-title-bg: $scheduler-workspace-background-color !default; $scheduler-workspace-month-text-color: null !default; $scheduler-dropdown-appointment-date-color: null !default; @@ -114,6 +116,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: $base-header-color !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; + $scheduler-form-subject-icon-color: darken(desaturate($base-accent, 44.18), 25.88) !default; $scheduler-workspace-month-text-color: $month-text-color-light !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-workspace-active-cell-color: $scheduler-accent-border-color !default; @@ -148,6 +151,7 @@ $agenda-appointment-text-color: null !default; $scheduler-appointment-base-color: $base-accent !default; $scheduler-appointment-text-color: $base-text-color !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; + $scheduler-form-subject-icon-color: $base-accent !default; $scheduler-appointment-focus-color: extcolor.difference(#fff, $base-text-color) !default; $scheduler-appointment-start-color: $base-inverted-bg !default; $scheduler-workspace-focused-cell-color: lighten($base-accent, 5%) !default; @@ -191,6 +195,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: $base-text-color !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; + $scheduler-form-subject-icon-color: darken(desaturate($base-accent, 44.18), 25.88) !default; $scheduler-workspace-month-text-color: $month-text-color-dark !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-workspace-active-cell-color: $scheduler-accent-border-color !default; @@ -232,6 +237,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: $base-text-color !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: #fff !default; + $scheduler-form-subject-icon-color: darken(desaturate($base-accent, 44.18), 25.88) !default; $scheduler-workspace-month-text-color: $month-text-color-dark !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-workspace-active-cell-color: $scheduler-accent-border-color !default; @@ -271,6 +277,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: $base-header-color !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: $base-text-color !default; + $scheduler-form-subject-icon-color: darken(desaturate($base-accent, 44.18), 25.88) !default; $scheduler-workspace-month-text-color: $month-text-color-dark !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-workspace-active-cell-color: $scheduler-accent-border-color !default; @@ -310,6 +317,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: lighten($base-text-color, 38.5%) !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; + $scheduler-form-subject-icon-color: lighten(desaturate(adjust-hue($base-accent, 1), 7.32), 43.33) !default; $scheduler-workspace-month-text-color: lighten($base-text-color, 38.5%) !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-time-panel-background-color: $scheduler-workspace-background-color !default; @@ -351,6 +359,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: $base-text-color !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; + $scheduler-form-subject-icon-color: lighten(desaturate(adjust-hue($base-accent, 1), 7.32), 43.33) !default; $scheduler-workspace-month-text-color: $month-text-color-light !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-workspace-active-cell-color: $scheduler-accent-border-color !default; @@ -389,6 +398,7 @@ $agenda-appointment-text-color: null !default; $scheduler-panel-text-color: $base-text-color !default; $scheduler-time-indicator-color: lighten($scheduler-current-time-cell-color, 15%) !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; + $scheduler-form-subject-icon-color: lighten(desaturate(adjust-hue($base-accent, 1), 7.32), 43.33) !default; $scheduler-workspace-month-text-color: $month-text-color-light !default; $scheduler-dropdown-appointment-date-color: lighten($base-text-color, 38.5%) !default; $scheduler-workspace-active-cell-color: $scheduler-accent-border-color !default; diff --git a/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss index 16f2080ed475..85e11745c946 100644 --- a/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/generic/scheduler/_index.scss @@ -220,7 +220,7 @@ $generic-scheduler-agenda-group-header-padding: $generic-scheduler-agenda-time-c } } -.dx-scheduler-appointment-popup { +.dx-scheduler-legacy-appointment-popup { .dx-popup-title { background-color: $scheduler-popup-title-bg; @@ -244,7 +244,63 @@ $generic-scheduler-agenda-group-header-padding: $generic-scheduler-agenda-time-c } } -.dx-scheduler-appointment-popup .dx-form-validation-summary { +.dx-scheduler-appointment-popup { + > .dx-overlay-content > .dx-toolbar.dx-widget { + > .dx-toolbar-items-container { + height: $generic-scheduler-appointment-popup-toolbar-height; + } + + .dx-toolbar-label { + font-size: $generic-scheduler-appointment-popup-toolbar-label-size; + } + } + + .dx-form { + .dx-scheduler-form-icon { + color: $scheduler-form-icon-color; + + &.dx-field-item { + height: $generic-scheduler-appointment-popup-icon-container-height; + padding-inline-end: $generic-scheduler-appointment-popup-icon-padding-right; + + .dx-icon { + font-size: $generic-scheduler-appointment-popup-icon-size; + } + } + } + + .dx-scheduler-form-subject-group .dx-scheduler-form-icon { + color: $scheduler-form-subject-icon-color; + } + + .dx-scheduler-form-description-group .dx-scheduler-form-icon, + .dx-scheduler-form-resources-group .dx-scheduler-default-resources-icon { + margin-top: $generic-scheduler-appointment-popup-description-icon-margin-top; + } + + .dx-field-item:not(.dx-first-col) { + padding-inline-start: $generic-scheduler-appointment-popup-item-padding-horizontal; + } + + .dx-field-item:not(.dx-last-col) { + padding-inline-end: $generic-scheduler-appointment-popup-item-padding-horizontal; + } + + .dx-field-item:not(.dx-first-row) { + padding-top: $generic-scheduler-appointment-popup-item-padding-top; + } + + .dx-scheduler-form-all-day-switch.dx-field-item.dx-label-h-align { + height: $generic-scheduler-appointment-popup-all-day-item-height; + + .dx-field-item-label-text { + color: $base-text-color; + } + } + } +} + +.dx-scheduler-legacy-appointment-popup .dx-form-validation-summary { padding: 10px 20px; } diff --git a/packages/devextreme-scss/scss/widgets/generic/scheduler/_sizes.scss b/packages/devextreme-scss/scss/widgets/generic/scheduler/_sizes.scss index d0c18fae8e88..bdf6464888f5 100644 --- a/packages/devextreme-scss/scss/widgets/generic/scheduler/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/generic/scheduler/_sizes.scss @@ -26,6 +26,16 @@ $generic-scheduler-dropdown-button-vertical-margin: null !default; $generic-scheduler-dropdown-button-adaptive-margin: null !default; $generic-scheduler-dropdown-button-adaptive-vertical-margin: null !default; +$generic-scheduler-appointment-popup-toolbar-height: null !default; +$generic-scheduler-appointment-popup-toolbar-label-size: null !default; +$generic-scheduler-appointment-popup-icon-size: null !default; +$generic-scheduler-appointment-popup-icon-container-height: null !default; +$generic-scheduler-appointment-popup-icon-padding-right: null !default; +$generic-scheduler-appointment-popup-description-icon-margin-top: null !default; +$generic-scheduler-appointment-popup-item-padding-horizontal: null !default; +$generic-scheduler-appointment-popup-item-padding-top: null !default; +$generic-scheduler-appointment-popup-all-day-item-height: null !default; + $agenda-appointment-title-font-size: null !default; $scheduler-timeline-cell-height: null !default; @@ -61,6 +71,16 @@ $generic-scheduler-group-header-agenda-font-size: 14px !default; $generic-scheduler-dropdown-button-adaptive-margin: 0 2px !default; $generic-scheduler-dropdown-button-adaptive-vertical-margin: 0 2px 0 0 !default; + $generic-scheduler-appointment-popup-toolbar-height: 43px !default; + $generic-scheduler-appointment-popup-toolbar-label-size: 20px !default; + $generic-scheduler-appointment-popup-icon-size: 18px !default; + $generic-scheduler-appointment-popup-icon-container-height: 36px !default; + $generic-scheduler-appointment-popup-icon-padding-right: 5px !default; + $generic-scheduler-appointment-popup-description-icon-margin-top: 22px !default; + $generic-scheduler-appointment-popup-item-padding-horizontal: 5px !default; + $generic-scheduler-appointment-popup-item-padding-top: 20px !default; + $generic-scheduler-appointment-popup-all-day-item-height: 36px !default; + $agenda-appointment-title-font-size: 16px; $scheduler-timeline-cell-height: 78px !default; @@ -95,6 +115,16 @@ $generic-scheduler-group-header-agenda-font-size: 14px !default; $generic-scheduler-dropdown-button-adaptive-margin: 0 2px !default; $generic-scheduler-dropdown-button-adaptive-vertical-margin: 0 2px 0 0 !default; + $generic-scheduler-appointment-popup-toolbar-height: 39px !default; + $generic-scheduler-appointment-popup-toolbar-label-size: 18px !default; + $generic-scheduler-appointment-popup-icon-size: 14px !default; + $generic-scheduler-appointment-popup-icon-container-height: 24px !default; + $generic-scheduler-appointment-popup-icon-padding-right: 5px !default; + $generic-scheduler-appointment-popup-description-icon-margin-top: 18px !default; + $generic-scheduler-appointment-popup-item-padding-horizontal: 5px !default; + $generic-scheduler-appointment-popup-item-padding-top: 10px !default; + $generic-scheduler-appointment-popup-all-day-item-height: 24px !default; + $agenda-appointment-title-font-size: 16px; $scheduler-timeline-cell-height: 50px !default; diff --git a/packages/devextreme-scss/scss/widgets/material/scheduler/_colors.scss b/packages/devextreme-scss/scss/widgets/material/scheduler/_colors.scss index 79404825c727..ec64d9dee4f0 100644 --- a/packages/devextreme-scss/scss/widgets/material/scheduler/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/material/scheduler/_colors.scss @@ -63,6 +63,8 @@ $scheduler-workspace-accent-color: $base-accent !default; $scheduler-current-time-cell-color: $base-accent !default; $scheduler-time-indicator-color: #eb5757 !default; $scheduler-dd-appointment-hover-text-color: $base-inverted-text-color !default; +$scheduler-form-icon-color: $base-label-color !default; +$scheduler-form-subject-icon-color: color.change($base-accent, $alpha: 0.24) !default; $scheduler-popup-title-bg: $scheduler-workspace-background-color !default; $scheduler-workspace-month-text-color: color.change($base-text-color, $alpha: 0.54) !default; $scheduler-dropdown-appointment-date-color: color.change($base-text-color, $alpha: 0.54) !default; diff --git a/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss b/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss index 663919122d5d..ede5daff388f 100644 --- a/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss +++ b/packages/devextreme-scss/scss/widgets/material/scheduler/_index.scss @@ -545,6 +545,78 @@ $material-scheduler-agenda-time-panel-cell-padding: 8px; } .dx-scheduler-appointment-popup { + > .dx-overlay-content { + border-radius: $material-scheduler-appointment-popup-border-radius; + } + + > .dx-overlay-content > .dx-toolbar.dx-widget { + > .dx-toolbar-items-container { + height: $material-scheduler-appointment-popup-toolbar-height; + } + + .dx-toolbar-label { + font-size: $material-scheduler-appointment-popup-toolbar-label-size; + } + } + + .dx-form { + .dx-scheduler-form-icon { + color: $scheduler-form-icon-color; + + &.dx-field-item { + height: $material-scheduler-appointment-popup-icon-container-height; + padding-inline-end: $material-scheduler-appointment-popup-icon-padding-right; + + .dx-icon { + font-size: $material-scheduler-appointment-popup-icon-size; + } + } + } + + .dx-scheduler-form-subject-group .dx-scheduler-form-icon { + color: $scheduler-form-subject-icon-color; + } + + .dx-scheduler-form-description-group .dx-scheduler-form-icon, + .dx-scheduler-form-resources-group .dx-scheduler-default-resources-icon { + margin-top: $material-scheduler-appointment-popup-description-icon-margin-top; + } + + .dx-field-item:not(.dx-first-col) { + padding-inline-start: $material-scheduler-appointment-popup-item-padding-horizontal; + } + + .dx-field-item:not(.dx-last-col) { + padding-inline-end: $material-scheduler-appointment-popup-item-padding-horizontal; + } + + .dx-field-item:not(.dx-first-row) { + padding-top: 6px; + } + + .dx-field-item:not(.dx-last-row) { + padding-bottom: 6px; + } + + .dx-scheduler-form-all-day-switch.dx-field-item.dx-label-h-align { + height: $material-scheduler-appointment-popup-all-day-item-height; + padding-inline-start: $material-scheduler-appointment-popup-all-day-item-padding-left; + + .dx-field-item-label-text { + font-size: $material-scheduler-appointment-popup-all-day-item-font-size; + color: $base-text-color; + } + + .dx-field-item-content { + .dx-switch.dx-widget { + margin-bottom: $material-scheduler-appointment-popup-all-day-item-margin-bottom; + } + } + } + } +} + +.dx-scheduler-legacy-appointment-popup { .dx-form { padding: 0 10px 0 10px; } @@ -569,7 +641,7 @@ $material-scheduler-agenda-time-panel-cell-padding: 8px; } } -.dx-scheduler-appointment-popup .dx-form-validation-summary { +.dx-scheduler-legacy-appointment-popup .dx-form-validation-summary { padding: 10px 20px; } diff --git a/packages/devextreme-scss/scss/widgets/material/scheduler/_sizes.scss b/packages/devextreme-scss/scss/widgets/material/scheduler/_sizes.scss index 9804502c260f..3cd270be9456 100644 --- a/packages/devextreme-scss/scss/widgets/material/scheduler/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/material/scheduler/_sizes.scss @@ -45,6 +45,19 @@ $agenda-appointment-title-font-size: null !default; $material-scheduler-header-height: null !default; $material-scheduler-header-offset: null !default; +$material-scheduler-appointment-popup-border-radius: null !default; +$material-scheduler-appointment-popup-toolbar-height: null !default; +$material-scheduler-appointment-popup-toolbar-label-size: null !default; +$material-scheduler-appointment-popup-icon-size: null !default; +$material-scheduler-appointment-popup-icon-container-height: null !default; +$material-scheduler-appointment-popup-icon-padding-right: null !default; +$material-scheduler-appointment-popup-description-icon-margin-top: null !default; +$material-scheduler-appointment-popup-item-padding-horizontal: null !default; +$material-scheduler-appointment-popup-all-day-item-height: null !default; +$material-scheduler-appointment-popup-all-day-item-padding-left: null !default; +$material-scheduler-appointment-popup-all-day-item-font-size: null !default; +$material-scheduler-appointment-popup-all-day-item-margin-bottom: null !default; + $scheduler-timeline-cell-height: 50px !default; @@ -77,6 +90,19 @@ $scheduler-timeline-cell-height: 50px !default; $material-scheduler-appointment-tooltip-title-margin-top: 4px !default; $material-scheduler-appointment-tooltip-remove-padding-top: 1px !default; + $material-scheduler-appointment-popup-border-radius: 8px !default; + $material-scheduler-appointment-popup-toolbar-height: 64px !default; + $material-scheduler-appointment-popup-toolbar-label-size: 18px !default; + $material-scheduler-appointment-popup-icon-size: 24px !default; + $material-scheduler-appointment-popup-icon-container-height: 48px !default; + $material-scheduler-appointment-popup-icon-padding-right: 8px !default; + $material-scheduler-appointment-popup-description-icon-margin-top: 33px !default; + $material-scheduler-appointment-popup-item-padding-horizontal: 8px !default; + $material-scheduler-appointment-popup-all-day-item-height: 54px !default; + $material-scheduler-appointment-popup-all-day-item-padding-left: 16px !default; + $material-scheduler-appointment-popup-all-day-item-font-size: 16px !default; + $material-scheduler-appointment-popup-all-day-item-margin-bottom: 3px !default; + $agenda-appointment-title-font-size: 14px; } @@ -109,5 +135,18 @@ $scheduler-timeline-cell-height: 50px !default; $material-scheduler-appointment-tooltip-title-margin-top: 3px !default; $material-scheduler-appointment-tooltip-remove-padding-top: 2px !default; + $material-scheduler-appointment-popup-border-radius: 4px !default; + $material-scheduler-appointment-popup-toolbar-height: 52px !default; + $material-scheduler-appointment-popup-toolbar-label-size: 16px !default; + $material-scheduler-appointment-popup-icon-size: 18px !default; + $material-scheduler-appointment-popup-icon-container-height: 32px !default; + $material-scheduler-appointment-popup-icon-padding-right: 6px !default; + $material-scheduler-appointment-popup-description-icon-margin-top: 22px !default; + $material-scheduler-appointment-popup-item-padding-horizontal: 6px !default; + $material-scheduler-appointment-popup-all-day-item-height: 38px !default; + $material-scheduler-appointment-popup-all-day-item-padding-left: 12px !default; + $material-scheduler-appointment-popup-all-day-item-font-size: 14px !default; + $material-scheduler-appointment-popup-all-day-item-margin-bottom: 1px !default; + $agenda-appointment-title-font-size: 13px; } diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts index e9490bc2ad6c..7c060a51d33b 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/model/popup.ts @@ -1,8 +1,46 @@ +import $ from '@js/core/renderer'; +import type dxForm from '@js/ui/form'; +import type dxPopup from '@js/ui/popup'; + export class PopupModel { element: HTMLDivElement; + component: dxPopup; + constructor(element: HTMLDivElement) { this.element = element; + + // @ts-expect-error + this.component = $('.dx-scheduler-appointment-popup.dx-popup.dx-widget').dxPopup('instance') as dxPopup; + } + + get form(): dxForm { + // @ts-expect-error + return $(this.element.querySelector('.dx-form')).dxForm('instance') as dxForm; + } + + get startDate(): Element | null { + return this.element.querySelector('.dx-scheduler-form-start-date-editor .dx-datebox.dx-widget'); + } + + get startTime(): Element | null { + return this.element.querySelector('.dx-scheduler-form-start-time-editor .dx-datebox.dx-widget'); + } + + get startTimeZone(): Element | null { + return this.element.querySelector('.dx-scheduler-form-start-date-timezone-editor .dx-selectbox.dx-widget'); + } + + get endDate(): Element | null { + return this.element.querySelector('.dx-scheduler-form-end-date-editor .dx-datebox.dx-widget'); + } + + get endTime(): Element | null { + return this.element.querySelector('.dx-scheduler-form-end-time-editor .dx-datebox.dx-widget'); + } + + get endTimeZone(): Element | null { + return this.element.querySelector('.dx-scheduler-form-end-date-timezone-editor .dx-selectbox.dx-widget'); } getLabelIdByText = (labelText: string): string => { @@ -100,14 +138,14 @@ export class PopupModel { getForm = (): HTMLElement | null => this.element.querySelector('.dx-form'); - getTitle = (): HTMLElement | null => document.querySelector('.dx-popup-title'); + getTitle = (): HTMLElement | null => document.querySelector('.dx-popup-title .dx-toolbar-label'); - getDoneButton = (): HTMLButtonElement => { - const doneButton = this.element.querySelector('.dx-button.dx-popup-done') as HTMLButtonElement; - if (!doneButton) { + getSaveButton = (): HTMLButtonElement => { + const saveButton = this.element.querySelector('.dx-button.dx-popup-done') as HTMLButtonElement; + if (!saveButton) { throw new Error('Done button not found'); } - return doneButton; + return saveButton; }; getCancelButton = (): HTMLButtonElement => { diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index 7f976f07982c..473a79188782 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -1,12 +1,15 @@ import { afterEach, beforeEach, describe, expect, it, jest, } from '@jest/globals'; +import $ from '@js/core/renderer'; +import type dxDateBox from '@js/ui/date_box'; +import { toMilliseconds } from '@ts/utils/toMilliseconds'; import fx from '../../../common/core/animation/fx'; import { createScheduler } from '../__tests__/__mock__/create_scheduler'; import { setupSchedulerTestEnvironment } from '../__tests__/__mock__/m_mock_scheduler'; -const defaultData = [ +const getDefaultData = () => [ { text: 'recurrent-app', startDate: new Date(2017, 4, 1, 9, 30), @@ -16,11 +19,24 @@ const defaultData = [ text: 'common-app', startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), + }, { + text: 'disabled-app', + startDate: new Date(2017, 4, 22, 9, 30), + endDate: new Date(2017, 4, 22, 11, 30), + disabled: true, + }, { + text: 'all-day-app', + startDate: new Date(2017, 4, 1), + endDate: new Date(2017, 4, 1), + allDay: true, }, ]; -const defaultOption = { - dataSource: defaultData, +const commonAppointment = getDefaultData()[1]; +const allDayAppointment = getDefaultData()[3]; + +const getDefaultConfig = () => ({ + dataSource: getDefaultData(), views: ['month'], currentView: 'month', currentDate: new Date(2017, 4, 25), @@ -28,9 +44,9 @@ const defaultOption = { startDayHour: 9, height: 600, width: 600, -}; +}); -describe('Appointment popup form', () => { +describe('Appointment Popup Form', () => { beforeEach(() => { fx.off = true; setupSchedulerTestEnvironment(); @@ -42,693 +58,897 @@ describe('Appointment popup form', () => { jest.useRealTimers(); }); - it('Original appointment\'s fields shouldn\'t fill if used fieldExpr', async () => { - const data: Record[] = []; - const textExpValue = 'Subject'; + describe('Appointment changes saving/canceling', () => { + it.each([ + 'startDate', 'startTime', 'endDate', 'endTime', + ])('should not close popup on save button click when %s is empty', async (field) => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - let newAppointment: any = null; + scheduler.showAppointmentPopup(commonAppointment); - const { scheduler, POM } = await createScheduler({ - dataSource: data, - views: ['week'], - currentView: 'week', - currentDate: new Date(2021, 4, 27), - textExpr: textExpValue, - onAppointmentAdded: ({ appointmentData }) => { - newAppointment = appointmentData; - }, - height: 600, + let fieldEditorElement: Element | null = null; + if (field === 'startDate') { fieldEditorElement = POM.popup.startDate; } + if (field === 'startTime') { fieldEditorElement = POM.popup.startTime; } + if (field === 'endDate') { fieldEditorElement = POM.popup.endDate; } + if (field === 'endTime') { fieldEditorElement = POM.popup.endTime; } + + // @ts-expect-error + const dateBox = $(fieldEditorElement).dxDateBox('instance') as dxDateBox; + + dateBox.option('value', null); + + POM.popup.getSaveButton().click(); + + expect(POM.popup.component.option('visible')).toBe(true); }); - scheduler.showAppointmentPopup(); + it('should save data to appointment after save button was clicked', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - POM.popup.setInputValueByLabel('Subject', 'qwerty'); + POM.openPopupByDblClick('common-app'); + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + POM.popup.getSaveButton().click(); - POM.popup.getDoneButton().click(); + const dataItem = scheduler.option('dataSource')?.[1]; - expect(newAppointment?.[textExpValue]).toBe('qwerty'); - expect(newAppointment?.text).toBeUndefined(); + expect(dataItem).toMatchObject({ + ...commonAppointment, + text: 'New Subject', + }); + }); - expect(data[0].Subject).toBe('qwerty'); - expect(data[0].text).toBeUndefined(); - }); + it('should not update appointment if popup was closed by cancel button', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - it('Recurrence form should work properly if recurrenceRule property mapped recurrenceRuleExpr', async () => { - const { scheduler, POM } = await createScheduler({ - dataSource: [{ - text: 'Watercolor Landscape', - startDate: new Date(2017, 4, 1, 9, 30), - endDate: new Date(2017, 4, 1, 11), - customRecurrenceRule: 'FREQ=WEEKLY;BYDAY=TU,FR;COUNT=10', - }], - views: ['month'], - currentView: 'month', - currentDate: new Date(2017, 4, 25), - recurrenceRuleExpr: 'customRecurrenceRule', - height: 600, + POM.openPopupByDblClick('common-app'); + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + POM.popup.getCancelButton().click(); + + const dataItem = scheduler.option('dataSource')?.[1]; + expect(dataItem).toMatchObject({ ...commonAppointment }); }); + }); - POM.openPopupByDblClick(); + describe('Toolbar', () => { + it.each([ + { allowUpdating: false, disabled: false }, + { allowUpdating: false, disabled: true }, + { allowUpdating: true, disabled: false }, + { allowUpdating: true, disabled: true }, + ])('Buttons visibility when %p', async ({ allowUpdating, disabled }) => { + setupSchedulerTestEnvironment({ height: 200 }); + const shouldHaveSaveButton = allowUpdating; - POM.popup.getEditSeriesButton().click(); + const { POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { allowUpdating }, + }); - const { value: repeatInputRecurrence } = POM.popup.getSwitchByName('repeat'); + POM.openPopupByDblClick(disabled ? 'disabled-app' : 'common-app'); + + if (shouldHaveSaveButton) { + expect(POM.popup.component.option('toolbarItems')).toMatchObject([ + { shortcut: 'done' }, + { shortcut: 'cancel' }, + ]); + } else { + expect(POM.popup.component.option('toolbarItems')).toMatchObject([ + { shortcut: 'cancel' }, + ]); + } + }); - scheduler.hideAppointmentPopup(); - scheduler.showAppointmentPopup(); + it('Buttons visibility after editing option changed', async () => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { + allowUpdating: true, + allowAdding: true, + }, + }); - const { value: repeatInput } = POM.popup.getSwitchByName('repeat'); + const newAppointment = { + text: 'a', + startDate: new Date(2015, 5, 15, 10), + endDate: new Date(2015, 5, 15, 11), + }; - expect(repeatInputRecurrence).toBe('true'); - expect(repeatInput).toBe('false'); - }); + scheduler.showAppointmentPopup(newAppointment); + expect(POM.popup.component.option('toolbarItems')).toMatchObject([ + { shortcut: 'done' }, + { shortcut: 'cancel' }, + ]); - it('showAppointmentPopup method should be work properly with no argument: baseOptions', async () => { - const { scheduler, POM } = await createScheduler({ - currentDate: new Date(2017, 4, 1), - views: ['month'], - currentView: 'month', + scheduler.option('editing', { allowUpdating: false }); + scheduler.showAppointmentPopup(newAppointment); + expect(POM.popup.component.option('toolbarItems')).toMatchObject([ + { shortcut: 'cancel' }, + ]); + + scheduler.showAppointmentPopup(); + expect(POM.popup.component.option('toolbarItems')).toMatchObject([ + { shortcut: 'done' }, + { shortcut: 'cancel' }, + ]); }); + }); - scheduler.option('dataSource', []); - await new Promise(process.nextTick); + describe('allDay switch', () => { + it('should be turned on when opening allDay appointment', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - scheduler.showAppointmentPopup(); + scheduler.showAppointmentPopup(allDayAppointment); - POM.popup.setInputValueByLabel('Subject', 'app'); - POM.popup.setInputValueByLabel('Start Date', '05/01/2017, 01:30 PM'); - POM.popup.setInputValueByLabel('End Date', '05/01/2017, 03:00 PM'); + expect(POM.popup.getSwitchByName('allDay').value).toBe('true'); + }); - POM.popup.getDoneButton().click(); + it('should be turned off when opening non-allDay appointment', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - const app = POM.getAppointment('app'); + scheduler.showAppointmentPopup(commonAppointment); - expect(app.getText()).toBe('app'); - expect(app.getDisplayDate()).toBe('1:30 PM - 3:00 PM'); - }); + expect(POM.popup.getSwitchByName('allDay').value).toBe('false'); + }); - it('showAppointmentPopup method should be work properly with no argument: cancelButton', async () => { - const { scheduler, POM } = await createScheduler(undefined); + it('should hide time editors when switched on', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - scheduler.option('dataSource', []); - await new Promise(process.nextTick); + scheduler.showAppointmentPopup(commonAppointment); - scheduler.showAppointmentPopup(); + expect(POM.popup.startDate).toBeDefined(); + expect(POM.popup.startTime).toBeDefined(); + expect(POM.popup.endDate).toBeDefined(); + expect(POM.popup.endTime).toBeDefined(); - POM.popup.setInputValueByLabel('Subject', 'app'); - POM.popup.setInputValueByLabel('Start Date', '05/01/2017, 01:30 PM'); - POM.popup.setInputValueByLabel('End Date', '05/01/2017, 03:00 PM'); + POM.popup.getSwitchByName('allDay').click(); - POM.popup.getCancelButton().click(); + expect(POM.popup.startDate).toBeDefined(); + expect(POM.popup.startTime).toBeNull(); + expect(POM.popup.endDate).toBeDefined(); + expect(POM.popup.endTime).toBeNull(); + }); - const appointments = POM.getAppointments(); + it('should show time editors when switched off', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - expect(appointments.length).toBe(0); - }); + scheduler.showAppointmentPopup(allDayAppointment); - it('showAppointmentPopup method should be work properly with no argument: all day appointments', async () => { - const { scheduler, POM } = await createScheduler({ - views: ['month'], - currentView: 'month', - }); + expect(POM.popup.startDate).toBeDefined(); + expect(POM.popup.startTime).toBeNull(); + expect(POM.popup.endDate).toBeDefined(); + expect(POM.popup.endTime).toBeNull(); - scheduler.option('dataSource', []); - await new Promise(process.nextTick); + POM.popup.getSwitchByName('allDay').click(); - scheduler.showAppointmentPopup(); + expect(POM.popup.startDate).toBeDefined(); + expect(POM.popup.startTime).toBeDefined(); + expect(POM.popup.endDate).toBeDefined(); + expect(POM.popup.endTime).toBeDefined(); + }); - POM.popup.setInputValueByLabel('Subject', 'app'); - POM.popup.setInputValueByLabel('Start Date', '05/01/2017, 01:30 PM'); - POM.popup.setInputValueByLabel('End Date', '05/01/2017, 03:00 PM'); - POM.popup.getSwitchByName('repeat').click(); + it.each(['day', 'week', 'month'])('should set correct dates when switching on then off in %p view', async (view) => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + currentView: view, + }); - await new Promise(process.nextTick); + scheduler.showAppointmentPopup(commonAppointment); - POM.popup.getDoneButton().click(); + POM.popup.getSwitchByName('allDay').click(); + POM.popup.getSwitchByName('allDay').click(); - const appointments = POM.getAppointments(); + const expectedStartDate = new Date(commonAppointment.startDate); + expectedStartDate.setHours(scheduler.option('startDayHour'), 0, 0, 0); - expect(appointments.length).toBe(42); - }); + let expectedEndDate: Date | null = null; - it.todo('Appointment popup form should have two named groups'); + if (view === 'month') { + expectedEndDate = new Date(expectedStartDate); + expectedEndDate.setHours(scheduler.option('endDayHour'), 0, 0, 0); + } + if (view === 'week' || view === 'day') { + const cellDuration = scheduler.option('cellDuration') * toMilliseconds('minute'); + expectedEndDate = new Date(expectedStartDate.getTime() + cellDuration); + } - it('Appointment popup should be with correct dates after chage allDay switch and w/o saving (T832711)', async () => { - const { scheduler, POM } = await createScheduler(undefined); + expect(POM.popup.form.option('formData')).toMatchObject({ + startDate: expectedStartDate, + endDate: expectedEndDate, + }); + }); - const data = { - text: 'all day apo', - startDate: new Date(2017, 4, 1, 9, 30), - endDate: new Date(2017, 4, 1, 11), - allDay: true, - }; + it('should show correct dates after switching on allDay and canceling changes (T832711)', async () => { + const { scheduler, POM } = await createScheduler(undefined); - scheduler.showAppointmentPopup(data); + const data = { + text: 'all day apo', + startDate: new Date(2017, 4, 1, 9, 30), + endDate: new Date(2017, 4, 1, 11), + allDay: true, + }; - POM.popup.getSwitchByName('allDay').click(); + scheduler.showAppointmentPopup(data); - POM.popup.getCancelButton().click(); + POM.popup.getSwitchByName('allDay').click(); - scheduler.showAppointmentPopup(data); + POM.popup.getCancelButton().click(); - const { value: startDateValue } = POM.popup.getInputByLabel('Start Date'); - const { value: endDateValue } = POM.popup.getInputByLabel('End Date'); + scheduler.showAppointmentPopup(data); - expect(startDateValue).toBe('5/1/2017'); - expect(endDateValue).toBe('5/1/2017'); - }); + const { value: startDateValue } = POM.popup.getInputByLabel('Start Date'); + const { value: endDateValue } = POM.popup.getInputByLabel('End Date'); - it('onAppointmentFormOpening event should pass e.popup argument', async () => { - const data = [{ - text: 'Website Re-Design Plan', - startDate: new Date(2017, 4, 22, 9, 30), - endDate: new Date(2017, 4, 22, 11, 30), - }]; - - const onAppointmentFormOpening = jest.fn((e: - { popup: { option: (key: string, value: unknown) => void } }) => { - e.popup.option('showTitle', true); - e.popup.option('title', 'Information'); + expect(startDateValue).toBe('5/1/2017'); + expect(endDateValue).toBe('5/1/2017'); }); + }); - const { POM } = await createScheduler({ - dataSource: data, - onAppointmentFormOpening, - currentDate: new Date(2017, 4, 22), - }); + describe('Timezones', () => { + it('should have correct values on popup open', async () => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { allowTimeZoneEditing: true }, + }); + scheduler.showAppointmentPopup({ + ...commonAppointment, + startDateTimeZone: 'America/Los_Angeles', + endDateTimeZone: 'America/New_York', + }); - POM.openPopupByDblClick('Website Re-Design Plan'); + // @ts-expect-error + const startTimeZoneSelectBox = $(POM.popup.startTimeZone).dxSelectBox('instance'); + // @ts-expect-error + const endTimeZoneSelectBox = $(POM.popup.endTimeZone).dxSelectBox('instance'); - expect(POM.popup.getTitle()?.textContent).toBe('Information'); - }); + expect(startTimeZoneSelectBox.option('value')).toBe('America/Los_Angeles'); + expect(endTimeZoneSelectBox.option('value')).toBe('America/New_York'); + }); - it('onAppointmentFormOpening event should handle e.cancel value: default settings', async () => { - const data = [{ - text: 'Website Re-Design Plan', - startDate: new Date(2017, 4, 22, 9, 30), - endDate: new Date(2017, 4, 22, 11, 30), - }]; + it('should be shown when editing.allowTimeZoneEditing is true', async () => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { allowTimeZoneEditing: true }, + }); - const { POM, scheduler } = await createScheduler({ - dataSource: data, - currentDate: new Date(2017, 4, 22), + scheduler.showAppointmentPopup(commonAppointment); + + expect(POM.popup.startTimeZone).toBeDefined(); + expect(POM.popup.endTimeZone).toBeDefined(); }); - POM.openPopupByDblClick('Website Re-Design Plan'); + it('should be hidden when editing.allowTimeZoneEditing is false', async () => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { allowTimeZoneEditing: false }, + }); - const popup = POM.getPopups(); - expect(popup.length).toBe(1); + scheduler.showAppointmentPopup(commonAppointment); - POM.popup.getCancelButton().click(); + expect(POM.popup.startTimeZone).toBeNull(); + expect(POM.popup.endTimeZone).toBeNull(); + }); - scheduler.showAppointmentPopup(data[0]); + it('change of startTimeZone value should trigger endTimeZone value change', async () => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { allowTimeZoneEditing: true }, + }); - expect(POM.getPopups().length).toBe(1); - }); + scheduler.showAppointmentPopup(commonAppointment); - it('onAppointmentFormOpening event should handle e.cancel value: true', async () => { - const data = [{ - text: 'Website Re-Design Plan', - startDate: new Date(2017, 4, 22, 9, 30), - endDate: new Date(2017, 4, 22, 11, 30), - }]; + // @ts-expect-error + const startTimeZoneSelectBox = $(POM.popup.startTimeZone).dxSelectBox('instance'); + // @ts-expect-error + const endTimeZoneSelectBox = $(POM.popup.endTimeZone).dxSelectBox('instance'); - const onAppointmentFormOpening = jest.fn((e: { cancel: boolean }) => { - e.cancel = true; - }); + startTimeZoneSelectBox.option('value', 'America/Los_Angeles'); - const { POM, scheduler } = await createScheduler({ - dataSource: data, - onAppointmentFormOpening, - currentDate: new Date(2017, 4, 22), + expect(startTimeZoneSelectBox.option('value')).toBe('America/Los_Angeles'); + expect(endTimeZoneSelectBox.option('value')).toBe('America/Los_Angeles'); }); - POM.openPopupByDblClick('Website Re-Design Plan'); + it('change of endTimeZone value should not trigger startTimeZone value change', async () => { + const { scheduler, POM } = await createScheduler({ + ...getDefaultConfig(), + editing: { allowTimeZoneEditing: true }, + }); - expect(POM.getPopups().length).toBe(0); + scheduler.showAppointmentPopup(commonAppointment); - scheduler.showAppointmentPopup(data[0]); + // @ts-expect-error + const startTimeZoneSelectBox = $(POM.popup.startTimeZone).dxSelectBox('instance'); + // @ts-expect-error + const endTimeZoneSelectBox = $(POM.popup.endTimeZone).dxSelectBox('instance'); - expect(POM.getPopups().length).toBe(0); + startTimeZoneSelectBox.option('value', 'America/Los_Angeles'); + endTimeZoneSelectBox.option('value', 'America/New_York'); + + expect(startTimeZoneSelectBox.option('value')).toBe('America/Los_Angeles'); + expect(endTimeZoneSelectBox.option('value')).toBe('America/New_York'); + }); }); - it('onAppointmentFormOpening event should handle e.cancel value: false', async () => { - const data = [{ - text: 'Website Re-Design Plan', - startDate: new Date(2017, 4, 22, 9, 30), - endDate: new Date(2017, 4, 22, 11, 30), - }]; + describe('Recurrence', () => { + it.skip('Recurrence form should work properly if recurrenceRule property mapped recurrenceRuleExpr', async () => { + const { scheduler, POM } = await createScheduler({ + dataSource: [{ + text: 'Watercolor Landscape', + startDate: new Date(2017, 4, 1, 9, 30), + endDate: new Date(2017, 4, 1, 11), + customRecurrenceRule: 'FREQ=WEEKLY;BYDAY=TU,FR;COUNT=10', + }], + views: ['month'], + currentView: 'month', + currentDate: new Date(2017, 4, 25), + recurrenceRuleExpr: 'customRecurrenceRule', + height: 600, + }); - const onAppointmentFormOpening = jest.fn((e: { cancel: boolean }) => { - e.cancel = false; - }); + POM.openPopupByDblClick(); - const { POM, scheduler } = await createScheduler({ - dataSource: data, - onAppointmentFormOpening, - currentDate: new Date(2017, 4, 22), + POM.popup.getEditSeriesButton().click(); + + const { value: repeatInputRecurrence } = POM.popup.getSwitchByName('repeat'); + + scheduler.hideAppointmentPopup(); + scheduler.showAppointmentPopup(); + + const { value: repeatInput } = POM.popup.getSwitchByName('repeat'); + + expect(repeatInputRecurrence).toBe('true'); + expect(repeatInput).toBe('false'); }); - POM.openPopupByDblClick('Website Re-Design Plan'); + it.skip('Appointment popup shouldn\'t render recurrence editor, if previous was with recurrence', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { POM } = await createScheduler({ + dataSource: [{ + text: 'recurrent-app', + startDate: new Date(2017, 4, 1, 9, 30), + endDate: new Date(2017, 4, 1, 11), + recurrenceRule: 'FREQ=DAILY;COUNT=5', + }, { + text: 'common-app', + startDate: new Date(2017, 4, 9, 9, 30), + endDate: new Date(2017, 4, 9, 11), + }], + views: ['month'], + currentView: 'month', + currentDate: new Date(2017, 4, 25), + firstDayOfWeek: 1, + startDayHour: 9, + }); - expect(POM.getPopups().length).toBe(1); + POM.openPopupByDblClick('recurrent-app'); + POM.popup.getEditSeriesButton().click(); - POM.popup.getCancelButton().click(); + expect(POM.popup.getSwitchByName('repeat').value).toBe('true'); + expect(POM.popup.getInputByLabel('Subject').value).toBe('recurrent-app'); - scheduler.showAppointmentPopup(data[0]); + jest.useFakeTimers(); - expect(POM.getPopups().length).toBe(1); - }); + POM.popup.getCancelButton().click(); - it('Appointment popup shouldn\'t render recurrence editor, if previous was with recurrence', async () => { - setupSchedulerTestEnvironment({ height: 200 }); - const { POM } = await createScheduler({ - dataSource: [{ - text: 'recurrent-app', - startDate: new Date(2017, 4, 1, 9, 30), - endDate: new Date(2017, 4, 1, 11), - recurrenceRule: 'FREQ=DAILY;COUNT=5', - }, { - text: 'common-app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }], - views: ['month'], - currentView: 'month', - currentDate: new Date(2017, 4, 25), - firstDayOfWeek: 1, - startDayHour: 9, + jest.runAllTimers(); + + POM.openPopupByDblClick('common-app'); + + expect(POM.popup.getSwitchByName('repeat').value).toBe('false'); + expect(POM.popup.getInputByLabel('Subject').value).toBe('common-app'); }); - POM.openPopupByDblClick('recurrent-app'); - POM.popup.getEditSeriesButton().click(); + it.skip('Recurrence repeat-end editor should have default \'never\' value after reopening appointment popup', async () => { + const firstAppointment = { startDate: new Date(2015, 1, 9), endDate: new Date(2015, 1, 9, 1), text: 'caption 1' }; + const secondAppointment = { startDate: new Date(2015, 1, 9), endDate: new Date(2015, 1, 9, 1), text: 'caption 2' }; + const { POM, scheduler } = await createScheduler(getDefaultConfig()); - expect(POM.popup.getSwitchByName('repeat').value).toBe('true'); - expect(POM.popup.getInputByLabel('Subject').value).toBe('recurrent-app'); + scheduler.showAppointmentPopup(firstAppointment); + POM.popup.getSwitchByName('repeat').click(); - jest.useFakeTimers(); + POM.popup.selectRadio('After'); - POM.popup.getCancelButton().click(); + POM.popup.getSaveButton().click(); - jest.runAllTimers(); + scheduler.showAppointmentPopup(secondAppointment); + POM.popup.getSwitchByName('repeat').click(); - POM.openPopupByDblClick('common-app'); + const radioValue = POM.popup.getSelectedRadioValue(); + + expect(radioValue).toBe('Never'); + }); - expect(POM.popup.getSwitchByName('repeat').value).toBe('false'); - expect(POM.popup.getInputByLabel('Subject').value).toBe('common-app'); + describe('Recurrence Editor visibility', () => { + it.todo('Recurrence editor container should be visible if recurrence rule was set'); + it.todo('Recurrence editor container should be visible after changing its visibility value'); + it.todo('Popup should show or not show reccurence editor after many opening with different data'); + it.todo('Popup should show or not to show reccurence editor after many opening with and change visibility'); + it.todo('Popup should not contain recurrence editor, if recurrenceRuleExpr is null'); + it.todo('Popup should not contain recurrence editor, if recurrenceRuleExpr is \'\''); + it.todo('Multiple showing appointment popup for recurrence appointments and after update options should work correct'); + }); }); - it('Appointment popup should work properly', async () => { - const NEW_EXPECTED_SUBJECT = 'NEW SUBJECT'; - setupSchedulerTestEnvironment({ height: 200 }); - const { scheduler, POM } = await createScheduler(defaultOption); + describe('Callbacks', () => { + describe('OnAppointmentFormOpening', () => { + it('should pass e.popup argument', async () => { + const data = [{ + text: 'Website Re-Design Plan', + startDate: new Date(2017, 4, 22, 9, 30), + endDate: new Date(2017, 4, 22, 11, 30), + }]; + + const onAppointmentFormOpening = jest.fn((e: + { popup: { option: (key: string, value: unknown) => void } }) => { + e.popup.option('showTitle', true); + e.popup.option('title', 'Information'); + }); + + const { POM } = await createScheduler({ + dataSource: data, + onAppointmentFormOpening, + currentDate: new Date(2017, 4, 22), + }); + + POM.openPopupByDblClick('Website Re-Design Plan'); + + expect(POM.popup.getTitle()?.textContent).toBe('Information'); + }); - expect(POM.getPopups().length).toBe(0); + it('should handle e.cancel value: default settings', async () => { + const data = [{ + text: 'Website Re-Design Plan', + startDate: new Date(2017, 4, 22, 9, 30), + endDate: new Date(2017, 4, 22, 11, 30), + }]; - jest.useFakeTimers(); - const appointment = POM.getAppointment('common-app'); - if (appointment?.element) { - appointment.element.click(); - } else { - throw new Error('Appointment "common-app" not found or has no element'); - } - jest.runAllTimers(); + const { POM, scheduler } = await createScheduler({ + dataSource: data, + currentDate: new Date(2017, 4, 22), + }); - POM.getTooltipAppointment()?.click(); + POM.openPopupByDblClick('Website Re-Design Plan'); - POM.popup.setInputValueByLabel('Subject', NEW_EXPECTED_SUBJECT); - expect(POM.popup.getInputByLabel('Subject').value).toBe(NEW_EXPECTED_SUBJECT); - expect(POM.getPopups().length).toBe(1); - POM.popup.getDoneButton().click(); - - const dataSource = scheduler.option('dataSource'); - const dataItem = dataSource ? dataSource[1] : null; - expect(Object.keys(dataItem).length).toBe(3); - expect(dataItem.text).toBe(NEW_EXPECTED_SUBJECT); - - const appointmentR = POM.getAppointment('recurrent-app'); - if (appointmentR?.element) { - appointmentR.element.click(); - } else { - throw new Error('Appointment "recurrent-app" not found or has no element'); - } - jest.runAllTimers(); - POM.getTooltipAppointment()?.click(); + const popup = POM.getPopups(); + expect(popup.length).toBe(1); - POM.popup.getEditSeriesButton().click(); + POM.popup.getCancelButton().click(); - expect(POM.popup.getSwitchByName('repeat').value).toBe('true'); - expect(POM.popup.getInputByLabel('Subject').value).toBe('recurrent-app'); - }); + scheduler.showAppointmentPopup(data[0]); - it('Recurrence repeat-end editor should have default \'never\' value after reopening appointment popup', async () => { - const firstAppointment = { startDate: new Date(2015, 1, 9), endDate: new Date(2015, 1, 9, 1), text: 'caption 1' }; - const secondAppointment = { startDate: new Date(2015, 1, 9), endDate: new Date(2015, 1, 9, 1), text: 'caption 2' }; - const { POM, scheduler } = await createScheduler(defaultOption); + expect(POM.getPopups().length).toBe(1); + }); - scheduler.showAppointmentPopup(firstAppointment); - POM.popup.getSwitchByName('repeat').click(); + it('should handle e.cancel value: true', async () => { + const data = [{ + text: 'Website Re-Design Plan', + startDate: new Date(2017, 4, 22, 9, 30), + endDate: new Date(2017, 4, 22, 11, 30), + }]; - POM.popup.selectRadio('After'); + const onAppointmentFormOpening = jest.fn((e: { cancel: boolean }) => { + e.cancel = true; + }); - POM.popup.getDoneButton().click(); + const { POM, scheduler } = await createScheduler({ + dataSource: data, + onAppointmentFormOpening, + currentDate: new Date(2017, 4, 22), + }); - scheduler.showAppointmentPopup(secondAppointment); - POM.popup.getSwitchByName('repeat').click(); + POM.openPopupByDblClick('Website Re-Design Plan'); - const radioValue = POM.popup.getSelectedRadioValue(); + expect(POM.getPopups().length).toBe(0); - expect(radioValue).toBe('Never'); - }); + scheduler.showAppointmentPopup(data[0]); - it('Update appointment if CustomStore', async () => { - const data: Record[] = [{ - startDate: new Date(2015, 4, 24, 9), - endDate: new Date(2015, 4, 24, 11), - }]; + expect(POM.getPopups().length).toBe(0); + }); - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: { - key: 'id', - load: () => data, - update: (key: unknown, values: Record) => Promise.resolve().then(() => { - const appointmentData = data.filter(( - item: Record, - ) => (item as { id: unknown }).id === key)[0]; - Object.assign(appointmentData, values); - scheduler.repaint(); - }), - }, - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - }); + it('should handle e.cancel value: false', async () => { + const data = [{ + text: 'Website Re-Design Plan', + startDate: new Date(2017, 4, 22, 9, 30), + endDate: new Date(2017, 4, 22, 11, 30), + }]; - scheduler.showAppointmentPopup({ - startDate: new Date(2015, 4, 24, 9), - endDate: new Date(2015, 4, 24, 11), - text: 'Subject', - }); + const onAppointmentFormOpening = jest.fn((e: { cancel: boolean }) => { + e.cancel = false; + }); - POM.popup.setInputValueByLabel('Subject', 'New Subject'); - POM.popup.getDoneButton().click(); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeTruthy(); - await new Promise(process.nextTick); - const loadPanelAfter = POM.getLoadPanel(); - expect(loadPanelAfter).toBeFalsy(); - }); + const { POM, scheduler } = await createScheduler({ + dataSource: data, + onAppointmentFormOpening, + currentDate: new Date(2017, 4, 22), + }); - it('Insert appointment if CustomStore', async () => { - const fn = jest.fn(); - const data: Record[] = []; - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: { - key: 'id', - load: () => data, - insert: (appointmentData: Record) => Promise.resolve().then(() => { - (appointmentData as { id: number }).id = data.length; - data.push(appointmentData); - fn(); - }), - }, - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - }); + POM.openPopupByDblClick('Website Re-Design Plan'); - scheduler.showAppointmentPopup(); + expect(POM.getPopups().length).toBe(1); - POM.popup.setInputValueByLabel('Subject', 'New Subject'); - POM.popup.setInputValueByLabel('Start Date', '05/24/2015, 9:00 AM'); - POM.popup.setInputValueByLabel('End Date', '05/24/2015, 11:00 AM'); - - POM.popup.getDoneButton().click(); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeTruthy(); - await new Promise(process.nextTick); - const loadPanelAfter = POM.getLoadPanel(); - expect(loadPanelAfter).toBeFalsy(); - expect(fn).toBeCalled(); - }); + POM.popup.getCancelButton().click(); - it('onAppointmentUpdating and e.cancel=true (T907281)', async () => { - const data = [{ - startDate: new Date(2015, 4, 24, 9), - endDate: new Date(2015, 4, 24, 11), - text: 'Subject', - }]; - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: data, - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - onAppointmentUpdating: (e: { cancel: boolean }) => { e.cancel = true; }, + scheduler.showAppointmentPopup(data[0]); + + expect(POM.getPopups().length).toBe(1); + }); }); - scheduler.showAppointmentPopup(data[0]); + describe('onAppointmentAdding', () => { + it('should handle e.cancel value: true', async () => { + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: [], + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + onAppointmentAdding: (e: { cancel: boolean }) => { e.cancel = true; }, + }); - POM.popup.setInputValueByLabel('Subject', 'New Subject'); + scheduler.showAppointmentPopup(); - POM.popup.getDoneButton().click(); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeFalsy(); + POM.popup.form.option('formData', { + startDate: new Date(2015, 4, 24, 9, 0), + endDate: new Date(2015, 4, 24, 11, 0), + text: 'New Subject', + }); - await new Promise(process.nextTick); + POM.popup.getSaveButton().click(); - const appointment = POM.getAppointment('Subject'); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeFalsy(); - expect(appointment.getText()).toEqual('Subject'); - }); + await new Promise(process.nextTick); - it('onAppointmentUpdating and e.cancel=false (T907281)', async () => { - const data = [{ - startDate: new Date(2015, 4, 24, 9), - endDate: new Date(2015, 4, 24, 11), - text: 'Subject', - }]; - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: data, - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - onAppointmentUpdating: (e: { cancel: boolean }) => { e.cancel = false; }, - }); + const appointments = POM.getAppointments(); - scheduler.showAppointmentPopup(data[0]); + expect(appointments.length).toBe(0); + }); - POM.popup.setInputValueByLabel('Subject', 'New Subject'); + it('should handle e.cancel value: false', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: [], + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + onAppointmentAdding: (e: { cancel: boolean }) => { e.cancel = false; }, + }); - POM.popup.getDoneButton().click(); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeFalsy(); + scheduler.showAppointmentPopup(); - await new Promise(process.nextTick); + POM.popup.form.option('formData', { + startDate: new Date(2015, 4, 24, 9, 0), + endDate: new Date(2015, 4, 24, 11, 0), + text: 'New Subject', + }); - const appointment = POM.getAppointment('New Subject'); + POM.popup.getSaveButton().click(); - expect(appointment.getText()).toEqual('New Subject'); - }); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeFalsy(); - it('onAppointmentAdding and e.cancel=true', async () => { - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: [], - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - onAppointmentAdding: (e: { cancel: boolean }) => { e.cancel = true; }, + await new Promise(process.nextTick); + + expect(POM.getAppointment('New Subject').getText()).toEqual('New Subject'); + }); }); - scheduler.showAppointmentPopup(); + describe('onAppointmentUpdating', () => { + it('onAppointmentUpdating and e.cancel=true (T907281)', async () => { + const data = [{ + startDate: new Date(2015, 4, 24, 9), + endDate: new Date(2015, 4, 24, 11), + text: 'Subject', + }]; + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: data, + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + onAppointmentUpdating: (e: { cancel: boolean }) => { e.cancel = true; }, + }); - POM.popup.setInputValueByLabel('Start Date', '05/24/2015, 9:00 AM'); - POM.popup.setInputValueByLabel('End Date', '05/24/2015, 11:00 AM'); - POM.popup.setInputValueByLabel('Subject', 'New Subject'); + scheduler.showAppointmentPopup(data[0]); - POM.popup.getDoneButton().click(); + POM.popup.setInputValueByLabel('Subject', 'New Subject'); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeFalsy(); + POM.popup.getSaveButton().click(); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeFalsy(); - await new Promise(process.nextTick); + await new Promise(process.nextTick); - const appointments = POM.getAppointments(); + const appointment = POM.getAppointment('Subject'); - expect(appointments.length).toBe(0); - }); + expect(appointment.getText()).toEqual('Subject'); + }); - it('onAppointmentAdding and e.cancel=false', async () => { - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: [], - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - onAppointmentAdding: (e: { cancel: boolean }) => { e.cancel = false; }, + it('onAppointmentUpdating and e.cancel=false (T907281)', async () => { + const data = [{ + startDate: new Date(2015, 4, 24, 9), + endDate: new Date(2015, 4, 24, 11), + text: 'Subject', + }]; + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: data, + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + onAppointmentUpdating: (e: { cancel: boolean }) => { e.cancel = false; }, + }); + + scheduler.showAppointmentPopup(data[0]); + + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + + POM.popup.getSaveButton().click(); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeFalsy(); + + await new Promise(process.nextTick); + + const appointment = POM.getAppointment('New Subject'); + + expect(appointment.getText()).toEqual('New Subject'); + }); }); - scheduler.showAppointmentPopup(); + describe('onAppointmentDeleting', () => { + it('onAppointmentDeleting and e.cancel=true', async () => { + const data = [{ + text: 'Some Text', + startDate: new Date(2015, 4, 24, 9), + endDate: new Date(2015, 4, 24, 11), + }]; - POM.popup.setInputValueByLabel('Start Date', '05/24/2015, 9:00 AM'); - POM.popup.setInputValueByLabel('End Date', '05/24/2015, 11:00 AM'); - POM.popup.setInputValueByLabel('Subject', 'New Subject'); + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: data, + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + onAppointmentDeleting: (e: { cancel: boolean }) => { e.cancel = true; }, + }); - POM.popup.getDoneButton().click(); + scheduler.deleteAppointment(data[0]); + await new Promise(process.nextTick); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeFalsy(); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeFalsy(); - await new Promise(process.nextTick); + const appointment = POM.getAppointment(); - const appointment = POM.getAppointment(); + expect(appointment.getText()).toEqual('Some Text'); + }); - expect(appointment.getText()).toEqual('New Subject'); - }); + it('onAppointmentDeleting and e.cancel=false', async () => { + const data = [{ + text: 'Some Text', + startDate: new Date(2015, 4, 24, 9), + endDate: new Date(2015, 4, 24, 11), + }]; - it('onAppointmentDeleting and e.cancel=true', async () => { - const data = [{ - text: 'Some Text', - startDate: new Date(2015, 4, 24, 9), - endDate: new Date(2015, 4, 24, 11), - }]; + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: data, + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + onAppointmentDeleting: (e: { cancel: boolean }) => { e.cancel = false; }, + }); - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: data, - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - onAppointmentDeleting: (e: { cancel: boolean }) => { e.cancel = true; }, + scheduler.deleteAppointment(data[0]); + await new Promise(process.nextTick); + + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeFalsy(); + + const appointment = POM.getAppointment(); + + expect(appointment.getText()).toEqual(''); + }); }); + }); - scheduler.deleteAppointment(data[0]); - await new Promise(process.nextTick); + describe('showAppointmentPopup', () => { + it('should open appointment popup without data', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeFalsy(); + scheduler.showAppointmentPopup(); - const appointment = POM.getAppointment(); + const expectedStartDate = new Date(scheduler.option('currentDate')); + const expectedEndDate = new Date(expectedStartDate.getTime() + scheduler.option('cellDuration') * toMilliseconds('minute')); + + expect(POM.popup.component.option('visible')).toBe(true); + expect(POM.popup.form.option('formData')).toEqual({ + text: undefined, + allDay: false, + startDate: expectedStartDate, + endDate: expectedEndDate, + description: undefined, + recurrenceRule: undefined, + startDateTimeZone: undefined, + endDateTimeZone: undefined, + }); + }); + it('should open appointment popup with correct data', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); + + scheduler.showAppointmentPopup(commonAppointment); - expect(appointment.getText()).toEqual('Some Text'); + expect(POM.popup.component.option('visible')).toBe(true); + expect(POM.popup.form.option('formData')).toMatchObject({ + ...commonAppointment, + }); + }); }); - it('onAppointmentDeleting and e.cancel=false', async () => { - const data = [{ - text: 'Some Text', - startDate: new Date(2015, 4, 24, 9), - endDate: new Date(2015, 4, 24, 11), - }]; + describe('hideAppointmentPopup', () => { + it('should hide appointment popup without saving changes', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - const { scheduler, POM } = await createScheduler({ - views: ['day'], - dataSource: data, - currentDate: new Date(2015, 4, 24), - startDayHour: 8, - endDayHour: 18, - onAppointmentDeleting: (e: { cancel: boolean }) => { e.cancel = false; }, + POM.openPopupByDblClick('common-app'); + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + scheduler.hideAppointmentPopup(); + + const dataItem = scheduler.option('dataSource')?.[1]; + + expect(dataItem).toMatchObject({ ...commonAppointment }); }); - scheduler.deleteAppointment(data[0]); - await new Promise(process.nextTick); + it('should hide appointment popup with saving changes', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - const loadPanel = POM.getLoadPanel(); - expect(loadPanel).toBeFalsy(); + POM.openPopupByDblClick('common-app'); + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + scheduler.hideAppointmentPopup(true); - const appointment = POM.getAppointment(); + const dataItem = scheduler.option('dataSource')?.[1]; - expect(appointment.getText()).toEqual(''); + expect(dataItem).toMatchObject({ ...commonAppointment, text: 'New Subject' }); + }); }); - describe('toolbar', () => { - const data = [{ - text: 'Website Re-Design Plan', - startDate: new Date(2017, 4, 22, 9, 30), - endDate: new Date(2017, 4, 22, 11, 30), - disabled: true, - }, { - text: 'Book Flights to San Fran for Sales Trip', - startDate: new Date(2017, 4, 22, 12, 0), - endDate: new Date(2017, 4, 22, 13, 0), - }]; - - it('done button visibility in case allowUpdatingValue = true', async () => { - const { POM } = await createScheduler({ - dataSource: data, - views: ['week'], - currentView: 'week', - currentDate: new Date(2017, 4, 25), - editing: { - allowUpdating: true, + describe('CustomStore', () => { + it('Update appointment if CustomStore', async () => { + const data: Record[] = [{ + startDate: new Date(2015, 4, 24, 9), + endDate: new Date(2015, 4, 24, 11), + }]; + + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: { + key: 'id', + load: () => data, + update: (key: unknown, values: Record) => Promise.resolve().then(() => { + const appointmentData = data.filter(( + item: Record, + ) => (item as { id: unknown }).id === key)[0]; + Object.assign(appointmentData, values); + scheduler.repaint(); + }), }, + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, + }); + + scheduler.showAppointmentPopup({ + startDate: new Date(2015, 4, 24, 9), + endDate: new Date(2015, 4, 24, 11), + text: 'Subject', }); - POM.openPopupByDblClick('Website Re-Design Plan'); - const doneButton = POM.popup.getDoneButton(); - expect(doneButton.getAttribute('aria-label')).toBe('Done'); + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + POM.popup.getSaveButton().click(); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeTruthy(); await new Promise(process.nextTick); - POM.popup.getCancelButton().click(); + const loadPanelAfter = POM.getLoadPanel(); + expect(loadPanelAfter).toBeFalsy(); }); - it('done button visibility in case allowUpdatingValue = false', async () => { - const { POM } = await createScheduler({ - dataSource: data, - views: ['week'], - currentView: 'week', - currentDate: new Date(2017, 4, 25), - editing: { - allowUpdating: false, + it('Insert appointment if CustomStore', async () => { + const fn = jest.fn(); + const data: Record[] = []; + const { scheduler, POM } = await createScheduler({ + views: ['day'], + dataSource: { + key: 'id', + load: () => data, + insert: (appointmentData: Record) => Promise.resolve().then(() => { + (appointmentData as { id: number }).id = data.length; + data.push(appointmentData); + fn(); + }), }, + currentDate: new Date(2015, 4, 24), + startDayHour: 8, + endDayHour: 18, }); - POM.openPopupByDblClick('Website Re-Design Plan'); - expect(() => POM.popup.getDoneButton()).toThrow('Done button not found'); - POM.popup.getCancelButton().click(); + scheduler.showAppointmentPopup(); + + POM.popup.setInputValueByLabel('Subject', 'New Subject'); + POM.popup.setInputValueByLabel('Start Date', '05/24/2015, 9:00 AM'); + POM.popup.setInputValueByLabel('End Date', '05/24/2015, 11:00 AM'); + + POM.popup.getSaveButton().click(); + const loadPanel = POM.getLoadPanel(); + expect(loadPanel).toBeTruthy(); + await new Promise(process.nextTick); + const loadPanelAfter = POM.getLoadPanel(); + expect(loadPanelAfter).toBeFalsy(); + expect(fn).toBeCalled(); }); + }); - it('toolbar should be re-rendered after change editing option', async () => { - const { scheduler, POM } = await createScheduler({ - dataSource: [], - views: ['week'], - currentView: 'week', - currentDate: new Date(2017, 4, 25), - editing: { - allowUpdating: true, - }, - }); + it('should update form data after another appointment was open', async () => { + const { scheduler, POM } = await createScheduler(getDefaultConfig()); - const dataObj = { - text: 'a', - startDate: new Date(2015, 5, 15, 10), - endDate: new Date(2015, 5, 15, 11), - }; - scheduler.showAppointmentPopup(dataObj); - let doneButton = POM.popup.getDoneButton(); - expect(doneButton.getAttribute('aria-label')).toBe('Done'); + scheduler.showAppointmentPopup(commonAppointment); - scheduler.option('editing', { allowUpdating: false }); - scheduler.showAppointmentPopup(dataObj); + expect(POM.popup.form.option('formData')).toMatchObject({ ...commonAppointment }); - expect(() => POM.popup.getDoneButton()).toThrow('Done button not found'); + POM.popup.getCancelButton().click(); - scheduler.showAppointmentPopup(); - doneButton = POM.popup.getDoneButton(); - expect(doneButton.getAttribute('aria-label')).toBe('Done'); - }); + scheduler.showAppointmentPopup(allDayAppointment); + + expect(POM.popup.form.option('formData')).toMatchObject({ ...allDayAppointment }); }); - describe('Appointment Popup and Recurrence Editor visibility', () => { - it.todo('Recurrence editor container should be visible if recurrence rule was set'); - it.todo('Recurrence editor container should be visible after changing its visibility value'); - it.todo('Popup should show or not show reccurence editor after many opening with different data'); - it.todo('Popup should show or not to show reccurence editor after many opening with and change visibility'); - it.todo('Popup should not contain recurrence editor, if recurrenceRuleExpr is null'); - it.todo('Popup should not contain recurrence editor, if recurrenceRuleExpr is \'\''); - it.todo('Multiple showing appointment popup for recurrence appointments and after update options should work correct'); + it('should open appointment on tooltip click', async () => { + setupSchedulerTestEnvironment({ height: 200 }); + const { POM } = await createScheduler(getDefaultConfig()); + + expect(POM.getPopups().length).toBe(0); + + jest.useFakeTimers(); + POM.getAppointment('common-app').element?.click(); + jest.runAllTimers(); + + POM.getTooltipAppointment()?.click(); + + expect(POM.getPopups().length).toBe(1); + expect(POM.popup.form.option('formData')).toMatchObject({ ...commonAppointment }); + }); + + it('should update correct field if textExpr is defined', async () => { + const data: Record[] = []; + const textExpValue = 'Subject'; + + let newAppointment: any = null; + + const { scheduler, POM } = await createScheduler({ + dataSource: data, + views: ['week'], + currentView: 'week', + currentDate: new Date(2021, 4, 27), + textExpr: textExpValue, + onAppointmentAdded: ({ appointmentData }) => { + newAppointment = appointmentData; + }, + height: 600, + }); + + scheduler.showAppointmentPopup(); + + POM.popup.setInputValueByLabel('Subject', 'qwerty'); + POM.popup.getSaveButton().click(); + + expect(newAppointment?.[textExpValue]).toBe('qwerty'); + expect(newAppointment?.text).toBeUndefined(); + + expect(data[0].Subject).toBe('qwerty'); + expect(data[0].text).toBeUndefined(); }); }); @@ -738,8 +958,6 @@ describe('Appointment Popup Content', () => { it.todo('showAppointmentPopup should render a popup only once'); it.todo('showAppointmentPopup should work correctly after scheduler repainting'); it.todo('changing editing should work correctly after showing popup'); - it.todo('hideAppointmentPopup should hide a popup'); - it.todo('hideAppointmentPopup should hide a popup and save changes'); it.todo('showAppointmentPopup should render a popup form only once'); it.todo('popup should have right height'); it.todo('showAppointmentPopup should render a popup content only once'); @@ -773,8 +991,6 @@ describe('Appointment Popup Content', () => { it.todo('Done button custom configuration should be correct'); it.todo('Load panel should be hidden if event validation fail'); it.todo('Load panel should be hidden at the second appointment form opening'); - it.todo('startDateBox & endDateBox should have required validation rules'); - it.todo('Changes shouldn\'t be saved if form is invalid'); it.todo('Appointment popup should contain resources and recurrence editor'); }); @@ -786,19 +1002,10 @@ describe('Appointment Popup', () => { it.todo('Appointment form will have right dates on multiple openings (T727713)'); it.todo('The vertical scroll bar is shown when an appointment popup fill to a small window\'s height'); it.todo('The resize event of appointment popup is triggered the the window is resize'); - it.todo('Popup should not be closed until the valid value is typed'); }); describe('Timezone Editors', () => { - it.todo('Popup should not contain startDateTimeZone editor by default'); - it.todo('Popup should not contain endDateTimeZone editor by default'); - it.todo('It should be possible to render startDateTimeZone editor on appt form'); - it.todo('It should be possible to render endDateTimeZone editor on appt form'); it.todo('timeZone editors should have correct options'); - it.todo('timeZone editors should have correct value & display value on init'); it.todo('timeZone editor should have correct display value for timezones with different offsets'); it.todo('dataSource of timezoneEditor should be filtered'); - it.todo('startDateTimeZone and endDateTimeZone editor should be rendered with allowTimeZoneEditing option'); - it.todo('Change value in startDateTimeZone editor should trigger change value in endDateTimeZone editor if allowTimeZoneEditing: true'); - it.todo('Change value in endDateTimeZone editor shouldn\'t trigger change value in startDateTimeZone editor if allowTimeZoneEditing: true'); }); diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/m_form.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/m_form.ts index 47eaceb45d60..22e74542694b 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/m_form.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/m_form.ts @@ -1,487 +1,698 @@ -import '../m_recurrence_editor'; -import '@js/ui/text_area'; -import '@js/ui/tag_box'; -import '@js/ui/switch'; -import '@js/ui/select_box'; - +import type { TextEditorButton } from '@js/common'; import messageLocalization from '@js/common/core/localization/message'; -import DataSource from '@js/common/data/data_source'; -import devices from '@js/core/devices'; +import { DataSource } from '@js/common/data'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import dateUtils from '@js/core/utils/date'; -import dateSerialization from '@js/core/utils/date_serialization'; import { extend } from '@js/core/utils/extend'; -import Form, { type Item } from '@js/ui/form'; +import type { Properties as DateBoxProperties } from '@js/ui/date_box'; +import type { + GroupItem, Item as FormItem, Properties as FormProperties, SimpleItem, +} from '@js/ui/form'; +import dxForm from '@js/ui/form'; +import type { Properties as SelectBoxProperties } from '@js/ui/select_box'; +import type { Properties as SwitchProperties } from '@js/ui/switch'; +import type { Properties as TextAreaProperties } from '@js/ui/text_area'; import { current, isFluent } from '@js/ui/themes'; +import { dateSerialization } from '@ts/core/utils/m_date_serialization'; import timeZoneUtils from '../m_utils_time_zone'; - -const SCREEN_SIZE_OF_SINGLE_COLUMN = 600; +import type { ResourceLoader } from '../utils/loader/resource_loader'; export const APPOINTMENT_FORM_GROUP_NAMES = { Main: 'mainGroup', Recurrence: 'recurrenceGroup', }; -// TODO: Remove duplication in the scheduler's popup testing model. -// NOTE: These CSS classes allow access the editors -// from e2e testcafe tests. -const E2E_TEST_CLASSES = { - form: 'e2e-dx-scheduler-form', - textEditor: 'e2e-dx-scheduler-form-text', - descriptionEditor: 'e2e-dx-scheduler-form-description', - startDateEditor: 'e2e-dx-scheduler-form-start-date', - endDateEditor: 'e2e-dx-scheduler-form-end-date', - startDateTimeZoneEditor: 'e2e-dx-scheduler-form-start-date-timezone', - endDateTimeZoneEditor: 'e2e-dx-scheduler-form-end-date-timezone', - allDaySwitch: 'e2e-dx-scheduler-form-all-day-switch', - recurrenceSwitch: 'e2e-dx-scheduler-form-recurrence-switch', +const CLASSES = { + form: 'dx-scheduler-form', + + groupWithIcon: 'dx-scheduler-form-group-with-icon', + icon: 'dx-scheduler-form-icon', + defaultResourceIcon: 'dx-scheduler-default-resources-icon', + + mainGroup: 'dx-scheduler-form-main-group', + subjectGroup: 'dx-scheduler-form-subject-group', + dateRangeGroup: 'dx-scheduler-form-date-range-group', + startDateGroup: 'dx-scheduler-form-start-date-group', + endDateGroup: 'dx-scheduler-form-end-date-group', + repeatGroup: 'dx-scheduler-form-repeat-group', + descriptionGroup: 'dx-scheduler-form-description-group', + resourcesGroup: 'dx-scheduler-form-resources-group', + + textEditor: 'dx-scheduler-form-text-editor', + allDaySwitch: 'dx-scheduler-form-all-day-switch', + startDateEditor: 'dx-scheduler-form-start-date-editor', + startTimeEditor: 'dx-scheduler-form-start-time-editor', + startDateTimeZoneEditor: 'dx-scheduler-form-start-date-timezone-editor', + endDateEditor: 'dx-scheduler-form-end-date-editor', + endTimeEditor: 'dx-scheduler-form-end-time-editor', + endDateTimeZoneEditor: 'dx-scheduler-form-end-date-timezone-editor', + repeatEditor: 'dx-scheduler-form-repeat-editor', + descriptionEditor: 'dx-scheduler-form-description-editor', + + recurrenceSettingsButton: 'dx-scheduler-form-recurrence-settings-button', +}; + +const EDITOR_NAMES = { + startDate: 'startDateEditor', + startTime: 'startTimeEditor', + endDate: 'endDateEditor', + endTime: 'endTimeEditor', + repeat: 'repeatEditor', }; -const createTimeZoneDataSource = () => new DataSource({ +const repeatSelectBoxItems = [ + { + recurrence: 'dxScheduler-recurrenceNever', + value: 'never', + }, { + recurrence: 'dxScheduler-recurrenceHourly', + value: 'hourly', + }, { + recurrence: 'dxScheduler-recurrenceDaily', + value: 'daily', + }, { + recurrence: 'dxScheduler-recurrenceWeekly', + value: 'weekly', + }, { + recurrence: 'dxScheduler-recurrenceMonthly', + value: 'monthly', + }, { + recurrence: 'dxScheduler-recurrenceYearly', + value: 'yearly', + }, +].map( + (item) => ({ + text: messageLocalization.format(item.recurrence), + value: item.value, + }), +); + +const createTimeZoneDataSource = (): DataSource => new DataSource({ store: timeZoneUtils.getTimeZonesCache(), paginate: true, pageSize: 10, }); -const getStylingModeFunc = (): string | undefined => (isFluent(current()) ? 'filled' : undefined); +export class AppointmentForm { + private readonly scheduler: any; -const getStartDateWithStartHour = (startDate, startDayHour) => new Date(new Date(startDate).setHours(startDayHour)); + private _dxForm?: dxForm; -const validateAppointmentFormDate = (editor, value, previousValue) => { - const isCurrentDateCorrect = value === null || Boolean(value); - const isPreviousDateCorrect = previousValue === null || Boolean(previousValue); - if (!isCurrentDateCorrect && isPreviousDateCorrect) { - editor.option('value', previousValue); + get dxForm(): dxForm { + return this._dxForm as dxForm; } -}; - -const updateRecurrenceItemVisibility = (recurrenceRuleExpr, value, form) => { - form.itemOption(APPOINTMENT_FORM_GROUP_NAMES.Recurrence, 'visible', value); - form.getEditor(recurrenceRuleExpr)?.changeValueByVisibility(value); -}; -const defaultFormOptions = { - showValidationSummary: true, - scrollingEnabled: true, - colCount: 'auto', - colCountByScreen: { - lg: 2, - xs: 1, - }, - showColonAfterLabel: false, - labelLocation: 'top', - screenByWidth: (width) => (width < SCREEN_SIZE_OF_SINGLE_COLUMN || devices.current().deviceType !== 'desktop' ? 'xs' : 'lg'), - elementAttr: { - class: E2E_TEST_CLASSES.form, - }, -}; - -export class AppointmentForm { - scheduler: any; + set readOnly(value: boolean) { + this.dxForm.option('readOnly', value); + } - form: Form; + get formData(): Record { + return this.dxForm.option('formData') as Record; + } - // NOTE: flag to prevent double value set during form updating - private isFormUpdating = false; + set formData(formData: Record) { + this.dxForm.option('formData', formData); + } - constructor(scheduler) { - this.scheduler = scheduler; - const element = $('
'); + get startDate(): Date | null { + const { startDateExpr } = this.scheduler.getDataAccessors().expr; + const value = this.formData[startDateExpr]; - this.form = this.scheduler.createComponent(element, Form, { - ...defaultFormOptions, - }); + return value ? new Date(dateSerialization.deserializeDate(value)) : null; } - get dxForm() { - return this.form; + get endDate(): Date | null { + const { endDateExpr } = this.scheduler.getDataAccessors().expr; + const value = this.formData[endDateExpr]; + + return value ? new Date(dateSerialization.deserializeDate(value)) : null; } - set readOnly(value) { - this.form.option('readOnly', value); + get recurrenceRule(): string | null { const { recurrenceRuleExpr } = this.scheduler.getDataAccessors().expr; + const value = this.formData[recurrenceRuleExpr] as string | undefined; - const recurrenceEditor = this.form.getEditor(recurrenceRuleExpr); - recurrenceEditor?.option('readOnly', value); + return value ?? null; } - get formData() { - return this.form.option('formData'); + constructor(scheduler: any) { + this.scheduler = scheduler; } - set formData(value) { - this.form.option('formData', value); - } + create(): void { + const mainGroup = this.createMainFormGroup(); - create(triggerResize, changeSize, formData) { - const { allowTimeZoneEditing } = this.scheduler.getEditingConfig(); - const dataAccessors = this.scheduler.getDataAccessors(); - const { expr } = dataAccessors; + const items = [mainGroup]; - const isRecurrence = Boolean(dataAccessors.get('recurrenceRule', formData)); - const colSpan = isRecurrence ? 1 : 2; + this.setStylingModeToEditors(mainGroup); - const mainItems = [ - ...this.createMainItems(expr, triggerResize, changeSize, allowTimeZoneEditing), - ...this.scheduler.createResourceEditorModel(), - ]; - - changeSize(isRecurrence); + this.createForm(items); + } - const items: Item[] = [ - { - itemType: 'group', - name: APPOINTMENT_FORM_GROUP_NAMES.Main, - colCountByScreen: { - lg: 2, - xs: 1, - }, - colSpan, - items: mainItems, - }, { - itemType: 'group', - name: APPOINTMENT_FORM_GROUP_NAMES.Recurrence, - visible: isRecurrence, - colSpan, - items: this.createRecurrenceEditor(expr), - }, - ]; + private createForm(items: FormProperties['items']): dxForm { + const element = $('
'); - this.form.option({ + return this.scheduler.createComponent(element, dxForm, { items, - formData, - }); + formData: {}, + showColonAfterLabel: false, + showValidationSummary: false, + scrollingEnabled: false, + labelLocation: 'top', + elementAttr: { + class: CLASSES.form, + }, + onFieldDataChanged: (e) => { + const { + startDateExpr, endDateExpr, recurrenceRuleExpr, allDayExpr, + } = this.scheduler.getDataAccessors().expr; + + const isAllDayChanged = e.dataField === allDayExpr; + const isDateRangeChanged = [startDateExpr, endDateExpr].includes(e.dataField); + const isRecurrenceRuleChanged = e.dataField === recurrenceRuleExpr; + + if (isAllDayChanged) { + this.updateDateTimeEditorsVisibility(); + } + + if (isDateRangeChanged) { + this.updateDateEditorsValues(); + } + + if (isRecurrenceRuleChanged) { + this.updateRepeatEditor(); + } + }, + onInitialized: (e): void => { + this._dxForm = e.component; + }, + } as FormProperties) as dxForm; } - private dateBoxValueChanged(args, dateExpr, isNeedCorrect) { - validateAppointmentFormDate(args.component, args.value, args.previousValue); - - const value = dateSerialization.deserializeDate(args.value); - const previousValue = dateSerialization.deserializeDate(args.previousValue); - const dateEditor = this.form.getEditor(dateExpr); - // @ts-expect-error should be fixed in the future - const dateValue = dateSerialization.deserializeDate(dateEditor.option('value')); + private createMainFormGroup(): GroupItem { + return { + name: APPOINTMENT_FORM_GROUP_NAMES.Main, + itemType: 'group', + colSpan: 1, + cssClass: CLASSES.mainGroup, + items: [ + this.createSubjectGroup(), + this.createDateRangeGroup(), + this.createRepeatGroup(), + this.createResourcesGroup(), + this.createDescriptionGroup(), + ], + } as GroupItem; + } - if (!this.isFormUpdating && dateValue && value && isNeedCorrect(dateValue, value)) { - const duration = previousValue ? dateValue.getTime() - previousValue.getTime() : 0; - // @ts-expect-error should be fixed in the future - dateEditor.option('value', new Date(value.getTime() + duration)); - } + private createRecurrenceFormGroup(): GroupItem { + throw new Error('Method not implemented.'); } - private createTimezoneEditor(timeZoneExpr, secondTimeZoneExpr, visibleIndex, colSpan, isMainTimeZone, cssClass, visible = false) { - const noTzTitle = messageLocalization.format('dxScheduler-noTimezoneTitle'); + private createSubjectGroup(): GroupItem { + const { textExpr } = this.scheduler.getDataAccessors().expr; return { - name: this.normalizeEditorName(timeZoneExpr), - dataField: timeZoneExpr, - editorType: 'dxSelectBox', - visibleIndex, - colSpan, - cssClass, - label: { - text: ' ', + itemType: 'group', + cssClass: `${CLASSES.subjectGroup} ${CLASSES.groupWithIcon}`, + colCount: 2, + colCountByScreen: { + xs: 2, }, - editorOptions: { - displayExpr: 'title', - valueExpr: 'id', - placeholder: noTzTitle, - searchEnabled: true, - dataSource: createTimeZoneDataSource(), - onValueChanged: (args) => { - const { form } = this; - const secondTimezoneEditor = form.getEditor(secondTimeZoneExpr); - if (isMainTimeZone) { - // @ts-expect-error should be fixed in the future - secondTimezoneEditor.option('value', args.value); - } + items: [ + { + colSpan: 1, + cssClass: CLASSES.icon, + template: this.createIconTemplate('isnotblank'), }, - }, - visible, - }; + { + colSpan: 1, + itemType: 'simple', + cssClass: CLASSES.textEditor, + dataField: textExpr, + label: { + text: messageLocalization.format('dxScheduler-editorLabelTitle'), + }, + editorType: 'dxTextBox', + }, + ], + } as GroupItem; } - private createDateBoxItems(dataExprs, allowTimeZoneEditing) { - const colSpan = allowTimeZoneEditing ? 2 : 1; - const firstDayOfWeek = this.scheduler.getFirstDayOfWeek(); - - return [ - this.createDateBoxEditor( - dataExprs.startDateExpr, - colSpan, - firstDayOfWeek, - 'dxScheduler-editorLabelStartDate', - E2E_TEST_CLASSES.startDateEditor, - (args) => { - this.dateBoxValueChanged(args, dataExprs.endDateExpr, (endValue, startValue) => endValue < startValue); + private createDateRangeGroup(): GroupItem { + return { + itemType: 'group', + cssClass: `${CLASSES.dateRangeGroup} ${CLASSES.groupWithIcon}`, + colCount: 2, + colCountByScreen: { + xs: 2, + }, + items: [ + { + colSpan: 1, + cssClass: CLASSES.icon, + template: this.createIconTemplate('clock'), }, - ), - - this.createTimezoneEditor( - dataExprs.startDateTimeZoneExpr, - dataExprs.endDateTimeZoneExpr, - 1, - colSpan, - true, - E2E_TEST_CLASSES.startDateTimeZoneEditor, - allowTimeZoneEditing, - ), - - this.createDateBoxEditor( - dataExprs.endDateExpr, - colSpan, - firstDayOfWeek, - 'dxScheduler-editorLabelEndDate', - E2E_TEST_CLASSES.endDateEditor, - (args) => { - this.dateBoxValueChanged(args, dataExprs.startDateExpr, (startValue, endValue) => endValue < startValue); + { + colSpan: 1, + itemType: 'group', + items: [ + this.createAllDaySwitch(), + this.createStartDateGroup(), + this.createEndDateGroup(), + ], }, - ), - - this.createTimezoneEditor( - dataExprs.endDateTimeZoneExpr, - dataExprs.startDateTimeZoneExpr, - 3, - colSpan, - false, - E2E_TEST_CLASSES.endDateTimeZoneEditor, - allowTimeZoneEditing, - ), - ]; + ], + } as GroupItem; } - private changeFormItemDateType(name: string, groupName: string, isAllDay: boolean): void { - const editorPath = this.getEditorPath(name, groupName); - const itemEditorOptions = this.form.itemOption(editorPath).editorOptions; + private createAllDaySwitch(): SimpleItem { + const { allDayExpr, startDateExpr, endDateExpr } = this.scheduler.getDataAccessors().expr; - const type = isAllDay ? 'date' : 'datetime'; + return { + itemType: 'simple', + dataField: allDayExpr, + cssClass: CLASSES.allDaySwitch, + label: { + text: messageLocalization.format('dxScheduler-allDay'), + location: 'left', + }, + editorType: 'dxSwitch', + editorOptions: { + onValueChanged: (e) => { + const { startDate } = this; + + if (!startDate) { + return; + } + + if (e.value) { + const allDayStartDate = dateUtils.trimTime(startDate); - const newEditorOption = { ...itemEditorOptions, type }; + this.dxForm.updateData(startDateExpr, allDayStartDate); + this.dxForm.updateData(endDateExpr, allDayStartDate); + } else { + const startHour = this.scheduler.getStartDayHour(); + startDate.setHours(startHour); - this.form.itemOption(editorPath, 'editorOptions', newEditorOption); + const endDate = this.scheduler.getCalculatedEndDate(startDate); + + this.dxForm.updateData(startDateExpr, startDate); + this.dxForm.updateData(endDateExpr, endDate); + } + }, + } as SwitchProperties, + } as SimpleItem; } - private createMainItems(dataExprs, triggerResize, changeSize, allowTimeZoneEditing) { - return [ + private createStartDateGroup(): GroupItem { + const { + startDateExpr, startDateTimeZoneExpr, endDateTimeZoneExpr, + } = this.scheduler.getDataAccessors().expr; + + return this.createDateGroup( + startDateExpr, { - name: this.normalizeEditorName(dataExprs.textExpr), - dataField: dataExprs.textExpr, - cssClass: E2E_TEST_CLASSES.textEditor, - editorType: 'dxTextBox', - colSpan: 2, + cssClass: CLASSES.startDateGroup, + }, + { + name: EDITOR_NAMES.startDate, label: { - text: messageLocalization.format('dxScheduler-editorLabelTitle'), + text: messageLocalization.format('dxScheduler-editorLabelStartDate'), }, + cssClass: CLASSES.startDateEditor, + }, + { + name: EDITOR_NAMES.startTime, + cssClass: CLASSES.startTimeEditor, + }, + { + dataField: startDateTimeZoneExpr, + cssClass: CLASSES.startDateTimeZoneEditor, editorOptions: { - stylingMode: getStylingModeFunc(), - }, + onValueChanged: (e) => { + const endDateTimeZoneEditor = this.dxForm.getEditor(endDateTimeZoneExpr); + + endDateTimeZoneEditor?.option('value', e.value); + }, + } as SelectBoxProperties, + }, + ); + } + + private createEndDateGroup(): GroupItem { + const { endDateExpr, endDateTimeZoneExpr } = this.scheduler.getDataAccessors().expr; + + return this.createDateGroup( + endDateExpr, + { + cssClass: CLASSES.endDateGroup, }, { - itemType: 'group', - colSpan: 2, - colCountByScreen: { - lg: 2, - xs: 1, + name: EDITOR_NAMES.endDate, + label: { + text: messageLocalization.format('dxScheduler-editorLabelEndDate'), }, - items: this.createDateBoxItems(dataExprs, allowTimeZoneEditing), + cssClass: CLASSES.endDateEditor, }, { - itemType: 'group', - colSpan: 2, - colCountByScreen: { - lg: 2, - xs: 2, + name: EDITOR_NAMES.endTime, + cssClass: CLASSES.endTimeEditor, + }, + { + dataField: endDateTimeZoneExpr, + cssClass: CLASSES.endDateTimeZoneEditor, + }, + ); + } + + private createDateGroup( + dateExpr: string, + groupItemOptions?: GroupItem, + dateItemOptions?: SimpleItem, + timeItemOptions?: SimpleItem, + timezoneItemOptions?: SimpleItem, + ): GroupItem { + const { allowTimeZoneEditing } = this.scheduler.getEditingConfig(); + const { startDateExpr, endDateExpr } = this.scheduler.getDataAccessors().expr; + const isStartDateEditor = dateExpr === startDateExpr; + + const getEditorsDate = (): Date | null => (isStartDateEditor ? this.startDate : this.endDate); + + const correctDateRange = (previousDateValue: Date): void => { + const { startDate, endDate } = this; + + if (!startDate || !endDate || startDate.getTime() <= endDate.getTime()) { + return; + } + + if (isStartDateEditor) { + const duration = previousDateValue ? endDate.getTime() - previousDateValue.getTime() : 0; + const correctedEndDate = new Date(startDate.getTime() + duration); + + this.dxForm.updateData(endDateExpr, correctedEndDate); + } else { + const duration = previousDateValue ? previousDateValue.getTime() - startDate.getTime() : 0; + const correctedStartDate = new Date(endDate.getTime() - duration); + + this.dxForm.updateData(startDateExpr, correctedStartDate); + } + }; + + const dateValueChanged = (e, modifyDate: (date: Date) => void): void => { + const currentDate = getEditorsDate(); + + if (!currentDate) { + this.dxForm.updateData(dateExpr, e.value); + return; + } + + if (!e.value) { + return; + } + + const previousDateValue = new Date(currentDate); + + modifyDate(currentDate); + + this.dxForm.updateData(dateExpr, currentDate); + correctDateRange(previousDateValue); + }; + + return { + itemType: 'group', + colCount: 2, + colCountByScreen: { + xs: 2, + }, + items: [ + extend(true, { + itemType: 'simple', + colSpan: 1, + editorType: 'dxDateBox', + validationRules: [{ + type: 'required', + }], + editorOptions: { + type: 'date', + useMaskBehavior: true, + onValueChanged: (e) => { + dateValueChanged(e, (date: Date): void => { + date.setFullYear(e.value.getFullYear(), e.value.getMonth(), e.value.getDate()); + }); + }, + onContentReady: (e): void => { + e.component.option('value', getEditorsDate()); + }, + } as DateBoxProperties, + }, dateItemOptions), + extend(true, { + itemType: 'simple', + colSpan: 1, + editorType: 'dxDateBox', + validationRules: [{ + type: 'required', + }], + editorOptions: { + type: 'time', + useMaskBehavior: true, + calendarOptions: { + firstDayOfWeek: this.scheduler.getFirstDayOfWeek(), + }, + onValueChanged: (e) => { + dateValueChanged(e, (date: Date): void => { + date.setHours(e.value.getHours(), e.value.getMinutes()); + }); + }, + onContentReady: (e): void => { + e.component.option('value', getEditorsDate()); + }, + } as DateBoxProperties, + }, timeItemOptions), + extend(true, { + itemType: 'simple', + colSpan: 2, + editorType: 'dxSelectBox', + visible: allowTimeZoneEditing, + editorOptions: { + displayExpr: 'title', + valueExpr: 'id', + placeholder: messageLocalization.format('dxScheduler-noTimezoneTitle'), + searchEnabled: true, + dataSource: createTimeZoneDataSource(), + } as SelectBoxProperties, + }, timezoneItemOptions), + ], + ...groupItemOptions, + } as GroupItem; + } + + private createRepeatGroup(): GroupItem { + return { + itemType: 'group', + colCount: 2, + colCountByScreen: { + xs: 2, + }, + cssClass: `${CLASSES.repeatGroup} ${CLASSES.groupWithIcon}`, + items: [ + { + colSpan: 1, + cssClass: CLASSES.icon, + template: this.createIconTemplate('repeat'), }, - items: [{ - name: this.normalizeEditorName(dataExprs.allDayExpr), - dataField: dataExprs.allDayExpr, - cssClass: `dx-appointment-form-switch ${E2E_TEST_CLASSES.allDaySwitch}`, - editorType: 'dxSwitch', + { + name: EDITOR_NAMES.repeat, + colSpan: 1, + itemType: 'simple', + cssClass: CLASSES.repeatEditor, label: { - text: messageLocalization.format('dxScheduler-allDay'), - location: 'right', + text: messageLocalization.format('dxScheduler-editorLabelRecurrence'), }, + editorType: 'dxSelectBox', editorOptions: { - onValueChanged: (args) => { - const { value } = args; - const startDateEditor = this.form.getEditor(dataExprs.startDateExpr); - const endDateEditor = this.form.getEditor(dataExprs.endDateExpr); - // @ts-expect-error should be fixed in the future - const startDate = dateSerialization.deserializeDate(startDateEditor.option('value')); - - if (!this.isFormUpdating && startDate) { - if (value) { - const allDayStartDate = dateUtils.trimTime(startDate); - // @ts-expect-error should be fixed in the future - startDateEditor.option('value', new Date(allDayStartDate)); - // @ts-expect-error should be fixed in the future - endDateEditor.option('value', new Date(allDayStartDate)); - } else { - const startDateWithStartHour = getStartDateWithStartHour(startDate, this.scheduler.getStartDayHour()); - const endDate = this.scheduler.getCalculatedEndDate(startDateWithStartHour); - // @ts-expect-error should be fixed in the future - startDateEditor.option('value', startDateWithStartHour); - // @ts-expect-error should be fixed in the future - endDateEditor.option('value', endDate); - } - } - - this.changeFormItemDateType(dataExprs.startDateExpr, 'Main', value); - this.changeFormItemDateType(dataExprs.endDateExpr, 'Main', value); + items: repeatSelectBoxItems, + valueExpr: 'value', + displayExpr: 'text', + onContentReady: (): void => { + this.updateRepeatEditor(); }, - }, - }, { - editorType: 'dxSwitch', - dataField: 'repeat', - cssClass: `dx-appointment-form-switch ${E2E_TEST_CLASSES.recurrenceSwitch}`, - name: 'visibilityChanged', + } as SelectBoxProperties, + }, + ], + } as GroupItem; + } + + private createDescriptionGroup(): GroupItem { + return { + itemType: 'group', + colCount: 2, + colCountByScreen: { + xs: 2, + }, + cssClass: `${CLASSES.descriptionGroup} ${CLASSES.groupWithIcon}`, + items: [ + { + colSpan: 1, + cssClass: CLASSES.icon, + template: this.createIconTemplate('description'), + }, + { + colSpan: 1, + itemType: 'simple', + cssClass: CLASSES.descriptionEditor, label: { - text: messageLocalization.format('dxScheduler-editorLabelRecurrence'), - location: 'right', + text: messageLocalization.format('dxScheduler-editorLabelDescription'), }, + editorType: 'dxTextArea', editorOptions: { - onValueChanged: (args) => { - const { form } = this; - const colSpan = args.value ? 1 : 2; + height: 100, + } as TextAreaProperties, + }, + ], + } as GroupItem; + } - form.itemOption(APPOINTMENT_FORM_GROUP_NAMES.Main, 'colSpan', colSpan); - form.itemOption(APPOINTMENT_FORM_GROUP_NAMES.Recurrence, 'colSpan', colSpan); + private createResourcesGroup(): GroupItem | undefined { + const resourcesLoaders: ResourceLoader[] = Object.values(this.scheduler.getResourceById()); - updateRecurrenceItemVisibility(dataExprs.recurrenceRuleExpr, args.value, form); + const resourcesItems = resourcesLoaders.map((resourceLoader) => { + const { dataSource, dataAccessor } = resourceLoader; + const dataField = resourceLoader.resourceIndex; + const label = resourceLoader.resourceName ?? dataField; + const editorType = resourceLoader.allowMultiple ? 'dxTagBox' : 'dxSelectBox'; - changeSize(args.value); - triggerResize(); + return { + itemType: 'group', + items: [ + { + itemType: 'simple', + dataField, + label: { text: label }, + editorType, + editorOptions: { + dataSource, + displayExpr: dataAccessor.textExpr, + valueExpr: dataAccessor.idExpr, }, }, - }], - }, - { - itemType: 'empty', - colSpan: 2, + ], + } as GroupItem; + }); + + return { + itemType: 'group', + visible: resourcesItems.length > 0, + colCount: 2, + colCountByScreen: { + xs: 2, }, - { - name: this.normalizeEditorName(dataExprs.descriptionExpr), - dataField: dataExprs.descriptionExpr, - cssClass: E2E_TEST_CLASSES.descriptionEditor, - editorType: 'dxTextArea', - colSpan: 2, - label: { - text: messageLocalization.format('dxScheduler-editorLabelDescription'), + cssClass: `${CLASSES.resourcesGroup} ${CLASSES.groupWithIcon}`, + items: [ + { + colSpan: 1, + cssClass: `${CLASSES.icon} ${CLASSES.defaultResourceIcon}`, + template: this.createIconTemplate('user'), // TODO: change icon to 'addcircleoutline' }, - editorOptions: { - stylingMode: getStylingModeFunc(), + { + itemType: 'group', + colSpan: 1, + items: resourcesItems, }, - }, - { - itemType: 'empty', - colSpan: 2, - }, - ]; - } - - private createRecurrenceEditor(dataExprs) { - return [{ - name: this.normalizeEditorName(dataExprs.recurrenceRuleExpr), - dataField: dataExprs.recurrenceRuleExpr, - editorType: 'dxRecurrenceEditor', - editorOptions: { - firstDayOfWeek: this.scheduler.getFirstDayOfWeek(), - timeZoneCalculator: this.scheduler.getTimeZoneCalculator(), - getStartDateTimeZone: () => this.scheduler.getDataAccessors().get('startDateTimeZone', this.formData), - }, - label: { - text: ' ', - visible: false, - }, - }]; + ], + } as GroupItem; } - private setEditorsType(allDay) { - const { startDateExpr, endDateExpr } = this.scheduler.getDataAccessors().expr; - - const startDateItemPath = this.getEditorPath(startDateExpr, 'Main'); - const endDateItemPath = this.getEditorPath(endDateExpr, 'Main'); + private setStylingModeToEditors(item: FormItem): void { + if (item.itemType === 'simple') { + const simpleItem = item as SimpleItem; + const stylingMode = isFluent(current()) ? 'filled' : undefined; - const startDateFormItem = this.form.itemOption(startDateItemPath); - const endDateFormItem = this.form.itemOption(endDateItemPath); + simpleItem.editorOptions = extend(simpleItem.editorOptions, { + stylingMode, + }); - if (startDateFormItem && endDateFormItem) { - const startDateEditorOptions = startDateFormItem.editorOptions; - const endDateEditorOptions = endDateFormItem.editorOptions; + return; + } - startDateEditorOptions.type = endDateEditorOptions.type = allDay ? 'date' : 'datetime'; + if (item.itemType === 'group') { + const groupItem = item as GroupItem; - this.form.itemOption(startDateItemPath, 'editorOptions', startDateEditorOptions); - this.form.itemOption(endDateItemPath, 'editorOptions', endDateEditorOptions); + groupItem.items?.forEach((child) => { + this.setStylingModeToEditors(child); + }); } } - private updateRecurrenceEditorStartDate(date, expression) { - const options = { startDate: date }; - - this.setEditorOptions(expression, 'Recurrence', options); + private showRecurrenceGroup(): void { + throw new Error('Method not implemented.'); } - private setEditorOptions(name, groupName: 'Main' | 'Recurrence', options) { - const editorPath = this.getEditorPath(name, groupName); - const editor = this.form.itemOption(editorPath); + private updateDateEditorsValues(): void { + const startDateEditor = this.dxForm.getEditor(EDITOR_NAMES.startDate); + const startTimeEditor = this.dxForm.getEditor(EDITOR_NAMES.startTime); + const endDateEditor = this.dxForm.getEditor(EDITOR_NAMES.endDate); + const endTimeEditor = this.dxForm.getEditor(EDITOR_NAMES.endTime); - editor && this.form.itemOption(editorPath, 'editorOptions', extend({}, editor.editorOptions, options)); + startDateEditor?.option('value', this.startDate); + startTimeEditor?.option('value', this.startDate); + endDateEditor?.option('value', this.endDate); + endTimeEditor?.option('value', this.endDate); } - updateFormData(formData: Record): void { - this.isFormUpdating = true; - this.form.option('formData', formData); - - const dataAccessors = this.scheduler.getDataAccessors(); - const { expr } = dataAccessors; + private updateRepeatEditor(): void { + const repeatEditor = this.dxForm.getEditor(EDITOR_NAMES.repeat); - const rawStartDate = dataAccessors.get('startDate', formData); - - const allDay = dataAccessors.get('allDay', formData); - const startDate = new Date(rawStartDate); - - this.updateRecurrenceEditorStartDate(startDate, expr.recurrenceRuleExpr); + if (!repeatEditor) { + return; + } - this.setEditorsType(allDay); - this.isFormUpdating = false; + repeatEditor.option('buttons', this.getRepeatEditorButtons()); } - private createDateBoxEditor(dataField, colSpan, firstDayOfWeek, label, cssClass, onValueChanged) { - return { - editorType: 'dxDateBox', - name: this.normalizeEditorName(dataField), - dataField, - colSpan, - cssClass, - label: { - text: messageLocalization.format(label), - }, - validationRules: [{ - type: 'required', - }], - editorOptions: { - stylingMode: getStylingModeFunc(), - width: '100%', - calendarOptions: { - firstDayOfWeek, + private getRepeatEditorButtons(): TextEditorButton[] { + const buttons: TextEditorButton[] = []; + + if (this.recurrenceRule !== undefined) { + buttons.push({ + location: 'after', + name: 'settings', + options: { + icon: 'optionsoutline', // todo this icon is missing in font + stylingMode: 'text', + onClick: (): void => { + this.showRecurrenceGroup(); + }, + elementAttr: { + class: CLASSES.recurrenceSettingsButton, + }, }, - onValueChanged, - useMaskBehavior: true, - }, - }; + }); + } + + buttons.push({ + name: 'dropDown', + }); + + return buttons; } - private getEditorPath(name: string, groupName: string): string { - const normalizedName = this.normalizeEditorName(name); - return `${APPOINTMENT_FORM_GROUP_NAMES[groupName]}.${normalizedName}`; + private updateDateTimeEditorsVisibility(): void { + const { allDayExpr } = this.scheduler.getDataAccessors().expr; + const visible = !this.formData[allDayExpr]; + const mainGroup = APPOINTMENT_FORM_GROUP_NAMES.Main; + + this.dxForm.beginUpdate(); + this.dxForm.itemOption(`${mainGroup}.${EDITOR_NAMES.startDate}`, 'colSpan', visible ? 1 : 2); + this.dxForm.itemOption(`${mainGroup}.${EDITOR_NAMES.startTime}`, 'visible', visible); + this.dxForm.itemOption(`${mainGroup}.${EDITOR_NAMES.endDate}`, 'colSpan', visible ? 1 : 2); + this.dxForm.itemOption(`${mainGroup}.${EDITOR_NAMES.endTime}`, 'visible', visible); + this.dxForm.endUpdate(); } - private normalizeEditorName(name: string): string { - // NOTE: This ternary operator covers the "recurrenceRuleExpr: null/''" scenarios. - return name - ? name.replace(/\./g, '_') - : name; + private createIconTemplate(iconName: string): () => void { + return (): dxElementWrapper => $('').addClass('dx-icon').addClass(`dx-icon-${iconName}`); } } diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/m_legacy_popup.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/m_legacy_popup.ts index efb8729ea4b1..60ead1a03da7 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/m_legacy_popup.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/m_legacy_popup.ts @@ -17,7 +17,7 @@ import { getAppointmentGroupValues, getRawAppointmentGroupValues } from '../util const toMs = dateUtils.dateToMilliseconds; -export const APPOINTMENT_POPUP_CLASS = 'dx-scheduler-appointment-popup'; +export const APPOINTMENT_POPUP_CLASS = 'dx-scheduler-legacy-appointment-popup'; const DAY_IN_MS = toMs('day'); diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/m_popup.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/m_popup.ts index efb8729ea4b1..2d054ef0d78c 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/m_popup.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/m_popup.ts @@ -1,43 +1,26 @@ import { triggerResizeEvent } from '@js/common/core/events/visibility_change'; import messageLocalization from '@js/common/core/localization/message'; -import devices from '@js/core/devices'; +import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import dateUtils from '@js/core/utils/date'; import { Deferred, when } from '@js/core/utils/deferred'; +import { getWidth } from '@js/core/utils/size'; +import { getWindow } from '@js/core/utils/window'; +import type { ToolbarItem } from '@js/ui/popup'; import Popup from '@js/ui/popup/ui.popup'; -import { - getMaxWidth, - getPopupToolbarItems, - isPopupFullScreenNeeded, -} from '@ts/scheduler/r1/appointment_popup/index'; +import { current, isFluent } from '@js/ui/themes'; import { hide as hideLoading, show as showLoading } from '../m_loading'; +import type { SafeAppointment } from '../types'; import { AppointmentAdapter } from '../utils/appointment_adapter/appointment_adapter'; import { getAppointmentGroupValues, getRawAppointmentGroupValues } from '../utils/resource_manager/appointment_groups_utils'; - -const toMs = dateUtils.dateToMilliseconds; +import type { AppointmentForm } from './m_form'; export const APPOINTMENT_POPUP_CLASS = 'dx-scheduler-appointment-popup'; -const DAY_IN_MS = toMs('day'); - -const POPUP_CONFIG = { - height: 'auto', - maxHeight: '100%', - showCloseButton: false, - showTitle: false, - preventScrollEvents: false, - enableBodyScroll: false, - defaultOptionsRules: [ - { - device: () => devices.current().android, - options: { - showTitle: false, - }, - }, - ], - _ignorePreventScrollEventsDeprecation: true, -}; +const POPUP_FULL_SCREEN_MODE_WINDOW_WIDTH_THRESHOLD = 460; + +const DAY_IN_MS = dateUtils.dateToMilliseconds('day'); export const ACTION_TO_APPOINTMENT = { CREATE: 0, @@ -48,7 +31,7 @@ export const ACTION_TO_APPOINTMENT = { export class AppointmentPopup { scheduler: any; - form: any; + form: AppointmentForm; popup: any; @@ -83,13 +66,8 @@ export class AppointmentPopup { this.popup = this._createPopup(popupConfig); } - this.popup.option( - 'toolbarItems', - getPopupToolbarItems( - config.isToolbarVisible, - (e) => this._doneButtonClickHandler(e), - ), - ); + const toolbarItems = this._getPopupToolbarItems(config.isToolbarVisible); + this.popup.option('toolbarItems', toolbarItems); this.popup.show(); } @@ -112,14 +90,55 @@ export class AppointmentPopup { _createPopupConfig() { return { - ...POPUP_CONFIG, - onHiding: () => this.scheduler.focus(), - contentTemplate: () => this._createPopupContent(), - onShowing: (e) => this._onShowing(e), + height: 'auto', + maxHeight: '90%', + showCloseButton: false, + showTitle: true, + title: messageLocalization.format('dxScheduler-editPopupTitle'), + preventScrollEvents: false, + enableBodyScroll: false, + _ignorePreventScrollEventsDeprecation: true, + onHiding: (): void => { this.scheduler.focus(); }, + contentTemplate: (): dxElementWrapper => { + this.form.create(); + return this.form.dxForm.$element(); + }, + onShowing: (e): void => this._onShowing(e), wrapperAttr: { class: APPOINTMENT_POPUP_CLASS }, }; } + _getPopupToolbarItems(allowUpdating: boolean): ToolbarItem[] { + const result: ToolbarItem[] = []; + + if (allowUpdating) { + result.push( + { + toolbar: 'top', + location: 'after', + options: { + onClick: (e) => this._doneButtonClickHandler(e), + stylingMode: 'contained', + type: 'default', + text: messageLocalization.format('dxScheduler-editPopupSaveButtonText'), + }, + shortcut: 'done', + } as ToolbarItem, + ); + } + + result.push({ + toolbar: 'top', + location: 'after', + shortcut: 'cancel', + options: { + stylingMode: 'outlined', + }, + } as ToolbarItem); + + return result; + } + _onShowing(e) { this._updateForm(); @@ -145,37 +164,8 @@ export class AppointmentPopup { }); } - _createPopupContent() { - this._createForm(); - return this.form.dxForm.$element(); // TODO - } - - _createFormData(rawAppointment) { - const appointment = this._createAppointmentAdapter(rawAppointment); - const resourceManager = this.scheduler.getResourceManager(); - const rawAppointmentGroupValues = getRawAppointmentGroupValues( - rawAppointment, - resourceManager.resources, - ); - - return { - ...rawAppointment, - ...rawAppointmentGroupValues, - repeat: Boolean(appointment.recurrenceRule), - }; - } - - _createForm() { - const rawAppointment = this.state.appointment.data; - const formData = this._createFormData(rawAppointment); - - this.form.create(this.triggerResize.bind(this), this.changeSize.bind(this), formData); // TODO - } - - _isReadOnly(rawAppointment) { - const appointment = this._createAppointmentAdapter(rawAppointment); - - if (rawAppointment && appointment.disabled) { + _isReadOnly(appointmentAdapter: AppointmentAdapter): boolean { + if (Boolean(appointmentAdapter.source) && appointmentAdapter.disabled) { return true; } @@ -186,49 +176,61 @@ export class AppointmentPopup { return !this.scheduler.getEditingConfig().allowUpdating; } - _createAppointmentAdapter(rawAppointment) { + _createAppointmentAdapter(rawAppointment): AppointmentAdapter { return new AppointmentAdapter( rawAppointment, this.scheduler.getDataAccessors(), ); } - _updateForm() { - const { data } = this.state.appointment; - const appointment = this._createFormData(data); - const formData = this._createAppointmentAdapter(appointment) + _updateForm(): void { + const rawAppointment = this.state.appointment.data; + const appointmentAdapter = this._createAppointmentAdapter(rawAppointment) .clone() - .calculateDates(this.scheduler.getTimeZoneCalculator(), 'toAppointment') - .source; + .calculateDates(this.scheduler.getTimeZoneCalculator(), 'toAppointment'); - this.form.readOnly = this._isReadOnly(formData); - this.form.updateFormData(formData); + const formData = this._createFormData(appointmentAdapter); + + this.form.readOnly = this._isReadOnly(appointmentAdapter); + this.form.formData = formData; } - triggerResize() { - if (this.popup) { - triggerResizeEvent(this.popup.$element()); - } + _createFormData(appointmentAdapter: AppointmentAdapter): Record { + const { resources } = this.scheduler.getResourceManager(); + const groupValues = getRawAppointmentGroupValues( + appointmentAdapter.source as SafeAppointment, + resources, + ); + + const { allDayExpr } = this.scheduler.getDataAccessors().expr; + + return { + ...appointmentAdapter.source, + ...groupValues, + [allDayExpr]: Boolean(appointmentAdapter.allDay), + }; } - changeSize(isRecurrence) { + triggerResize(): void { if (this.popup) { - const isFullScreen = isPopupFullScreenNeeded(); - const maxWidth = isFullScreen - ? '100%' - : getMaxWidth(isRecurrence); - this.popup.option('fullScreen', isFullScreen); - this.popup.option('maxWidth', maxWidth); + triggerResizeEvent(this.popup.$element()); } } - updatePopupFullScreenMode() { - if (this.form.dxForm && this.visible) { // TODO - const { formData } = this.form; - const dataAccessors = this.scheduler.getDataAccessors(); - const isRecurrence = dataAccessors.get('recurrenceRule', formData); + updatePopupFullScreenMode(): void { + if (this.form.dxForm && this.visible) { + const isPopupFullScreenNeeded = () => { + const window = getWindow(); + const width = window && getWidth(window); - this.changeSize(isRecurrence); + return width < POPUP_FULL_SCREEN_MODE_WINDOW_WIDTH_THRESHOLD; + }; + + const isFullScreen = isPopupFullScreenNeeded(); + const maxWidth = isFluent(current()) ? 380 : 420; + + this.popup.option('fullScreen', isFullScreen); + this.popup.option('maxWidth', isFullScreen ? '100%' : maxWidth); } } @@ -239,28 +241,21 @@ export class AppointmentPopup { isShowLoadPanel && this._showLoadPanel(); - when(validation?.complete || validation).done((validation) => { - if (validation && !validation.isValid) { + when(validation?.complete ?? validation).done((validation) => { + if (validation && !(validation as any).isValid) { hideLoading(); deferred.resolve(false); return; } - const { repeat } = this.form.formData; const adapter = this._createAppointmentAdapter(this.form.formData); const clonedAdapter = adapter .clone() .calculateDates(this.scheduler.getTimeZoneCalculator(), 'fromAppointment'); - const shouldClearRecurrenceRule = !repeat && Boolean(clonedAdapter.recurrenceRule); this._addMissingDSTTime(adapter, clonedAdapter); - if (shouldClearRecurrenceRule) { - clonedAdapter.recurrenceRule = ''; - } - const appointment = clonedAdapter.source; - delete appointment.repeat; // TODO switch (this.state.action) { case ACTION_TO_APPOINTMENT.CREATE: @@ -373,7 +368,7 @@ export class AppointmentPopup { const shiftDifference = originTimezoneShift - clonedTimezoneShift; return shiftDifference - ? new Date(clonedDate.getTime() + shiftDifference * toMs('hour')) + ? new Date(clonedDate.getTime() + shiftDifference * dateUtils.dateToMilliseconds('hour')) : clonedDate; } } diff --git a/packages/devextreme/js/__internal/scheduler/m_scheduler.ts b/packages/devextreme/js/__internal/scheduler/m_scheduler.ts index 58e92ebaddf8..54e9f41f326c 100644 --- a/packages/devextreme/js/__internal/scheduler/m_scheduler.ts +++ b/packages/devextreme/js/__internal/scheduler/m_scheduler.ts @@ -1048,7 +1048,7 @@ class Scheduler extends SchedulerOptionsBaseWidget { createAppointmentForm() { const scheduler = { - createResourceEditorModel: () => createResourceEditorModel(this.resourceManager.resourceById), + getResourceById: () => this.resourceManager.resourceById, getDataAccessors: () => this._dataAccessors, // @ts-expect-error createComponent: (element, component, options) => this._createComponent(element, component, options), @@ -1061,9 +1061,13 @@ class Scheduler extends SchedulerOptionsBaseWidget { getTimeZoneCalculator: () => this.timeZoneCalculator, }; - return this._editing.legacyForm - ? new AppointmentLegacyForm(scheduler) - : new AppointmentForm(scheduler); + if (this._editing.legacyForm) { + (scheduler as any).createResourceEditorModel = () => createResourceEditorModel(this.resourceManager.resourceById); + + return new AppointmentLegacyForm(scheduler); + } + + return new AppointmentForm(scheduler); } createAppointmentPopup(form) { diff --git a/packages/devextreme/js/localization/messages/ar.json b/packages/devextreme/js/localization/messages/ar.json index 4241f751ef09..c3fb24d53ce5 100644 --- a/packages/devextreme/js/localization/messages/ar.json +++ b/packages/devextreme/js/localization/messages/ar.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "الموضوع", "dxScheduler-editorLabelStartDate": "تاريخ البدء", "dxScheduler-editorLabelEndDate": "تاريخ الانتهاء", diff --git a/packages/devextreme/js/localization/messages/bg.json b/packages/devextreme/js/localization/messages/bg.json index a30f04fb4279..3518f1433485 100644 --- a/packages/devextreme/js/localization/messages/bg.json +++ b/packages/devextreme/js/localization/messages/bg.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Заглавие", "dxScheduler-editorLabelStartDate": "Начална дата", "dxScheduler-editorLabelEndDate": "Краен срок", diff --git a/packages/devextreme/js/localization/messages/ca.json b/packages/devextreme/js/localization/messages/ca.json index 0df257797fdd..cd2551afd2e3 100644 --- a/packages/devextreme/js/localization/messages/ca.json +++ b/packages/devextreme/js/localization/messages/ca.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Assignatura", "dxScheduler-editorLabelStartDate": "Data d'inici", "dxScheduler-editorLabelEndDate": "Data de finalització", diff --git a/packages/devextreme/js/localization/messages/cs.json b/packages/devextreme/js/localization/messages/cs.json index e8b539ca75a0..2c2bcda75531 100644 --- a/packages/devextreme/js/localization/messages/cs.json +++ b/packages/devextreme/js/localization/messages/cs.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Předmět", "dxScheduler-editorLabelStartDate": "Počáteční datum", "dxScheduler-editorLabelEndDate": "Koncové datum", diff --git a/packages/devextreme/js/localization/messages/da.json b/packages/devextreme/js/localization/messages/da.json index 9aa31bffaba1..b148ae921b19 100644 --- a/packages/devextreme/js/localization/messages/da.json +++ b/packages/devextreme/js/localization/messages/da.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Aftaleliste", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Emne", "dxScheduler-editorLabelStartDate": "Startdato", "dxScheduler-editorLabelEndDate": "Slutdato", diff --git a/packages/devextreme/js/localization/messages/de.json b/packages/devextreme/js/localization/messages/de.json index 8580115cfca4..7c84a8ae5986 100644 --- a/packages/devextreme/js/localization/messages/de.json +++ b/packages/devextreme/js/localization/messages/de.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Terminliste", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Betreff", "dxScheduler-editorLabelStartDate": "Anfangszeit", "dxScheduler-editorLabelEndDate": "Endzeit", diff --git a/packages/devextreme/js/localization/messages/el.json b/packages/devextreme/js/localization/messages/el.json index 6bcff69bffc8..7c872d2bcdd4 100644 --- a/packages/devextreme/js/localization/messages/el.json +++ b/packages/devextreme/js/localization/messages/el.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Θέμα", "dxScheduler-editorLabelStartDate": "Ημερομηνία έναρξης", "dxScheduler-editorLabelEndDate": "Ημερομηνία λήξης", diff --git a/packages/devextreme/js/localization/messages/en.json b/packages/devextreme/js/localization/messages/en.json index 7483c18b4f66..0d9f561e91ba 100644 --- a/packages/devextreme/js/localization/messages/en.json +++ b/packages/devextreme/js/localization/messages/en.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Subject", "dxScheduler-editorLabelStartDate": "Start Date", "dxScheduler-editorLabelEndDate": "End Date", diff --git a/packages/devextreme/js/localization/messages/es.json b/packages/devextreme/js/localization/messages/es.json index 044532a55989..35c88d4f3da3 100644 --- a/packages/devextreme/js/localization/messages/es.json +++ b/packages/devextreme/js/localization/messages/es.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Asunto", "dxScheduler-editorLabelStartDate": "Fecha inicial", "dxScheduler-editorLabelEndDate": "Fecha final", diff --git a/packages/devextreme/js/localization/messages/fa.json b/packages/devextreme/js/localization/messages/fa.json index 923695468fe6..bb82c60e2d93 100644 --- a/packages/devextreme/js/localization/messages/fa.json +++ b/packages/devextreme/js/localization/messages/fa.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "موضوع", "dxScheduler-editorLabelStartDate": "تاریخ شروع", "dxScheduler-editorLabelEndDate": "تاریخ پایان", diff --git a/packages/devextreme/js/localization/messages/fi.json b/packages/devextreme/js/localization/messages/fi.json index d3c1a77d957e..159b39b5c3fc 100644 --- a/packages/devextreme/js/localization/messages/fi.json +++ b/packages/devextreme/js/localization/messages/fi.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Aihe", "dxScheduler-editorLabelStartDate": "Alkamispäivä", "dxScheduler-editorLabelEndDate": "Päättymispäivä", diff --git a/packages/devextreme/js/localization/messages/fr.json b/packages/devextreme/js/localization/messages/fr.json index 8cded5e4fb25..71e46458c788 100644 --- a/packages/devextreme/js/localization/messages/fr.json +++ b/packages/devextreme/js/localization/messages/fr.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Liste des rendez-vous ", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Titre", "dxScheduler-editorLabelStartDate": "Date de début", "dxScheduler-editorLabelEndDate": "Date de fin", diff --git a/packages/devextreme/js/localization/messages/hu.json b/packages/devextreme/js/localization/messages/hu.json index b986f5fc4733..f52b132fefa7 100644 --- a/packages/devextreme/js/localization/messages/hu.json +++ b/packages/devextreme/js/localization/messages/hu.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Tárgy", "dxScheduler-editorLabelStartDate": "Kezdés dátuma", "dxScheduler-editorLabelEndDate": "Befejezés dátuma", diff --git a/packages/devextreme/js/localization/messages/it.json b/packages/devextreme/js/localization/messages/it.json index 8cc1b2c8e820..04e1d6d9b103 100644 --- a/packages/devextreme/js/localization/messages/it.json +++ b/packages/devextreme/js/localization/messages/it.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Oggetto", "dxScheduler-editorLabelStartDate": "Data inizio", "dxScheduler-editorLabelEndDate": "Data fine", diff --git a/packages/devextreme/js/localization/messages/ja.json b/packages/devextreme/js/localization/messages/ja.json index 7b929ac121f4..98851193ab2c 100644 --- a/packages/devextreme/js/localization/messages/ja.json +++ b/packages/devextreme/js/localization/messages/ja.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "件名", "dxScheduler-editorLabelStartDate": "開始時刻", "dxScheduler-editorLabelEndDate": "終了時刻", diff --git a/packages/devextreme/js/localization/messages/lt.json b/packages/devextreme/js/localization/messages/lt.json index abad65781955..c683edb67476 100644 --- a/packages/devextreme/js/localization/messages/lt.json +++ b/packages/devextreme/js/localization/messages/lt.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Tema", "dxScheduler-editorLabelStartDate": "Pradžios data", "dxScheduler-editorLabelEndDate": "Pabaigos data", diff --git a/packages/devextreme/js/localization/messages/lv.json b/packages/devextreme/js/localization/messages/lv.json index 99b8724a7356..2ef21fb6ba41 100644 --- a/packages/devextreme/js/localization/messages/lv.json +++ b/packages/devextreme/js/localization/messages/lv.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Nosaukums", "dxScheduler-editorLabelStartDate": "Sākuma Datums", "dxScheduler-editorLabelEndDate": "Beigu Datums", diff --git a/packages/devextreme/js/localization/messages/nb.json b/packages/devextreme/js/localization/messages/nb.json index f2c921e17344..d5762a92bc11 100644 --- a/packages/devextreme/js/localization/messages/nb.json +++ b/packages/devextreme/js/localization/messages/nb.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Emne", "dxScheduler-editorLabelStartDate": "Startdato", "dxScheduler-editorLabelEndDate": "Sluttdato", diff --git a/packages/devextreme/js/localization/messages/nl.json b/packages/devextreme/js/localization/messages/nl.json index 2cc53577c749..9b8cc46ec47f 100644 --- a/packages/devextreme/js/localization/messages/nl.json +++ b/packages/devextreme/js/localization/messages/nl.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Onderwerp", "dxScheduler-editorLabelStartDate": "Startdatum", "dxScheduler-editorLabelEndDate": "Einddatum", diff --git a/packages/devextreme/js/localization/messages/pl.json b/packages/devextreme/js/localization/messages/pl.json index ede60d63acb6..eb370a90d11a 100644 --- a/packages/devextreme/js/localization/messages/pl.json +++ b/packages/devextreme/js/localization/messages/pl.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Dotyczy", "dxScheduler-editorLabelStartDate": "Czas rozpoczęcia", "dxScheduler-editorLabelEndDate": "Czas zakończenia", diff --git a/packages/devextreme/js/localization/messages/pt.json b/packages/devextreme/js/localization/messages/pt.json index 73b40b59f521..486f5d4fe808 100644 --- a/packages/devextreme/js/localization/messages/pt.json +++ b/packages/devextreme/js/localization/messages/pt.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Lista de compromissos", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Assunto", "dxScheduler-editorLabelStartDate": "Data de Início", "dxScheduler-editorLabelEndDate": "Data Final", diff --git a/packages/devextreme/js/localization/messages/ro.json b/packages/devextreme/js/localization/messages/ro.json index f7311897d4e9..5eb0ed99c3e6 100644 --- a/packages/devextreme/js/localization/messages/ro.json +++ b/packages/devextreme/js/localization/messages/ro.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Subiect", "dxScheduler-editorLabelStartDate": "Data de început", "dxScheduler-editorLabelEndDate": "Data de încheiere", diff --git a/packages/devextreme/js/localization/messages/ru.json b/packages/devextreme/js/localization/messages/ru.json index 8bf56aaad0e7..d0257715eebf 100644 --- a/packages/devextreme/js/localization/messages/ru.json +++ b/packages/devextreme/js/localization/messages/ru.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Название", "dxScheduler-editorLabelStartDate": "Дата начала", "dxScheduler-editorLabelEndDate": "Дата завершения", diff --git a/packages/devextreme/js/localization/messages/sl.json b/packages/devextreme/js/localization/messages/sl.json index 5df0cf13f19a..adc63ebcc760 100644 --- a/packages/devextreme/js/localization/messages/sl.json +++ b/packages/devextreme/js/localization/messages/sl.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Predmet", "dxScheduler-editorLabelStartDate": "Datum začetka", "dxScheduler-editorLabelEndDate": "Datum konca", diff --git a/packages/devextreme/js/localization/messages/sv.json b/packages/devextreme/js/localization/messages/sv.json index c1f654049e42..948441fc9a4f 100644 --- a/packages/devextreme/js/localization/messages/sv.json +++ b/packages/devextreme/js/localization/messages/sv.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Ämne", "dxScheduler-editorLabelStartDate": "Startdatum", "dxScheduler-editorLabelEndDate": "Slutdatum", diff --git a/packages/devextreme/js/localization/messages/tr.json b/packages/devextreme/js/localization/messages/tr.json index 365ebc9eacc4..3b81de84e994 100644 --- a/packages/devextreme/js/localization/messages/tr.json +++ b/packages/devextreme/js/localization/messages/tr.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Konu", "dxScheduler-editorLabelStartDate": "Başlangıç Tarihi", "dxScheduler-editorLabelEndDate": "Bitiş Tarihi", diff --git a/packages/devextreme/js/localization/messages/uk.json b/packages/devextreme/js/localization/messages/uk.json index f1c990ac5a9b..c9ce444b4beb 100644 --- a/packages/devextreme/js/localization/messages/uk.json +++ b/packages/devextreme/js/localization/messages/uk.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Список подій", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Тема", "dxScheduler-editorLabelStartDate": "Дата початку", "dxScheduler-editorLabelEndDate": "Дата завершення", diff --git a/packages/devextreme/js/localization/messages/vi.json b/packages/devextreme/js/localization/messages/vi.json index c5be5ec738ec..cc18cbc48edd 100644 --- a/packages/devextreme/js/localization/messages/vi.json +++ b/packages/devextreme/js/localization/messages/vi.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "Chủ đề", "dxScheduler-editorLabelStartDate": "Ngày bắt đầu", "dxScheduler-editorLabelEndDate": "Ngày kết thúc", diff --git a/packages/devextreme/js/localization/messages/zh-tw.json b/packages/devextreme/js/localization/messages/zh-tw.json index 1f64a4d59f51..d2462032b988 100644 --- a/packages/devextreme/js/localization/messages/zh-tw.json +++ b/packages/devextreme/js/localization/messages/zh-tw.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "標題", "dxScheduler-editorLabelStartDate": "開始日期", "dxScheduler-editorLabelEndDate": "結束日期", diff --git a/packages/devextreme/js/localization/messages/zh.json b/packages/devextreme/js/localization/messages/zh.json index 9c09194a61cd..59c571263f3f 100644 --- a/packages/devextreme/js/localization/messages/zh.json +++ b/packages/devextreme/js/localization/messages/zh.json @@ -266,7 +266,9 @@ "dxScheduler-appointmentListAriaLabel": "Appointment list", - + "dxScheduler-editPopupTitle": "Edit Appointment", + "dxScheduler-editPopupSaveButtonText": "Save", + "dxScheduler-editorLabelTitle": "标题", "dxScheduler-editorLabelStartDate": "开始日期", "dxScheduler-editorLabelEndDate": "结束日期", diff --git a/packages/devextreme/testing/helpers/scheduler/helpers.js b/packages/devextreme/testing/helpers/scheduler/helpers.js index e28b6fea30fa..706b47f77559 100644 --- a/packages/devextreme/testing/helpers/scheduler/helpers.js +++ b/packages/devextreme/testing/helpers/scheduler/helpers.js @@ -567,14 +567,14 @@ export class SchedulerTestWrapper extends ElementWrapper { hide: () => $(CLASSES.dialog).find('.dx-closebutton.dx-button').trigger('dxclick') }, - getPopup: () => $('.dx-overlay-wrapper.dx-scheduler-appointment-popup'), + getPopup: () => $('.dx-overlay-wrapper.dx-scheduler-appointment-popup, .dx-overlay-wrapper.dx-scheduler-legacy-appointment-popup'), getRecurrenceDialog: () => $(`${CLASSES.dialog}${CLASSES.popup}`), getPopupTitleElement: () => this.appointmentPopup.getPopup().find('.dx-popup-title'), hasVerticalScroll: () => { const scrollableContainer = this.appointmentPopup.getPopup().find('.dx-scrollable-container').get(0); return scrollableContainer.scrollHeight > scrollableContainer.clientHeight; }, - getPopupInstance: () => $('.dx-scheduler-appointment-popup.dx-widget').dxPopup('instance'), + getPopupInstance: () => $('.dx-scheduler-appointment-popup.dx-widget, .dx-scheduler-legacy-appointment-popup.dx-widget').dxPopup('instance'), isVisible: () => this.appointmentPopup.getPopup().length !== 0, setPopupHeight: height => this.appointmentPopup.getPopupInstance().option('height', height), getToolbarElementByLocation: location => { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.editing.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.editing.tests.js index f6d125ba9fc7..e95e31956c12 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.editing.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.editing.tests.js @@ -100,7 +100,8 @@ module('Integration: Appointment editing', { recurrenceEditMode: 'series', views: ['month'], startDateExpr: 'start', - endDateExpr: 'end' + endDateExpr: 'end', + editing: { legacyForm: true }, }); scheduler.appointments.dblclick(0); @@ -209,7 +210,11 @@ module('Integration: Appointment editing', { store: this.tasks }); - const scheduler = await this.createInstance({ currentDate: new Date(2015, 1, 9), dataSource: data }); + const scheduler = await this.createInstance({ + currentDate: new Date(2015, 1, 9), + dataSource: data, + editing: { legacyForm: true } + }); const addAppointment = scheduler.instance.addAppointment; const spy = sinon.spy(() => new Deferred()); const newItem = { startDate: new Date(2015, 1, 1, 1), endDate: new Date(2015, 1, 1, 2), text: 'caption' }; @@ -217,7 +222,7 @@ module('Integration: Appointment editing', { try { scheduler.instance.showAppointmentPopup(newItem, true); - $('.dx-scheduler-appointment-popup .dx-popup-done').trigger('dxclick'); + $('.dx-scheduler-legacy-appointment-popup .dx-popup-done').trigger('dxclick'); assert.ok(spy.calledOnce, 'Add method is called'); assert.deepEqual(spy.getCall(0).args[0], newItem, 'New item is correct'); @@ -306,7 +311,11 @@ module('Integration: Appointment editing', { store: this.tasks }); - const scheduler = await this.createInstance({ currentDate: new Date(2015, 1, 9), dataSource: data }); + const scheduler = await this.createInstance({ + currentDate: new Date(2015, 1, 9), + dataSource: data, + editing: { legacyForm: true } + }); const updateAppointment = scheduler.instance.updateAppointment; const spy = sinon.spy(() => new Deferred()); @@ -315,7 +324,7 @@ module('Integration: Appointment editing', { try { scheduler.instance.showAppointmentPopup(updatedItem); - $('.dx-scheduler-appointment-popup .dx-popup-done').trigger('dxclick'); + $('.dx-scheduler-legacy-appointment-popup .dx-popup-done').trigger('dxclick'); hide(); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.monthView.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.monthView.tests.js index be2dc0a0903b..6bb5826cd87f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.monthView.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.monthView.tests.js @@ -397,7 +397,10 @@ module('Integration: Appointments in Month view', { currentView: 'month', views: ['month'], startDateExpr: 'start', - endDateExpr: 'end' + endDateExpr: 'end', + editing: { + legacyForm: true, + } }); scheduler.instance.showAppointmentPopup(tasks[0]); @@ -436,7 +439,10 @@ module('Integration: Appointments in Month view', { currentView: 'month', views: ['month'], startDateExpr: 'start', - endDateExpr: 'end' + endDateExpr: 'end', + editing: { + legacyForm: true, + } }); scheduler.instance.showAppointmentPopup(tasks[0]); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.week.based.views.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.week.based.views.tests.js index 4561e019ad9c..388d97d54f42 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.week.based.views.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointment.week.based.views.tests.js @@ -259,7 +259,8 @@ module('Integration: Appointment Day, Week views', { dataSource: new DataSource({ store: [task] }), - currentDate: new Date(2015, 3, 23) + currentDate: new Date(2015, 3, 23), + editing: { legacyForm: true } }); scheduler.instance.showAppointmentPopup(task); @@ -827,7 +828,8 @@ module('Integration: Appointment Day, Week views', { views: ['week'], startDateExpr: 'start', endDateExpr: 'end', - allDayExpr: 'AllDay' + allDayExpr: 'AllDay', + editing: { legacyForm: true } }); scheduler.instance.showAppointmentPopup(tasks[0]); scheduler.instance.hideAppointmentPopup(); @@ -901,6 +903,7 @@ module('Integration: Appointment Day, Week views', { views: ['week'], startDateExpr: 'StartDate', endDateExpr: 'EndDate', + editing: { legacyForm: true }, onAppointmentFormOpening: function(data) { const form = data.form; let startDate = data.appointmentData.StartDate; @@ -941,7 +944,7 @@ module('Integration: Appointment Day, Week views', { startDateEditor.option('value', '2016-05-25T10:40:00'); - $('.dx-scheduler-appointment-popup .dx-popup-done').trigger('dxclick').trigger('dxclick'); + $('.dx-scheduler-legacy-appointment-popup .dx-popup-done').trigger('dxclick').trigger('dxclick'); const $appointments = scheduler.instance.$element().find('.' + APPOINTMENT_CLASS); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.events.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.events.tests.js index edb536cd8749..3200867028da 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.events.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/common.events.tests.js @@ -622,7 +622,10 @@ QUnit.module('Events', { }; const scheduler = await createWrapper({ currentView: 'month', - onAppointmentFormOpening: stub + onAppointmentFormOpening: stub, + editing: { + legacyForm: true + }, }); scheduler.instance.showAppointmentPopup(data); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js index 53f2a37fe4bd..bd07c01a8e17 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js @@ -81,7 +81,12 @@ QUnit.test('Appointment should not be draggable & resizable', async function(ass }); QUnit.test('ReadOnly option should be passed to the details appointment view', async function(assert) { - await this.createInstance(); + await this.createInstance({ + editing: { + allowUpdating: false, + legacyForm: true + } + }); this.instance.showAppointmentPopup({ text: 'a', @@ -93,7 +98,7 @@ QUnit.test('ReadOnly option should be passed to the details appointment view', a assert.ok(detailsAppointmentView.option('readOnly'), 'ReadOnly option is correct'); - this.instance.option('editing', true); + this.instance.option('editing.allowUpdating', true); this.instance.showAppointmentPopup({ text: 'a', startDate: new Date(2015, 5, 15, 10), @@ -107,7 +112,8 @@ QUnit.test('ReadOnly option should be passed to the details appointment view', a QUnit.test('Details appointment view should be readOnly if editing.allowUpdating=false', async function(assert) { await this.createInstance({ editing: { - allowUpdating: false + allowUpdating: false, + legacyForm: true } }); @@ -139,7 +145,8 @@ QUnit.test('Details appointment view shouldn\'t be readOnly when adding new appo currentDate: new Date(2015, 5, 14), editing: { allowUpdating: false, - allowAdding: true + allowAdding: true, + legacyForm: true } }); @@ -158,7 +165,8 @@ QUnit.test('Details appointment form should be readOnly after adding new appoint await this.createInstance({ currentDate: new Date(2015, 5, 14), editing: { - allowUpdating: false + allowUpdating: false, + legacyForm: true }, dataSource: [] }); @@ -183,7 +191,8 @@ QUnit.test('Details form of new appointment shouldn\'t be readOnly after try to await this.createInstance({ currentDate: new Date(2015, 5, 14), editing: { - allowUpdating: false + allowUpdating: false, + legacyForm: true }, dataSource: [first] }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js index 9d4e36157990..ea20f1398f2f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js @@ -159,7 +159,7 @@ if(isDesktopEnvironment()) { } }, () => { test('Items has layout with one column when the form\'s width < 600px', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); setWindowWidth(500); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -168,7 +168,7 @@ if(isDesktopEnvironment()) { }); test('Items with recurrence editor has layout with one column when the form\'s width < 600px', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); setWindowWidth(500); scheduler.option('dataSource', [{ startDate: new Date(2015, 1, 1), @@ -183,7 +183,7 @@ if(isDesktopEnvironment()) { }); test('Items has layout with non-one column when the form\'s width > 600px', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); setWindowWidth(700); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -192,7 +192,7 @@ if(isDesktopEnvironment()) { }); test('Items with recurrence editor has layout with non-one column when the form\'s width > 600px', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); setWindowWidth(700); scheduler.option('dataSource', [{ startDate: new Date(2015, 1, 1), @@ -207,7 +207,7 @@ if(isDesktopEnvironment()) { }); test('Items has layout with one column when the form\'s width < 600px on window resizing', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); setWindowWidth(700); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -219,7 +219,7 @@ if(isDesktopEnvironment()) { }); test('Items has layout with non-one column when the form\'s width > 600px on window resizing', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); setWindowWidth(500); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -245,7 +245,7 @@ if(!isDesktopEnvironment()) { } }, () => { test('Items has layout with one column', async function(assert) { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -268,7 +268,7 @@ if(isDesktopEnvironment()) { test('The fullscreen mode is enabled of popup when window\'s width < 1000px', async function(assert) { setWindowWidth(900); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); const popup = scheduler.appointmentPopup.getPopupInstance(); @@ -280,7 +280,7 @@ if(isDesktopEnvironment()) { test('The fullscreen mode is disabled of popup when window\'s width > 1000px', async function(assert) { setWindowWidth(1001); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); const popup = scheduler.appointmentPopup.getPopupInstance(); @@ -292,7 +292,7 @@ if(isDesktopEnvironment()) { test('The fullscreen mode is disabled of popup when window\'s width > 1000px, with recurrence editor', async function(assert) { setWindowWidth(1001); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.option('dataSource', [{ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2), @@ -311,7 +311,7 @@ if(isDesktopEnvironment()) { test('The fullscreen mode is enabled of popup when the window\'s width < 1000px by resizing the window', async function(assert) { setWindowWidth(1001); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); const popup = scheduler.appointmentPopup.getPopupInstance(); @@ -326,7 +326,7 @@ if(isDesktopEnvironment()) { test('The fullscreen mode is disabled of popup when the window\'s width > 1000px by resizing the window', async function(assert) { setWindowWidth(799); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); const popup = scheduler.appointmentPopup.getPopupInstance(); @@ -354,7 +354,7 @@ if(!isDesktopEnvironment()) { test('The fullscreen mode is enabled of popup when window\'s width < 500px', async function(assert) { setWindowWidth(499); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); const popup = scheduler.appointmentPopup.getPopupInstance(); @@ -366,7 +366,7 @@ if(!isDesktopEnvironment()) { test('The fullscreen mode is disabled of popup when window\'s width > 500px', async function(assert) { setWindowWidth(501); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); const popup = scheduler.appointmentPopup.getPopupInstance(); @@ -378,7 +378,7 @@ if(!isDesktopEnvironment()) { test('The fullscreen mode is disabled of popup when window\'s width > 500px, with recurrence editor', async function(assert) { setWindowWidth(501); - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.option('dataSource', [{ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2), @@ -404,7 +404,7 @@ module('Appointment popup buttons', moduleConfig, () => { test('Buttons location of the top toolbar for the iOs device', async function(assert) { this.realDeviceMock = sinon.stub(devices, 'current').returns({ platform: 'ios' }); try { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -419,7 +419,7 @@ module('Appointment popup buttons', moduleConfig, () => { test('Buttons location of the top toolbar for the desktop', async function(assert) { this.realDeviceMock = sinon.stub(devices, 'current').returns({ platform: 'generic' }); try { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); @@ -433,7 +433,7 @@ module('Appointment popup buttons', moduleConfig, () => { test('Buttons location of the top toolbar for the android device', async function(assert) { this.realDeviceMock = sinon.stub(devices, 'current').returns({ platform: 'android' }); try { - const scheduler = await createInstance(); + const scheduler = await createInstance({ editing: { legacyForm: true } }); scheduler.appointments.compact.click(); scheduler.tooltip.clickOnItem(); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.agenda.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.agenda.tests.js index ee3c7c245b7c..d33299f57fb5 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.agenda.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.agenda.tests.js @@ -1220,7 +1220,8 @@ module('Integration: Agenda', moduleConfig, () => { startDateExpr: 'Start', dataSource: [ { Start: new Date(2016, 1, 24, 1), endDate: new Date(2016, 1, 27, 1, 30), text: 'a' } - ] + ], + editing: { legacyForm: true } }); const $appointment = $(instance.$element()).find('.dx-scheduler-appointment').eq(1); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentCollector.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentCollector.tests.js index 87e3a102e133..5b3586ad5d3e 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentCollector.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointmentCollector.tests.js @@ -62,6 +62,9 @@ module('Integration: collector', baseConfig, () => { onAppointmentFormOpening: e => { const startDate = e.form.getEditor('startDate').option('value'); assert.equal(startDate.getDate(), 16, 'Recurrence appointment date should be display equal targetedAppointmentData date in form'); + }, + editing: { + legacyForm: true } }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.base.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.base.tests.js index e3a3cb739c31..dc1cf677db1f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.base.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.base.tests.js @@ -260,7 +260,7 @@ QUnit.test('Scheduler should not throw an error when the details form is opened }); QUnit.test('The \'scrollingEnabled\' option of an appointment form should be \'true\'', async function(assert) { - await this.createInstance(); + await this.createInstance({ editing: { legacyForm: true } }); this.instance.showAppointmentPopup({ startDate: new Date() }); assert.strictEqual(this.instance.getAppointmentDetailsForm().option('scrollingEnabled'), true, 'the scrollingEnabled option is OK'); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.recurringAppointments.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.recurringAppointments.tests.js index c08b7fa5395c..e5ec8bf1aeeb 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.recurringAppointments.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.recurringAppointments.tests.js @@ -683,7 +683,8 @@ supportedScrollingModes.forEach(scrollingMode => { currentDate: new Date(2015, 1, 9), dataSource: data, currentView: 'week', - firstDayOfWeek: 1 + firstDayOfWeek: 1, + editing: { legacyForm: true } }); const clock = sinon.useFakeTimers(); @@ -732,6 +733,7 @@ supportedScrollingModes.forEach(scrollingMode => { onAppointmentAdding: (e) => { e.appointmentData.customData.texts.push('456'); }, + editing: { legacyForm: true }, firstDayOfWeek: 1 }); @@ -880,7 +882,8 @@ supportedScrollingModes.forEach(scrollingMode => { currentDate: new Date(2015, 1, 9), dataSource: data, currentView: 'week', - firstDayOfWeek: 1 + firstDayOfWeek: 1, + editing: { legacyForm: true } }); const clock = sinon.useFakeTimers(); $(scheduler.instance.$element()).find('.dx-scheduler-appointment').eq(2).trigger(dblclickEvent.name); @@ -1327,6 +1330,7 @@ supportedScrollingModes.forEach(scrollingMode => { endDate: '2018-05-23T10:30:00Z', recurrenceRule: 'FREQ=DAILY' }], + editing: { legacyForm: true }, views: ['week'], currentView: 'week', currentDate: new Date(2018, 4, 23), @@ -1674,6 +1678,7 @@ supportedScrollingModes.forEach(scrollingMode => { endDate: apptEndDate, recurrenceRule: 'FREQ=MINUTELY;COUNT=3' }], + editing: { legacyForm: true }, currentDate: apptStartDate, }); @@ -1701,6 +1706,7 @@ supportedScrollingModes.forEach(scrollingMode => { endDate: apptEndDate, recurrenceRule: 'FREQ=HOURLY;COUNT=3' }], + editing: { legacyForm: true }, currentDate: apptStartDate, }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js index ab1aaf07eb2c..96bff3b68c17 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/integration.resources.tests.js @@ -177,6 +177,7 @@ QUnit.module('Integration: Resources', moduleConfig, () => { onAppointmentFormOpeningRaised = true; }, + editing: { legacyForm: true }, resources: resources, dataSource: dataSource, currentDate: new Date(2015, 1, 9) @@ -239,7 +240,8 @@ QUnit.module('Integration: Resources', moduleConfig, () => { dataSource: new DataSource({ store: [task1, task2] }), - currentDate: new Date(2015, 1, 9) + currentDate: new Date(2015, 1, 9), + editing: { legacyForm: true } }); scheduler.instance.showAppointmentPopup(task1); @@ -293,7 +295,8 @@ QUnit.module('Integration: Resources', moduleConfig, () => { dataSource: new DataSource({ store: [task] }), - currentDate: new Date(2015, 1, 9) + currentDate: new Date(2015, 1, 9), + editing: { legacyForm: true } }); scheduler.instance.showAppointmentPopup(task); @@ -343,7 +346,8 @@ QUnit.module('Integration: Resources', moduleConfig, () => { const scheduler = await createWrapper({ resources: resources, dataSource: [appointment], - currentDate: new Date(2015, 4, 24) + currentDate: new Date(2015, 4, 24), + editing: { legacyForm: true } }); scheduler.instance.showAppointmentPopup(appointment); @@ -501,7 +505,8 @@ QUnit.module('Integration: Resources', moduleConfig, () => { load: loadStub, byKey: byKeyStub }) - }] + }], + editing: { legacyForm: true } }); assert.equal(loadStub.callCount, 1, 'Resources are loaded only once'); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/legacyAppointmentPopup.tests.js similarity index 96% rename from packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js rename to packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/legacyAppointmentPopup.tests.js index bf39e042c724..ad0d6af8a98b 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/legacyAppointmentPopup.tests.js @@ -40,10 +40,13 @@ const checkFormWithRecurrenceEditor = (assert, instance, visibility) => { const createInstance = (options) => { const defaultOption = { dataSource: [], - maxAppointmentsPerCell: 2 + maxAppointmentsPerCell: 2, + editing: { + legacyForm: true, + } }; - return createWrapper($.extend(defaultOption, options)); + return createWrapper($.extend(true, defaultOption, options)); }; const moduleOptions = { @@ -89,7 +92,10 @@ const createScheduler = (options = {}) => { firstDayOfWeek: 1, startDayHour: 9, height: 600, - width: 600 + width: 600, + editing: { + legacyForm: true, + } }; return createWrapper($.extend(defaultOption, options)); @@ -797,7 +803,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { assert.equal(popupChoiceAppointmentEdit.length, 1, 'Popup with choice edit mode is rendered'); popupChoiceAppointmentEdit.find('.dx-popup-bottom .dx-button:eq(1)').trigger('dxclick'); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Appointment popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Appointment popup is rendered'); const form = scheduler.instance.getAppointmentDetailsForm(); const startDateBox = form.getEditor('startDate'); @@ -812,10 +818,10 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2) }); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Popup is rendered'); scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2) }); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Popup is rendered'); }); QUnit.test('showAppointmentPopup should work correctly after scheduler repainting', async function(assert) { @@ -823,11 +829,11 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2) }); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Popup is rendered'); scheduler.instance.repaint(); scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2) }); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Popup is rendered'); }); QUnit.test('changing editing should work correctly after showing popup', async function(assert) { @@ -847,9 +853,9 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2) }); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Popup is rendered'); scheduler.instance.hideAppointmentPopup(); - assert.equal($('.dx-scheduler-appointment-popup').length, 1, 'Popup is hidden'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 1, 'Popup is hidden'); }); QUnit.test('hideAppointmentPopup should hide a popup and save changes', async function(assert) { @@ -860,9 +866,9 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ text: '1', startDate: new Date(2016, 9, 10), endDate: new Date(2016, 9, 11) }, true); - assert.equal($('.dx-scheduler-appointment-popup').length, 2, 'Popup is rendered'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 2, 'Popup is rendered'); scheduler.instance.hideAppointmentPopup(true); - assert.equal($('.dx-scheduler-appointment-popup').length, 1, 'Popup is hidden'); + assert.equal($('.dx-scheduler-legacy-appointment-popup').length, 1, 'Popup is hidden'); assert.equal($('.dx-scheduler-appointment').length, 1, 'appointment is created'); }); @@ -871,7 +877,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1), endDate: new Date(2015, 1, 2), text: 'appointment 1' }); - const $form = $('.dx-scheduler-appointment-popup').find('.dx-form').not('.dx-recurrence-editor-container'); + const $form = $('.dx-scheduler-legacy-appointment-popup').find('.dx-form').not('.dx-recurrence-editor-container'); assert.equal($form.length, 1, 'Form was rendered'); scheduler.instance.hideAppointmentPopup(); @@ -908,11 +914,11 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { }); QUnit.test('Popup should contain editors and components with right dx-rtl classes and rtlEnabled option value', async function(assert) { - const scheduler = await createWrapper({ rtlEnabled: true }); + const scheduler = await createWrapper({ rtlEnabled: true, editing: { legacyForm: true } }); scheduler.instance.showAppointmentPopup({}); - const $innerSwitch = $('.dx-scheduler-appointment-popup .dx-switch').eq(0); + const $innerSwitch = $('.dx-scheduler-legacy-appointment-popup .dx-switch').eq(0); assert.ok($innerSwitch.hasClass('dx-rtl'), 'Inner editor has dx-rtl class'); assert.equal($innerSwitch.dxSwitch('instance').option('rtlEnabled'), true, 'rtlEnabled option value is right'); @@ -923,7 +929,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1, 1), endDate: new Date(2015, 1, 1, 2), text: 'caption' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const $dateBox = $popupContent.find('.dx-datebox').eq(0); assert.equal($dateBox.length, 1, 'Start date box is rendered'); @@ -938,7 +944,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1, 1), endDate: new Date(2015, 1, 1, 2), text: 'caption' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const startDateBox = $popupContent.find('.dx-datebox').eq(0).dxDateBox('instance'); startDateBox.open(); @@ -955,7 +961,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1, 1), endDate: new Date(2015, 1, 1, 2), text: 'caption' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const $dateBox = $popupContent.find('.dx-datebox').eq(1); assert.equal($dateBox.length, 1, 'End datebox is rendered'); @@ -970,7 +976,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1, 1), endDate: new Date(2015, 1, 1, 2), text: 'caption' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const endDateBox = $popupContent.find('.dx-datebox').eq(1).dxDateBox('instance'); endDateBox.open(); @@ -1033,7 +1039,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 10), endDate: new Date(2015, 1, 13), text: 'caption' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const startDateBox = $popupContent.find('.dx-datebox').eq(0).dxDateBox('instance'); const endDateBox = $popupContent.find('.dx-datebox').eq(1).dxDateBox('instance'); @@ -1051,7 +1057,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { scheduler.instance.showAppointmentPopup({ startDate: '1/10/2015', endDate: '1/13/2015', text: 'caption' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const startDateBox = $popupContent.find('.dx-datebox').eq(0).dxDateBox('instance'); const endDateBox = $popupContent.find('.dx-datebox').eq(1).dxDateBox('instance'); @@ -1214,7 +1220,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { endDate: new Date(2015, 1, 2, 7), text: 'caption', description: 'First task of this day' }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const $allDayEditor = $popupContent.find('.dx-switch').eq(0); const allDayEditor = $allDayEditor.dxSwitch('instance'); @@ -1245,7 +1251,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { allDay: true }, true, null); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const $allDayEditor = $popupContent.find('.dx-switch').eq(0); const allDayEditor = $allDayEditor.dxSwitch('instance'); @@ -1281,7 +1287,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { recurrenceException: null }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const startDate = $popupContent.find('.dx-datebox').eq(0).dxDateBox('instance'); const dateToTest = new Date(); @@ -1306,7 +1312,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { recurrenceException: null }); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const endDate = $popupContent.find('.dx-datebox').eq(1).dxDateBox('instance'); const dateToTest = new Date(); @@ -1329,7 +1335,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { recurrenceException: null }, true, null); - const $popupContent = $('.dx-scheduler-appointment-popup .dx-popup-content'); + const $popupContent = $('.dx-scheduler-legacy-appointment-popup .dx-popup-content'); const startDate = $popupContent.find('.dx-datebox').eq(0).dxDateBox('instance'); const endDate = $popupContent.find('.dx-datebox').eq(1).dxDateBox('instance'); const dateToTest = new Date(); @@ -1356,7 +1362,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { const form = scheduler.instance.getAppointmentDetailsForm(); const validation = sinon.stub(form, 'validate'); - $('.dx-scheduler-appointment-popup .dx-popup-done').trigger('dxclick'); + $('.dx-scheduler-legacy-appointment-popup .dx-popup-done').trigger('dxclick'); assert.ok(validation.calledOnce); }); @@ -1496,7 +1502,7 @@ QUnit.module('Appointment Popup Content', moduleOptions, () => { sinon.stub(form, 'validate').returns({ isValid: false }); - $('.dx-scheduler-appointment-popup .dx-popup-done').trigger('dxclick'); + $('.dx-scheduler-legacy-appointment-popup .dx-popup-done').trigger('dxclick'); assert.notOk(addingAppointment.calledOnce); }); @@ -1531,7 +1537,7 @@ QUnit.module('Appointment Popup', moduleOptions, () => { const spy = sinon.spy(scheduler.instance, 'focus'); - $('.dx-scheduler-appointment-popup .dx-overlay-content .dx-popup-cancel').trigger('dxclick'); + $('.dx-scheduler-legacy-appointment-popup .dx-overlay-content .dx-popup-cancel').trigger('dxclick'); assert.ok(spy.calledOnce, 'focus is called'); }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js index b884f23b7047..bfa2b65b2d6e 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/timezones.tests.js @@ -183,7 +183,8 @@ module('Common', moduleConfig, () => { currentView: 'day', firstDayOfWeek: 1, dataSource: [config.appointment], - timeZone: config.schedulerTimeZone + timeZone: config.schedulerTimeZone, + editing: config.editing, }); assert.equal(scheduler.appointments.getDateText(), config.expectedContent, 'Appointment content has correct dates'); @@ -200,15 +201,17 @@ module('Common', moduleConfig, () => { cases.forEach(config => { test(`Appointment should have correct size, position and popup content if ${config.caseName}`, async function(assert) { + const schedulerOptions = { ...config, editing: { legacyForm: true } }; + if(config.stubClientTimeZone) { const tzOffsetStub = sinon.stub(timeZoneUtils, 'getClientTimezoneOffset').returns(-10800000); try { - await runTest(config, assert); + await runTest(schedulerOptions, assert); } finally { tzOffsetStub.restore(); } } else { - await runTest(config, assert); + await runTest(schedulerOptions, assert); } }); }); @@ -306,6 +309,7 @@ module('Common', moduleConfig, () => { allowTimeZoneEditing: true, allowAdding: true, allowUpdating: true, + legacyForm: true, }, height: 600, appointmentDragging: { @@ -1776,7 +1780,7 @@ module('Appointment popup', moduleConfig, () => { cases.forEach((testCase, index) => { test('StartDate and endDate should be valid', async function(assert) { - const scheduler = await createScheduler({ timeZone: timeZones.NewYork }); // -4 offset + const scheduler = await createScheduler({ timeZone: timeZones.NewYork, editing: { legacyForm: true } }); // -4 offset scheduler.appointments.dblclick(index); @@ -1804,7 +1808,7 @@ module('Appointment popup', moduleConfig, () => { cases.forEach((testCase, index) => { test('StartDate and endDate should be valid', async function(assert) { - const scheduler = await createScheduler(); + const scheduler = await createScheduler({ editing: { legacyForm: true } }); scheduler.appointments.dblclick(index); @@ -1835,6 +1839,9 @@ module('Appointment popup', moduleConfig, () => { dataSource: new DataSource({ store: [appointment] }), + editing: { + legacyForm: true, + }, currentDate: new Date(2015, 3, 23), startDateExpr: 'Start', endDateExpr: 'End' @@ -1852,7 +1859,7 @@ module('Appointment popup', moduleConfig, () => { }); }); - test('Appointment startDate and endDate should be correct in the details view for new appointment, if custom timeZone was set', + test('Appointment startDate and endDate should be correct in the details view for new appointment, if custom timeZone was set, legacyForm', async function(assert) { const scheduler = await createWrapper({ dataSource: new DataSource({ @@ -1861,7 +1868,8 @@ module('Appointment popup', moduleConfig, () => { currentDate: new Date(2015, 3, 23), startDateExpr: 'Start', endDateExpr: 'End', - timeZone: 'Asia/Calcutta' + timeZone: 'Asia/Calcutta', + editing: { legacyForm: true } }); pointerMock(scheduler.getElement().find(CLASSES.dateTableCell).eq(22)).start().click().click(); diff --git a/packages/testcafe-models/scheduler/appointment/legacyPopup.ts b/packages/testcafe-models/scheduler/appointment/legacyPopup.ts new file mode 100644 index 000000000000..af2bf9baa31e --- /dev/null +++ b/packages/testcafe-models/scheduler/appointment/legacyPopup.ts @@ -0,0 +1,114 @@ +import { Selector, ClientFunction } from 'testcafe'; + +export const CLASS = { + appointmentPopup: 'dx-scheduler-legacy-appointment-popup', + popup: 'dx-popup', + popupWrapper: 'dx-popup-wrapper', + popupContent: 'dx-overlay-content', + cancelButton: 'dx-popup-cancel.dx-button', + stateInvisible: 'dx-state-invisible', + recurrenceEditor: 'dx-recurrence-editor', + textEditorInput: 'dx-texteditor-input', + overlayWrapper: 'dx-overlay-wrapper', + fullScreen: 'dx-popup-fullscreen', + switch: 'dx-switch', + // e2e + form: 'e2e-dx-scheduler-form', + textEditor: 'e2e-dx-scheduler-form-text', + descriptionEditor: 'e2e-dx-scheduler-form-description', + startDateEditor: 'e2e-dx-scheduler-form-start-date', + endDateEditor: 'e2e-dx-scheduler-form-end-date', + startDateTimeZoneEditor: 'e2e-dx-scheduler-form-start-date-timezone', + endDateTimeZoneEditor: 'e2e-dx-scheduler-form-end-date-timezone', + allDaySwitch: 'e2e-dx-scheduler-form-all-day-switch', + recurrenceSwitch: 'e2e-dx-scheduler-form-recurrence-switch', + selectItem: 'dx-list-item', + radioButton: 'dx-radiobutton', +}; +export const SELECTORS = { + textInput: `.${CLASS.textEditor} .${CLASS.textEditorInput}`, + descriptionTextArea: `.${CLASS.descriptionEditor} .${CLASS.textEditorInput}`, + startDateInput: `.${CLASS.startDateEditor} .${CLASS.textEditorInput}`, + endDateInput: `.${CLASS.endDateEditor} .${CLASS.textEditorInput}`, + startDateTimeZoneInput: `.${CLASS.startDateTimeZoneEditor} .${CLASS.textEditorInput}`, + endDateTimeZoneInput: `.${CLASS.endDateTimeZoneEditor} .${CLASS.textEditorInput}`, + allDaySwitch: `.${CLASS.allDaySwitch} .${CLASS.switch}`, + recurrenceSwitch: `.${CLASS.recurrenceSwitch} .${CLASS.switch}`, + repeatUntilInput: '.dx-recurrence-datebox-until-date input[type="text"]', + repeatCountInput: '.dx-recurrence-numberbox-repeat-count input[type="text"]', +}; + +export default class LegacyAppointmentPopup { + element = this.scheduler.find(`.${CLASS.popup}.${CLASS.appointmentPopup}`); + + form = Selector(`.${CLASS.form}`); + + wrapper = Selector(`.${CLASS.popupWrapper}.${CLASS.appointmentPopup}`); + + content = Selector(`.${CLASS.popupWrapper}.${CLASS.appointmentPopup} .${CLASS.popupContent}`); + + subjectElement = this.wrapper.find(SELECTORS.textInput); + + descriptionElement = this.wrapper.find(SELECTORS.descriptionTextArea); + + startDateElement = this.wrapper.find(SELECTORS.startDateInput); + + endDateElement = this.wrapper.find(SELECTORS.endDateInput); + + startDateTimeZoneElement = this.wrapper.find(SELECTORS.startDateTimeZoneInput); + + endDateTimeZoneElement = this.wrapper.find(SELECTORS.endDateTimeZoneInput); + + doneButton = this.wrapper.find('.dx-popup-done.dx-button'); + + cancelButton = this.wrapper.find(`.${CLASS.cancelButton}`); + + allDayElement = this.wrapper.find(SELECTORS.allDaySwitch); + + recurrenceElement = this.wrapper.find(SELECTORS.recurrenceSwitch); + + freqElement = this.wrapper.find('.dx-recurrence-selectbox-freq .dx-selectbox'); + + recurrenceTypeElement = this.wrapper.find(`.${CLASS.recurrenceEditor} .${CLASS.textEditorInput}`).nth(0); + + endRepeatDateElement = this.wrapper.find(`.${CLASS.recurrenceEditor} .${CLASS.textEditorInput}`).nth(2); + + repeatEveryElement = this.wrapper.find(`.${CLASS.recurrenceEditor} .${CLASS.textEditorInput}`).nth(1); + + fullScreen = this.wrapper.find(`.${CLASS.overlayWrapper} .${CLASS.fullScreen}`).exists; + + repeatUntilElement = this.wrapper.find(SELECTORS.repeatUntilInput); + + repeatCountElement = this.wrapper.find(SELECTORS.repeatCountInput); + + constructor(private readonly scheduler: Selector) { + } + + isVisible(): Promise { + const { element } = this; + const invisibleStateClass = CLASS.stateInvisible; + + return ClientFunction(() => !(element() as any).classList.contains(invisibleStateClass), { + dependencies: { element, invisibleStateClass }, + })(); + } + + getAllDaySwitchValue(): Promise { + return this.allDayElement.find('input[type="hidden"]').value; + } + + getRecurrenceRuleSwitchValue(): Promise { + return this.recurrenceElement.find('input[type="hidden"]').value; + } + + getRecurrenceTypeSelectItem(nth = 0): Selector { + return Selector(`.${CLASS.overlayWrapper}`) + .nth(1) + .find(`.${CLASS.selectItem}`) + .nth(nth); + } + + getEndRepeatRadioButton(nth = 0): Selector { + return this.wrapper.find(`.${CLASS.radioButton}`).nth(nth); + } +} diff --git a/packages/testcafe-models/scheduler/appointment/popup.ts b/packages/testcafe-models/scheduler/appointment/popup.ts index 01a33dc77184..aab17b8fc51a 100644 --- a/packages/testcafe-models/scheduler/appointment/popup.ts +++ b/packages/testcafe-models/scheduler/appointment/popup.ts @@ -1,114 +1,56 @@ -import { Selector, ClientFunction } from 'testcafe'; +import { Selector } from 'testcafe'; +import Form from '../../form/form'; +import Popup from '../../popup'; +import TextBox from '../../textBox'; +import TextArea from '../../textArea'; +import SelectBox from '../../selectBox'; +import DateBox from '../../dateBox'; +import Button from '../../button'; -export const CLASS = { - appointmentPopup: 'dx-scheduler-appointment-popup', - popup: 'dx-popup', - popupWrapper: 'dx-popup-wrapper', - popupContent: 'dx-overlay-content', - cancelButton: 'dx-popup-cancel.dx-button', - stateInvisible: 'dx-state-invisible', - recurrenceEditor: 'dx-recurrence-editor', - textEditorInput: 'dx-texteditor-input', - overlayWrapper: 'dx-overlay-wrapper', - fullScreen: 'dx-popup-fullscreen', - switch: 'dx-switch', - // e2e - form: 'e2e-dx-scheduler-form', - textEditor: 'e2e-dx-scheduler-form-text', - descriptionEditor: 'e2e-dx-scheduler-form-description', - startDateEditor: 'e2e-dx-scheduler-form-start-date', - endDateEditor: 'e2e-dx-scheduler-form-end-date', - startDateTimeZoneEditor: 'e2e-dx-scheduler-form-start-date-timezone', - endDateTimeZoneEditor: 'e2e-dx-scheduler-form-end-date-timezone', - allDaySwitch: 'e2e-dx-scheduler-form-all-day-switch', - recurrenceSwitch: 'e2e-dx-scheduler-form-recurrence-switch', - selectItem: 'dx-list-item', - radioButton: 'dx-radiobutton', -}; export const SELECTORS = { - textInput: `.${CLASS.textEditor} .${CLASS.textEditorInput}`, - descriptionTextArea: `.${CLASS.descriptionEditor} .${CLASS.textEditorInput}`, - startDateInput: `.${CLASS.startDateEditor} .${CLASS.textEditorInput}`, - endDateInput: `.${CLASS.endDateEditor} .${CLASS.textEditorInput}`, - startDateTimeZoneInput: `.${CLASS.startDateTimeZoneEditor} .${CLASS.textEditorInput}`, - endDateTimeZoneInput: `.${CLASS.endDateTimeZoneEditor} .${CLASS.textEditorInput}`, - allDaySwitch: `.${CLASS.allDaySwitch} .${CLASS.switch}`, - recurrenceSwitch: `.${CLASS.recurrenceSwitch} .${CLASS.switch}`, - repeatUntilInput: '.dx-recurrence-datebox-until-date input[type="text"]', - repeatCountInput: '.dx-recurrence-numberbox-repeat-count input[type="text"]', + appointmentPopup: `.dx-scheduler-appointment-popup.dx-popup.dx-widget`, + appointmentPopupContent: '.dx-scheduler-appointment-popup .dx-overlay-content', + appointmentPopupToolbar: '.dx-scheduler-appointment-popup .dx-popup-title', + form: `.dx-scheduler-form`, + doneButton: `.dx-popup-done.dx-button.dx-widget`, + cancelButton: `.dx-popup-cancel.dx-button.dx-widget`, + textEditor: `.dx-textbox.dx-widget`, + allDaySwitch: `.dx-scheduler-form-all-day-switch .dx-switch.dx-widget`, + startDateEditor: `.dx-scheduler-form-start-date-editor .dx-datebox.dx-datebox-date.dx-widget`, + startTimeEditor: `.dx-scheduler-form-start-time-editor .dx-datebox.dx-datebox-time.dx-widget`, + startTimeZoneEditor: `.dx-scheduler-form-start-date-timezone-editor .dx-selectbox.dx-widget`, + endDateEditor: `.dx-scheduler-form-end-date-editor .dx-datebox.dx-datebox-date.dx-widget`, + endTimeEditor: `.dx-scheduler-form-end-time-editor .dx-datebox.dx-datebox-time.dx-widget`, + endTimeZoneEditor: `.dx-scheduler-form-end-date-timezone-editor .dx-selectbox.dx-widget`, + repeatEditor: `.dx-scheduler-form-repeat-editor .dx-selectbox.dx-widget`, + descriptionEditor: `.dx-scheduler-form-description-editor .dx-textarea.dx-widget`, }; export default class AppointmentPopup { - element = this.scheduler.find(`.${CLASS.popup}.${CLASS.appointmentPopup}`); - - form = Selector(`.${CLASS.form}`); - - wrapper = Selector(`.${CLASS.popupWrapper}.${CLASS.appointmentPopup}`); - - content = Selector(`.${CLASS.popupWrapper}.${CLASS.appointmentPopup} .${CLASS.popupContent}`); - - subjectElement = this.wrapper.find(SELECTORS.textInput); - - descriptionElement = this.wrapper.find(SELECTORS.descriptionTextArea); - - startDateElement = this.wrapper.find(SELECTORS.startDateInput); - - endDateElement = this.wrapper.find(SELECTORS.endDateInput); - - startDateTimeZoneElement = this.wrapper.find(SELECTORS.startDateTimeZoneInput); - - endDateTimeZoneElement = this.wrapper.find(SELECTORS.endDateTimeZoneInput); - - doneButton = this.wrapper.find('.dx-popup-done.dx-button'); - - cancelButton = this.wrapper.find(`.${CLASS.cancelButton}`); - - allDayElement = this.wrapper.find(SELECTORS.allDaySwitch); - - recurrenceElement = this.wrapper.find(SELECTORS.recurrenceSwitch); - - freqElement = this.wrapper.find('.dx-recurrence-selectbox-freq .dx-selectbox'); - - recurrenceTypeElement = this.wrapper.find(`.${CLASS.recurrenceEditor} .${CLASS.textEditorInput}`).nth(0); - - endRepeatDateElement = this.wrapper.find(`.${CLASS.recurrenceEditor} .${CLASS.textEditorInput}`).nth(2); - - repeatEveryElement = this.wrapper.find(`.${CLASS.recurrenceEditor} .${CLASS.textEditorInput}`).nth(1); - - fullScreen = this.wrapper.find(`.${CLASS.overlayWrapper} .${CLASS.fullScreen}`).exists; + popup: Popup = new Popup(SELECTORS.appointmentPopup); + contentElement: Selector = Selector(SELECTORS.appointmentPopupContent); + toolbarElement: Selector = Selector(SELECTORS.appointmentPopupToolbar); - repeatUntilElement = this.wrapper.find(SELECTORS.repeatUntilInput); + saveButton: Button = new Button(this.toolbarElement.find(SELECTORS.doneButton)); + cancelButton: Button = new Button(this.toolbarElement.find(SELECTORS.cancelButton)); - repeatCountElement = this.wrapper.find(SELECTORS.repeatCountInput); + form: Form = new Form(this.contentElement.find(SELECTORS.form)); - constructor(private readonly scheduler: Selector) { - } + textEditor: TextBox = new TextBox(this.contentElement.find(SELECTORS.textEditor)); - isVisible(): Promise { - const { element } = this; - const invisibleStateClass = CLASS.stateInvisible; + allDaySwitch: Selector = Selector(this.contentElement.find(SELECTORS.allDaySwitch)); - return ClientFunction(() => !(element() as any).classList.contains(invisibleStateClass), { - dependencies: { element, invisibleStateClass }, - })(); - } + startDateEditor: DateBox = new DateBox(this.contentElement.find(SELECTORS.startDateEditor)); + startTimeEditor: DateBox = new DateBox(this.contentElement.find(SELECTORS.startTimeEditor)); + startTimeZoneEditor: SelectBox = new SelectBox(this.contentElement.find(SELECTORS.startTimeZoneEditor)); - getAllDaySwitchValue(): Promise { - return this.allDayElement.find('input[type="hidden"]').value; - } + endDateEditor: DateBox = new DateBox(this.contentElement.find(SELECTORS.endDateEditor)); + endTimeEditor: DateBox = new DateBox(this.contentElement.find(SELECTORS.endTimeEditor)); + endTimeZoneEditor: SelectBox = new SelectBox(this.contentElement.find(SELECTORS.endTimeZoneEditor)); - getRecurrenceRuleSwitchValue(): Promise { - return this.recurrenceElement.find('input[type="hidden"]').value; - } + repeatEditor: SelectBox = new SelectBox(this.contentElement.find(SELECTORS.repeatEditor)); - getRecurrenceTypeSelectItem(nth = 0): Selector { - return Selector(`.${CLASS.overlayWrapper}`) - .nth(1) - .find(`.${CLASS.selectItem}`) - .nth(nth); - } + descriptionEditor: TextArea = new TextArea(this.contentElement.find(SELECTORS.descriptionEditor)); - getEndRepeatRadioButton(nth = 0): Selector { - return this.wrapper.find(`.${CLASS.radioButton}`).nth(nth); - } + constructor(private readonly scheduler: Selector) { } } diff --git a/packages/testcafe-models/scheduler/index.ts b/packages/testcafe-models/scheduler/index.ts index 208518cf7248..5fc6bb3246cd 100644 --- a/packages/testcafe-models/scheduler/index.ts +++ b/packages/testcafe-models/scheduler/index.ts @@ -1,5 +1,6 @@ import { ClientFunction } from 'testcafe'; import Widget from '../internal/widget'; +import LegacyAppointmentPopup from './appointment/legacyPopup'; import AppointmentPopup from './appointment/popup'; import AppointmentTooltip from './appointment/tooltip'; import AppointmentDialog from './appointment/dialog'; @@ -76,6 +77,8 @@ export default class Scheduler extends Widget { readonly workSpaceScroll: { left: Promise; top: Promise }; + readonly legacyAppointmentPopup: LegacyAppointmentPopup; + readonly appointmentPopup: AppointmentPopup; readonly appointmentTooltip: AppointmentTooltip; @@ -121,6 +124,7 @@ export default class Scheduler extends Widget { top: this.workspaceScrollable.scrollTop, }; + this.legacyAppointmentPopup = new LegacyAppointmentPopup(this.element); this.appointmentPopup = new AppointmentPopup(this.element); this.appointmentTooltip = new AppointmentTooltip(this.element); this.reducedIconTooltip = new ReducedIconTooltip();