From 2753c436f3349565c2077c176ff346e88c3729e4 Mon Sep 17 00:00:00 2001 From: "JUST.in DO IT" Date: Wed, 7 Jun 2023 09:23:58 -0700 Subject: [PATCH] fix(dashboard): max call size stack error (#24304) (cherry picked from commit 9c7b8b8c7832eddd7e09f7ad2a9f9bd0ea4085e3) --- .../components/nativeFilters/utils.test.ts | 40 ++++++++++++++++++- .../components/nativeFilters/utils.ts | 9 +++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.test.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.test.ts index b38f4bce1681a..142153c27896d 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/utils.test.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.test.ts @@ -18,7 +18,8 @@ */ import { Behavior, FeatureFlag } from '@superset-ui/core'; import * as featureFlags from 'src/featureFlags'; -import { nativeFilterGate } from './utils'; +import { DashboardLayout } from 'src/dashboard/types'; +import { nativeFilterGate, findTabsWithChartsInScope } from './utils'; let isFeatureEnabledMock: jest.MockInstance; @@ -124,3 +125,40 @@ describe('nativeFilterGate', () => { }); }); }); + +test('findTabsWithChartsInScope should handle a recursive layout structure', () => { + const dashboardLayout = { + DASHBOARD_VERSION_KEY: 'v2', + ROOT_ID: { + children: ['GRID_ID'], + id: 'ROOT_ID', + type: 'ROOT', + }, + GRID_ID: { + children: ['TAB-LrujeuD5Qn', 'TABS-kN7tw6vFif'], + id: 'GRID_ID', + parents: ['ROOT_ID'], + type: 'GRID', + }, + 'TAB-LrujeuD5Qn': { + children: ['TABS-kN7tw6vFif'], + id: 'TAB-LrujeuD5Qn', + meta: { + text: 'View by Totals', + }, + parents: ['ROOT_ID'], + type: 'TAB', + }, + 'TABS-kN7tw6vFif': { + children: ['TAB-LrujeuD5Qn', 'TAB--7BUkKkNl'], + id: 'TABS-kN7tw6vFif', + meta: {}, + parents: ['ROOT_ID'], + type: 'TABS', + }, + } as any as DashboardLayout; + + expect(Array.from(findTabsWithChartsInScope(dashboardLayout, []))).toEqual( + [], + ); +}); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts index 32a060057b7c3..ef347de4c2df9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts @@ -154,7 +154,12 @@ const findTabsWithChartsInScopeHelper = ( componentId: string, tabIds: string[], tabsToHighlight: Set, + visited: Set, ) => { + if (visited.has(componentId)) { + return; + } + visited.add(componentId); if ( dashboardLayout?.[componentId]?.type === CHART_TYPE && chartsInScope.includes(dashboardLayout[componentId]?.meta?.chartId) @@ -175,6 +180,7 @@ const findTabsWithChartsInScopeHelper = ( childId, isComponentATab(dashboardLayout, childId) ? [...tabIds, childId] : tabIds, tabsToHighlight, + visited, ), ); }; @@ -187,6 +193,7 @@ export const findTabsWithChartsInScope = ( const rootChildId = dashboardRoot.children[0]; const hasTopLevelTabs = rootChildId !== DASHBOARD_GRID_ID; const tabsInScope = new Set(); + const visited = new Set(); if (hasTopLevelTabs) { dashboardLayout[rootChildId]?.children?.forEach(tabId => findTabsWithChartsInScopeHelper( @@ -195,6 +202,7 @@ export const findTabsWithChartsInScope = ( tabId, [tabId], tabsInScope, + visited, ), ); } else { @@ -207,6 +215,7 @@ export const findTabsWithChartsInScope = ( element.id, [element.id], tabsInScope, + visited, ), ); }