This is an automated email from the ASF dual-hosted git repository.
asoare pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 761cee2d85b fix(componentParent): Newly created tabs don't show up in
Scoping tab (#37807)
761cee2d85b is described below
commit 761cee2d85b3773668c535852cb002327b8a01a7
Author: Alexandru Soare <[email protected]>
AuthorDate: Fri Feb 27 11:34:32 2026 +0200
fix(componentParent): Newly created tabs don't show up in Scoping tab
(#37807)
---
.../src/dashboard/reducers/dashboardLayout.test.ts | 105 +++++++++++++++++++++
.../src/dashboard/reducers/dashboardLayout.ts | 12 ++-
2 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/superset-frontend/src/dashboard/reducers/dashboardLayout.test.ts
b/superset-frontend/src/dashboard/reducers/dashboardLayout.test.ts
index 73b2610003f..011acfdc87a 100644
--- a/superset-frontend/src/dashboard/reducers/dashboardLayout.test.ts
+++ b/superset-frontend/src/dashboard/reducers/dashboardLayout.test.ts
@@ -422,14 +422,17 @@ describe('dashboardLayout reducer', () => {
[DASHBOARD_GRID_ID]: {
id: DASHBOARD_GRID_ID,
children: ['child', 'child2'],
+ parents: [DASHBOARD_ROOT_ID],
},
child: {
id: 'child',
children: [],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID],
},
child2: {
id: 'child2',
children: [],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID],
},
});
});
@@ -467,6 +470,108 @@ describe('dashboardLayout reducer', () => {
expect(result[newId].type).toBe(ROW_TYPE);
});
+ test('should update parents array when creating top-level tabs', () => {
+ const layout = {
+ [DASHBOARD_ROOT_ID]: {
+ id: DASHBOARD_ROOT_ID,
+ type: DASHBOARD_ROOT_TYPE,
+ children: [DASHBOARD_GRID_ID],
+ parents: [],
+ },
+ [DASHBOARD_GRID_ID]: {
+ id: DASHBOARD_GRID_ID,
+ type: DASHBOARD_GRID_TYPE,
+ children: ['row1'],
+ parents: [DASHBOARD_ROOT_ID],
+ },
+ row1: {
+ id: 'row1',
+ type: ROW_TYPE,
+ children: ['chart1'],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID],
+ },
+ chart1: {
+ id: 'chart1',
+ type: CHART_TYPE,
+ children: [],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID, 'row1'],
+ },
+ };
+
+ const dropResult = {
+ source: { id: NEW_COMPONENTS_SOURCE_ID, type: '' },
+ destination: {
+ id: DASHBOARD_ROOT_ID,
+ type: DASHBOARD_ROOT_TYPE,
+ index: 0,
+ },
+ dragging: { id: NEW_TABS_ID, type: TABS_TYPE },
+ };
+
+ const result = testReducer(layout, {
+ type: CREATE_TOP_LEVEL_TABS,
+ payload: { dropResult },
+ });
+
+ const tabComponent = Object.values(result).find(
+ component => component.type === TAB_TYPE,
+ )!;
+
+ // Verify parents are updated for moved components
+ expect(result.row1.parents).toContain(tabComponent.id);
+ expect(result.chart1.parents).toContain(tabComponent.id);
+ });
+
+ test('should update parents array when moving a component', () => {
+ const layout = {
+ [DASHBOARD_ROOT_ID]: {
+ id: DASHBOARD_ROOT_ID,
+ type: DASHBOARD_ROOT_TYPE,
+ children: [DASHBOARD_GRID_ID],
+ parents: [],
+ },
+ [DASHBOARD_GRID_ID]: {
+ id: DASHBOARD_GRID_ID,
+ type: DASHBOARD_GRID_TYPE,
+ children: ['row1', 'row2'],
+ parents: [DASHBOARD_ROOT_ID],
+ },
+ row1: {
+ id: 'row1',
+ type: ROW_TYPE,
+ children: ['chart1'],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID],
+ },
+ row2: {
+ id: 'row2',
+ type: ROW_TYPE,
+ children: [],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID],
+ },
+ chart1: {
+ id: 'chart1',
+ type: CHART_TYPE,
+ children: [],
+ parents: [DASHBOARD_ROOT_ID, DASHBOARD_GRID_ID, 'row1'],
+ },
+ };
+
+ const dropResult = {
+ source: { id: 'row1', type: ROW_TYPE, index: 0 },
+ destination: { id: 'row2', type: ROW_TYPE, index: 0 },
+ dragging: { id: 'chart1', type: CHART_TYPE },
+ };
+
+ const result = testReducer(layout, {
+ type: MOVE_COMPONENT,
+ payload: { dropResult },
+ });
+
+ // Chart should now have row2 as parent instead of row1
+ expect(result.chart1.parents).toContain('row2');
+ expect(result.chart1.parents).not.toContain('row1');
+ });
+
test('recursivelyDeleteChildren should be error proof with bad inputs', ()
=> {
/*
** The recursivelyDeleteChildren function was missing runtime safety
checks before operating
diff --git a/superset-frontend/src/dashboard/reducers/dashboardLayout.ts
b/superset-frontend/src/dashboard/reducers/dashboardLayout.ts
index 77840ee8462..aab6cd25a32 100644
--- a/superset-frontend/src/dashboard/reducers/dashboardLayout.ts
+++ b/superset-frontend/src/dashboard/reducers/dashboardLayout.ts
@@ -368,7 +368,17 @@ export default function layoutReducer(
): DashboardLayout {
if (action.type in actionHandlers) {
const handler = actionHandlers[action.type];
- return handler(state, action);
+ const nextState = handler(state, action);
+
+ // Update parents list after any layout change
+ if (nextState !== state && nextState[DASHBOARD_ROOT_ID]) {
+ updateComponentParentsList({
+ currentComponent: nextState[DASHBOARD_ROOT_ID],
+ layout: nextState,
+ });
+ }
+
+ return nextState;
}
return state;