You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by cc...@apache.org on 2018/04/04 18:40:21 UTC
[incubator-superset] 01/02: [edit mode] add edit mode to redux and
propogate to all s
This is an automated email from the ASF dual-hosted git repository.
ccwilliams pushed a commit to branch chris--grid-root-and-spacer
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
commit 1a4bc3172d0b992c91b6ef9b05af83fcbd1f7e8d
Author: Chris Williams <ch...@airbnb.com>
AuthorDate: Tue Apr 3 15:56:07 2018 -0700
[edit mode] add edit mode to redux and propogate to all <DashboardComponent />s
---
superset/assets/javascripts/dashboard/index.jsx | 1 +
.../javascripts/dashboard/v2/actions/editMode.js | 9 ++++++
.../dashboard/v2/components/DashboardBuilder.jsx | 16 ++++++----
.../dashboard/v2/components/DashboardGrid.jsx | 10 +++---
.../dashboard/v2/components/DashboardHeader.jsx | 10 +++---
.../dashboard/v2/components/dnd/DragDroppable.jsx | 4 +++
.../v2/components/gridComponents/Chart.jsx | 17 ++++++----
.../v2/components/gridComponents/Column.jsx | 22 ++++++++-----
.../v2/components/gridComponents/Divider.jsx | 10 ++++--
.../v2/components/gridComponents/Header.jsx | 13 +++++---
.../dashboard/v2/components/gridComponents/Row.jsx | 21 +++++++-----
.../dashboard/v2/components/gridComponents/Tab.jsx | 6 +++-
.../v2/components/gridComponents/Tabs.jsx | 25 +++++++++------
.../gridComponents/new/DraggableNewComponent.jsx | 1 +
.../v2/components/menu/WithPopoverMenu.jsx | 37 ++++++++++++++--------
.../v2/components/resizable/ResizableContainer.jsx | 14 ++++++--
.../dashboard/v2/containers/DashboardBuilder.jsx | 3 +-
.../dashboard/v2/containers/DashboardComponent.jsx | 3 +-
.../dashboard/v2/containers/DashboardGrid.jsx | 2 +-
.../dashboard/v2/containers/DashboardHeader.jsx | 6 +++-
.../javascripts/dashboard/v2/reducers/editMode.js | 11 +++++++
.../javascripts/dashboard/v2/reducers/index.js | 2 ++
.../dashboard/v2/stylesheets/builder.less | 6 ++--
.../dashboard/v2/stylesheets/components/chart.less | 4 +--
.../v2/stylesheets/components/column.less | 17 ++++++++++
.../v2/stylesheets/components/divider.less | 2 +-
.../dashboard/v2/stylesheets/components/row.less | 18 +++++++++++
.../javascripts/dashboard/v2/stylesheets/grid.less | 24 +++-----------
28 files changed, 211 insertions(+), 103 deletions(-)
diff --git a/superset/assets/javascripts/dashboard/index.jsx b/superset/assets/javascripts/dashboard/index.jsx
index 926f6b2..f7471f5 100644
--- a/superset/assets/javascripts/dashboard/index.jsx
+++ b/superset/assets/javascripts/dashboard/index.jsx
@@ -25,6 +25,7 @@ const initState = {
present: emptyDashboardLayout,
future: [],
},
+ editMode: true,
};
const store = createStore(
diff --git a/superset/assets/javascripts/dashboard/v2/actions/editMode.js b/superset/assets/javascripts/dashboard/v2/actions/editMode.js
new file mode 100644
index 0000000..0a849ea
--- /dev/null
+++ b/superset/assets/javascripts/dashboard/v2/actions/editMode.js
@@ -0,0 +1,9 @@
+export const SET_EDIT_MODE = 'SET_EDIT_MODE';
+export function setEditMode(editMode) {
+ return {
+ type: SET_EDIT_MODE,
+ payload: {
+ editMode,
+ },
+ };
+}
diff --git a/superset/assets/javascripts/dashboard/v2/components/DashboardBuilder.jsx b/superset/assets/javascripts/dashboard/v2/components/DashboardBuilder.jsx
index 2a0bfe7..fc938b1 100644
--- a/superset/assets/javascripts/dashboard/v2/components/DashboardBuilder.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/DashboardBuilder.jsx
@@ -1,3 +1,4 @@
+import cx from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
import HTML5Backend from 'react-dnd-html5-backend';
@@ -18,11 +19,10 @@ import {
} from '../util/constants';
const propTypes = {
- editMode: PropTypes.bool,
-
// redux
dashboardLayout: PropTypes.object.isRequired,
deleteTopLevelTabs: PropTypes.func.isRequired,
+ editMode: PropTypes.bool.isRequired,
handleComponentDrop: PropTypes.func.isRequired,
};
@@ -52,7 +52,7 @@ class DashboardBuilder extends React.Component {
render() {
const { tabIndex } = this.state;
- const { handleComponentDrop, dashboardLayout, deleteTopLevelTabs } = this.props;
+ const { handleComponentDrop, dashboardLayout, deleteTopLevelTabs, editMode } = this.props;
const dashboardRoot = dashboardLayout[DASHBOARD_ROOT_ID];
const rootChildId = dashboardRoot.children[0];
const topLevelTabs = rootChildId !== DASHBOARD_GRID_ID && dashboardLayout[rootChildId];
@@ -64,8 +64,8 @@ class DashboardBuilder extends React.Component {
const gridComponent = dashboardLayout[gridComponentId];
return (
- <div className="dashboard-v2">
- {topLevelTabs ? ( // you cannot drop on/displace tabs if they already exist
+ <div className={cx('dashboard-v2', editMode && 'dashboard-v2--editing')}>
+ {topLevelTabs || !editMode ? ( // you cannot drop on/displace tabs if they already exist
<DashboardHeader />
) : (
<DragDroppable
@@ -75,6 +75,7 @@ class DashboardBuilder extends React.Component {
index={0}
orientation="column"
onDrop={handleComponentDrop}
+ editMode
>
{({ dropIndicatorProps }) => (
<div>
@@ -94,6 +95,7 @@ class DashboardBuilder extends React.Component {
onClick={deleteTopLevelTabs}
/>,
]}
+ editMode={editMode}
>
<DashboardComponent
id={topLevelTabs.id}
@@ -105,12 +107,12 @@ class DashboardBuilder extends React.Component {
/>
</WithPopoverMenu>}
- <div className="dashboard-builder">
+ <div className="dashboard-content">
<DashboardGrid
gridComponent={gridComponent}
depth={DASHBOARD_ROOT_DEPTH + 1}
/>
- <BuilderComponentPane />
+ {editMode && <BuilderComponentPane />}
</div>
</div>
);
diff --git a/superset/assets/javascripts/dashboard/v2/components/DashboardGrid.jsx b/superset/assets/javascripts/dashboard/v2/components/DashboardGrid.jsx
index cfe99c7..9f4cb93 100644
--- a/superset/assets/javascripts/dashboard/v2/components/DashboardGrid.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/DashboardGrid.jsx
@@ -13,6 +13,7 @@ import {
const propTypes = {
depth: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
gridComponent: componentShape.isRequired,
handleComponentDrop: PropTypes.func.isRequired,
resizeComponent: PropTypes.func.isRequired,
@@ -70,7 +71,7 @@ class DashboardGrid extends React.PureComponent {
}
render() {
- const { gridComponent, handleComponentDrop, depth } = this.props;
+ const { gridComponent, handleComponentDrop, depth, editMode } = this.props;
const { isResizing, rowGuideTop } = this.state;
return (
@@ -99,18 +100,19 @@ class DashboardGrid extends React.PureComponent {
))}
{/* render an empty drop target */}
- {gridComponent.children.length === 0 &&
+ {editMode &&
<DragDroppable
component={gridComponent}
depth={depth}
parentComponent={null}
- index={0}
+ index={gridComponent.children.length}
orientation="column"
onDrop={handleComponentDrop}
className="empty-grid-droptarget"
+ editMode
>
{({ dropIndicatorProps }) => dropIndicatorProps &&
- <div {...dropIndicatorProps} />}
+ <div className="drop-indicator drop-indicator--top" />}
</DragDroppable>}
{isResizing && Array(GRID_COLUMN_COUNT).fill(null).map((_, i) => (
diff --git a/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx b/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx
index 2c89f33..ca204e5 100644
--- a/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx
@@ -7,8 +7,7 @@ import { componentShape } from '../util/propShapes';
import EditableTitle from '../../../components/EditableTitle';
const propTypes = {
- // editMode: PropTypes.bool.isRequired,
- // setEditMode: PropTypes.func.isRequired,
+ editMode: PropTypes.bool.isRequired,
component: componentShape.isRequired,
// redux
@@ -17,6 +16,7 @@ const propTypes = {
onRedo: PropTypes.func.isRequired,
canUndo: PropTypes.bool.isRequired,
canRedo: PropTypes.bool.isRequired,
+ setEditMode: PropTypes.func.isRequired,
};
class DashboardHeader extends React.Component {
@@ -27,8 +27,7 @@ class DashboardHeader extends React.Component {
}
toggleEditMode() {
- console.log('@TODO toggleEditMode');
- // this.props.setEditMode(!this.props.editMode);
+ this.props.setEditMode(!this.props.editMode);
}
handleChangeText(nextText) {
@@ -47,8 +46,7 @@ class DashboardHeader extends React.Component {
}
render() {
- const { component, onUndo, onRedo, canUndo, canRedo } = this.props;
- const editMode = true;
+ const { component, onUndo, onRedo, canUndo, canRedo, editMode } = this.props;
return (
<div className="dashboard-header">
diff --git a/superset/assets/javascripts/dashboard/v2/components/dnd/DragDroppable.jsx b/superset/assets/javascripts/dashboard/v2/components/dnd/DragDroppable.jsx
index 89664e5..775e092 100644
--- a/superset/assets/javascripts/dashboard/v2/components/dnd/DragDroppable.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/dnd/DragDroppable.jsx
@@ -18,6 +18,7 @@ const propTypes = {
index: PropTypes.number.isRequired,
style: PropTypes.object,
onDrop: PropTypes.func,
+ editMode: PropTypes.bool.isRequired,
// from react-dnd
isDragging: PropTypes.bool.isRequired,
@@ -70,8 +71,11 @@ class DragDroppable extends React.Component {
isDragging,
isDraggingOver,
style,
+ editMode,
} = this.props;
+ if (!editMode) return children({});
+
const { dropIndicator } = this.state;
return (
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Chart.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Chart.jsx
index 7ca506d..668d268 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Chart.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Chart.jsx
@@ -9,10 +9,7 @@ import ResizableContainer from '../resizable/ResizableContainer';
import WithPopoverMenu from '../menu/WithPopoverMenu';
import { componentShape } from '../../util/propShapes';
import { ROW_TYPE } from '../../util/componentTypes';
-import {
- GRID_MIN_COLUMN_COUNT,
- GRID_MIN_ROW_UNITS,
-} from '../../util/constants';
+import { GRID_MIN_COLUMN_COUNT, GRID_MIN_ROW_UNITS } from '../../util/constants';
const propTypes = {
id: PropTypes.string.isRequired,
@@ -21,6 +18,7 @@ const propTypes = {
parentComponent: componentShape.isRequired,
index: PropTypes.number.isRequired,
depth: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
// grid related
availableColumnCount: PropTypes.number.isRequired,
@@ -71,6 +69,7 @@ class Chart extends React.Component {
onResize,
onResizeStop,
handleComponentDrop,
+ editMode,
} = this.props;
return (
@@ -82,6 +81,7 @@ class Chart extends React.Component {
depth={depth}
onDrop={handleComponentDrop}
disableDragDrop={isFocused}
+ editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
<ResizableContainer
@@ -97,16 +97,19 @@ class Chart extends React.Component {
onResizeStart={onResizeStart}
onResize={onResize}
onResizeStop={onResizeStop}
+ editMode={editMode}
>
- <HoverMenu innerRef={dragSourceRef} position="top">
- <DragHandle position="top" />
- </HoverMenu>
+ {editMode &&
+ <HoverMenu innerRef={dragSourceRef} position="top">
+ <DragHandle position="top" />
+ </HoverMenu>}
<WithPopoverMenu
onChangeFocus={this.handleChangeFocus}
menuItems={[
<DeleteComponentButton onDelete={this.handleDeleteComponent} />,
]}
+ editMode={editMode}
>
<div className="dashboard-component dashboard-component-chart">
<div className="fa fa-area-chart" />
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Column.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Column.jsx
index bf33710..fe5a721 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Column.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Column.jsx
@@ -24,6 +24,7 @@ const propTypes = {
parentComponent: componentShape.isRequired,
index: PropTypes.number.isRequired,
depth: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
// grid related
availableColumnCount: PropTypes.number.isRequired,
@@ -90,6 +91,7 @@ class Column extends React.PureComponent {
onResize,
onResizeStop,
handleComponentDrop,
+ editMode,
} = this.props;
const columnItems = columnComponent.children || [];
@@ -105,6 +107,7 @@ class Column extends React.PureComponent {
index={index}
depth={depth}
onDrop={handleComponentDrop}
+ editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
<ResizableContainer
@@ -118,6 +121,7 @@ class Column extends React.PureComponent {
onResizeStart={onResizeStart}
onResize={onResize}
onResizeStop={onResizeStop}
+ editMode={editMode}
>
<WithPopoverMenu
isFocused={this.state.isFocused}
@@ -130,6 +134,7 @@ class Column extends React.PureComponent {
onChange={this.handleChangeBackground}
/>,
]}
+ editMode={editMode}
>
<div
className={cx(
@@ -138,14 +143,15 @@ class Column extends React.PureComponent {
backgroundStyle.className,
)}
>
- <HoverMenu innerRef={dragSourceRef} position="top">
- <DragHandle position="top" />
- <DeleteComponentButton onDelete={this.handleDeleteComponent} />
- <IconButton
- onClick={this.handleChangeFocus}
- className="fa fa-cog"
- />
- </HoverMenu>
+ {editMode &&
+ <HoverMenu innerRef={dragSourceRef} position="top">
+ <DragHandle position="top" />
+ <DeleteComponentButton onDelete={this.handleDeleteComponent} />
+ <IconButton
+ onClick={this.handleChangeFocus}
+ className="fa fa-cog"
+ />
+ </HoverMenu>}
{columnItems.map((componentId, itemIndex) => (
<DashboardComponent
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Divider.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Divider.jsx
index ff29c3f..b3010e9 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Divider.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Divider.jsx
@@ -13,6 +13,7 @@ const propTypes = {
depth: PropTypes.number.isRequired,
parentComponent: componentShape.isRequired,
index: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
handleComponentDrop: PropTypes.func.isRequired,
deleteComponent: PropTypes.func.isRequired,
};
@@ -35,6 +36,7 @@ class Divider extends React.PureComponent {
parentComponent,
index,
handleComponentDrop,
+ editMode,
} = this.props;
return (
@@ -45,12 +47,14 @@ class Divider extends React.PureComponent {
index={index}
depth={depth}
onDrop={handleComponentDrop}
+ editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
<div ref={dragSourceRef}>
- <HoverMenu position="left">
- <DeleteComponentButton onDelete={this.handleDeleteComponent} />
- </HoverMenu>
+ {editMode &&
+ <HoverMenu position="left">
+ <DeleteComponentButton onDelete={this.handleDeleteComponent} />
+ </HoverMenu>}
<div className="dashboard-component dashboard-component-divider" />
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Header.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Header.jsx
index d8744d6..594cf6b 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Header.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Header.jsx
@@ -22,6 +22,7 @@ const propTypes = {
depth: PropTypes.number.isRequired,
parentComponent: componentShape.isRequired,
index: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
// redux
handleComponentDrop: PropTypes.func.isRequired,
@@ -79,6 +80,7 @@ class Header extends React.PureComponent {
parentComponent,
index,
handleComponentDrop,
+ editMode,
} = this.props;
const headerStyle = headerStyleOptions.find(
@@ -98,12 +100,14 @@ class Header extends React.PureComponent {
depth={depth}
onDrop={handleComponentDrop}
disableDragDrop={isFocused}
+ editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
<div ref={dragSourceRef}>
- <HoverMenu position="left">
- <DragHandle position="left" />
- </HoverMenu>
+ {editMode &&
+ <HoverMenu position="left">
+ <DragHandle position="left" />
+ </HoverMenu>}
<WithPopoverMenu
onChangeFocus={this.handleChangeFocus}
@@ -122,6 +126,7 @@ class Header extends React.PureComponent {
/>,
<DeleteComponentButton onDelete={this.handleDeleteComponent} />,
]}
+ editMode={editMode}
>
<div
className={cx(
@@ -133,7 +138,7 @@ class Header extends React.PureComponent {
>
<EditableTitle
title={component.meta.text}
- canEdit={isFocused}
+ canEdit={editMode && isFocused}
onSaveTitle={this.handleChangeText}
showTooltip={false}
/>
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Row.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Row.jsx
index 99296dd..9866bc8 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Row.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Row.jsx
@@ -22,6 +22,7 @@ const propTypes = {
parentComponent: componentShape.isRequired,
index: PropTypes.number.isRequired,
depth: PropTypes.number.isRequired,
+ editMode: PropTypes.bool.isRequired,
// grid related
availableColumnCount: PropTypes.number.isRequired,
@@ -90,6 +91,7 @@ class Row extends React.PureComponent {
onResize,
onResizeStop,
handleComponentDrop,
+ editMode,
} = this.props;
const rowItems = rowComponent.children || [];
@@ -106,6 +108,7 @@ class Row extends React.PureComponent {
index={index}
depth={depth}
onDrop={handleComponentDrop}
+ editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
<WithPopoverMenu
@@ -119,6 +122,7 @@ class Row extends React.PureComponent {
onChange={this.handleChangeBackground}
/>,
]}
+ editMode={editMode}
>
<div
className={cx(
@@ -127,14 +131,15 @@ class Row extends React.PureComponent {
backgroundStyle.className,
)}
>
- <HoverMenu innerRef={dragSourceRef} position="left">
- <DragHandle position="left" />
- <DeleteComponentButton onDelete={this.handleDeleteComponent} />
- <IconButton
- onClick={this.handleChangeFocus}
- className="fa fa-cog"
- />
- </HoverMenu>
+ {editMode &&
+ <HoverMenu innerRef={dragSourceRef} position="left">
+ <DragHandle position="left" />
+ <DeleteComponentButton onDelete={this.handleDeleteComponent} />
+ <IconButton
+ onClick={this.handleChangeFocus}
+ className="fa fa-cog"
+ />
+ </HoverMenu>}
{rowItems.map((componentId, itemIndex) => (
<DashboardComponent
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tab.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tab.jsx
index 9b41949..218c4e7 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tab.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tab.jsx
@@ -22,6 +22,7 @@ const propTypes = {
renderType: PropTypes.oneOf([RENDER_TAB, RENDER_TAB_CONTENT]).isRequired,
onDropOnTab: PropTypes.func,
onDeleteTab: PropTypes.func,
+ editMode: PropTypes.bool.isRequired,
// grid related
availableColumnCount: PropTypes.number,
@@ -127,6 +128,7 @@ export default class Tab extends React.PureComponent {
parentComponent,
index,
depth,
+ editMode,
} = this.props;
return (
@@ -141,6 +143,7 @@ export default class Tab extends React.PureComponent {
// itself, e.g. if a top-level Tab has a Tabs child, dragging the Tab into the Tabs would
// reusult in circular children
disableDragDrop={isFocused || depth === DASHBOARD_ROOT_DEPTH + 1}
+ editMode={editMode}
>
{({ dropIndicatorProps, dragSourceRef }) => (
<div className="dragdroppable-tab" ref={dragSourceRef}>
@@ -149,10 +152,11 @@ export default class Tab extends React.PureComponent {
menuItems={parentComponent.children.length <= 1 ? [] : [
<DeleteComponentButton onDelete={this.handleDeleteComponent} />,
]}
+ editMode={editMode}
>
<EditableTitle
title={component.meta.text}
- canEdit={isFocused}
+ canEdit={editMode && isFocused}
onSaveTitle={this.handleChangeText}
showTooltip={false}
/>
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tabs.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tabs.jsx
index f76fa19..1f5f0c6 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tabs.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/Tabs.jsx
@@ -22,7 +22,8 @@ const propTypes = {
parentComponent: componentShape.isRequired,
index: PropTypes.number.isRequired,
depth: PropTypes.number.isRequired,
- renderTabContent: PropTypes.bool,
+ renderTabContent: PropTypes.bool, // whether to render tabs + content or just tabs
+ editMode: PropTypes.bool.isRequired,
// grid related
availableColumnCount: PropTypes.number,
@@ -130,6 +131,7 @@ class Tabs extends React.PureComponent {
onResizeStop,
handleComponentDrop,
renderTabContent,
+ editMode,
} = this.props;
const { tabIndex: selectedTabIndex } = this.state;
@@ -143,13 +145,15 @@ class Tabs extends React.PureComponent {
index={index}
depth={depth}
onDrop={handleComponentDrop}
+ editMode={editMode}
>
{({ dropIndicatorProps: tabsDropIndicatorProps, dragSourceRef: tabsDragSourceRef }) => (
<div className="dashboard-component dashboard-component-tabs">
- <HoverMenu innerRef={tabsDragSourceRef} position="left">
- <DragHandle position="left" />
- <DeleteComponentButton onDelete={this.handleDeleteComponent} />
- </HoverMenu>
+ {editMode &&
+ <HoverMenu innerRef={tabsDragSourceRef} position="left">
+ <DragHandle position="left" />
+ <DeleteComponentButton onDelete={this.handleDeleteComponent} />
+ </HoverMenu>}
<BootstrapTabs
id={tabsComponent.id}
@@ -200,11 +204,12 @@ class Tabs extends React.PureComponent {
</BootstrapTab>
))}
- {tabIds.length < MAX_TAB_COUNT &&
- <BootstrapTab
- eventKey={NEW_TAB_INDEX}
- title={<div className="fa fa-plus" />}
- />}
+ {editMode &&
+ tabIds.length < MAX_TAB_COUNT &&
+ <BootstrapTab
+ eventKey={NEW_TAB_INDEX}
+ title={<div className="fa fa-plus" />}
+ />}
</BootstrapTabs>
diff --git a/superset/assets/javascripts/dashboard/v2/components/gridComponents/new/DraggableNewComponent.jsx b/superset/assets/javascripts/dashboard/v2/components/gridComponents/new/DraggableNewComponent.jsx
index 778f58e..eebd6e0 100644
--- a/superset/assets/javascripts/dashboard/v2/components/gridComponents/new/DraggableNewComponent.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/gridComponents/new/DraggableNewComponent.jsx
@@ -26,6 +26,7 @@ export default class DraggableNewComponent extends React.PureComponent {
parentComponent={{ id: NEW_COMPONENTS_SOURCE_ID, type: NEW_COMPONENT_SOURCE_TYPE }}
index={0}
depth={0}
+ editMode
>
{({ dragSourceRef }) => (
<div ref={dragSourceRef} className="new-component">
diff --git a/superset/assets/javascripts/dashboard/v2/components/menu/WithPopoverMenu.jsx b/superset/assets/javascripts/dashboard/v2/components/menu/WithPopoverMenu.jsx
index a1d4c0e..f213442 100644
--- a/superset/assets/javascripts/dashboard/v2/components/menu/WithPopoverMenu.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/menu/WithPopoverMenu.jsx
@@ -9,6 +9,7 @@ const propTypes = {
onChangeFocus: PropTypes.func,
isFocused: PropTypes.bool,
shouldFocus: PropTypes.func,
+ editMode: PropTypes.bool.isRequired,
};
const defaultProps = {
@@ -32,10 +33,14 @@ class WithPopoverMenu extends React.PureComponent {
}
componentWillReceiveProps(nextProps) {
- if (nextProps.isFocused && !this.state.isFocused) {
+ if (nextProps.editMode && nextProps.isFocused && !this.state.isFocused) {
document.addEventListener('click', this.handleClick, true);
document.addEventListener('drag', this.handleClick, true);
this.setState({ isFocused: true });
+ } else if (this.state.isFocused && !nextProps.editMode) {
+ document.removeEventListener('click', this.handleClick, true);
+ document.removeEventListener('drag', this.handleClick, true);
+ this.setState({ isFocused: false });
}
}
@@ -49,10 +54,14 @@ class WithPopoverMenu extends React.PureComponent {
}
handleClick(event) {
- const { onChangeFocus, shouldFocus: shouldFocusThunk } = this.props;
- const shouldFocus = shouldFocusThunk(event, this.container);
+ const { onChangeFocus, shouldFocus: shouldFocusFunc, disableClick, editMode } = this.props;
+ const shouldFocus = shouldFocusFunc(event, this.container);
+
+ if (!editMode) {
+ return;
+ }
- if (shouldFocus && !this.state.isFocused) {
+ if (!disableClick && shouldFocus && !this.state.isFocused) {
// if not focused, set focus and add a window event listener to capture outside clicks
// this enables us to not set a click listener for ever item on a dashboard
document.addEventListener('click', this.handleClick, true);
@@ -72,26 +81,28 @@ class WithPopoverMenu extends React.PureComponent {
}
render() {
- const { children, menuItems, disableClick } = this.props;
+ const { children, menuItems, editMode } = this.props;
const { isFocused } = this.state;
return (
<div
ref={this.setRef}
- onClick={!disableClick && this.handleClick}
+ onClick={this.handleClick}
role="none"
className={cx(
'with-popover-menu',
- isFocused && 'with-popover-menu--focused',
+ editMode && isFocused && 'with-popover-menu--focused',
)}
>
{children}
- {isFocused && menuItems.length ?
- <div className="popover-menu" >
- {menuItems.map((node, i) => (
- <div className="menu-item" key={`menu-item-${i}`}>{node}</div>
- ))}
- </div> : null}
+ {editMode &&
+ isFocused &&
+ menuItems.length > 0 &&
+ <div className="popover-menu" >
+ {menuItems.map((node, i) => (
+ <div className="menu-item" key={`menu-item-${i}`}>{node}</div>
+ ))}
+ </div>}
</div>
);
}
diff --git a/superset/assets/javascripts/dashboard/v2/components/resizable/ResizableContainer.jsx b/superset/assets/javascripts/dashboard/v2/components/resizable/ResizableContainer.jsx
index 0b1e975..a532ff0 100644
--- a/superset/assets/javascripts/dashboard/v2/components/resizable/ResizableContainer.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/resizable/ResizableContainer.jsx
@@ -28,6 +28,7 @@ const propTypes = {
onResizeStop: PropTypes.func,
onResize: PropTypes.func,
onResizeStart: PropTypes.func,
+ editMode: PropTypes.bool.isRequired,
};
const defaultProps = {
@@ -101,9 +102,9 @@ class ResizableContainer extends React.PureComponent {
if (onResizeStop) {
const nextWidthMultiple =
- widthMultiple + Math.floor(delta.width / (widthStep + gutterWidth));
+ widthMultiple + Math.round(delta.width / (widthStep + gutterWidth));
const nextHeightMultiple =
- heightMultiple + Math.ceil(delta.height / heightStep);
+ heightMultiple + Math.round(delta.height / heightStep);
onResizeStop({
id,
@@ -133,6 +134,7 @@ class ResizableContainer extends React.PureComponent {
minHeightMultiple,
maxHeightMultiple,
gutterWidth,
+ editMode,
} = this.props;
const size = {
@@ -148,6 +150,14 @@ class ResizableContainer extends React.PureComponent {
|| undefined,
};
+ if (!editMode) {
+ return (
+ <div style={{ ...size }}>
+ {children}
+ </div>
+ );
+ }
+
let enableConfig = resizableConfig.notAdjustable;
if (adjustableWidth && adjustableHeight) enableConfig = resizableConfig.widthAndHeight;
else if (adjustableWidth) enableConfig = resizableConfig.widthOnly;
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx
index 7ed5bfc..b8d717e 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx
@@ -7,9 +7,10 @@ import {
handleComponentDrop,
} from '../actions/dashboardLayout';
-function mapStateToProps({ dashboardLayout: undoableLayout }) {
+function mapStateToProps({ dashboardLayout: undoableLayout, editMode }) {
return {
dashboardLayout: undoableLayout.present,
+ editMode,
};
}
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx
index 7af3f5f..add5a6d 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx
@@ -25,13 +25,14 @@ const propTypes = {
handleComponentDrop: PropTypes.func.isRequired,
};
-function mapStateToProps({ dashboardLayout: undoableLayout, selectedTabs }, ownProps) {
+function mapStateToProps({ dashboardLayout: undoableLayout, editMode }, ownProps) {
const dashboardLayout = undoableLayout.present;
const { id, parentId } = ownProps;
const component = dashboardLayout[id];
const props = {
component,
parentComponent: dashboardLayout[parentId],
+ editMode,
};
// rows and columns need more data about their child dimensions
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardGrid.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardGrid.jsx
index ddb2fc0..67b2396 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardGrid.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardGrid.jsx
@@ -14,4 +14,4 @@ function mapDispatchToProps(dispatch) {
}, dispatch);
}
-export default connect(null, mapDispatchToProps)(DashboardGrid);
+export default connect(({ editMode }) => ({ editMode }), mapDispatchToProps)(DashboardGrid);
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx
index 985f9ee..8855d2c 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx
@@ -10,11 +10,14 @@ import {
handleComponentDrop,
} from '../actions/dashboardLayout';
-function mapStateToProps({ dashboardLayout: undoableLayout }) {
+import { setEditMode } from '../actions/editMode';
+
+function mapStateToProps({ dashboardLayout: undoableLayout, editMode }) {
return {
component: undoableLayout.present[DASHBOARD_HEADER_ID],
canUndo: undoableLayout.past.length > 0,
canRedo: undoableLayout.future.length > 0,
+ editMode,
};
}
@@ -24,6 +27,7 @@ function mapDispatchToProps(dispatch) {
handleComponentDrop,
onUndo: UndoActionCreators.undo,
onRedo: UndoActionCreators.redo,
+ setEditMode,
}, dispatch);
}
diff --git a/superset/assets/javascripts/dashboard/v2/reducers/editMode.js b/superset/assets/javascripts/dashboard/v2/reducers/editMode.js
new file mode 100644
index 0000000..b1a1630
--- /dev/null
+++ b/superset/assets/javascripts/dashboard/v2/reducers/editMode.js
@@ -0,0 +1,11 @@
+import { SET_EDIT_MODE } from '../actions/editMode';
+
+export default function editModeReducer(editMode = false, action) {
+ switch (action.type) {
+ case SET_EDIT_MODE:
+ return action.payload.editMode;
+
+ default:
+ return editMode;
+ }
+}
diff --git a/superset/assets/javascripts/dashboard/v2/reducers/index.js b/superset/assets/javascripts/dashboard/v2/reducers/index.js
index 994a1df..b824e9a 100644
--- a/superset/assets/javascripts/dashboard/v2/reducers/index.js
+++ b/superset/assets/javascripts/dashboard/v2/reducers/index.js
@@ -2,6 +2,7 @@ import { combineReducers } from 'redux';
import undoable, { distinctState } from 'redux-undo';
import dashboardLayout from './dashboardLayout';
+import editMode from './editMode';
const undoableLayout = undoable(dashboardLayout, {
limit: 15,
@@ -10,4 +11,5 @@ const undoableLayout = undoable(dashboardLayout, {
export default combineReducers({
dashboardLayout: undoableLayout,
+ editMode,
});
diff --git a/superset/assets/javascripts/dashboard/v2/stylesheets/builder.less b/superset/assets/javascripts/dashboard/v2/stylesheets/builder.less
index 206d63b..3651c57 100644
--- a/superset/assets/javascripts/dashboard/v2/stylesheets/builder.less
+++ b/superset/assets/javascripts/dashboard/v2/stylesheets/builder.less
@@ -14,7 +14,7 @@
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.1); /* @TODO color */
}
-.dashboard-builder {
+.dashboard-content {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
@@ -32,12 +32,12 @@
padding-left: 8px; /* note this is added to tab-level padding, to match header */
}
-.dashboard-builder .grid-container .dashboard-component-tabs {
+.dashboard-content .grid-container .dashboard-component-tabs {
box-shadow: none;
padding-left: 0;
}
-.dashboard-builder > div:first-child {
+.dashboard-content > div:first-child {
width: 100%;
flex-grow: 1;
position: relative;
diff --git a/superset/assets/javascripts/dashboard/v2/stylesheets/components/chart.less b/superset/assets/javascripts/dashboard/v2/stylesheets/components/chart.less
index 2bdf3cc..141c3e9 100644
--- a/superset/assets/javascripts/dashboard/v2/stylesheets/components/chart.less
+++ b/superset/assets/javascripts/dashboard/v2/stylesheets/components/chart.less
@@ -14,8 +14,6 @@
opacity: 0.3;
}
-.grid-container--resizing .dashboard-component-chart,
-.dashboard-builder--dragging .dashboard-component-chart,
-.dashboard-component-chart:hover {
+.dashboard-v2--editing .dashboard-component-chart:hover {
box-shadow: inset 0 0 0 1px @gray-light;
}
diff --git a/superset/assets/javascripts/dashboard/v2/stylesheets/components/column.less b/superset/assets/javascripts/dashboard/v2/stylesheets/components/column.less
index caf31e7..9565112 100644
--- a/superset/assets/javascripts/dashboard/v2/stylesheets/components/column.less
+++ b/superset/assets/javascripts/dashboard/v2/stylesheets/components/column.less
@@ -2,10 +2,27 @@
width: 100%;
}
+/* gutters between elements in a column */
.grid-column > :not(:only-child):not(.hover-menu):not(:last-child) {
margin-bottom: 16px;
}
+.dashboard-v2--editing .grid-column:after {
+ border: 1px dashed transparent;
+ content: "";
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 1px;
+ left: 0;
+ z-index: 1;
+ pointer-events: none;
+}
+
+.dashboard-v2--editing .grid-column:hover:after {
+ border: 1px solid @gray-light;
+}
+
.grid-column > .hover-menu--top {
top: -20px;
}
diff --git a/superset/assets/javascripts/dashboard/v2/stylesheets/components/divider.less b/superset/assets/javascripts/dashboard/v2/stylesheets/components/divider.less
index f1d3d86..9347a4e 100644
--- a/superset/assets/javascripts/dashboard/v2/stylesheets/components/divider.less
+++ b/superset/assets/javascripts/dashboard/v2/stylesheets/components/divider.less
@@ -1,6 +1,6 @@
.dashboard-component-divider {
width: 100%;
- padding: 24px 0; /* this is padding not margin to enable a larger mouse target */
+ padding: 16px 0; /* this is padding not margin to enable a larger mouse target */
background-color: transparent;
}
diff --git a/superset/assets/javascripts/dashboard/v2/stylesheets/components/row.less b/superset/assets/javascripts/dashboard/v2/stylesheets/components/row.less
index 30f14b8..956966d 100644
--- a/superset/assets/javascripts/dashboard/v2/stylesheets/components/row.less
+++ b/superset/assets/javascripts/dashboard/v2/stylesheets/components/row.less
@@ -7,10 +7,28 @@
height: fit-content;
}
+/* gutters between elements in a row */
.grid-row > :not(:only-child):not(:last-child):not(.hover-menu) {
margin-right: 16px;
}
+/* hover indicator */
+.dashboard-v2--editing .grid-row:after {
+ border: 1px dashed transparent;
+ content: "";
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 1px;
+ left: 0;
+ z-index: 1;
+ pointer-events: none;
+}
+
+.dashboard-v2--editing .grid-row:hover:after {
+ border: 1px solid @gray-light;
+}
+
.grid-row.grid-row--empty {
align-items: center; /* this centers the empty note content */
height: 80px;
diff --git a/superset/assets/javascripts/dashboard/v2/stylesheets/grid.less b/superset/assets/javascripts/dashboard/v2/stylesheets/grid.less
index 7c55dee..45b8a42 100644
--- a/superset/assets/javascripts/dashboard/v2/stylesheets/grid.less
+++ b/superset/assets/javascripts/dashboard/v2/stylesheets/grid.less
@@ -9,6 +9,11 @@
flex-direction: column;
}
+/* gutters between rows */
+.grid-content > div:not(:only-child):not(:last-child):not(.empty-grid-droptarget) {
+ margin-bottom: 16px;
+}
+
.empty-grid-droptarget {
width: 100%;
height: 100%;
@@ -33,22 +38,3 @@
pointer-events: none;
z-index: 10;
}
-
-
-.grid-container .grid-row:after,
-.grid-container .grid-column:after {
- border: 1px dashed transparent;
- content: "";
- position: absolute;
- width: 100%;
- height: 100%;
- top: 1px;
- left: 0;
- z-index: 1;
- pointer-events: none;
-}
-
-.grid-container .grid-row:hover:after,
-.grid-container .grid-column:hover:after {
- border: 1px solid @gray-light;
-}
--
To stop receiving notification emails like this one, please contact
ccwilliams@apache.org.