From commits-return-910-archive-asf-public=cust-asf.ponee.io@superset.incubator.apache.org Thu Apr 19 02:05:04 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id A3160180792 for ; Thu, 19 Apr 2018 02:05:01 +0200 (CEST) Received: (qmail 895 invoked by uid 500); 19 Apr 2018 00:05:00 -0000 Mailing-List: contact commits-help@superset.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@superset.incubator.apache.org Delivered-To: mailing list commits@superset.incubator.apache.org Received: (qmail 877 invoked by uid 99); 19 Apr 2018 00:05:00 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 19 Apr 2018 00:05:00 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id 2BF7382FEB; Thu, 19 Apr 2018 00:04:59 +0000 (UTC) Date: Thu, 19 Apr 2018 00:04:59 +0000 To: "commits@superset.apache.org" Subject: [incubator-superset] 04/05: [dashboard builder] static layout + toasts (#4763) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit From: ccwilliams@apache.org In-Reply-To: <152409629510.21509.5183236418937626696@gitbox.apache.org> References: <152409629510.21509.5183236418937626696@gitbox.apache.org> X-Git-Host: gitbox.apache.org X-Git-Repo: incubator-superset X-Git-Refname: refs/heads/dashboard-builder X-Git-Reftype: branch X-Git-Rev: 0656955b9a52af8e527d492dcc7f4837ad33c151 X-Git-NotificationType: diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated Message-Id: <20180419000459.2BF7382FEB@gitbox.apache.org> This is an automated email from the ASF dual-hosted git repository. ccwilliams pushed a commit to branch dashboard-builder in repository https://gitbox.apache.org/repos/asf/incubator-superset.git commit 0656955b9a52af8e527d492dcc7f4837ad33c151 Author: Chris Williams AuthorDate: Wed Apr 4 17:34:11 2018 -0700 [dashboard builder] static layout + toasts (#4763) * [dashboard-builder] remove spacer component * [dashboard-builder] better transparent indicator, better grid gutter logic, no dragging top-level tabs, headers are multiples of grid unit, fix row height granularity, update redux state key dashboard => dashboardLayout * [dashboard-builder] don't blast column child dimensions on resize * [dashboard-builder] ResizableContainer min size can't be smaller than size, fix row style, role=none on WithPopoverMenu container * [edit mode] add edit mode to redux and propogate to all s * [toasts] add Toast component, ToastPresenter container and component, and toast redux actions + reducers * [dashboard-builder] add info toast when dropResult overflows parent --- .../v2/actions/{index.js => dashboardLayout.js} | 35 +++--- .../javascripts/dashboard/v2/actions/editMode.js | 9 ++ .../dashboard/v2/actions/messageToasts.js | 49 ++++++++ .../v2/components/BuilderComponentPane.jsx | 2 - .../dashboard/v2/components/DashboardBuilder.jsx | 28 +++-- .../dashboard/v2/components/DashboardGrid.jsx | 10 +- .../dashboard/v2/components/DashboardHeader.jsx | 14 +-- .../javascripts/dashboard/v2/components/Toast.jsx | 87 ++++++++++++++ .../dashboard/v2/components/ToastPresenter.jsx | 39 +++++++ .../dashboard/v2/components/dnd/DragDroppable.jsx | 4 + .../dashboard/v2/components/dnd/handleDrop.js | 2 +- .../v2/components/gridComponents/Chart.jsx | 17 +-- .../v2/components/gridComponents/Column.jsx | 75 +++++------- .../v2/components/gridComponents/Divider.jsx | 10 +- .../v2/components/gridComponents/Header.jsx | 13 ++- .../dashboard/v2/components/gridComponents/Row.jsx | 69 +++++------ .../v2/components/gridComponents/Spacer.jsx | 106 ----------------- .../dashboard/v2/components/gridComponents/Tab.jsx | 18 ++- .../v2/components/gridComponents/Tabs.jsx | 39 ++++--- .../v2/components/gridComponents/index.js | 4 - .../gridComponents/new/DraggableNewComponent.jsx | 1 + .../v2/components/gridComponents/new/NewSpacer.jsx | 24 ---- .../v2/components/menu/WithPopoverMenu.jsx | 40 ++++--- .../v2/components/resizable/ResizableContainer.jsx | 32 ++++-- .../dashboard/v2/containers/DashboardBuilder.jsx | 7 +- .../dashboard/v2/containers/DashboardComponent.jsx | 17 +-- .../dashboard/v2/containers/DashboardGrid.jsx | 4 +- .../dashboard/v2/containers/DashboardHeader.jsx | 16 ++- .../dashboard/v2/containers/ToastPresenter.jsx | 10 ++ .../reducers/{dashboard.js => dashboardLayout.js} | 5 +- .../javascripts/dashboard/v2/reducers/editMode.js | 11 ++ .../javascripts/dashboard/v2/reducers/index.js | 12 +- .../dashboard/v2/reducers/messageToasts.js | 18 +++ .../dashboard/v2/stylesheets/builder.less | 14 ++- .../v2/stylesheets/components/DashboardBuilder.jsx | 127 --------------------- .../dashboard/v2/stylesheets/components/chart.less | 4 +- .../v2/stylesheets/components/column.less | 30 +++-- .../v2/stylesheets/components/divider.less | 2 +- .../v2/stylesheets/components/header.less | 28 ++++- .../dashboard/v2/stylesheets/components/index.less | 1 - .../v2/stylesheets/components/new-component.less | 12 -- .../dashboard/v2/stylesheets/components/row.less | 23 ++-- .../v2/stylesheets/components/spacer.less | 13 --- .../javascripts/dashboard/v2/stylesheets/grid.less | 24 +--- .../dashboard/v2/stylesheets/index.less | 1 + .../dashboard/v2/stylesheets/popover-menu.less | 4 +- .../dashboard/v2/stylesheets/resizable.less | 16 +-- .../dashboard/v2/stylesheets/toast.less | 59 ++++++++++ .../dashboard/v2/stylesheets/variables.less | 8 ++ .../dashboard/v2/util/componentIsResizable.js | 2 - .../dashboard/v2/util/componentTypes.js | 2 - .../javascripts/dashboard/v2/util/constants.js | 8 +- .../dashboard/v2/util/dropOverflowsParent.js | 24 ++++ .../javascripts/dashboard/v2/util/getChildWidth.js | 5 +- .../dashboard/v2/util/getDropPosition.js | 2 + .../javascripts/dashboard/v2/util/isValidChild.js | 11 +- .../dashboard/v2/util/newComponentFactory.js | 6 +- .../dashboard/v2/util/newComponentIdToType.js | 35 ------ .../javascripts/dashboard/v2/util/propShapes.jsx | 7 ++ superset/assets/src/components/EditableTitle.jsx | 16 ++- superset/assets/src/dashboard/index.jsx | 5 +- superset/assets/stylesheets/superset.less | 29 +++-- 62 files changed, 715 insertions(+), 630 deletions(-) diff --git a/superset/assets/javascripts/dashboard/v2/actions/index.js b/superset/assets/javascripts/dashboard/v2/actions/dashboardLayout.js similarity index 79% rename from superset/assets/javascripts/dashboard/v2/actions/index.js rename to superset/assets/javascripts/dashboard/v2/actions/dashboardLayout.js index a6c7b77..b6d41c4 100644 --- a/superset/assets/javascripts/dashboard/v2/actions/index.js +++ b/superset/assets/javascripts/dashboard/v2/actions/dashboardLayout.js @@ -1,10 +1,8 @@ +import { addInfoToast } from './messageToasts'; +import { CHART_TYPE, MARKDOWN_TYPE, TABS_TYPE } from '../util/componentTypes'; import { DASHBOARD_ROOT_ID, NEW_COMPONENTS_SOURCE_ID } from '../util/constants'; +import dropOverflowsParent from '../util/dropOverflowsParent'; import findParentId from '../util/findParentId'; -import { - CHART_TYPE, - MARKDOWN_TYPE, - TABS_TYPE, -} from '../util/componentTypes'; // Component CRUD ------------------------------------------------------------- export const UPDATE_COMPONENTS = 'UPDATE_COMPONENTS'; @@ -61,8 +59,8 @@ export function deleteTopLevelTabs() { export const RESIZE_COMPONENT = 'RESIZE_COMPONENT'; export function resizeComponent({ id, width, height }) { return (dispatch, getState) => { - const { dashboard: undoableDashboard } = getState(); - const { present: dashboard } = undoableDashboard; + const { dashboardLayout: undoableLayout } = getState(); + const { present: dashboard } = undoableLayout; const component = dashboard[id]; if ( @@ -88,8 +86,8 @@ export function resizeComponent({ id, width, height }) { ...child, meta: { ...child.meta, - width: width || component.meta.width, - height: height || component.meta.height, + width: width || child.meta.width, + height: height || child.meta.height, }, }; } @@ -114,6 +112,15 @@ export function moveComponent(dropResult) { export const HANDLE_COMPONENT_DROP = 'HANDLE_COMPONENT_DROP'; export function handleComponentDrop(dropResult) { return (dispatch, getState) => { + const overflowsParent = dropOverflowsParent(dropResult, getState().dashboardLayout.present); + + if (overflowsParent) { + return dispatch(addInfoToast( + `Parent does not have enough space for this component. + Try decreasing its width or add it to a new row.`, + )); + } + const { source, destination } = dropResult; const droppedOnRoot = destination && destination.id === DASHBOARD_ROOT_ID; const isNewComponent = source.id === NEW_COMPONENTS_SOURCE_ID; @@ -133,14 +140,14 @@ export function handleComponentDrop(dropResult) { dispatch(moveComponent(dropResult)); } - // if we moved a tab and the parent tabs no longer has children, delete it. + // if we moved a Tab and the parent Tabs no longer has children, delete it. if (!isNewComponent) { - const { dashboard: undoableDashboard } = getState(); - const { present: dashboard } = undoableDashboard; - const sourceComponent = dashboard[source.id]; + const { dashboardLayout: undoableLayout } = getState(); + const { present: layout } = undoableLayout; + const sourceComponent = layout[source.id]; if (sourceComponent.type === TABS_TYPE && sourceComponent.children.length === 0) { - const parentId = findParentId({ childId: source.id, components: dashboard }); + const parentId = findParentId({ childId: source.id, components: layout }); dispatch(deleteComponent(source.id, parentId)); } } 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/actions/messageToasts.js b/superset/assets/javascripts/dashboard/v2/actions/messageToasts.js new file mode 100644 index 0000000..af10ead --- /dev/null +++ b/superset/assets/javascripts/dashboard/v2/actions/messageToasts.js @@ -0,0 +1,49 @@ +import { INFO_TOAST, SUCCESS_TOAST, WARNING_TOAST, DANGER_TOAST } from '../util/constants'; + +function getToastUuid(type) { + return `${Math.random().toString(16).slice(2)}-${type}-${Math.random().toString(16).slice(2)}`; +} + +export const ADD_TOAST = 'ADD_TOAST'; +export function addToast({ toastType, text }) { + debugger; + return { + type: ADD_TOAST, + payload: { + id: getToastUuid(toastType), + toastType, + text, + }, + }; +} + +export const REMOVE_TOAST = 'REMOVE_TOAST'; +export function removeToast(id) { + return { + type: REMOVE_TOAST, + payload: { + id, + }, + }; +} + +// Different types of toasts +export const ADD_INFO_TOAST = 'ADD_INFO_TOAST'; +export function addInfoToast(text) { + return dispatch => dispatch(addToast({ text, toastType: INFO_TOAST })); +} + +export const ADD_SUCCESS_TOAST = 'ADD_SUCCESS_TOAST'; +export function addSuccessToast(text) { + return dispatch => dispatch(addToast({ text, toastType: SUCCESS_TOAST })); +} + +export const ADD_WARNING_TOAST = 'ADD_WARNING_TOAST'; +export function addWarningToast(text) { + return dispatch => dispatch(addToast({ text, toastType: WARNING_TOAST })); +} + +export const ADD_DANGER_TOAST = 'ADD_DANGER_TOAST'; +export function addDangerToast(text) { + return dispatch => dispatch(addToast({ text, toastType: DANGER_TOAST })); +} diff --git a/superset/assets/javascripts/dashboard/v2/components/BuilderComponentPane.jsx b/superset/assets/javascripts/dashboard/v2/components/BuilderComponentPane.jsx index 86f3788..efef5a5 100644 --- a/superset/assets/javascripts/dashboard/v2/components/BuilderComponentPane.jsx +++ b/superset/assets/javascripts/dashboard/v2/components/BuilderComponentPane.jsx @@ -6,7 +6,6 @@ import NewColumn from './gridComponents/new/NewColumn'; import NewDivider from './gridComponents/new/NewDivider'; import NewHeader from './gridComponents/new/NewHeader'; import NewRow from './gridComponents/new/NewRow'; -import NewSpacer from './gridComponents/new/NewSpacer'; import NewTabs from './gridComponents/new/NewTabs'; const propTypes = { @@ -24,7 +23,6 @@ class BuilderComponentPane extends React.PureComponent { - diff --git a/superset/assets/javascripts/dashboard/v2/components/DashboardBuilder.jsx b/superset/assets/javascripts/dashboard/v2/components/DashboardBuilder.jsx index f371718..8e2d985 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'; @@ -9,6 +10,7 @@ import DashboardGrid from '../containers/DashboardGrid'; import IconButton from './IconButton'; import DragDroppable from './dnd/DragDroppable'; import DashboardComponent from '../containers/DashboardComponent'; +import ToastPresenter from '../containers/ToastPresenter'; import WithPopoverMenu from './menu/WithPopoverMenu'; import { @@ -18,11 +20,10 @@ import { } from '../util/constants'; const propTypes = { - editMode: PropTypes.bool, - // redux - dashboard: PropTypes.object.isRequired, + dashboardLayout: PropTypes.object.isRequired, deleteTopLevelTabs: PropTypes.func.isRequired, + editMode: PropTypes.bool.isRequired, handleComponentDrop: PropTypes.func.isRequired, }; @@ -52,20 +53,20 @@ class DashboardBuilder extends React.Component { render() { const { tabIndex } = this.state; - const { handleComponentDrop, dashboard, deleteTopLevelTabs } = this.props; - const dashboardRoot = dashboard[DASHBOARD_ROOT_ID]; + const { handleComponentDrop, dashboardLayout, deleteTopLevelTabs, editMode } = this.props; + const dashboardRoot = dashboardLayout[DASHBOARD_ROOT_ID]; const rootChildId = dashboardRoot.children[0]; - const topLevelTabs = rootChildId !== DASHBOARD_GRID_ID && dashboard[rootChildId]; + const topLevelTabs = rootChildId !== DASHBOARD_GRID_ID && dashboardLayout[rootChildId]; const gridComponentId = topLevelTabs ? topLevelTabs.children[Math.min(topLevelTabs.children.length - 1, tabIndex)] : DASHBOARD_GRID_ID; - const gridComponent = dashboard[gridComponentId]; + const gridComponent = dashboardLayout[gridComponentId]; return ( -
- {topLevelTabs ? ( // you cannot drop on/displace tabs if they already exist +
+ {topLevelTabs || !editMode ? ( // you cannot drop on/displace tabs if they already exist ) : ( {({ dropIndicatorProps }) => (
@@ -94,6 +96,7 @@ class DashboardBuilder extends React.Component { onClick={deleteTopLevelTabs} />, ]} + editMode={editMode} > } -
+
- + {editMode && }
+
); } 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 && {({ dropIndicatorProps }) => dropIndicatorProps && -
} +
} } {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 e0d14c4..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,19 +46,18 @@ 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 (
-

+
-

+