fix(dashboard): resolve tab reorder state sync issues (#36855)

This commit is contained in:
Enzo Martellucci
2025-12-31 13:50:58 +01:00
committed by GitHub
parent fe5d5fdae6
commit e112d863bf
3 changed files with 30 additions and 7 deletions

View File

@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import type { FC } from 'react';
import { css, styled, useTheme } from '@apache-superset/core/ui';
// eslint-disable-next-line no-restricted-imports
@@ -161,7 +162,9 @@ export const StyledLineEditableTabs = styled(EditableTabs)`
}
`;
export const LineEditableTabs = Object.assign(StyledLineEditableTabs, {
export const LineEditableTabs: FC<TabsProps> & {
TabPane: typeof StyledTabPane;
} = Object.assign(StyledLineEditableTabs, {
TabPane: StyledTabPane,
});

View File

@@ -362,7 +362,7 @@ const Tabs = props => {
setActiveKey(currentActiveTabId);
}
},
[props.component, props.updateComponents, selectedTabIndex],
[props.component, props.updateComponents, selectedTabIndex, activeKey],
);
const {

View File

@@ -22,6 +22,7 @@ import {
ReactElement,
RefObject,
useCallback,
useRef,
useState,
} from 'react';
import { styled } from '@apache-superset/core/ui';
@@ -61,6 +62,16 @@ const StyledTabsContainer = styled.div<{ isDragging?: boolean }>`
height: calc(100% - 47px);
}
/* Ensure tab labels maintain full opacity during drag */
.ant-tabs-tab {
.dragdroppable-tab,
.editable-title,
textarea {
opacity: 1;
color: inherit;
}
}
/* Hide ink-bar during drag */
${({ isDragging }) =>
isDragging &&
@@ -126,7 +137,7 @@ const DraggableTabNode: React.FC<Readonly<DraggableTabNodeProps>> = ({
...props.style,
position: 'relative',
transform: transform ? `translate3d(${transform.x}px, 0, 0)` : undefined,
transition,
transition: isDragging ? 'none' : transition,
cursor: disabled ? 'default' : 'move',
zIndex: isDragging ? 1000 : 'auto',
opacity: 1,
@@ -163,6 +174,10 @@ const TabsRenderer = memo<TabsRendererProps>(
}) => {
const [activeId, setActiveId] = useState<string | null>(null);
// Use ref to always have access to the current tabIds in callbacks
const tabIdsRef = useRef(tabIds);
tabIdsRef.current = tabIds;
const sensor = useSensor(PointerSensor, {
activationConstraint: { distance: 10 },
});
@@ -173,14 +188,18 @@ const TabsRenderer = memo<TabsRendererProps>(
const onDragEnd = useCallback(
({ active, over }: DragEndEvent) => {
const currentTabIds = tabIdsRef.current;
// Only reorder when we have a valid drop target and both IDs are found
if (active.id !== over?.id && onTabsReorder) {
const activeIndex = tabIds.findIndex(id => id === active.id);
const overIndex = tabIds.findIndex(id => id === over?.id);
onTabsReorder(activeIndex, overIndex);
const activeIndex = currentTabIds.findIndex(id => id === active.id);
const overIndex = currentTabIds.findIndex(id => id === over?.id);
if (activeIndex !== -1 && overIndex !== -1) {
onTabsReorder(activeIndex, overIndex);
}
}
setActiveId(null);
},
[onTabsReorder, tabIds],
[onTabsReorder],
);
const onDragCancel = useCallback(() => {
@@ -220,6 +239,7 @@ const TabsRenderer = memo<TabsRendererProps>(
{...(editMode && {
renderTabBar: (tabBarProps, DefaultTabBar) => (
<DndContext
key={tabIds.join('-')}
sensors={[sensor]}
onDragStart={onDragStart}
onDragEnd={onDragEnd}