Skip to content

Scheduler: refactor appointment_popup module (TS)#33575

Open
bit-byte0 wants to merge 4 commits into
DevExpress:26_1from
bit-byte0:refactor/type-appointment-popup
Open

Scheduler: refactor appointment_popup module (TS)#33575
bit-byte0 wants to merge 4 commits into
DevExpress:26_1from
bit-byte0:refactor/type-appointment-popup

Conversation

@bit-byte0
Copy link
Copy Markdown

@bit-byte0 bit-byte0 commented May 13, 2026

Scheduler: refactor appointment_popup module (TS) #4124

What does the PR change?

  • Removed m_ prefix from files in appointment_popup/ folder.
  • Also added types and replaced old Deferred with native Promise.

How did you achieve this?

Removing from files _m prefix turned strict mode on, and strict mode complained about missing types and the Deferred usage (it needed @ts-expect-error to even compile). Fixed all that: added interfaces, switched to async/await + native Promise.

One more thing - some tests broke after switching to Promise because they expected the save to finish synchronously (which Deferred kinda allowed). Native Promise always resolves async, so added await Promise.resolve() after save calls in those tests to let the chain settle before asserting.

How can we verify these changes?

  • Run Jest: pnpm run test-jest
  • Run QUnit scheduler tests
  • Open demo app, try creating/editing/deleting regular and recurring appointments - should work same as before

@bit-byte0 bit-byte0 self-assigned this May 13, 2026
Copilot AI review requested due to automatic review settings May 13, 2026 15:43
@bit-byte0 bit-byte0 requested a review from a team as a code owner May 13, 2026 15:43
@bit-byte0 bit-byte0 added the 26_1 label May 13, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the internal Scheduler appointment popup module by splitting/renaming legacy m_* modules into clearer TS modules (form, popup), tightening types around scheduler/form/popup interactions, and extracting form-item customization logic into a dedicated utility with Jest coverage.

Changes:

  • Renamed/refactored appointment popup modules (m_formform, m_popuppopup) and updated Scheduler + test mocks imports accordingly.
  • Strengthened TypeScript typings across appointment popup/form/recurrence utilities (e.g., DayOfWeek, scheduler “proxy” interfaces).
  • Added customize_form_items.ts helper + updated unit tests to use the new module.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/devextreme/js/__internal/scheduler/m_scheduler.ts Updates appointment popup imports and includes minor formatting cleanups.
packages/devextreme/js/__internal/scheduler/appointment_popup/utils.ts Tightens firstDayOfWeek typing to DayOfWeek.
packages/devextreme/js/__internal/scheduler/appointment_popup/recurrence_form.ts Repoints scheduler typing to the new form scheduler interface and improves typing in component creation.
packages/devextreme/js/__internal/scheduler/appointment_popup/popup.ts Major refactor: introduces explicit state/types and replaces Deferred/when flow with Promises for saving + popup show/hide.
packages/devextreme/js/__internal/scheduler/appointment_popup/form.ts Major refactor: introduces AppointmentFormScheduler interface, updates customization pipeline, and improves typing.
packages/devextreme/js/__internal/scheduler/appointment_popup/customize_form_items.ts New extracted helper for merging default form items with user config.
packages/devextreme/js/__internal/scheduler/appointment_popup/customize_form_items.test.ts Updates tests to import the new helper module.
packages/devextreme/js/__internal/scheduler/tests/mock/model/scheduler.ts Updates appointment popup constant import to the renamed module.
packages/devextreme/js/__internal/scheduler/tests/mock/create_appointment_popup.ts Updates appointment popup/form imports to renamed modules and keeps mocks aligned.
Comments suppressed due to low confidence (2)

packages/devextreme/js/__internal/scheduler/appointment_popup/popup.ts:139

  • show()/hide() throw errors.Error('E1033') when popupInstance is not set. E1033 is an existing UI widgets error code for an unrelated case (date navigator step) and expects a parameter, so this will produce a misleading error message here. Prefer not throwing at all (e.g., no-op/return) or throw a dedicated error with a correct code/message; alternatively, capture the instance from createComponent synchronously so popupInstance is always defined before calling show()/hide().
    packages/devextreme/js/__internal/scheduler/appointment_popup/popup.ts:343
  • saveChangesAsync() calls hideLoading() only in the success .then() branch. If this.config.onSave() (or the validation promise) rejects/throws, the chain goes to .catch(noop) and the load panel is never hidden, leaving the UI stuck. Use a finally to always call hideLoading() (or call it in both success and error paths) and avoid swallowing the error before the load panel is cleaned up.

Copilot AI review requested due to automatic review settings May 14, 2026 13:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

packages/devextreme/js/__internal/scheduler/appointment_popup/popup.ts:341

  • This makes saveChangesAsync defer the save work to a native Promise microtask even when form validation is synchronous. hideAppointmentPopup(true) still calls saveChangesAsync() without awaiting it and then returns immediately, so callers that currently rely on the appointment being saved when hideAppointmentPopup(true) returns will now observe stale data until the microtask runs (the existing integration tests around hideAppointmentPopup(true) assert synchronously). Consider preserving the synchronous path for already-complete validation or updating the caller/API contract to await the returned promise.
    packages/devextreme/js/__internal/scheduler/appointment_popup/popup.ts:138
  • E1033 is the date-navigator error ("Unknown step in the date navigator: '{0}'"), so throwing it here would produce a misleading message unrelated to appointment popup creation/hiding. Use an error that matches this failure mode, or keep the previous no-op behavior for hide() when no popup instance exists.

if (this.popupInstance) {
this.popupInstance.show().catch(noop);
} else {
throw errors.Error('E1033');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E1033: 'Unknown step in the date navigator: '{0}'',

I am not sure that we need to display this error here. And not sure if we need to return any errors here or in hide step

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://js.devexpress.com/jQuery/Documentation/ApiReference/UI_Components/Errors_and_Warnings/#E1033

A [Scheduler](https://js.devexpress.com/jQuery/Documentation/ApiReference/UI_Components/dxScheduler/) internal error.

To solve the issue, please submit a ticket to our [Support Center](https://www.devexpress.com/ask). Include your UI component configuration, fake data, and the steps needed to reproduce the issue in the ticket.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, looks like a mistake of mine

getResourceManager: () => this.resourceManager,

getFirstDayOfWeek: () => this.option('firstDayOfWeek'),
getFirstDayOfWeek: () => this.getFirstDayOfWeek(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aleksei-semikozov I think you had a bug related to this string when you were also passing a function instead of option.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this function, we use the firstDayOfWeek option in this way, but if this otpion is not specified, the localization settings are applied. This is the same way we use it in the header

code link


scheduler.instance.showAppointmentPopup(newItem, true);
$('.dx-scheduler-appointment-popup .dx-popup-done').trigger('dxclick');
await Promise.resolve();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this in tests?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because Deferred that was used before refactoring were acting synchronously even that it is Promise analogue and all tests also were set up to check synchronous behavior. After refactoring we used Promise that acts asynchronous and tests were not ready for it - they didn't have any option to wait a bit (save button clicks before Promise resolves) and that's why I needed to add async behavior to tests

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants