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/03/16 06:46:49 UTC

[incubator-superset] branch chris--top-level-tabs updated: [undo-redo] add redux undo redo

This is an automated email from the ASF dual-hosted git repository.

ccwilliams pushed a commit to branch chris--top-level-tabs
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/chris--top-level-tabs by this push:
     new 43d6ec7  [undo-redo] add redux undo redo
43d6ec7 is described below

commit 43d6ec7000244966bafb8cef029a995b7f0ac0eb
Author: Chris Williams <ch...@airbnb.com>
AuthorDate: Thu Mar 15 23:46:32 2018 -0700

    [undo-redo] add redux undo redo
---
 superset/assets/javascripts/dashboard/index.jsx    |  6 +++++-
 .../javascripts/dashboard/v2/actions/index.js      |  3 ++-
 .../dashboard/v2/components/DashboardHeader.jsx    | 25 ++++++++++++++++++++--
 .../dashboard/v2/containers/DashboardBuilder.jsx   |  4 ++--
 .../dashboard/v2/containers/DashboardComponent.jsx |  3 ++-
 .../dashboard/v2/containers/DashboardHeader.jsx    |  9 ++++++--
 .../javascripts/dashboard/v2/reducers/index.js     |  9 +++++++-
 superset/assets/package.json                       |  1 +
 8 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/superset/assets/javascripts/dashboard/index.jsx b/superset/assets/javascripts/dashboard/index.jsx
index f3480d3..bb21a43 100644
--- a/superset/assets/javascripts/dashboard/index.jsx
+++ b/superset/assets/javascripts/dashboard/index.jsx
@@ -20,7 +20,11 @@ const appContainer = document.getElementById('app');
 // const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
 // const initState = Object.assign({}, getInitialState(bootstrapData));
 const initState = {
-  dashboard: emptyDashboardLayout,
+  dashboard: {
+    past: [],
+    present: emptyDashboardLayout,
+    future: [],
+  },
 };
 
 const store = createStore(
diff --git a/superset/assets/javascripts/dashboard/v2/actions/index.js b/superset/assets/javascripts/dashboard/v2/actions/index.js
index effdeeb..99ce5f3 100644
--- a/superset/assets/javascripts/dashboard/v2/actions/index.js
+++ b/superset/assets/javascripts/dashboard/v2/actions/index.js
@@ -87,7 +87,8 @@ export function handleComponentDrop(dropResult) {
     }
 
     if (source) {
-      const { dashboard } = getState();
+      const { dashboard: undoableDashboard } = getState();
+      const { present: dashboard } = undoableDashboard;
       const sourceComponent = dashboard[source.droppableId];
 
       if (sourceComponent.type === TABS_TYPE && sourceComponent.children.length === 0) {
diff --git a/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx b/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx
index f65e55a..e0d14c4 100644
--- a/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx
+++ b/superset/assets/javascripts/dashboard/v2/components/DashboardHeader.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { ButtonToolbar, DropdownButton, MenuItem } from 'react-bootstrap';
+import { ButtonGroup, ButtonToolbar, DropdownButton, MenuItem } from 'react-bootstrap';
 
 import Button from '../../../components/Button';
 import { componentShape } from '../util/propShapes';
@@ -13,6 +13,10 @@ const propTypes = {
 
   // redux
   updateComponents: PropTypes.func.isRequired,
+  onUndo: PropTypes.func.isRequired,
+  onRedo: PropTypes.func.isRequired,
+  canUndo: PropTypes.bool.isRequired,
+  canRedo: PropTypes.bool.isRequired,
 };
 
 class DashboardHeader extends React.Component {
@@ -43,7 +47,7 @@ class DashboardHeader extends React.Component {
   }
 
   render() {
-    const { component } = this.props;
+    const { component, onUndo, onRedo, canUndo, canRedo } = this.props;
     const editMode = true;
 
     return (
@@ -57,6 +61,23 @@ class DashboardHeader extends React.Component {
           />
         </h1>
         <ButtonToolbar>
+          <ButtonGroup>
+            <Button
+              bsSize="small"
+              onClick={onUndo}
+              disabled={!canUndo}
+            >
+              Undo
+            </Button>
+            <Button
+              bsSize="small"
+              onClick={onRedo}
+              disabled={!canRedo}
+            >
+              Redo
+            </Button>
+          </ButtonGroup>
+
           <DropdownButton title="Actions" bsSize="small" id="btn-dashboard-actions">
             <MenuItem>Action 1</MenuItem>
             <MenuItem>Action 2</MenuItem>
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx
index 5505f20..48305ef 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardBuilder.jsx
@@ -8,9 +8,9 @@ import {
   handleComponentDrop,
 } from '../actions';
 
-function mapStateToProps({ dashboard = {} }) {
+function mapStateToProps({ dashboard: undoableDashboard }) {
   return {
-    dashboard,
+    dashboard: undoableDashboard.present,
   };
 }
 
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx
index 1340781..df18233 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardComponent.jsx
@@ -24,7 +24,8 @@ const propTypes = {
   handleComponentDrop: PropTypes.func.isRequired,
 };
 
-function mapStateToProps({ dashboard = {} }, ownProps) {
+function mapStateToProps({ dashboard: undoableDashboard }, ownProps) {
+  const dashboard = undoableDashboard.present;
   const { id, parentId } = ownProps;
   const props = {
     component: dashboard[id],
diff --git a/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx b/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx
index 1356057..52e7e7a 100644
--- a/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx
+++ b/superset/assets/javascripts/dashboard/v2/containers/DashboardHeader.jsx
@@ -1,3 +1,4 @@
+import { ActionCreators as UndoActionCreators } from 'redux-undo'
 import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
 
@@ -9,9 +10,11 @@ import {
   handleComponentDrop,
 } from '../actions';
 
-function mapStateToProps({ dashboard }) {
+function mapStateToProps({ dashboard: undoableDashboard }) {
   return {
-    component: dashboard[DASHBOARD_HEADER_ID],
+    component: undoableDashboard.present[DASHBOARD_HEADER_ID],
+    canUndo: undoableDashboard.past.length > 0,
+    canRedo: undoableDashboard.future.length > 0,
   };
 }
 
@@ -19,6 +22,8 @@ function mapDispatchToProps(dispatch) {
   return bindActionCreators({
     updateComponents,
     handleComponentDrop,
+    onUndo: UndoActionCreators.undo,
+    onRedo: UndoActionCreators.redo,
   }, dispatch);
 }
 
diff --git a/superset/assets/javascripts/dashboard/v2/reducers/index.js b/superset/assets/javascripts/dashboard/v2/reducers/index.js
index 103fda0..9c0575e 100644
--- a/superset/assets/javascripts/dashboard/v2/reducers/index.js
+++ b/superset/assets/javascripts/dashboard/v2/reducers/index.js
@@ -1,6 +1,13 @@
 import { combineReducers } from 'redux';
+import undoable, { distinctState } from 'redux-undo';
+
 import dashboard from './dashboard';
 
+const undoableDashboard = undoable(dashboard, {
+  limit: 10,
+  filter: distinctState(),
+});
+
 export default combineReducers({
-  dashboard,
+  dashboard: undoableDashboard,
 });
diff --git a/superset/assets/package.json b/superset/assets/package.json
index d2a2022..cd6e9e3 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -107,6 +107,7 @@
     "redux": "^3.5.2",
     "redux-localstorage": "^0.4.1",
     "redux-thunk": "^2.1.0",
+    "redux-undo": "^0.6.1",
     "shortid": "^2.2.6",
     "sprintf-js": "^1.1.1",
     "srcdoc-polyfill": "^1.0.0",

-- 
To stop receiving notification emails like this one, please contact
ccwilliams@apache.org.