Scheduler - Appointments refactoring - Drag-n-Drop#33690
Conversation
| ); | ||
| } | ||
|
|
||
| public getCellFromDragTarget($dragTarget: dxElementWrapper): dxElementWrapper | null { |
There was a problem hiding this comment.
This method has the same logic as old method
| appointment, | ||
| targetedAppointment, | ||
| color: this.resourceManager.getAppointmentColor(appointmentConfig), | ||
| settings, |
There was a problem hiding this comment.
This change won't affect anything for the old impl. Needed to match AppointmentTooltipItem type
There was a problem hiding this comment.
Pull request overview
This PR advances the Scheduler “new appointments” refactoring by introducing a dedicated drag-and-drop controller and wiring it into the workspace + tooltip flows when _newAppointments is enabled, while gating/annotating legacy drag code paths.
Changes:
- Added
AppointmentDragControllerand integrated it intoSchedulerfor workspace appointment dragging and tooltip list item dragging under_newAppointments. - Added workspace hit-testing (
getCellFromDragTarget) and tooltip list lifecycle hooks (onInitialized/onDisposing) to support the new DnD flow. - Updated/added Jest tests and test POM helpers for the new dragging behavior; adjusted an existing QUnit tooltip test assertion.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/desktopTooltip.tests.js | Loosened List options assertion (removed “keys length” check). |
| packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts | Disabled legacy drag events for new appointments; added drag target → cell hit-testing helpers. |
| packages/devextreme/js/__internal/scheduler/types.ts | Updated tooltip/compact appointment typing (settings on tooltip items; simplified compact items type). |
| packages/devextreme/js/__internal/scheduler/tooltip_strategies/tooltip_strategy_base.ts | Added List lifecycle hooks (onInitialized / onDisposing) to tooltip list options. |
| packages/devextreme/js/__internal/scheduler/tooltip_strategies/desktop_tooltip_strategy.ts | For new appointments: forward list initialization; skip legacy drag behavior hook in onContentReady. |
| packages/devextreme/js/__internal/scheduler/m_subscribes.ts | Added TODO markers around legacy-only subscribe methods. |
| packages/devextreme/js/__internal/scheduler/m_scheduler.ts | Integrated AppointmentDragController, added draggable container, and added drop-update path for new DnD. |
| packages/devextreme/js/__internal/scheduler/m_appointment_drag_behavior.ts | Marked legacy drag behavior file as TODO for removal. |
| packages/devextreme/js/__internal/scheduler/appointments_new/appointments.ts | Refactored rendering flow, added tooltip item construction and drag-clone rendering helpers. |
| packages/devextreme/js/__internal/scheduler/appointments_new/appointments.test.ts | Updated tests for unified showAppointmentTooltip callback shape/signature. |
| packages/devextreme/js/__internal/scheduler/appointment_drag_controller.ts | New controller implementing workspace + tooltip dragging, clone creation, and cell highlighting. |
| packages/devextreme/js/__internal/scheduler/tests/appointments_dragging.test.ts | New Jest test suite covering new appointment dragging behavior. |
| packages/devextreme/js/__internal/scheduler/tests/mock/model/tooltip.ts | Updated tooltip selectors and added a helper to retrieve the tooltip list element. |
| packages/devextreme/js/__internal/scheduler/tests/mock/model/scheduler.ts | Added helper to locate the dragged clone in the new draggable container. |
| packages/devextreme/js/__internal/scheduler/tests/mock/model/appointment.ts | Added isDragSource() helper for drag-source class assertions. |
| this.mainContainer = $('<div>').addClass('dx-scheduler-container'); | ||
| this.$draggableContainer = $('<div>') | ||
| .addClass('dx-scheduler-draggable-container') | ||
| .appendTo(this.mainContainer); |
There was a problem hiding this comment.
In the old implementation the drag clones were placed in the workspace.$fixedContainer.
In new implementation I create a container inside scheduler's mainContainer, because I pass the container to the draggable at DragController's creation at this moment workSpace is not defined yet.
And if feels more right, because draggable container is used not only by workspace, but also by tooltip
| } | ||
|
|
||
| if (isPromise(updatingOptions.cancel) && dragEvent) { | ||
| if (isPromise(updatingOptions.cancel) && (dragEvent || this.option('_newAppointments'))) { |
There was a problem hiding this comment.
in new appts no need to pass dragEvent, because dragController receives promise on updateAppointmentOnDrop, after which it removes the necessary css classes.
| return this.viewItemBySortedIndex[sortedIndex]; | ||
| } | ||
|
|
||
| public getViewModelBySortedIndex(sortedIndex: number): AppointmentViewModelPlain { |
There was a problem hiding this comment.
needed to create tooltip item for single appt (not collector) on tooltip showing
| return result; | ||
| } | ||
|
|
||
| public getAppointmentData($element: dxElementWrapper): SafeAppointment { |
There was a problem hiding this comment.
needed by DnD, because to update the dragged appointment, the appointmentData is needed.
Currently it's a linear search, which I think is ok (drop happens very rarely).
Another approach would be to use $element.data('appointmentData') to attach appointmentData to the element, but I don't think this is a good idea, because later it could be used anywhere in the codebase which is not supposed to happen
|
|
||
| // TODO: remove passing index to appointmentTemplate, need only to avoid BC | ||
| private renderViewItem( | ||
| fragment: DocumentFragment, |
There was a problem hiding this comment.
moved fragment logic to the viewModel rendering functions, because renderDragClone doesn't pass fragment.
|
|
||
| this.options.updateAppointmentOnDrop(e.itemData, this.$highlightedCell) | ||
| .finally(() => { this.removeDraggingClasses($(e.itemElement)); }) | ||
| .catch((err) => { throw err; }); |
There was a problem hiding this comment.
.catch((err) => { throw err; });
Seems like a unhandled promise rejection. Maybe its better to write something like
import { noop } from '@js/core/utils/common';
...
.catch(noop);
What do you think?
There was a problem hiding this comment.
In this code, catch will fire only if function inside finally throws, because updateAppointmentOnDrop always resolve (L1685).
I don't want to put noop here, because in this case we wouldn't notice if the error actually happens. This .catch handler is here just to make eslint happy, but basically it's no difference if it's present or not
| this.removeCellHighlight(); | ||
| } | ||
|
|
||
| private onDragCancel(e): void { |
There was a problem hiding this comment.
Can you add type here for e?
There was a problem hiding this comment.
onDragCancel is a private callback, so there's no type for it, but I will add DragEndEvent because they have similar parameters
| this.removeDraggingClasses($(e.itemElement)); | ||
| } | ||
|
|
||
| public removeDraggingClasses($dragSource: dxElementWrapper): void { |
There was a problem hiding this comment.
Do we need this method to be public? Its being used only in class
|
I think I found a bug:
|
This PR adds DnD functionality for refactored appointments.
The old DnD implementation was scattered across several files:
dragEventand managed it depending on the update resultsIn the new implementation the whole DnD is located in the appointments_drag_controller.ts and
dragEventis not passed to the scheduler at all.