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:
After quickly draging the tz
to the first postion:
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
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.
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?