diff --git a/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx b/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx index 890084be4c6..9a5cabb0b7c 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx @@ -227,8 +227,15 @@ const CustomModal = ({ draggableConfig, destroyOnHidden, openerRef, + bodyStyle, + styles: stylesProp, ...rest }: ModalProps) => { + // Convert deprecated bodyStyle to styles.body + const styles = useMemo( + () => (bodyStyle ? { ...stylesProp, body: bodyStyle } : stylesProp), + [bodyStyle, stylesProp], + ); const draggableRef = useRef(null); const [bounds, setBounds] = useState(); const [dragDisabled, setDragDisabled] = useState(true); @@ -361,6 +368,7 @@ const CustomModal = ({ draggable={draggable} resizable={resizable} destroyOnHidden={destroyOnHidden} + styles={styles} {...rest} > {children} diff --git a/superset-frontend/packages/superset-ui-core/src/components/Modal/types.ts b/superset-frontend/packages/superset-ui-core/src/components/Modal/types.ts index 7876a1bc46c..4966bc7ac1e 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/Modal/types.ts +++ b/superset-frontend/packages/superset-ui-core/src/components/Modal/types.ts @@ -51,7 +51,9 @@ export interface ModalProps { destroyOnHidden?: boolean; maskClosable?: boolean; zIndex?: number; + /** @deprecated Use styles.body instead */ bodyStyle?: CSSProperties; + styles?: { body?: CSSProperties; [key: string]: CSSProperties | undefined }; openerRef?: React.RefObject; } diff --git a/superset-frontend/packages/superset-ui-core/src/components/PageHeaderWithActions/index.tsx b/superset-frontend/packages/superset-ui-core/src/components/PageHeaderWithActions/index.tsx index ae11b6ceff8..e15f1813cd1 100644 --- a/superset-frontend/packages/superset-ui-core/src/components/PageHeaderWithActions/index.tsx +++ b/superset-frontend/packages/superset-ui-core/src/components/PageHeaderWithActions/index.tsx @@ -155,19 +155,21 @@ export const PageHeaderWithActions = ({ popupRender={() => additionalActionsMenu} {...menuDropdownProps} > - + + + )} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx index 95e31481264..3b85b5326ba 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx @@ -179,7 +179,13 @@ function Echart( } if (!divRef.current) return; if (!chartRef.current) { - chartRef.current = init(divRef.current, null, { locale }); + // Pass width and height to init to avoid "Can't get DOM width or height" warning + // since the DOM element may not have its dimensions yet when init is called + chartRef.current = init(divRef.current, null, { + locale, + width, + height, + }); } // did mount handleSizeChange({ width, height }); diff --git a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx index 58f8a529a31..fb2bb1eba14 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx @@ -829,7 +829,7 @@ export default function TableChart( th { border-right: 1px solid ${theme.colorSplit}; } - th:first-child { + th:first-of-type { border-left: none; } th:last-child { diff --git a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx index f03f399583c..10b976c3c42 100644 --- a/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx +++ b/superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx @@ -22,7 +22,7 @@ import { connect } from 'react-redux'; import type { QueryEditor, SqlLabRootState } from 'src/SqlLab/types'; import { t } from '@apache-superset/core/translation'; import { FeatureFlag, isFeatureEnabled } from '@superset-ui/core'; -import { styled, css } from '@apache-superset/core/theme'; +import { styled } from '@apache-superset/core/theme'; import { Logger } from 'src/logger/LogUtils'; import { EmptyState, Tooltip } from '@superset-ui/core/components'; import { detectOS } from 'src/utils/common'; @@ -89,6 +89,11 @@ const TabTitle = styled.span` text-transform: none; `; +const AddTabIconWrapper = styled.span` + display: inline-flex; + vertical-align: middle; +`; + // Get the user's OS const userOS = detectOS(); @@ -194,13 +199,9 @@ class TabbedSqlEditors extends PureComponent { : t('New tab (Ctrl + t)') } > - + + + ); @@ -241,13 +242,9 @@ class TabbedSqlEditors extends PureComponent { : t('New tab (Ctrl + t)') } > - + + + } items={tabItems} diff --git a/superset-frontend/src/components/DatabaseSelector/index.tsx b/superset-frontend/src/components/DatabaseSelector/index.tsx index 9ef37463b1e..b8f5aeb2377 100644 --- a/superset-frontend/src/components/DatabaseSelector/index.tsx +++ b/superset-frontend/src/components/DatabaseSelector/index.tsx @@ -139,9 +139,11 @@ const LabelStyle = styled.div` } `; -const SelectButton = styled(Button)<{ empty: boolean }>` - color: ${({ theme, empty }) => - empty ? theme.colorTextPlaceholder : theme.colorTextBase}; +const SelectButton = styled(Button, { + shouldForwardProp: prop => prop !== '$empty', +})<{ $empty: boolean }>` + color: ${({ theme, $empty }) => + $empty ? theme.colorTextPlaceholder : theme.colorTextBase}; `; export const SelectLabel = ({ @@ -410,7 +412,7 @@ export function DatabaseSelector({ buttonStyle="tertiary" disabled={sqlLabModeConfig.disabled} loading={sqlLabModeConfig.loading} - empty={!sqlLabModeConfig.displayValue} + $empty={!sqlLabModeConfig.displayValue} > {displayValue} diff --git a/superset-frontend/src/components/ListView/ActionsBar.tsx b/superset-frontend/src/components/ListView/ActionsBar.tsx index 33bde585790..dfdf076d8f3 100644 --- a/superset-frontend/src/components/ListView/ActionsBar.tsx +++ b/superset-frontend/src/components/ListView/ActionsBar.tsx @@ -68,7 +68,7 @@ export function ActionsBar({ actions }: ActionsBarProps) { const IconComponent = Icons[icon as IconNameType]; return ( } tooltip={tooltip} {...rest} diff --git a/superset-frontend/src/components/ListView/Filters/index.tsx b/superset-frontend/src/components/ListView/Filters/index.tsx index c32d2393b21..1686864ca2b 100644 --- a/superset-frontend/src/components/ListView/Filters/index.tsx +++ b/superset-frontend/src/components/ListView/Filters/index.tsx @@ -81,7 +81,7 @@ function UIFilters( dateFilterValueType, min, max, - dropdownStyle, + popupStyle, autoComplete, inputName, }, @@ -114,7 +114,7 @@ function UIFilters( paginate={paginate} selects={selects} loading={loading ?? false} - dropdownStyle={dropdownStyle} + dropdownStyle={popupStyle} /> ); } diff --git a/superset-frontend/src/components/ListView/types.ts b/superset-frontend/src/components/ListView/types.ts index 5d72d3dabe2..16dcf339dd9 100644 --- a/superset-frontend/src/components/ListView/types.ts +++ b/superset-frontend/src/components/ListView/types.ts @@ -66,7 +66,7 @@ export interface ListViewFilter { dateFilterValueType?: 'unix' | 'iso'; min?: number; max?: number; - dropdownStyle?: React.CSSProperties; + popupStyle?: React.CSSProperties; autoComplete?: string; inputName?: string; } diff --git a/superset-frontend/src/components/Modal/StandardModal.tsx b/superset-frontend/src/components/Modal/StandardModal.tsx index f19ea08def6..963afdbca53 100644 --- a/superset-frontend/src/components/Modal/StandardModal.tsx +++ b/superset-frontend/src/components/Modal/StandardModal.tsx @@ -76,7 +76,7 @@ const StyledModal = styled(Modal)` .ant-collapse { border: none; - > .ant-collapse-item:first-child { + > .ant-collapse-item:first-of-type { border-top: none; } diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx index a507c65318d..68dd1971df1 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx @@ -252,7 +252,7 @@ const DashboardContentWrapper = styled.div` width: 100%; } - & > .empty-droptarget:first-child:not(.empty-droptarget--full) { + & > .empty-droptarget:first-of-type:not(.empty-droptarget--full) { height: ${theme.sizeUnit * 4}px; top: 0; } @@ -298,7 +298,7 @@ const StyledDashboardContent = styled.div<{ `} /* this is the ParentSize wrapper */ - & > div:first-child { + & > div:first-of-type { height: 100% !important; } } diff --git a/superset-frontend/src/dashboard/components/DashboardGrid.tsx b/superset-frontend/src/dashboard/components/DashboardGrid.tsx index 9fdefeb5cbf..3882debd270 100644 --- a/superset-frontend/src/dashboard/components/DashboardGrid.tsx +++ b/superset-frontend/src/dashboard/components/DashboardGrid.tsx @@ -102,7 +102,7 @@ const GridContent = styled.div<{ editMode?: boolean }>` } } - & > .empty-droptarget:first-child { + & > .empty-droptarget:first-of-type { height: ${theme.sizeUnit * 4}px; margin-top: ${theme.sizeUnit * -4}px; } diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx index 557e6e31b6f..508b83c0bc1 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx @@ -148,7 +148,7 @@ type SliceHeaderControlsPropsWithRouter = SliceHeaderControlsProps & RouteComponentProps; const dropdownIconsStyles = css` - &&.anticon > .anticon:first-child { + &&.anticon > .anticon:first-of-type { margin-right: 0; vertical-align: 0; } diff --git a/superset-frontend/src/dashboard/components/gridComponents/Column/Column.tsx b/superset-frontend/src/dashboard/components/gridComponents/Column/Column.tsx index 4f8baf16a69..f6b31cc5adf 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Column/Column.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Column/Column.tsx @@ -104,11 +104,11 @@ const ColumnStyles = styled.div<{ editMode: boolean }>` z-index: ${EMPTY_CONTAINER_Z_INDEX}; width: 100%; height: ${theme.sizeUnit * 4}px; - &:first-child { + &:first-of-type { inset-block-start: 0; } } - &:first-child:not(.droptarget-edge) { + &:first-of-type:not(.droptarget-edge) { position: absolute; top: 0; left: 0; @@ -116,7 +116,7 @@ const ColumnStyles = styled.div<{ editMode: boolean }>` width: 100%; height: 100%; } - &:not(:first-child):not(.droptarget-edge) { + &:not(:first-of-type):not(.droptarget-edge) { width: 100%; min-height: ${theme.sizeUnit * 4}px; } diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx b/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx index 707370d4050..c5ec0c497f5 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx @@ -100,7 +100,7 @@ const GridRow = styled.div<{ editMode: boolean }>` &:not(:last-child) { width: ${theme.sizeUnit * 4}px; } - &:first-child:not(.droptarget-side) { + &:first-of-type:not(.droptarget-side) { z-index: ${EMPTY_CONTAINER_Z_INDEX}; position: absolute; width: 100%; @@ -111,7 +111,7 @@ const GridRow = styled.div<{ editMode: boolean }>` z-index: ${EMPTY_CONTAINER_Z_INDEX}; position: absolute; width: ${theme.sizeUnit * 4}px; - &:first-child { + &:first-of-type { inset-inline-start: 0; } } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx index 22d32e64a4c..a06f92e3c66 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterDivider.tsx @@ -45,7 +45,7 @@ const HorizontalDivider = ({ title, description }: FilterDividerProps) => { border-left: 1px solid ${theme.colorSplit}; padding-left: ${4 * theme.sizeUnit}px; - .filter-item-wrapper:first-child & { + .filter-item-wrapper:first-of-type & { border-left: none; padding-left: 0; } diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.tsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.tsx index c9f2904abc8..76de0d526d2 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.tsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.tsx @@ -130,7 +130,7 @@ interface AnnotationLayerState { const AUTOMATIC_COLOR = ''; const NotFoundContentWrapper = styled.div` - && > div:first-child { + && > div:first-of-type { padding-left: 0; padding-right: 0; } diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx index 9538264b22a..556e08089bf 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx @@ -257,7 +257,7 @@ class AnnotationLayerControl extends PureComponent { )} title={t('Add annotation layer')} open={this.state.popoverVisible[addLayerPopoverKey]} - destroyTooltipOnHide + destroyOnHidden onOpenChange={visible => this.handleVisibleChange(visible, addLayerPopoverKey) } diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx index 52cb263f503..757bc66596d 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/ConditionalFormattingControl.tsx @@ -162,7 +162,7 @@ const ConditionalFormattingControl = ({ onChange={(newConfig: ConditionalFormattingConfig) => onEdit(newConfig, index) } - destroyTooltipOnHide + destroyOnHidden extraColorChoices={extraColorChoices} allColumns={allColumns} > @@ -179,7 +179,7 @@ const ConditionalFormattingControl = ({ title={t('Add new formatter')} columns={columnOptions} onChange={onSave} - destroyTooltipOnHide + destroyOnHidden extraColorChoices={extraColorChoices} allColumns={allColumns} > diff --git a/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx index 315a34e7985..69e4b90fefe 100644 --- a/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx +++ b/superset-frontend/src/explore/components/controls/ContourControl/ContourPopoverTrigger.tsx @@ -50,7 +50,7 @@ const ContourPopoverTrigger = ({ defaultOpen={visible} open={visible} onOpenChange={setVisibility} - destroyTooltipOnHide + destroyOnHidden > {props.children} diff --git a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx index 49e3551949e..fcb9d07d741 100644 --- a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx +++ b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.test.tsx @@ -134,7 +134,7 @@ test('Should place popover at the bottom', async () => { test('Should close popover on escape press', async () => { setupTest({ ...createProps(), - destroyTooltipOnHide: true, + destroyOnHidden: true, }); expect(screen.getByTestId('control-popover')).toBeInTheDocument(); @@ -165,7 +165,7 @@ test('Should close popover on escape press', async () => { test('Controlled mode', async () => { const baseProps = { ...createProps(), - destroyTooltipOnHide: true, + destroyOnHidden: true, open: false, }; diff --git a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx index 6837e350d5b..301266bd859 100644 --- a/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx +++ b/superset-frontend/src/explore/components/controls/ControlPopover/ControlPopover.tsx @@ -52,7 +52,7 @@ const ControlPopover: FC = ({ getPopupContainer, getVisibilityRatio = getElementVisibilityRatio, open: visibleProp, - destroyTooltipOnHide = false, + destroyOnHidden = false, placement: initialPlacement = 'right', ...props }) => { @@ -200,7 +200,7 @@ const ControlPopover: FC = ({ placement={placement} onOpenChange={handleOnVisibleChange} getPopupContainer={handleGetPopupContainer} - destroyTooltipOnHide={destroyTooltipOnHide} + destroyOnHidden={destroyOnHidden} afterOpenChange={handleAfterOpenChange} /> ); diff --git a/superset-frontend/src/explore/components/controls/CurrencyControl/CurrencyControl.tsx b/superset-frontend/src/explore/components/controls/CurrencyControl/CurrencyControl.tsx index c2a31de9ff7..136d02852b6 100644 --- a/superset-frontend/src/explore/components/controls/CurrencyControl/CurrencyControl.tsx +++ b/superset-frontend/src/explore/components/controls/CurrencyControl/CurrencyControl.tsx @@ -41,7 +41,7 @@ const CurrencyControlContainer = styled.div` display: flex; align-items: center; - & > :first-child { + & > :first-of-type { margin-right: ${theme.sizeUnit * 4}px; min-width: 0; flex: 1; @@ -162,7 +162,7 @@ export const CurrencyControl = ({ :first-child { + & > :first-of-type { ${symbolSelectAdditionalStyles}; } & > :nth-child(2) { diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx index 3aa6a1415d3..9f6a02b49fd 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx @@ -360,7 +360,7 @@ export default function DateFilterLabel(props: DateFilterControlProps) { open={show} onOpenChange={toggleOverlay} overlayStyle={{ width: '600px' }} - destroyTooltipOnHide + destroyOnHidden getPopupContainer={nodeTrigger => isOverflowingFilterBar ? (nodeTrigger.parentNode as HTMLElement) diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx index cde8a498ec8..cf8692b7503 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx @@ -199,7 +199,7 @@ const ColumnSelectPopoverTriggerInner = ({ open={visible} onOpenChange={handleTogglePopover} title={popoverTitle} - destroyTooltipOnHide + destroyOnHidden > {children} diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx index 3f9c525e920..37fbe7210f8 100644 --- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx +++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx @@ -357,6 +357,7 @@ const DndFilterSelect = (props: DndFilterSelectProps) => { () => values.map((adhocFilter: AdhocFilter, index: number) => ( {this.props.children} diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx index b26346933b8..77ae48b51a6 100644 --- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx +++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricPopoverTrigger.tsx @@ -272,7 +272,7 @@ class AdhocMetricPopoverTrigger extends PureComponent< open={visible} onOpenChange={togglePopover} title={popoverTitle} - destroyTooltipOnHide + destroyOnHidden > {this.props.children} diff --git a/superset-frontend/src/features/alerts/components/NotificationMethod.tsx b/superset-frontend/src/features/alerts/components/NotificationMethod.tsx index e7f69a5c7c8..72b19c2cbc2 100644 --- a/superset-frontend/src/features/alerts/components/NotificationMethod.tsx +++ b/superset-frontend/src/features/alerts/components/NotificationMethod.tsx @@ -100,7 +100,7 @@ const StyledNotificationMethod = styled.div` margin-left: ${theme.sizeUnit * 4}px; } - .ghost-button:first-child[style*='none'] + .ghost-button { + .ghost-button:first-of-type[style*='none'] + .ghost-button { margin-left: 0px; /* Remove margin when the first button is hidden */ } `} diff --git a/superset-frontend/src/features/home/ActivityTable.tsx b/superset-frontend/src/features/home/ActivityTable.tsx index 52a3714b6bf..e71006a3adb 100644 --- a/superset-frontend/src/features/home/ActivityTable.tsx +++ b/superset-frontend/src/features/home/ActivityTable.tsx @@ -126,19 +126,28 @@ export default function ActivityTable({ const [editedCards, setEditedCards] = useState(); const [isFetchingEditedCards, setIsFetchingEditedCards] = useState(false); - const getEditedCards = () => { - setIsFetchingEditedCards(true); - getEditedObjects(user.userId).then(r => { - setEditedCards([...r.editedChart, ...r.editedDash]); - setIsFetchingEditedCards(false); - }); - }; - useEffect(() => { + let isMounted = true; + if (activeChild === TableTab.Edited) { - getEditedCards(); + setIsFetchingEditedCards(true); + getEditedObjects(user.userId).then(r => { + if (!isMounted) return; + // `getEditedObjects` swallows errors via `.catch(err => err)` and + // returns the raw error object, which has no `editedChart` / + // `editedDash` arrays. Guard against that so spreading can't throw. + const editedChart = Array.isArray(r?.editedChart) ? r.editedChart : []; + const editedDash = Array.isArray(r?.editedDash) ? r.editedDash : []; + setEditedCards([...editedChart, ...editedDash]); + setIsFetchingEditedCards(false); + }); } - }, [activeChild]); + + return () => { + isMounted = false; + setIsFetchingEditedCards(false); + }; + }, [activeChild, user.userId]); const tabs = [ { diff --git a/superset-frontend/src/features/home/SubMenu.tsx b/superset-frontend/src/features/home/SubMenu.tsx index 44385e7f66e..a7ef5ba7d27 100644 --- a/superset-frontend/src/features/home/SubMenu.tsx +++ b/superset-frontend/src/features/home/SubMenu.tsx @@ -28,7 +28,7 @@ import { } from '@apache-superset/core/theme'; import cx from 'classnames'; import { debounce } from 'lodash'; -import { Menu, MenuMode, MainNav } from '@superset-ui/core/components/Menu'; +import { Menu, MenuMode } from '@superset-ui/core/components/Menu'; import { Button, Tooltip, @@ -166,8 +166,6 @@ export interface SubMenuProps { backgroundColor?: string; } -const { SubMenu } = MainNav; - const SubMenuComponent: FunctionComponent = props => { const [showMenu, setMenu] = useState('horizontal'); const [navRightStyle, setNavRightStyle] = useState('nav-right'); @@ -183,7 +181,10 @@ const SubMenuComponent: FunctionComponent = props => { } useEffect(() => { + let isMounted = true; + function handleResize() { + if (!isMounted) return; if (window.innerWidth <= 767) setMenu('inline'); else setMenu('horizontal'); @@ -192,7 +193,6 @@ const SubMenuComponent: FunctionComponent = props => { props.buttons.length >= 3 && window.innerWidth >= 795 ) { - // eslint-disable-next-line no-unused-expressions setNavRightStyle('nav-right'); } else if ( props.buttons && @@ -205,7 +205,11 @@ const SubMenuComponent: FunctionComponent = props => { handleResize(); const resize = debounce(handleResize, 10); window.addEventListener('resize', resize); - return () => window.removeEventListener('resize', resize); + return () => { + isMounted = false; + resize.cancel(); + window.removeEventListener('resize', resize); + }; }, [props.buttons]); return ( @@ -254,52 +258,60 @@ const SubMenuComponent: FunctionComponent = props => { })} />
- - {props.dropDownLinks?.map((link, i) => ( - } - popupOffset={[10, 20]} - className="dropdown-menu-links" - > - {link.childs?.map(item => { - if (typeof item === 'object') { - return item.disable ? ( - - - {item.label} - - - ) : ( - - - {item.label} - - - ); - } - return null; - })} - - ))} - + ({ + key: `dropdown-${i}`, + label: link.label, + icon: , + popupOffset: [10, 20], + className: 'dropdown-menu-links', + children: link.childs + ?.filter( + (item): item is Exclude => + typeof item === 'object', + ) + .map(item => + item.disable + ? { + key: item.label, + disabled: true, + label: ( + + + {item.label} + + + ), + } + : { + key: item.label, + label: ( + + {item.label} + + ), + }, + ), + }))} + /> {props.buttons?.map((btn, i) => (