diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx index cc897b8df5740..d16e76174d7a6 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx @@ -18,7 +18,7 @@ */ /* eslint-env browser */ import cx from 'classnames'; -import React, { FC } from 'react'; +import React, { FC, useCallback, useMemo } from 'react'; import { JsonObject, styled, css } from '@superset-ui/core'; import ErrorBoundary from 'src/components/ErrorBoundary'; import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane'; @@ -157,15 +157,14 @@ const DashboardBuilder: FC = () => { state => state.dashboardState.fullSizeChartId, ); - const handleChangeTab = ({ - pathToTabIndex, - }: { - pathToTabIndex: string[]; - }) => { - dispatch(setDirectPathToChild(pathToTabIndex)); - }; + const handleChangeTab = useCallback( + ({ pathToTabIndex }: { pathToTabIndex: string[] }) => { + dispatch(setDirectPathToChild(pathToTabIndex)); + }, + [dispatch], + ); - const handleDeleteTopLevelTabs = () => { + const handleDeleteTopLevelTabs = useCallback(() => { dispatch(deleteTopLevelTabs()); const firstTab = getDirectPathToTabIndex( @@ -173,7 +172,12 @@ const DashboardBuilder: FC = () => { 0, ); dispatch(setDirectPathToChild(firstTab)); - }; + }, [dashboardLayout, dispatch]); + + const handleDrop = useCallback( + dropResult => dispatch(handleComponentDrop(dropResult)), + [dispatch], + ); const dashboardRoot = dashboardLayout[DASHBOARD_ROOT_ID]; const rootChildId = dashboardRoot.children[0]; @@ -217,6 +221,54 @@ const DashboardBuilder: FC = () => { const filterBarHeight = `calc(100vh - ${offset}px)`; const filterBarOffset = dashboardFiltersOpen ? 0 : barTopOffset + 20; + const draggableStyle = useMemo( + () => ({ + marginLeft: dashboardFiltersOpen || editMode ? 0 : -32, + }), + [dashboardFiltersOpen, editMode], + ); + + const renderDraggableContent = useCallback( + ({ dropIndicatorProps }: { dropIndicatorProps: JsonObject }) => ( +
+ {!hideDashboardHeader && } + {dropIndicatorProps &&
} + {!isReport && topLevelTabs && ( + } + label="Collapse tab content" + onClick={handleDeleteTopLevelTabs} + />, + ]} + editMode={editMode} + > + {/* @ts-ignore */} + + + )} +
+ ), + [ + editMode, + handleChangeTab, + handleDeleteTopLevelTabs, + hideDashboardHeader, + isReport, + topLevelTabs, + ], + ); + return ( {nativeFiltersEnabled && !editMode && ( @@ -244,45 +296,13 @@ const DashboardBuilder: FC = () => { depth={DASHBOARD_ROOT_DEPTH} index={0} orientation="column" - onDrop={dropResult => dispatch(handleComponentDrop(dropResult))} + onDrop={handleDrop} editMode={editMode} // you cannot drop on/displace tabs if they already exist disableDragDrop={!!topLevelTabs} - style={{ - marginLeft: dashboardFiltersOpen || editMode ? 0 : -32, - }} + style={draggableStyle} > - {({ dropIndicatorProps }: { dropIndicatorProps: JsonObject }) => ( -
- {!hideDashboardHeader && } - {dropIndicatorProps &&
} - {!isReport && topLevelTabs && ( - } - label="Collapse tab content" - onClick={handleDeleteTopLevelTabs} - />, - ]} - editMode={editMode} - > - {/* - // @ts-ignore */} - - - )} -
- )} + {renderDraggableContent} diff --git a/superset-frontend/src/dashboard/components/DashboardGrid.jsx b/superset-frontend/src/dashboard/components/DashboardGrid.jsx index 9fb0fb5fd55e5..ad03859fa4da5 100644 --- a/superset-frontend/src/dashboard/components/DashboardGrid.jsx +++ b/superset-frontend/src/dashboard/components/DashboardGrid.jsx @@ -38,6 +38,16 @@ const propTypes = { const defaultProps = {}; +const renderDraggableContentBottom = dropProps => + dropProps.dropIndicatorProps && ( +
+ ); + +const renderDraggableContentTop = dropProps => + dropProps.dropIndicatorProps && ( +
+ ); + class DashboardGrid extends React.PureComponent { constructor(props) { super(props); @@ -144,11 +154,7 @@ class DashboardGrid extends React.PureComponent { className="empty-droptarget" editMode > - {({ dropIndicatorProps }) => - dropIndicatorProps && ( -
- ) - } + {renderDraggableContentBottom} )} @@ -181,11 +187,7 @@ class DashboardGrid extends React.PureComponent { className="empty-droptarget" editMode > - {({ dropIndicatorProps }) => - dropIndicatorProps && ( -
- ) - } + {renderDraggableContentTop} )} diff --git a/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx b/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx index a841be7827174..a29d0475e53b4 100644 --- a/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx +++ b/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx @@ -66,7 +66,7 @@ const defaultProps = { }; // export unwrapped component for testing -export class UnwrappedDragDroppable extends React.Component { +export class UnwrappedDragDroppable extends React.PureComponent { constructor(props) { super(props); this.state = { diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx index faa1e046eff7a..17691b842bc68 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx @@ -74,6 +74,16 @@ const TabTitleContainer = styled.div` `} `; +const renderDraggableContentBottom = dropProps => + dropProps.dropIndicatorProps && ( +
+ ); + +const renderDraggableContentTop = dropProps => + dropProps.dropIndicatorProps && ( +
+ ); + export default class Tab extends React.PureComponent { constructor(props) { super(props); @@ -148,11 +158,7 @@ export default class Tab extends React.PureComponent { editMode className="empty-droptarget" > - {({ dropIndicatorProps }) => - dropIndicatorProps && ( -
- ) - } + {renderDraggableContentTop} )} {tabComponent.children.map((componentId, componentIndex) => ( @@ -184,11 +190,7 @@ export default class Tab extends React.PureComponent { editMode className="empty-droptarget" > - {({ dropIndicatorProps }) => - dropIndicatorProps && ( -
- ) - } + {renderDraggableContentBottom} )}
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx index 9916520c76116..1966dd5ff0eea 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Tabs.jsx @@ -129,6 +129,7 @@ export class Tabs extends React.PureComponent { this.handleDeleteComponent = this.handleDeleteComponent.bind(this); this.handleDeleteTab = this.handleDeleteTab.bind(this); this.handleDropOnTab = this.handleDropOnTab.bind(this); + this.handleDrop = this.handleDrop.bind(this); } componentDidMount() { @@ -281,6 +282,12 @@ export class Tabs extends React.PureComponent { } } + handleDrop(dropResult) { + if (dropResult.dragging.type !== TABS_TYPE) { + this.props.handleComponentDrop(dropResult); + } + } + render() { const { depth, @@ -292,7 +299,6 @@ export class Tabs extends React.PureComponent { onResizeStart, onResize, onResizeStop, - handleComponentDrop, renderTabContent, renderHoverMenu, isComponentVisible: isCurrentTabVisible, @@ -315,11 +321,7 @@ export class Tabs extends React.PureComponent { orientation="row" index={index} depth={depth} - onDrop={dropResult => { - if (dropResult.dragging.type !== TABS_TYPE) { - handleComponentDrop(dropResult); - } - }} + onDrop={this.handleDrop} editMode={editMode} > {({