Bug description

When I drag a metric very quickly (i.e., I move the mouse in one swift motion) inside the Metrics control of Explore, the original order of all metrics that the cursor passes over becomes corrupted.
The problem does not occur when I move the metric slowly, one position at a time.

Screenshots/recordings

before the draging:

Image

After quickly draging the tz to the first postion:

Image

Superset version

master / latest-dev

Python version

3.10

Node version

18 or greater

Browser

Chrome

Additional context

No response

Checklist

  • [x] I have searched Superset docs and Slack and didn't find a solution to my problem.
  • [x] I have searched the GitHub issue tracker and didn't find a similar bug report.
  • [x] I have checked Superset's logs for errors and if I found a relevant Python stacktrace, I included it here as text in the "additional context" section.

Comment From: dosubot[bot]

This looks like a real bug with the drag-and-drop reordering in Explore controls. The frontend uses the react-sortable-hoc library (which is no longer maintained) to handle drag-and-drop, and the item order is updated using its arrayMove function when a drag ends. There’s no built-in throttling or debouncing, so rapid movements can cause state inconsistencies and scramble the order, especially during fast drags. I couldn’t find any existing reports or fixes for this issue in the repo or docs, and there aren’t any comments in the code about handling rapid drag events or known limitations with this approach. If you need to investigate or patch this, the relevant logic is in the DndColumnSelectControl component and its onSortEnd handler, where the array order is updated using arrayMove from react-sortable-hoc
(source).

A possible workaround would be to try slower, one-at-a-time drags for now, or to look into replacing or patching the drag-and-drop logic to better handle rapid movements.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

Comment From: rusackas

I wonder if AntD provides vanilla components for this to just get rid of react-sortable-hoc (@geido @msyavuz)

Comment From: msyavuz

I don't think antd provides something like this. They recommend popular dnd libraries for this as well.

Comment From: rusackas

They recommend popular dnd libraries for this as well.

Anything better that's easy to migrate to? Or do we just need a debounce added here?

Comment From: msyavuz

Yeah, debounce seems like the way to go

Comment From: amaannawab923

This react-sortable-hoc is not maintained anymore , Although debounce will be a good fix but we should migrate to dnd-kit which is from the same author as react sortable hoc but well maintained, Also it has better animations and easier to replace since they from same author , Let me know your thoughts on the same @msyavuz @rusackas @geido

Comment From: msyavuz

We should definitely migrate when we can to dnd-kit but that part of the codebase is pretty old so not sure about how easy it would be.

Comment From: amaannawab923

I was able to analyze the drag & drop logic — turns out react-sortable-hoc isn’t responsible for it. It’s actually handled by react-dnd.

In OptionsWrapper.tsx, the function onShiftOptions is responsible for reordering dimensions. The issue is that it’s being called during onHover, which leads to repeated execution before the drop event — causing incorrect shuffling.

If we instead move this logic to the drop handler, it works as expected.

Here's the corrected code:


drop: (item: OptionItemInterface) => {
  // Instead of repetitive calls on drag, 
  // we only execute the shift on drop
  const { dragIndex } = item;
  const hoverIndex = index;

  if (dragIndex === hoverIndex) return;
  onShiftOptions(dragIndex, hoverIndex);
  item.dragIndex = hoverIndex;
},

This prevents premature reordering and executes onShiftOptions only once when the drop actually happens.

cc: @msyavuz @rusackas

Comment From: wuqicyber

I was able to analyze the drag & drop logic — turns out react-sortable-hoc isn’t responsible for it. It’s actually handled by react-dnd.

In OptionsWrapper.tsx, the function onShiftOptions is responsible for reordering dimensions. The issue is that it’s being called during onHover, which leads to repeated execution before the drop event — causing incorrect shuffling.

If we instead move this logic to the drop handler, it works as expected.

Here's the corrected code:

```

drop: (item: OptionItemInterface) => { // Instead of repetitive calls on drag, // we only execute the shift on drop const { dragIndex } = item; const hoverIndex = index;

if (dragIndex === hoverIndex) return; onShiftOptions(dragIndex, hoverIndex); item.dragIndex = hoverIndex; }, ```

This prevents premature reordering and executes onShiftOptions only once when the drop actually happens.

cc: @msyavuz @rusackas

Thanks for the explanation and the fix — I tried this approach, but it seems this only swaps the two items’ positions rather than moving the dragged item to the target position.

Do you have any suggestions on how to properly shift the item to the desired index instead of just swapping?

Comment From: amaannawab923

Yes thats why i closed the pr .... the whole component needs to be re designed , Its not a simple change because the architecture of re arranging the elements in value renderer itself isn't correct for the long term or smooth interactions @wuqicyber

Comment From: msyavuz

Hey @kgabryje, do you have an idea for a way forward for this bug?