Skip to content

Conversation

@HendrikThePendric
Copy link
Collaborator

@HendrikThePendric HendrikThePendric commented Dec 9, 2025

Implements DHIS2-20118

Description

This ports the DnD functionality of the chips from LL to EVER. I have attempted to clean things up a bit as follows:

  • I've split up the code in the provider / wrapper into separate parts:
    • The DndContextProvider is the actual wrapper that defines the DnD behaviour and renders children in a DndContext
    • The DimensionDragOverlay is responsible for rendering the "drag-overlay", which is the representation of the element that is being dragged
    • The collisionDetector is the brains of the operation: it figures out which droppable container (i.e. chip/axis) is the "active" one (in dnd-kit language the is the over one). It's now doing what we did before (in LL), which is to just check element overlaps, but when it doesn't detect an overlap it also check for the best "line end match". This is basically tov ensure we can drop at various empty spots in the axis, this can be just the axis itself, if there are not matches, but also let's you drop behind the last chip at a certain line.
    • The useOnDragEnd hook is responsible for dispatching actions to the store, to update the layout when an OnDragEnd event takes place. It is used to populate the onDragEnd prop of the DndContext
  • I have also tried to simplify the general logic by leveraging the data field of the useSortable/ useDroppable hooks:
    • Considering that the drag-overlay should render a representation of the element that is currently being dragged, it makes most sense that the draggable component provides the props for the overlay via the data.overlayItemProps field. This avoids having to compute things again in the drag-overlay
    • Similarly it is possible to simplify the sorting logic by setting the correct properties on the data attribute, like axis, dimensionId, insertAfter, and isEmptyAxis, see type definitions for more info
  • Obviously we have not really implemented dragging from the sidebar yet, but I have done work to (hopefully) make adding support for this a fairly easy:
    • In the type definitions you can the data in both cases will be of a slightly different shape.
    • The useOnDragEnd treats these types different and use a different reducer for each type.
    • The DimensionDragOverlay already takes into account that it will need to render a different component when dragging a sidebar-item
  • I have also restructured the chip/axis components completely. I have ended up with a solution that is a different than in LL. This wasn't a very conscious decision at first: it stemmed from the fact that I couldn't really wrap my head around how things worked in LL exactly. And I kept thinking of scenarios where the last chip happens to be very close to the right edge: how would we trigger showing the marker after the last item when there is very little space around it? So then I built things a bit differently, and realised I had some subtle bugs. And then I realised that some of these are present in LL "in the opposite direction" (i.e. in EVER you can't insert at the chip-line-end and in LL you can't insert at the chip-line-start). What I ended up with is this:
    • The Axis itself is now also droppable. This helps in various ways, the obvious one being that it helps when you want to drag something onto an empty axis. The less obvious one is that they can be now be used by the collision detection logic to determine "if a chip is over a particular line of chips within a particular axis".
    • We now have a InsertMarker component, which serves two purposed as well. It renders the "insert marker" tot the DOM, but it also monitors the dragged-item-position and is responsible for controlling the insertAfter prop of the sortable. This is not only used to position the marker but also by the sort reducers.
  • The actual add/move/remove logic is done in the reducer and this part of the code is heavily tested (because I found some bugs)
  • I have also added a lot of tests to assert the collision logic and if the insert-marker shows at the right spot.

Quality checklist

  • Dashboard tested N/A
  • Cypress and/or Jest tests added/updated*
  • d2-ci dependency replaced N/A

[*] I actually ended up writing a lot of tests for this, because I found a lot of bugs.


Screenshots

Screen.Recording.2025-12-18.at.17.16.25.mov

@dhis2-bot
Copy link

dhis2-bot commented Dec 9, 2025

🚀 Deployed on https://pr-111.event-visualizer.netlify.dhis2.org

@dhis2-bot dhis2-bot temporarily deployed to netlify December 9, 2025 16:23 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 9, 2025 16:29 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 11, 2025 15:03 Inactive
@HendrikThePendric HendrikThePendric changed the title Feat/drag-and-drop-chips-in-layout-panel feat: drag-and-drop chips in layout panel Dec 11, 2025
@HendrikThePendric HendrikThePendric marked this pull request as ready for review December 11, 2025 15:55
@dhis2-bot dhis2-bot temporarily deployed to netlify December 11, 2025 16:04 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 11, 2025 17:01 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 16, 2025 08:34 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 16, 2025 08:37 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 16, 2025 16:23 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 18, 2025 08:13 Inactive
@dhis2-bot dhis2-bot temporarily deployed to netlify December 18, 2025 15:50 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants