diff --git a/superset-frontend/src/dashboard/containers/DashboardPage.tsx b/superset-frontend/src/dashboard/containers/DashboardPage.tsx index 01f488684f16d..4cb1e5b457396 100644 --- a/superset-frontend/src/dashboard/containers/DashboardPage.tsx +++ b/superset-frontend/src/dashboard/containers/DashboardPage.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useEffect, FC } from 'react'; +import React, { useEffect, useRef, FC } from 'react'; import { t } from '@superset-ui/core'; import { useDispatch } from 'react-redux'; import { useParams } from 'react-router-dom'; @@ -57,17 +57,16 @@ const DashboardPage: FC = () => { const { result: datasets, error: datasetsApiError } = useDashboardDatasets( idOrSlug, ); + const isDashboardHydrated = useRef(false); const error = dashboardApiError || chartsApiError; const readyToRender = Boolean(dashboard && charts); const { dashboard_title, css } = dashboard || {}; - useEffect(() => { - if (readyToRender) { - dispatch(hydrateDashboard(dashboard, charts)); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [readyToRender]); + if (readyToRender && !isDashboardHydrated.current) { + isDashboardHydrated.current = true; + dispatch(hydrateDashboard(dashboard, charts)); + } useEffect(() => { if (dashboard_title) { diff --git a/superset-frontend/src/dashboard/reducers/dashboardState.js b/superset-frontend/src/dashboard/reducers/dashboardState.js index 4b0a401c3ee56..0f1d78418fa03 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardState.js +++ b/superset-frontend/src/dashboard/reducers/dashboardState.js @@ -150,16 +150,12 @@ export default function dashboardStateReducer(state = {}, action) { }; }, [SET_ACTIVE_TABS]() { - const prevActiveTabs = state.activeTabs ?? []; - const newActiveTabs = action.prevTabId - ? [ - ...prevActiveTabs.filter(tabId => tabId !== action.prevTabId), - action.tabId, - ] - : [...prevActiveTabs, action.tabId]; + const newActiveTabs = new Set(state.activeTabs); + newActiveTabs.delete(action.prevTabId); + newActiveTabs.add(action.tabId); return { ...state, - activeTabs: newActiveTabs, + activeTabs: Array.from(newActiveTabs), }; }, [SET_FOCUSED_FILTER_FIELD]() { diff --git a/superset-frontend/src/dashboard/reducers/dashboardState.test.ts b/superset-frontend/src/dashboard/reducers/dashboardState.test.ts new file mode 100644 index 0000000000000..274b26733ce1d --- /dev/null +++ b/superset-frontend/src/dashboard/reducers/dashboardState.test.ts @@ -0,0 +1,38 @@ +/** + * 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. + */ + +import dashboardStateReducer from './dashboardState'; +import { setActiveTabs } from '../actions/dashboardState'; + +describe('DashboardState reducer', () => { + it('SET_ACTIVE_TABS', () => { + expect( + dashboardStateReducer({ activeTabs: [] }, setActiveTabs('tab1')), + ).toEqual({ activeTabs: ['tab1'] }); + expect( + dashboardStateReducer({ activeTabs: ['tab1'] }, setActiveTabs('tab1')), + ).toEqual({ activeTabs: ['tab1'] }); + expect( + dashboardStateReducer( + { activeTabs: ['tab1'] }, + setActiveTabs('tab2', 'tab1'), + ), + ).toEqual({ activeTabs: ['tab2'] }); + }); +}); diff --git a/superset-frontend/src/reduxUtils.ts b/superset-frontend/src/reduxUtils.ts index 53d84c63bf79e..605e7690ca1ad 100644 --- a/superset-frontend/src/reduxUtils.ts +++ b/superset-frontend/src/reduxUtils.ts @@ -141,7 +141,12 @@ export function initEnhancer( const composeEnhancers = process.env.WEBPACK_MODE === 'development' ? /* eslint-disable-next-line no-underscore-dangle, dot-notation */ - window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] || compose + window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] + ? /* eslint-disable-next-line no-underscore-dangle, dot-notation */ + window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__']({ + trace: true, + }) + : compose : compose; return persist