Compare commits

...

2 Commits

Author SHA1 Message Date
Joe Li
2c4538c379 Merge branch 'master' into fix-no-top-level-tab 2026-04-20 21:59:48 -07:00
Joe Li
862b00494a fix(dashboard): restore top-level tab drop target height for dashboards with content
PR #37891 moved the DashboardHeader out of the root Droppable, leaving
it with zero height when no top-level tabs exist. This made it impossible
to drag a Tabs component onto dashboards that already have content.

Add min-height to .empty-droptarget in StyledHeader, matching the pattern
used by DashboardGrid for its drop targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:42:30 -07:00
2 changed files with 46 additions and 0 deletions

View File

@@ -487,6 +487,48 @@ test('should render ParentSize wrapper with height 100% for tabs', async () => {
expect(tabPanels.length).toBeGreaterThan(0);
});
test('should apply min-height to the top-level tab drop target so tabs can be dropped on dashboards with content', () => {
(useStoredSidebarWidth as jest.Mock).mockImplementation(() => [
100,
jest.fn(),
]);
(fetchFaveStar as jest.Mock).mockReturnValue({ type: 'mock-action' });
(setActiveTab as jest.Mock).mockReturnValue({ type: 'mock-action' });
const { container } = render(<DashboardBuilder />, {
useRedux: true,
store: storeWithState({
...mockState,
dashboardLayout: undoableDashboardLayout,
dashboardState: { ...mockState.dashboardState, editMode: true },
}),
useDnd: true,
useTheme: true,
});
const headerWrapper = container.querySelector(
'[data-test="dashboard-header-wrapper"]',
);
expect(headerWrapper).toBeInTheDocument();
// Verify the StyledHeader CSS includes min-height for the empty drop target.
// Without this, the drop target has zero height and users cannot drag tabs
// onto dashboards that already have content (the Droppable renders an empty
// div and needs explicit min-height to be a valid react-dnd hover target).
const allRules = Array.from(document.styleSheets).flatMap(sheet => {
try {
return Array.from(sheet.cssRules).map(rule => rule.cssText);
} catch {
return [];
}
});
const emptyDroptargetRule = allRules.find(
rule =>
rule.includes('.empty-droptarget') && rule.includes('min-height'),
);
expect(emptyDroptargetRule).toBeDefined();
});
test('should maintain layout when switching between tabs', async () => {
(useStoredSidebarWidth as jest.Mock).mockImplementation(() => [
100,

View File

@@ -99,6 +99,10 @@ const StyledHeader = styled.div<{ filterBarWidth: number }>`
z-index: 99;
max-width: calc(100vw - ${filterBarWidth}px);
.empty-droptarget {
min-height: ${theme.sizeUnit * 4}px;
}
.empty-droptarget:before {
position: absolute;
content: '';