Skip to content

Commit

Permalink
Merge pull request #1 from williaster/chris--fixed-tabs
Browse files Browse the repository at this point in the history
[dashboard builder] sticky tabs, container hierarchy, undo-redo fixes
  • Loading branch information
Grace Guo authored May 7, 2018
2 parents 2717baf + 5c55dfe commit 4018398
Show file tree
Hide file tree
Showing 43 changed files with 789 additions and 437 deletions.
118 changes: 109 additions & 9 deletions superset/assets/src/dashboard/actions/dashboardLayout.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { ActionCreators as UndoActionCreators } from 'redux-undo';

import { addInfoToast } from './messageToasts';
import { setUnsavedChanges } from './dashboardState';
import { CHART_TYPE, MARKDOWN_TYPE, TABS_TYPE } from '../util/componentTypes';
import {
DASHBOARD_ROOT_ID,
NEW_COMPONENTS_SOURCE_ID,
GRID_MIN_COLUMN_COUNT,
DASHBOARD_HEADER_ID,
} from '../util/constants';
import dropOverflowsParent from '../util/dropOverflowsParent';
import findParentId from '../util/findParentId';

// Component CRUD -------------------------------------------------------------
export const UPDATE_COMPONENTS = 'UPDATE_COMPONENTS';
export function updateComponents(nextComponents) {
function updateLayoutComponents(nextComponents) {
return {
type: UPDATE_COMPONENTS,
payload: {
Expand All @@ -20,8 +23,34 @@ export function updateComponents(nextComponents) {
};
}

export function updateComponents(nextComponents) {
return (dispatch, getState) => {
dispatch(updateLayoutComponents(nextComponents));

if (!getState().dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
};
}

export function updateDashboardTitle(text) {
return (dispatch, getState) => {
const { dashboardLayout } = getState();
dispatch(
updateComponents({
[DASHBOARD_HEADER_ID]: {
...dashboardLayout.present[DASHBOARD_HEADER_ID],
meta: {
text,
},
},
}),
);
};
}

export const DELETE_COMPONENT = 'DELETE_COMPONENT';
export function deleteComponent(id, parentId) {
function deleteLayoutComponent(id, parentId) {
return {
type: DELETE_COMPONENT,
payload: {
Expand All @@ -31,8 +60,18 @@ export function deleteComponent(id, parentId) {
};
}

export function deleteComponent(id, parentId) {
return (dispatch, getState) => {
dispatch(deleteLayoutComponent(id, parentId));

if (!getState().dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
};
}

export const CREATE_COMPONENT = 'CREATE_COMPONENT';
export function createComponent(dropResult) {
function createLayoutComponent(dropResult) {
return {
type: CREATE_COMPONENT,
payload: {
Expand All @@ -41,9 +80,19 @@ export function createComponent(dropResult) {
};
}

export function createComponent(dropResult) {
return (dispatch, getState) => {
dispatch(createLayoutComponent(dropResult));

if (!getState().dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
};
}

// Tabs -----------------------------------------------------------------------
export const CREATE_TOP_LEVEL_TABS = 'CREATE_TOP_LEVEL_TABS';
export function createTopLevelTabs(dropResult) {
function createTopLevelTabsAction(dropResult) {
return {
type: CREATE_TOP_LEVEL_TABS,
payload: {
Expand All @@ -52,19 +101,39 @@ export function createTopLevelTabs(dropResult) {
};
}

export function createTopLevelTabs(dropResult) {
return (dispatch, getState) => {
dispatch(createTopLevelTabsAction(dropResult));

if (!getState().dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
};
}

export const DELETE_TOP_LEVEL_TABS = 'DELETE_TOP_LEVEL_TABS';
export function deleteTopLevelTabs() {
function deleteTopLevelTabsAction() {
return {
type: DELETE_TOP_LEVEL_TABS,
payload: {},
};
}

export function deleteTopLevelTabs(dropResult) {
return (dispatch, getState) => {
dispatch(deleteTopLevelTabsAction(dropResult));

if (!getState().dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
};
}

// Resize ---------------------------------------------------------------------
export const RESIZE_COMPONENT = 'RESIZE_COMPONENT';
export function resizeComponent({ id, width, height }) {
return (dispatch, getState) => {
const { dashboardLayout: undoableLayout } = getState();
const { dashboardLayout: undoableLayout, dashboardState } = getState();
const { present: dashboard } = undoableLayout;
const component = dashboard[id];
const widthChanged = width && component.meta.width !== width;
Expand Down Expand Up @@ -99,7 +168,9 @@ export function resizeComponent({ id, width, height }) {
});

dispatch(updateComponents(updatedComponents));
dispatch(setUnsavedChanges(true));
if (!dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
}
};
}
Expand Down Expand Up @@ -149,9 +220,10 @@ export function handleComponentDrop(dropResult) {
dispatch(moveComponent(dropResult));
}

const { dashboardLayout: undoableLayout, dashboardState } = getState();

// if we moved a Tab and the parent Tabs no longer has children, delete it.
if (!isNewComponent) {
const { dashboardLayout: undoableLayout } = getState();
const { present: layout } = undoableLayout;
const sourceComponent = layout[source.id];

Expand All @@ -167,8 +239,36 @@ export function handleComponentDrop(dropResult) {
}
}

dispatch(setUnsavedChanges(true));
if (!dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}

return null;
};
}

// Undo redo ------------------------------------------------------------------
export function undoLayoutAction() {
return (dispatch, getState) => {
dispatch(UndoActionCreators.undo());

const { dashboardLayout, dashboardState } = getState();

if (
dashboardLayout.past.length === 0 &&
!dashboardState.maxUndoHistoryExceeded
) {
dispatch(setUnsavedChanges(false));
}
};
}

export function redoLayoutAction() {
return (dispatch, getState) => {
dispatch(UndoActionCreators.redo());

if (!getState().dashboardState.hasUnsavedChanges) {
dispatch(setUnsavedChanges(true));
}
};
}
43 changes: 35 additions & 8 deletions superset/assets/src/dashboard/actions/dashboardState.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint camelcase: 0 */
import $ from 'jquery';
import { ActionCreators as UndoActionCreators } from 'redux-undo';

import { addChart, removeChart, refreshChart } from '../../chart/chartAction';
import { chart as initChart } from '../../chart/chartReducer';
import { fetchDatasourceMetadata } from '../../dashboard/actions/datasources';
import { applyDefaultFormData } from '../../explore/stores/store';
import { addWarningToast } from './messageToasts';

export const SET_UNSAVED_CHANGES = 'SET_UNSAVED_CHANGES';
export function setUnsavedChanges(hasUnsavedChanges) {
Expand All @@ -21,11 +23,6 @@ export function removeFilter(sliceId, col, vals, refresh = true) {
return { type: REMOVE_FILTER, sliceId, col, vals, refresh };
}

export const UPDATE_DASHBOARD_TITLE = 'UPDATE_DASHBOARD_TITLE';
export function updateDashboardTitle(title) {
return { type: UPDATE_DASHBOARD_TITLE, title };
}

export const ADD_SLICE = 'ADD_SLICE';
export function addSlice(slice) {
return { type: ADD_SLICE, slice };
Expand Down Expand Up @@ -84,6 +81,14 @@ export function onSave() {
return { type: ON_SAVE };
}

export function saveDashboard() {
return dispatch => {
dispatch(onSave());
// clear layout undo history
dispatch(UndoActionCreators.clearHistory());
};
}

export function fetchCharts(chartList = [], force = false, interval = 0) {
return (dispatch, getState) => {
const timeout = getState().dashboardInfo.common.conf
Expand Down Expand Up @@ -168,9 +173,31 @@ export function addSliceToDashboard(id) {
};
}

export function removeSliceFromDashboard(chart) {
export function removeSliceFromDashboard(id) {
return dispatch => {
dispatch(removeSlice(chart.id));
dispatch(removeChart(chart.id));
dispatch(removeSlice(id));
dispatch(removeChart(id));
};
}

// Undo history ---------------------------------------------------------------
export const SET_MAX_UNDO_HISTORY_EXCEEDED = 'SET_MAX_UNDO_HISTORY_EXCEEDED';
export function setMaxUndoHistoryExceeded(maxUndoHistoryExceeded = true) {
return {
type: SET_MAX_UNDO_HISTORY_EXCEEDED,
payload: { maxUndoHistoryExceeded },
};
}

export function maxUndoHistoryToast() {
return (dispatch, getState) => {
const { dashboardLayout } = getState();
const historyLength = dashboardLayout.past.length;

return dispatch(
addWarningToast(
`You have used all ${historyLength} undo slots and will not be able to fully undo subsequent actions. You may save your current state to reset the history.`,
),
);
};
}
35 changes: 0 additions & 35 deletions superset/assets/src/dashboard/actions/sliceEntities.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,6 @@
/* eslint camelcase: 0 */
/* global notify */
import $ from 'jquery';

export const UPDATE_SLICE_NAME = 'UPDATE_SLICE_NAME';
export function updateSliceName(key, sliceName) {
return { type: UPDATE_SLICE_NAME, key, sliceName };
}

export function saveSliceName(slice, sliceName) {
const oldName = slice.slice_name;
return dispatch => {
const sliceParams = {};
sliceParams.slice_id = slice.slice_id;
sliceParams.action = 'overwrite';
sliceParams.slice_name = sliceName;

const url = `${slice.slice_url}&${Object.keys(sliceParams)
.map(key => `${key}=${sliceParams[key]}`)
.join('&')}`;
const key = slice.slice_id;
return $.ajax({
url,
type: 'POST',
success: () => {
dispatch(updateSliceName(key, sliceName));
notify.success('This slice name was saved successfully.');
},
error: () => {
// if server-side reject the overwrite action,
// revert to old state
dispatch(updateSliceName(key, oldName));
notify.error("You don't have the rights to alter this slice");
},
});
};
}

export const SET_ALL_SLICES = 'SET_ALL_SLICES';
export function setAllSlices(slices) {
return { type: SET_ALL_SLICES, slices };
Expand Down
Loading

0 comments on commit 4018398

Please sign in to comment.