Skip to content

Conversation

@SBIN2010
Copy link
Contributor

@SBIN2010 SBIN2010 commented Nov 28, 2025

SUMMARY

Users can now select a specific tab when saving a chart to a dashboard. This allows for more precise control over chart placement in complex dashboards with multiple tabs.

Add the ability to select a tab in the chart save modal window when placing it on a dashboard:

  • Load and display available tabs when an existing dashboard is selected
  • Allow users to choose a specific tab for the new chart
  • Automatically position the chart on the selected tab

Added TreeSelect from Ant Design for tab selection

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Снимок экрана от 2025-11-28 22-43-07
demo2_can_select_tab.webm

TESTING INSTRUCTIONS

run test src/explore/components/SaveModal.test.jsx

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

SBIN2010 and others added 30 commits October 22, 2024 23:07
@SBIN2010 SBIN2010 marked this pull request as ready for review November 30, 2025 19:18
@SBIN2010 SBIN2010 added the 🎪 ⚡ showtime-trigger-start Create new ephemeral environment for this PR label Nov 30, 2025
@github-actions github-actions bot added 🎪 a339bd9 🚦 building Environment a339bd9 status: building 🎪 a339bd9 📅 2025-11-30T19-49 Environment a339bd9 created at 2025-11-30T19-49 🎪 a339bd9 ⌛ 48h Environment a339bd9 expires after 48h 🎪 a339bd9 🤡 SBIN2010 Environment a339bd9 requested by SBIN2010 and removed 🎪 ⚡ showtime-trigger-start Create new ephemeral environment for this PR labels Nov 30, 2025
@github-actions
Copy link
Contributor

🎪 Showtime is building environment on GHA for a339bd9

@github-actions github-actions bot added 🎪 a339bd9 🚦 failed Environment a339bd9 status: failed and removed 🎪 a339bd9 🚦 building Environment a339bd9 status: building labels Nov 30, 2025
@SBIN2010 SBIN2010 added the 🎪 🛑 showtime-trigger-stop Destroy ephemeral environment and clean up AWS resources label Dec 1, 2025
@github-actions github-actions bot removed 🎪 🛑 showtime-trigger-stop Destroy ephemeral environment and clean up AWS resources 🎪 a339bd9 🚦 failed Environment a339bd9 status: failed 🎪 a339bd9 ⌛ 48h Environment a339bd9 expires after 48h 🎪 a339bd9 🤡 SBIN2010 Environment a339bd9 requested by SBIN2010 🎪 a339bd9 📅 2025-11-30T19-49 Environment a339bd9 created at 2025-11-30T19-49 labels Dec 1, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

⚠️ DEPRECATED WORKFLOW ⚠️

@SBIN2010 This workflow is deprecated! Please use the new Superset Showtime system instead:

Processing your ephemeral environment request here. Action: up. More information on how to use or configure ephemeral environments

@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

@SBIN2010 Ephemeral environment spinning up at http://34.221.129.14:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.

@rusackas rusackas requested review from EnxDev and Copilot December 1, 2025 18:47
Copilot finished reviewing on behalf of rusackas December 1, 2025 18:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds the ability to select a specific tab when saving a chart to a dashboard, providing users with more precise control over chart placement in multi-tab dashboards.

Key Changes:

  • Added TreeSelect component from Ant Design for tab selection in the save modal
  • Implemented loadTabs method to fetch available tabs from a selected dashboard
  • Created addChartToDashboardTab method to programmatically place charts on specific tabs
  • Added TypeScript interfaces TabNode and TreeDataNode for type safety

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 19 comments.

File Description
superset-frontend/src/explore/types.ts Added TypeScript type definitions for tab tree structures (TabNode and TreeDataNode)
superset-frontend/src/explore/components/SaveModal.tsx Enhanced save modal with tab selection functionality, including state management, API calls, and dashboard layout manipulation
superset-frontend/src/explore/components/SaveModal.test.jsx Added unit tests for tab selector rendering and behavior, including mock setup for TreeSelect component

Comment on lines +488 to +501
const findTabInTree = (data: TabNode[]): TabNode | null => {
for (const item of data) {
if (item.value === value) {
return item;
}
if (item.children) {
const found = findTabInTree(item.children);
if (found) return found;
}
}
return null;
};

const selectedTab = findTabInTree(this.state.tabsData);
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type mismatch in findTabInTree: the function is defined to accept TabNode[] but is being called with this.state.tabsData which is typed as Array<{ value: string; title: string; key: string }> (and should actually be TreeDataNode[]). The parameter type should match the actual state type: (data: TreeDataNode[]) or change state type to use TabNode[].

Copilot uses AI. Check for mistakes.
Comment on lines +329 to +333
addChartToDashboardTab = async (
dashboardId: number,
chartId: number,
tabId: string,
) => {
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing documentation for the addChartToDashboardTab method. This complex method modifies dashboard layout structure and should include JSDoc comments explaining:

  • The purpose of the method
  • Parameters and their meanings
  • The return value
  • The layout structure it creates (parents hierarchy, row/chart relationship)
  • Potential errors and when they might occur

Copilot uses AI. Check for mistakes.
Comment on lines +133 to +137
export interface TreeDataNode {
value: string;
title: string;
key: string;
children?: TreeDataNode[];
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Inconsistent naming: The type is named TreeDataNode but TreeSelect component from Ant Design typically uses treeData prop with nodes that have standard properties. Consider renaming to TabTreeNode to better reflect that this represents tab data in tree structure, making it more domain-specific and clearer.

Suggested change
export interface TreeDataNode {
value: string;
title: string;
key: string;
children?: TreeDataNode[];
export interface TabTreeNode {
value: string;
title: string;
key: string;
children?: TabTreeNode[];

Copilot uses AI. Check for mistakes.
Comment on lines +456 to +484
loadTabs = async (dashboardId: number) => {
try {
const response = await SupersetClient.get({
endpoint: `/api/v1/dashboard/${dashboardId}/tabs`,
});

const { result } = response.json;
const tabTree = result.tab_tree || [];

const convertToTreeData = (nodes: TabNode[]): TreeDataNode[] =>
nodes.map(node => ({
value: node.value,
title: node.title,
key: node.value,
children:
node.children && node.children.length > 0
? convertToTreeData(node.children)
: undefined,
}));

const treeData = convertToTreeData(tabTree);
this.setState({ tabsData: treeData });
return treeData;
} catch (error) {
logging.error('Error loading tabs:', error);
this.setState({ tabsData: [] });
return [];
}
};
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the loadTabs method. This method handles API calls and data transformation. Tests should verify:

  • Successful loading and conversion of tab data
  • Error handling when API call fails
  • Proper conversion from TabNode to TreeDataNode structure
  • State updates with correct data

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +252
if (this.state.action === 'saveas') {
selectedTabId = this.state.selectedTab?.value as string;
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition on line 251 only adds the chart to the selected tab when action === 'saveas', but line 586 shows that the tab selector is only displayed for 'saveas' action. This means charts saved with the 'overwrite' action will be added to the dashboard but not to any specific tab. Consider if this is the intended behavior, or if the condition should check this.state.selectedTab instead.

Suggested change
if (this.state.action === 'saveas') {
selectedTabId = this.state.selectedTab?.value as string;
if (this.state.selectedTab) {
selectedTabId = this.state.selectedTab.value as string;

Copilot uses AI. Check for mistakes.
width: 4,
height: 50,
chartId: chartId,
sliceName: `Chart ${chartId}`,
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meta object is missing the uuid property which is required according to the LayoutItemMeta type definition (line 217 in dashboard/types.ts shows uuid is required). This will cause type inconsistencies and potential runtime errors. Add a uuid property:

meta: {
  width: 4,
  height: 50,
  chartId: chartId,
  sliceName: `Chart ${chartId}`,
  uuid: `${chartKey}-${Date.now()}`, // or use a proper UUID generator
},
Suggested change
sliceName: `Chart ${chartId}`,
sliceName: `Chart ${chartId}`,
uuid: `${chartKey}-${Date.now()}`,

Copilot uses AI. Check for mistakes.
Comment on lines +407 to +410
component.state.tabsData = [
{ value: 'tab1', title: 'Main Tab', key: 'tab1' },
{ value: 'tab2', title: 'Analytics Tab', key: 'tab2' },
];
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use setState instead of directly modifying component state.

Suggested change
component.state.tabsData = [
{ value: 'tab1', title: 'Main Tab', key: 'tab1' },
{ value: 'tab2', title: 'Analytics Tab', key: 'tab2' },
];
component.setState({
tabsData: [
{ value: 'tab1', title: 'Main Tab', key: 'tab1' },
{ value: 'tab2', title: 'Analytics Tab', key: 'tab2' },
],
});

Copilot uses AI. Check for mistakes.
@rusackas
Copy link
Member

rusackas commented Dec 1, 2025

I LOVE THIS FEATURE!

Lots of copilot suggestions... I committed a couple of the "no-brainer" ones on your behalf, but I'm curious what you think of the rest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboard:tab Related to the usage of tabs in the Dashboard explore:save Related to saving changes in Explore size/L testenv-up

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants