Skip to content

Commit fb9032c

Browse files
authored
fix: Cosmetic issues (#35122)
1 parent 7a9dbfe commit fb9032c

File tree

14 files changed

+682
-911
lines changed

14 files changed

+682
-911
lines changed

superset-frontend/src/components/Chart/ChartContextMenu/ChartContextMenu.tsx

Lines changed: 84 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
*/
1919
import {
2020
forwardRef,
21-
Key,
2221
ReactNode,
2322
RefObject,
2423
useCallback,
@@ -43,18 +42,18 @@ import {
4342
useTheme,
4443
} from '@superset-ui/core';
4544
import { RootState } from 'src/dashboard/types';
46-
import { Menu } from '@superset-ui/core/components/Menu';
45+
import { MenuItem } from '@superset-ui/core/components/Menu';
4746
import { usePermissions } from 'src/hooks/usePermissions';
4847
import { Dropdown } from '@superset-ui/core/components';
4948
import { updateDataMask } from 'src/dataMask/actions';
5049
import DrillByModal from 'src/components/Chart/DrillBy/DrillByModal';
5150
import { useDatasetDrillInfo } from 'src/hooks/apiResources/datasets';
5251
import { ResourceStatus } from 'src/hooks/apiResources/apiResources';
53-
import { DrillDetailMenuItems } from '../DrillDetail';
52+
import { useDrillDetailMenuItems } from '../useDrillDetailMenuItems';
5453
import { getMenuAdjustedY } from '../utils';
55-
import { MenuItemTooltip } from '../DisabledMenuItemTooltip';
56-
import { DrillByMenuItems } from '../DrillBy/DrillByMenuItems';
54+
import { DrillBySubmenu } from '../DrillBy/DrillBySubmenu';
5755
import DrillDetailModal from '../DrillDetail/DrillDetailModal';
56+
import { MenuItemTooltip } from '../DisabledMenuItemTooltip';
5857

5958
export enum ContextMenuItem {
6059
CrossFilter,
@@ -94,8 +93,8 @@ const ChartContextMenu = (
9493
}: ChartContextMenuProps,
9594
ref: RefObject<ChartContextMenuRef>,
9695
) => {
97-
const theme = useTheme();
9896
const dispatch = useDispatch();
97+
const theme = useTheme();
9998
const { canDrillToDetail, canDrillBy, canDownload } = usePermissions();
10099

101100
const crossFiltersEnabled = useSelector<RootState, boolean>(
@@ -104,7 +103,6 @@ const ChartContextMenu = (
104103
const dashboardId = useSelector<RootState, number>(
105104
({ dashboardInfo }) => dashboardInfo.id,
106105
);
107-
const [openKeys, setOpenKeys] = useState<Key[]>([]);
108106

109107
const [modalFilters, setFilters] = useState<BinaryQueryObjectFilterClause[]>(
110108
[],
@@ -160,7 +158,6 @@ const ChartContextMenu = (
160158

161159
const closeContextMenu = useCallback(() => {
162160
setVisible(false);
163-
setOpenKeys([]);
164161
onClose();
165162
}, [onClose]);
166163

@@ -177,7 +174,7 @@ const ChartContextMenu = (
177174
setShowDrillByModal(false);
178175
}, []);
179176

180-
const menuItems: React.JSX.Element[] = [];
177+
const menuItems: MenuItem[] = [];
181178

182179
const showDrillToDetail =
183180
isFeatureEnabled(FeatureFlag.DrillToDetail) &&
@@ -264,6 +261,20 @@ const ChartContextMenu = (
264261
itemsCount = 1; // "No actions" appears if no actions in menu
265262
}
266263

264+
const drillDetailMenuItems = useDrillDetailMenuItems({
265+
formData: drillFormData,
266+
filters: filters?.drillToDetail,
267+
setFilters,
268+
isContextMenu: true,
269+
contextMenuY: clientY,
270+
onSelection,
271+
submenuIndex: showCrossFilters ? 2 : 1,
272+
setShowModal: setDrillModalIsOpen,
273+
dataset: filteredDataset,
274+
isLoadingDataset,
275+
...(additionalConfig?.drillToDetail || {}),
276+
});
277+
267278
if (showCrossFilters) {
268279
const isCrossFilterDisabled =
269280
!isCrossFilteringSupportedByChart ||
@@ -305,74 +316,65 @@ const ChartContextMenu = (
305316
</>
306317
);
307318
}
319+
308320
menuItems.push(
309-
<>
310-
<Menu.Item
311-
key="cross-filtering-menu-item"
312-
disabled={isCrossFilterDisabled}
313-
onClick={() => {
314-
if (filters?.crossFilter) {
315-
dispatch(updateDataMask(id, filters.crossFilter.dataMask));
316-
}
317-
}}
318-
>
319-
{filters?.crossFilter?.isCurrentValueSelected ? (
320-
t('Remove cross-filter')
321-
) : (
322-
<div>
323-
{t('Add cross-filter')}
324-
<MenuItemTooltip
325-
title={crossFilteringTooltipTitle}
326-
color={!isCrossFilterDisabled ? theme.colorIcon : undefined}
327-
/>
328-
</div>
329-
)}
330-
</Menu.Item>
331-
{itemsCount > 1 && <Menu.Divider />}
332-
</>,
321+
{
322+
key: 'cross-filtering-menu-item',
323+
label: filters?.crossFilter?.isCurrentValueSelected ? (
324+
t('Remove cross-filter')
325+
) : (
326+
<span>
327+
{t('Add cross-filter')}
328+
<MenuItemTooltip
329+
title={crossFilteringTooltipTitle}
330+
color={!isCrossFilterDisabled ? theme.colorIcon : undefined}
331+
/>
332+
</span>
333+
),
334+
disabled: isCrossFilterDisabled,
335+
onClick: () => {
336+
if (filters?.crossFilter) {
337+
dispatch(updateDataMask(id, filters.crossFilter.dataMask));
338+
}
339+
},
340+
},
341+
...(itemsCount > 1
342+
? [{ key: 'divider-1', type: 'divider' as const }]
343+
: []),
333344
);
334345
}
335346
if (showDrillToDetail) {
336-
menuItems.push(
337-
<DrillDetailMenuItems
338-
formData={drillFormData}
339-
filters={filters?.drillToDetail}
340-
setFilters={setFilters}
341-
isContextMenu
342-
contextMenuY={clientY}
343-
onSelection={onSelection}
344-
submenuIndex={showCrossFilters ? 2 : 1}
345-
setShowModal={setDrillModalIsOpen}
346-
dataset={filteredDataset}
347-
isLoadingDataset={isLoadingDataset}
348-
{...(additionalConfig?.drillToDetail || {})}
349-
/>,
350-
);
347+
menuItems.push(...drillDetailMenuItems);
351348
}
349+
352350
if (showDrillBy) {
353-
let submenuIndex = 0;
354-
if (showCrossFilters) {
355-
submenuIndex += 1;
356-
}
357-
if (showDrillToDetail) {
358-
submenuIndex += 2;
351+
if (menuItems.length > 0) {
352+
menuItems.push({ key: 'divider-drill-by', type: 'divider' as const });
359353
}
360-
menuItems.push(
361-
<DrillByMenuItems
362-
drillByConfig={enhancedFilters?.drillBy}
363-
onSelection={onSelection}
364-
onCloseMenu={closeContextMenu}
365-
formData={formData}
366-
contextMenuY={clientY}
367-
submenuIndex={submenuIndex}
368-
open={openKeys.includes('drill-by-submenu')}
369-
key="drill-by-submenu"
370-
onDrillBy={handleDrillBy}
371-
dataset={filteredDataset}
372-
isLoadingDataset={isLoadingDataset}
373-
{...(additionalConfig?.drillBy || {})}
374-
/>,
375-
);
354+
355+
const hasDrillBy = enhancedFilters?.drillBy?.groupbyFieldName;
356+
const handlesDimensionContextMenu = getChartMetadataRegistry()
357+
.get(formData.viz_type)
358+
?.behaviors.find(behavior => behavior === Behavior.DrillBy);
359+
const isDrillByDisabled = !handlesDimensionContextMenu || !hasDrillBy;
360+
361+
// Add a custom render component for DrillBy submenu to support react-window
362+
menuItems.push({
363+
key: 'drill-by-submenu',
364+
disabled: isDrillByDisabled,
365+
label: (
366+
<DrillBySubmenu
367+
drillByConfig={enhancedFilters?.drillBy}
368+
onSelection={onSelection}
369+
onCloseMenu={closeContextMenu}
370+
formData={formData}
371+
onDrillBy={handleDrillBy}
372+
dataset={filteredDataset}
373+
isLoadingDataset={isLoadingDataset}
374+
{...(additionalConfig?.drillBy || {})}
375+
/>
376+
),
377+
});
376378
}
377379

378380
const open = useCallback(
@@ -404,30 +406,22 @@ const ChartContextMenu = (
404406
return ReactDOM.createPortal(
405407
<>
406408
<Dropdown
407-
popupRender={() => (
408-
<Menu
409-
className="chart-context-menu"
410-
data-test="chart-context-menu"
411-
onOpenChange={setOpenKeys}
412-
onClick={() => {
413-
setVisible(false);
414-
setOpenKeys([]);
415-
onClose();
416-
}}
417-
>
418-
{menuItems.length ? (
419-
menuItems
420-
) : (
421-
<Menu.Item disabled>{t('No actions')}</Menu.Item>
422-
)}
423-
</Menu>
409+
menu={{
410+
items:
411+
menuItems.length > 0
412+
? menuItems
413+
: [{ key: 'no-actions', label: t('No actions'), disabled: true }],
414+
onClick: () => {
415+
setVisible(false);
416+
onClose();
417+
},
418+
}}
419+
dropdownRender={menu => (
420+
<div data-test="chart-context-menu">{menu}</div>
424421
)}
425422
trigger={['click']}
426423
onOpenChange={value => {
427424
setVisible(value);
428-
if (!value) {
429-
setOpenKeys([]);
430-
}
431425
}}
432426
open={visible}
433427
>

0 commit comments

Comments
 (0)