[DREAM-755] Draggable autocompleter on Pragmatic DnD (new sortable-lists engine + directives)#24229
Open
myabc wants to merge 5 commits into
Open
[DREAM-755] Draggable autocompleter on Pragmatic DnD (new sortable-lists engine + directives)#24229myabc wants to merge 5 commits into
myabc wants to merge 5 commits into
Conversation
myabc
changed the base branch from
dev
to
implementation/74970-backlogs-pragmatic-dnd
July 13, 2026 10:24
Contributor
There was a problem hiding this comment.
Pull request overview
This PR migrates the Angular DraggableAutocompleteComponent from Dragula (ng2-dragula) to Atlaskit Pragmatic Drag and Drop, aligning this autocompleter’s chip reordering behavior with the newer DnD approach already used elsewhere in the frontend.
Changes:
- Remove Dragula module usage from shared/autocompleter Angular modules and replace chip reordering with Pragmatic DnD (
draggable,dropTargetForElements,monitorForElements). - Introduce reusable Pragmatic DnD helper utilities (payload tagging, reorder helper, drop indicator, auto-scroll).
- Add a dedicated component spec suite and update chip styling to reflect drag/drop state (opacity + edge indicator).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/app/shared/shared.module.ts | Removes DragulaModule from shared module imports. |
| frontend/src/app/shared/helpers/drag-and-drop/pragmatic/reorder.ts | Adds reorderById helper + closest-edge re-export utilities for list reordering. |
| frontend/src/app/shared/helpers/drag-and-drop/pragmatic/payload.ts | Adds symbol-keyed payload helpers to identify sortable items during drags. |
| frontend/src/app/shared/helpers/drag-and-drop/pragmatic/drop-indicator.ts | Adds attribute-based drop indicator contract (data-drop-position). |
| frontend/src/app/shared/helpers/drag-and-drop/pragmatic/auto-scroll.ts | Adds helper to register Pragmatic auto-scroll for sortable drags. |
| frontend/src/app/shared/components/autocompleter/openproject-autocompleter.module.ts | Removes DragulaModule from autocompleter module imports. |
| frontend/src/app/shared/components/autocompleter/draggable-autocomplete/draggable-autocomplete.component.ts | Replaces Dragula wiring with Pragmatic DnD monitor + chip-level draggable/drop targets. |
| frontend/src/app/shared/components/autocompleter/draggable-autocomplete/draggable-autocomplete.component.spec.ts | Adds unit tests for rendering, selection/removal, hidden inputs, and drag-reorder behavior. |
| frontend/src/app/shared/components/autocompleter/draggable-autocomplete/draggable-autocomplete.component.sass | Adds drag opacity and left/right edge drop indicator styling. |
| frontend/src/app/shared/components/autocompleter/draggable-autocomplete/draggable-autocomplete.component.html | Removes Dragula directives and adds #chip refs for @ViewChildren registration. |
Base automatically changed from
implementation/74970-backlogs-pragmatic-dnd
to
dev
July 14, 2026 12:27
myabc
force-pushed
the
code-maintenance/77285-draggable-autocomplete-pragmatic-dnd
branch
2 times, most recently
from
July 15, 2026 14:41
8be7973 to
bac06fc
Compare
myabc
force-pushed
the
code-maintenance/77285-draggable-autocomplete-pragmatic-dnd
branch
from
July 15, 2026 21:16
bac06fc to
87709c2
Compare
myabc
marked this pull request as ready for review
July 15, 2026 21:18
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
Replaces the component's direct Dragula usage with Pragmatic drag and drop, integrated through new opSortableLists/opSortableListsItem directives so Angular's view lifecycle owns each adapter registration instead of re-pairing rendered chips with items after view changes. The drag payload is scoped per list instance and drop-target stickiness is bounded to the list rectangle, so coexisting autocompleters cannot react to each other's drags and a drop outside the list cancels rather than reordering next to the last hovered chip. Framework-neutral helpers move to `src/common/drag-and-drop/` under a new `core-common` alias, reusable by the Stimulus sortable-lists controllers and the upcoming `DragAndDropService` rewrite. https://community.openproject.org/wp/DREAM-755
The builder defaults `isolate` to false to mimic Karma, sharing one module registry across specs. Specs driving the real Pragmatic adapters and specs mocking the same `@atlaskit` ids poison each other, whichever imports first. Costs ~75s of suite wall clock.
Adds a framework-neutral Pragmatic engine to core-common: a root monitor resolves drops into intents, an optimistic two-phase transaction serializes drags via a busy attribute, and the DOM attribute contract matches the Stimulus sortable-lists controllers. Also extends the shared helpers: list-aware payloads, append reorders and drop-indicator ownership. https://community.openproject.org/wp/DREAM-756
Rebinds the directives as a thin layer over the shared engine in the final three-role shape: root, list and item. A root without explicit lists collapses to one implicit list; cross-list moves emit removed before drop, carrying the transaction for optimistic completion. https://community.openproject.org/wp/DREAM-755
Completes drop transactions synchronously, since chips only persist on form submit, and covers the append, remove-button suppression and consecutive-drag paths. https://community.openproject.org/wp/DREAM-755
myabc
force-pushed
the
code-maintenance/77285-draggable-autocomplete-pragmatic-dnd
branch
from
July 18, 2026 17:46
b218533 to
9fb3902
Compare
Deploying openproject with ⚡ PullPreview
|
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ticket
https://community.openproject.org/wp/DREAM-755
https://community.openproject.org/wp/DREAM-756 (engine commit; the consumer migrations stack on this PR in #24243)
What are you trying to accomplish?
Migrates the Angular draggable autocompleter — the chip list used for column selection in the work package table configuration modal, and its other embeddings — from Dragula to Pragmatic drag and drop, and introduces the foundation the remaining Angular DnD surfaces migrate onto: a framework-neutral sortable-lists engine plus thin Angular directives. This is one step in retiring Dragula, not the last one:
ng2-dragulastays in the tree for now, since the team planner and the sharedDragAndDropServicestill depend on it.Two bugs surfaced while migrating and are fixed here:
Symbolshared across every instance. The payload scope is now created per root instance.The remove affordance is now a real
<button>with anaria-label, replacing a<div>withtabindexand hand-rolled enter/space key handlers.Drag-and-drop screens touched
The draggable autocompleter is the only user-facing surface this PR changes. Its embeddings (breadcrumbs per the drag-and-drop inventory in https://community.openproject.org/wp/DREAM-777):
The engine and directives ship no other consumer in this PR; the remaining Angular surfaces (work package table, card view, boards, BIM BCF) follow in #24243.
Screenshots
Not yet captured — manual browser verification is still outstanding (see the checklist below), so I would rather not publish stills that imply it is done.
For review, the visible change is the drag affordance itself: Dragula's mirror element and placeholder gap are replaced by a 2px accent line (
--fgColor-accent) on the edge where the chip would be inserted, and the dragged chip dims to0.4opacity while in flight.What approach did you choose and why?
Three layers, one commit each:
core-common/drag-and-drop/sortable-lists-engine.ts).createSortableRootowns the Pragmatic wiring for one drag scope: item/list drop-target registration, a single root monitor that resolves every drop from the target stack into an intent (the pattern both the Stimulus root controller and Atlassian's React examples use), an optimistic two-phase transaction (completefrom the target side,finalizefrom the source side; busy state serializes drags until both settle), axis-aware bounded stickiness with item→list handoff, drag-start suppression on interactive descendants, and a custom-preview hook. The engine also owns the DOM state attributes, deliberately the same contract the Stimulussortable-listscontrollers established —data-dragging="source",data-drop-position(+ owner),data-drop-container,data-sortable-lists-busy— so the two frontends share one styling vocabulary.opSortableLists(root) /opSortableListsList/opSortableListsItem, mirroring the Stimulus root/list/item topology. A root without explicit child lists collapses to a single implicit list, so a simple consumer like the autocompleter binds one attribute and one(opSortableListsDrop)handler. Registration follows the Angular view lifecycle (@forchurn is free); cross-list moves emitremovedon the source list beforedropon the target list, carrying the transaction — that contract is what [DREAM-756] WP table, cards, boards and BCF on Pragmatic DnD #24243's boards migration consumes.An earlier iteration wired the Pragmatic adapters directly in the component; a second one put all behavior in the directives. Both were discarded: the first had to re-pair rendered chips with items after every view change, the second would have duplicated the engine per framework once the
DragAndDropServicerewrite (#24243, stacked on this branch) needed the same core for the work-package fast-table, whose builder-rendered rows can't host directives.dragAreaNameis kept as a deprecated input. Instance isolation no longer needs a group name, but custom-element embeddings still pass the attribute, so removing it now would break them silently.Two changes worth a conscious decision from a reviewer, since neither is strictly about this component:
test.isolate: true(its own commit). Specs that drive the real Pragmatic adapters and the Stimulussortable-listsspecs that mock the same@atlaskitmodule ids share one module registry, because the Angular builder defaultsisolatetofalseto mimic Karma. Whichever file imports first wins the cache and the other sees a real function where it expects a spy — which shows up as a flaky, import-order-dependent failure count rather than a clean one. Isolating fixes it, and costs roughly 22s → 99s of frontend suite wall clock.column_spec.rbmoved fromfirefox_detochrome_de. Reordering columns is a native HTML5 drag now, and geckodriver starts one —dragstartanddragoverboth fire — but never completes it, so nodropever reaches the page and the columns silently stay put. This is a limitation of the driver, not of the feature; real Firefox users drag fine. The German locale the example has always carried is preserved.Merge checklist