From f2d0be3cfd7143b55c9dc63adeae9b5cb1c8f594 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 12 Sep 2022 16:36:26 +0200 Subject: [PATCH 1/7] perf(dashboard): Virtualization POC --- .../src/components/Chart/Chart.jsx | 45 ++++++++++++++++--- superset/config.py | 1 + 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/superset-frontend/src/components/Chart/Chart.jsx b/superset-frontend/src/components/Chart/Chart.jsx index 893665ab15c7a..c6035b320e6b3 100644 --- a/superset-frontend/src/components/Chart/Chart.jsx +++ b/superset-frontend/src/components/Chart/Chart.jsx @@ -124,6 +124,11 @@ class Chart extends React.PureComponent { super(props); this.handleRenderContainerFailure = this.handleRenderContainerFailure.bind(this); + + this.containerRef = React.createRef(); + this.observer = null; + + this.state = { isInView: false }; } componentDidMount() { @@ -134,6 +139,25 @@ class Chart extends React.PureComponent { ) { this.runQuery(); } + + if (isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION)) { + this.observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !this.state.isInView) { + this.setState({ isInView: true }); + } else if (!entry.isIntersecting && this.state.isInView) { + this.setState({ isInView: false }); + } + }, + { + rootMargin: '100% 0px', + }, + ); + const element = this.containerRef.current; + if (element) { + this.observer.observe(element); + } + } } componentDidUpdate() { @@ -306,12 +330,21 @@ class Chart extends React.PureComponent { height={height} width={width} > -
- +
+ {this.state.isInView || + !isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION) ? ( + + ) : ( + + )}
{isLoading && !isDeactivatedViz && } diff --git a/superset/config.py b/superset/config.py index a7b7e655ecbb9..dc710ec5846da 100644 --- a/superset/config.py +++ b/superset/config.py @@ -422,6 +422,7 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: "ESCAPE_MARKDOWN_HTML": False, "DASHBOARD_NATIVE_FILTERS": True, "DASHBOARD_CROSS_FILTERS": False, + "DASHBOARD_VIRTUALIZATION": False, # Feature is under active development and breaking changes are expected "DASHBOARD_NATIVE_FILTERS_SET": False, "DASHBOARD_FILTERS_EXPERIMENTAL": False, From 2c8356f30e6bbeb5b9040b476c74de7afcf6e1e1 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Tue, 13 Sep 2022 17:12:52 +0200 Subject: [PATCH 2/7] Move IntersectionObserver to Row, make virtualization a config instead of a feature flag --- .../src/components/Chart/Chart.jsx | 53 ++++++++----------- .../components/gridComponents/Chart.jsx | 3 ++ .../components/gridComponents/ChartHolder.tsx | 4 ++ .../components/gridComponents/Row.jsx | 53 ++++++++++++++++++- .../utils/isDashboardVirtualizationEnabled.ts | 30 +++++++++++ superset/config.py | 2 +- superset/views/base.py | 1 + 7 files changed, 112 insertions(+), 34 deletions(-) create mode 100644 superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts diff --git a/superset-frontend/src/components/Chart/Chart.jsx b/superset-frontend/src/components/Chart/Chart.jsx index c6035b320e6b3..ec53548f245bb 100644 --- a/superset-frontend/src/components/Chart/Chart.jsx +++ b/superset-frontend/src/components/Chart/Chart.jsx @@ -18,6 +18,7 @@ */ import PropTypes from 'prop-types'; import React from 'react'; +import { connect } from 'react-redux'; import { styled, logging, t, ensureIsArray } from '@superset-ui/core'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; @@ -29,6 +30,7 @@ import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; import { ResourceStatus } from 'src/hooks/apiResources/apiResources'; +import { isDashboardVirtualizationEnabled } from 'src/utils/isDashboardVirtualizationEnabled'; import ChartRenderer from './ChartRenderer'; import { ChartErrorMessage } from './ChartErrorMessage'; import { getChartRequiredFieldsMissingMessage } from '../../utils/getChartRequiredFieldsMissingMessage'; @@ -74,6 +76,12 @@ const propTypes = { ownState: PropTypes.object, postTransformProps: PropTypes.func, datasetsStatus: PropTypes.oneOf(['loading', 'error', 'complete']), + isInView: PropTypes.bool, + dashboardVirtualizationMode: PropTypes.oneOf([ + 'NONE', + 'VIEWPORT', + 'PAGINATED', + ]), }; const BLANK = {}; @@ -92,6 +100,7 @@ const defaultProps = { chartStackTrace: null, isDeactivatedViz: false, force: false, + isInView: true, }; const Styles = styled.div` @@ -124,11 +133,6 @@ class Chart extends React.PureComponent { super(props); this.handleRenderContainerFailure = this.handleRenderContainerFailure.bind(this); - - this.containerRef = React.createRef(); - this.observer = null; - - this.state = { isInView: false }; } componentDidMount() { @@ -139,25 +143,6 @@ class Chart extends React.PureComponent { ) { this.runQuery(); } - - if (isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION)) { - this.observer = new IntersectionObserver( - ([entry]) => { - if (entry.isIntersecting && !this.state.isInView) { - this.setState({ isInView: true }); - } else if (!entry.isIntersecting && this.state.isInView) { - this.setState({ isInView: false }); - } - }, - { - rootMargin: '100% 0px', - }, - ); - const element = this.containerRef.current; - if (element) { - this.observer.observe(element); - } - } } componentDidUpdate() { @@ -330,13 +315,11 @@ class Chart extends React.PureComponent { height={height} width={width} > -
- {this.state.isInView || - !isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION) ? ( +
+ {this.props.isInView || + !isDashboardVirtualizationEnabled( + this.props.dashboardVirtualizationMode, + ) ? (
diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx index c3cffe338c8e5..103fbf273efa2 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.tsx @@ -67,6 +67,8 @@ interface ChartHolderProps { handleComponentDrop: (...args: unknown[]) => unknown; setFullSizeChartId: (chartId: number | null) => void; postAddSliceFromDashboard?: () => void; + + isInView: boolean; } const ChartHolder: React.FC = ({ @@ -91,6 +93,7 @@ const ChartHolder: React.FC = ({ handleComponentDrop, setFullSizeChartId, postAddSliceFromDashboard, + isInView, }) => { const { chartId } = component.meta; const isFullSize = fullSizeChartId === chartId; @@ -314,6 +317,7 @@ const ChartHolder: React.FC = ({ setControlValue={handleExtraControl} extraControls={extraControls} postTransformProps={handlePostTransformProps} + isInView={isInView} /> {editMode && ( diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx index b0037bf12322a..6c5e5ba16315b 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx @@ -19,6 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { connect } from 'react-redux'; import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; import DragHandle from 'src/dashboard/components/dnd/DragHandle'; @@ -32,6 +33,10 @@ import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import { componentShape } from 'src/dashboard/util/propShapes'; import backgroundStyleOptions from 'src/dashboard/util/backgroundStyleOptions'; import { BACKGROUND_TRANSPARENT } from 'src/dashboard/util/constants'; +import { + DASHBOARD_VIRTUALIZATION_MODE, + isDashboardVirtualizationEnabled, +} from 'src/utils/isDashboardVirtualizationEnabled'; const propTypes = { id: PropTypes.string.isRequired, @@ -54,6 +59,12 @@ const propTypes = { handleComponentDrop: PropTypes.func.isRequired, deleteComponent: PropTypes.func.isRequired, updateComponents: PropTypes.func.isRequired, + + dashboardVirtualizationMode: PropTypes.oneOf([ + 'NONE', + 'VIEWPORT', + 'PAGINATED', + ]), }; class Row extends React.PureComponent { @@ -61,6 +72,7 @@ class Row extends React.PureComponent { super(props); this.state = { isFocused: false, + isInView: false, }; this.handleDeleteComponent = this.handleDeleteComponent.bind(this); this.handleUpdateMeta = this.handleUpdateMeta.bind(this); @@ -69,6 +81,37 @@ class Row extends React.PureComponent { 'background', ); this.handleChangeFocus = this.handleChangeFocus.bind(this); + + this.containerRef = React.createRef(); + this.observer = null; + } + + componentDidMount() { + if ( + isDashboardVirtualizationEnabled(this.props.dashboardVirtualizationMode) + ) { + this.observer = new IntersectionObserver( + ([entry]) => { + if (entry.isIntersecting && !this.state.isInView) { + this.setState({ isInView: true }); + } else if ( + !entry.isIntersecting && + this.state.isInView && + this.props.dashboardVirtualizationMode === + DASHBOARD_VIRTUALIZATION_MODE.VIEWPORT + ) { + this.setState({ isInView: false }); + } + }, + { + rootMargin: '100% 0px', + }, + ); + const element = this.containerRef.current; + if (element) { + this.observer.observe(element); + } + } } handleChangeFocus(nextFocus) { @@ -161,6 +204,7 @@ class Row extends React.PureComponent { backgroundStyle.className, )} data-test={`grid-row-${backgroundStyle.className}`} + ref={this.containerRef} > {rowItems.map((componentId, itemIndex) => ( ))} @@ -192,4 +237,10 @@ class Row extends React.PureComponent { Row.propTypes = propTypes; -export default Row; +function mapStateToProps({ common }) { + const dashboardVirtualizationMode = common.conf?.DASHBOARD_VIRTUALIZATION; + return { + dashboardVirtualizationMode, + }; +} +export default connect(mapStateToProps)(Row); diff --git a/superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts b/superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts new file mode 100644 index 0000000000000..f27b8c849f3c5 --- /dev/null +++ b/superset-frontend/src/utils/isDashboardVirtualizationEnabled.ts @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export enum DASHBOARD_VIRTUALIZATION_MODE { + NONE = 'NONE', + VIEWPORT = 'VIEWPORT', + PAGINATED = 'PAGINATED', +} + +export const isDashboardVirtualizationEnabled = ( + virtualizationMode: DASHBOARD_VIRTUALIZATION_MODE, +) => + virtualizationMode === DASHBOARD_VIRTUALIZATION_MODE.VIEWPORT || + virtualizationMode === DASHBOARD_VIRTUALIZATION_MODE.PAGINATED; diff --git a/superset/config.py b/superset/config.py index dc710ec5846da..7a5fd307c9590 100644 --- a/superset/config.py +++ b/superset/config.py @@ -422,7 +422,6 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: "ESCAPE_MARKDOWN_HTML": False, "DASHBOARD_NATIVE_FILTERS": True, "DASHBOARD_CROSS_FILTERS": False, - "DASHBOARD_VIRTUALIZATION": False, # Feature is under active development and breaking changes are expected "DASHBOARD_NATIVE_FILTERS_SET": False, "DASHBOARD_FILTERS_EXPERIMENTAL": False, @@ -762,6 +761,7 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # Force refresh while auto-refresh in dashboard DASHBOARD_AUTO_REFRESH_MODE: Literal["fetch", "force"] = "force" +DASHBOARD_VIRTUALIZATION: Literal["NONE", "VIEWPORT", "PAGINATED"] = "NONE" # Default celery config is to use SQLA as a broker, in a production setting # you'll want to use a proper broker as specified here: diff --git a/superset/views/base.py b/superset/views/base.py index b790ca709c261..cf7868eaf1c04 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -103,6 +103,7 @@ "SQLALCHEMY_DISPLAY_TEXT", "GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL", "DASHBOARD_AUTO_REFRESH_MODE", + "DASHBOARD_VIRTUALIZATION", "SCHEDULED_QUERIES", "EXCEL_EXTENSIONS", "CSV_EXTENSIONS", From a4e2ea7b2f6ae7bee12ba3d805ba43b044fdaaac Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Tue, 13 Sep 2022 18:29:29 +0200 Subject: [PATCH 3/7] Fix lint --- .../dashboard/components/gridComponents/ChartHolder.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx index 62ad0584f0b77..4470d616fc591 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx @@ -137,7 +137,7 @@ describe('ChartHolder', () => { rerender( - + , ); @@ -414,6 +414,7 @@ describe('ChartHolder', () => { deleteComponent={deleteComponent} fullSizeChartId={null} editMode + isInView /> , ); From 8f22d4b9d59533fd2c7b95dac2935e7b72fe8768 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Sun, 9 Oct 2022 17:07:21 +0200 Subject: [PATCH 4/7] Exclude bot user from virtualization --- .../src/utils/featureFlags.ts | 1 + .../src/components/Chart/Chart.jsx | 21 +++---------- .../components/gridComponents/Row.jsx | 31 ++++--------------- superset-frontend/src/utils/isBot.ts | 21 +++++++++++++ superset/config.py | 3 +- 5 files changed, 33 insertions(+), 44 deletions(-) create mode 100644 superset-frontend/src/utils/isBot.ts diff --git a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts index f314748c14661..229a88d6a6f9b 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts @@ -31,6 +31,7 @@ export enum FeatureFlag { DASHBOARD_FILTERS_EXPERIMENTAL = 'DASHBOARD_FILTERS_EXPERIMENTAL', DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS', DASHBOARD_NATIVE_FILTERS_SET = 'DASHBOARD_NATIVE_FILTERS_SET', + DASHBOARD_VIRTUALIZATION = 'DASHBOARD_VIRTUALIZATION', DASHBOARD_RBAC = 'DASHBOARD_RBAC', DATAPANEL_CLOSED_BY_DEFAULT = 'DATAPANEL_CLOSED_BY_DEFAULT', DISABLE_DATASET_SOURCE_EDIT = 'DISABLE_DATASET_SOURCE_EDIT', diff --git a/superset-frontend/src/components/Chart/Chart.jsx b/superset-frontend/src/components/Chart/Chart.jsx index ec53548f245bb..38b092bc877e2 100644 --- a/superset-frontend/src/components/Chart/Chart.jsx +++ b/superset-frontend/src/components/Chart/Chart.jsx @@ -18,7 +18,6 @@ */ import PropTypes from 'prop-types'; import React from 'react'; -import { connect } from 'react-redux'; import { styled, logging, t, ensureIsArray } from '@superset-ui/core'; import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; @@ -29,8 +28,8 @@ import ErrorBoundary from 'src/components/ErrorBoundary'; import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils'; import { URL_PARAMS } from 'src/constants'; import { getUrlParam } from 'src/utils/urlUtils'; +import { isCurrentUserBot } from 'src/utils/isBot'; import { ResourceStatus } from 'src/hooks/apiResources/apiResources'; -import { isDashboardVirtualizationEnabled } from 'src/utils/isDashboardVirtualizationEnabled'; import ChartRenderer from './ChartRenderer'; import { ChartErrorMessage } from './ChartErrorMessage'; import { getChartRequiredFieldsMissingMessage } from '../../utils/getChartRequiredFieldsMissingMessage'; @@ -77,11 +76,6 @@ const propTypes = { postTransformProps: PropTypes.func, datasetsStatus: PropTypes.oneOf(['loading', 'error', 'complete']), isInView: PropTypes.bool, - dashboardVirtualizationMode: PropTypes.oneOf([ - 'NONE', - 'VIEWPORT', - 'PAGINATED', - ]), }; const BLANK = {}; @@ -317,9 +311,8 @@ class Chart extends React.PureComponent { >
{this.props.isInView || - !isDashboardVirtualizationEnabled( - this.props.dashboardVirtualizationMode, - ) ? ( + !isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION) || + isCurrentUserBot() ? ( { if (entry.isIntersecting && !this.state.isInView) { this.setState({ isInView: true }); - } else if ( - !entry.isIntersecting && - this.state.isInView && - this.props.dashboardVirtualizationMode === - DASHBOARD_VIRTUALIZATION_MODE.VIEWPORT - ) { + } else if (!entry.isIntersecting && this.state.isInView) { this.setState({ isInView: false }); } }, @@ -237,10 +224,4 @@ class Row extends React.PureComponent { Row.propTypes = propTypes; -function mapStateToProps({ common }) { - const dashboardVirtualizationMode = common.conf?.DASHBOARD_VIRTUALIZATION; - return { - dashboardVirtualizationMode, - }; -} -export default connect(mapStateToProps)(Row); +export default Row; diff --git a/superset-frontend/src/utils/isBot.ts b/superset-frontend/src/utils/isBot.ts new file mode 100644 index 0000000000000..8509a43c85c9e --- /dev/null +++ b/superset-frontend/src/utils/isBot.ts @@ -0,0 +1,21 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// navigator.webdriver is true when browser is controlled by a bot +export const isCurrentUserBot = () => window?.navigator?.webdriver; diff --git a/superset/config.py b/superset/config.py index 7a5fd307c9590..aec2dba890c0b 100644 --- a/superset/config.py +++ b/superset/config.py @@ -425,6 +425,7 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # Feature is under active development and breaking changes are expected "DASHBOARD_NATIVE_FILTERS_SET": False, "DASHBOARD_FILTERS_EXPERIMENTAL": False, + "DASHBOARD_VIRTUALIZATION": False, "GLOBAL_ASYNC_QUERIES": False, "VERSIONED_EXPORT": True, "EMBEDDED_SUPERSET": False, @@ -761,8 +762,6 @@ def _try_json_readsha(filepath: str, length: int) -> Optional[str]: # Force refresh while auto-refresh in dashboard DASHBOARD_AUTO_REFRESH_MODE: Literal["fetch", "force"] = "force" -DASHBOARD_VIRTUALIZATION: Literal["NONE", "VIEWPORT", "PAGINATED"] = "NONE" - # Default celery config is to use SQLA as a broker, in a production setting # you'll want to use a proper broker as specified here: # http://docs.celeryproject.org/en/latest/getting-started/brokers/index.html From 5d99cecc618c6399ac46ef9106146ad9ca60ada1 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Sun, 9 Oct 2022 17:48:08 +0200 Subject: [PATCH 5/7] Separate enabler and disabler observers --- .../components/gridComponents/Row.jsx | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx index e526d5380f046..c59290fbe9af7 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx @@ -74,33 +74,53 @@ class Row extends React.PureComponent { this.handleChangeFocus = this.handleChangeFocus.bind(this); this.containerRef = React.createRef(); - this.observer = null; + this.observerEnabler = null; + this.observerDisabler = null; } + // if chart not rendered - render it if it's less than 1 view height away from current viewport + // if chart rendered - remove it if it's more than 4 view heights away from current viewport componentDidMount() { if ( isFeatureEnabled(FeatureFlag.DASHBOARD_VIRTUALIZATION) && !isCurrentUserBot() ) { - this.observer = new IntersectionObserver( + this.observerEnabler = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting && !this.state.isInView) { this.setState({ isInView: true }); - } else if (!entry.isIntersecting && this.state.isInView) { - this.setState({ isInView: false }); } }, { rootMargin: '100% 0px', }, ); + this.observerDisabler = new IntersectionObserver( + ([entry]) => { + if (!entry.isIntersecting && this.state.isInView) { + this.setState({ isInView: false }); + } + }, + { + rootMargin: '400% 0px', + }, + ); const element = this.containerRef.current; if (element) { - this.observer.observe(element); + this.observerEnabler.observe(element); + this.observerDisabler.observe(element); } } } + componentWillUnmount() { + const element = this.containerRef.current; + if (element) { + this.observerEnabler.unobserve(element); + this.observerDisabler.unobserve(element); + } + } + handleChangeFocus(nextFocus) { this.setState(() => ({ isFocused: Boolean(nextFocus) })); } From d169d723087ded37fe9920701e5dfdfdbaeccb96 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Sun, 9 Oct 2022 18:28:01 +0200 Subject: [PATCH 6/7] Replace unobserve with disconnect --- .../src/dashboard/components/gridComponents/Row.jsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx index c59290fbe9af7..a5a1f2d770ed3 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx @@ -114,11 +114,8 @@ class Row extends React.PureComponent { } componentWillUnmount() { - const element = this.containerRef.current; - if (element) { - this.observerEnabler.unobserve(element); - this.observerDisabler.unobserve(element); - } + this.observerEnabler.disconnect(); + this.observerDisabler.disconnect(); } handleChangeFocus(nextFocus) { From 67052ffed42be3a25891989d995601694b1d12a1 Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 10 Oct 2022 12:23:54 +0200 Subject: [PATCH 7/7] fix test --- .../src/dashboard/components/gridComponents/Row.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx index a5a1f2d770ed3..26980701c7a4f 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Row.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Row.jsx @@ -114,8 +114,8 @@ class Row extends React.PureComponent { } componentWillUnmount() { - this.observerEnabler.disconnect(); - this.observerDisabler.disconnect(); + this.observerEnabler?.disconnect(); + this.observerDisabler?.disconnect(); } handleChangeFocus(nextFocus) {