diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx index 73cdca34ed15..faa1e046eff7 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx @@ -18,6 +18,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; +import { styled } from '@superset-ui/core'; import DashboardComponent from '../../containers/DashboardComponent'; import DragDroppable from '../dnd/DragDroppable'; @@ -62,6 +63,17 @@ const defaultProps = { onResizeStop() {}, }; +const TabTitleContainer = styled.div` + ${({ isHighlighted, theme: { gridUnit, colors } }) => ` + padding: ${gridUnit}px ${gridUnit * 2}px; + margin: ${-gridUnit}px ${gridUnit * -2}px; + transition: box-shadow 0.2s ease-in-out; + ${ + isHighlighted && `box-shadow: 0 0 ${gridUnit}px ${colors.primary.light1};` + } + `} +`; + export default class Tab extends React.PureComponent { constructor(props) { super(props); @@ -192,6 +204,7 @@ export default class Tab extends React.PureComponent { editMode, filters, isFocused, + isHighlighted, } = this.props; return ( @@ -205,7 +218,11 @@ export default class Tab extends React.PureComponent { editMode={editMode} > {({ dropIndicatorProps, dragSourceRef }) => ( -
+ } -
+ )} ); diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx index 427145b89eb1..bdf60f8f4236 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx @@ -33,7 +33,38 @@ import getLeafComponentIdFromPath from '../../util/getLeafComponentIdFromPath'; import { componentShape } from '../../util/propShapes'; import { NEW_TAB_ID, DASHBOARD_ROOT_ID } from '../../util/constants'; import { RENDER_TAB, RENDER_TAB_CONTENT } from './Tab'; -import { TAB_TYPE } from '../../util/componentTypes'; +import { CHART_TYPE, TAB_TYPE } from '../../util/componentTypes'; +import { getChartIdsInFilterScope } from '../../util/activeDashboardFilters'; + +const findTabsWithChartsInScope = ( + dashboardLayout, + chartsInScope, + childId, + tabId, + tabsToHighlight, +) => { + if ( + dashboardLayout[childId].type === CHART_TYPE && + chartsInScope.includes(dashboardLayout[childId].meta.chartId) + ) { + tabsToHighlight.add(tabId); + } + if ( + dashboardLayout[childId].children.length === 0 || + (dashboardLayout[childId].type === TAB_TYPE && tabsToHighlight.has(childId)) + ) { + return; + } + dashboardLayout[childId].children.forEach(subChildId => + findTabsWithChartsInScope( + dashboardLayout, + chartsInScope, + subChildId, + tabId, + tabsToHighlight, + ), + ); +}; const propTypes = { id: PropTypes.string.isRequired, @@ -268,11 +299,30 @@ class Tabs extends React.PureComponent { renderHoverMenu, isComponentVisible: isCurrentTabVisible, editMode, + focusedFilterScope, + dashboardLayout, } = this.props; const { children: tabIds } = tabsComponent; const { tabIndex: selectedTabIndex, activeKey } = this.state; + const tabsToHighlight = new Set(); + if (focusedFilterScope) { + const chartsInScope = getChartIdsInFilterScope({ + filterScope: focusedFilterScope.scope, + }); + tabIds.forEach(tabId => { + if (!tabsToHighlight.has(tabId)) { + findTabsWithChartsInScope( + dashboardLayout, + chartsInScope, + tabId, + tabId, + tabsToHighlight, + ); + } + }); + } return ( } > diff --git a/superset-frontend/src/dashboard/containers/DashboardComponent.jsx b/superset-frontend/src/dashboard/containers/DashboardComponent.jsx index f47a8734ab4e..42f408cd0d9c 100644 --- a/superset-frontend/src/dashboard/containers/DashboardComponent.jsx +++ b/superset-frontend/src/dashboard/containers/DashboardComponent.jsx @@ -107,6 +107,7 @@ function mapStateToProps( const component = dashboardLayout[id]; const props = { component, + dashboardLayout, parentComponent: dashboardLayout[parentId], editMode: dashboardState.editMode, undoLength: undoableLayout.past.length,