mirror of
https://github.com/apache/superset.git
synced 2024-09-18 19:49:37 -04:00
feat(dashboard): Implement empty states for empty tabs (#19408)
* feat(dashboard): Implement empty states in empty tabs * Change button to in text link * Add edit dashboard button to dashboard empty state * Add tests * Fix test
This commit is contained in:
parent
11bf0d09cb
commit
fc8cb22376
@ -58,6 +58,15 @@ const EmptyStateContainer = styled.div`
|
|||||||
& .ant-empty-image svg {
|
& .ant-empty-image svg {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& a,
|
||||||
|
& span[role='button'] {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
&:hover {
|
||||||
|
color: ${theme.colors.grayscale.base};
|
||||||
|
}
|
||||||
|
}
|
||||||
`}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -34,7 +34,10 @@ import getDirectPathToTabIndex from 'src/dashboard/util/getDirectPathToTabIndex'
|
|||||||
import { URL_PARAMS } from 'src/constants';
|
import { URL_PARAMS } from 'src/constants';
|
||||||
import { getUrlParam } from 'src/utils/urlUtils';
|
import { getUrlParam } from 'src/utils/urlUtils';
|
||||||
import { DashboardLayout, RootState } from 'src/dashboard/types';
|
import { DashboardLayout, RootState } from 'src/dashboard/types';
|
||||||
import { setDirectPathToChild } from 'src/dashboard/actions/dashboardState';
|
import {
|
||||||
|
setDirectPathToChild,
|
||||||
|
setEditMode,
|
||||||
|
} from 'src/dashboard/actions/dashboardState';
|
||||||
import { useElementOnScreen } from 'src/hooks/useElementOnScreen';
|
import { useElementOnScreen } from 'src/hooks/useElementOnScreen';
|
||||||
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||||
import {
|
import {
|
||||||
@ -398,6 +401,8 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
|
|||||||
'Go to the edit mode to configure the dashboard and add charts',
|
'Go to the edit mode to configure the dashboard and add charts',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
buttonText={canEdit && t('Edit the dashboard')}
|
||||||
|
buttonAction={() => dispatch(setEditMode(true))}
|
||||||
image="dashboard.svg"
|
image="dashboard.svg"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -24,6 +24,7 @@ import { componentShape } from '../util/propShapes';
|
|||||||
import DashboardComponent from '../containers/DashboardComponent';
|
import DashboardComponent from '../containers/DashboardComponent';
|
||||||
import DragDroppable from './dnd/DragDroppable';
|
import DragDroppable from './dnd/DragDroppable';
|
||||||
import { GRID_GUTTER_SIZE, GRID_COLUMN_COUNT } from '../util/constants';
|
import { GRID_GUTTER_SIZE, GRID_COLUMN_COUNT } from '../util/constants';
|
||||||
|
import { TAB_TYPE } from '../util/componentTypes';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
depth: PropTypes.number.isRequired,
|
depth: PropTypes.number.isRequired,
|
||||||
@ -137,9 +138,11 @@ class DashboardGrid extends React.PureComponent {
|
|||||||
gridComponent,
|
gridComponent,
|
||||||
handleComponentDrop,
|
handleComponentDrop,
|
||||||
depth,
|
depth,
|
||||||
editMode,
|
|
||||||
width,
|
width,
|
||||||
isComponentVisible,
|
isComponentVisible,
|
||||||
|
editMode,
|
||||||
|
canEdit,
|
||||||
|
setEditMode,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const columnPlusGutterWidth =
|
const columnPlusGutterWidth =
|
||||||
(width + GRID_GUTTER_SIZE) / GRID_COLUMN_COUNT;
|
(width + GRID_GUTTER_SIZE) / GRID_COLUMN_COUNT;
|
||||||
@ -147,26 +150,70 @@ class DashboardGrid extends React.PureComponent {
|
|||||||
const columnWidth = columnPlusGutterWidth - GRID_GUTTER_SIZE;
|
const columnWidth = columnPlusGutterWidth - GRID_GUTTER_SIZE;
|
||||||
const { isResizing, rowGuideTop } = this.state;
|
const { isResizing, rowGuideTop } = this.state;
|
||||||
|
|
||||||
|
const shouldDisplayEmptyState = gridComponent?.children?.length === 0;
|
||||||
|
const shouldDisplayTopLevelTabEmptyState =
|
||||||
|
shouldDisplayEmptyState && gridComponent.type === TAB_TYPE;
|
||||||
|
|
||||||
|
const dashboardEmptyState = editMode && (
|
||||||
|
<EmptyStateBig
|
||||||
|
title={t('Drag and drop components and charts to the dashboard')}
|
||||||
|
description={t(
|
||||||
|
'You can create a new chart or use existing ones from the panel on the right',
|
||||||
|
)}
|
||||||
|
buttonText={
|
||||||
|
<>
|
||||||
|
<i className="fa fa-plus" />
|
||||||
|
{t('Create a new chart')}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
buttonAction={() => {
|
||||||
|
window.open('/chart/add', '_blank', 'noopener noreferrer');
|
||||||
|
}}
|
||||||
|
image="chart.svg"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const topLevelTabEmptyState = editMode ? (
|
||||||
|
<EmptyStateBig
|
||||||
|
title={t('Drag and drop components to this tab')}
|
||||||
|
description={t(
|
||||||
|
`You can create a new chart or use existing ones from the panel on the right`,
|
||||||
|
)}
|
||||||
|
buttonText={
|
||||||
|
<>
|
||||||
|
<i className="fa fa-plus" />
|
||||||
|
{t('Create a new chart')}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
buttonAction={() => {
|
||||||
|
window.open('/chart/add', '_blank', 'noopener noreferrer');
|
||||||
|
}}
|
||||||
|
image="chart.svg"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<EmptyStateBig
|
||||||
|
title={t('There are no components added to this tab')}
|
||||||
|
description={
|
||||||
|
canEdit && t('You can add the components in the edit mode.')
|
||||||
|
}
|
||||||
|
buttonText={canEdit && t('Edit the dashboard')}
|
||||||
|
buttonAction={
|
||||||
|
canEdit &&
|
||||||
|
(() => {
|
||||||
|
setEditMode(true);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
image="chart.svg"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return width < 100 ? null : (
|
return width < 100 ? null : (
|
||||||
<>
|
<>
|
||||||
{editMode && gridComponent?.children?.length === 0 && (
|
{shouldDisplayEmptyState && (
|
||||||
<DashboardEmptyStateContainer>
|
<DashboardEmptyStateContainer>
|
||||||
<EmptyStateBig
|
{shouldDisplayTopLevelTabEmptyState
|
||||||
title={t('Drag and drop components and charts to the dashboard')}
|
? topLevelTabEmptyState
|
||||||
description={t(
|
: dashboardEmptyState}
|
||||||
'You can create new charts or use existing ones from the panel on the right',
|
|
||||||
)}
|
|
||||||
buttonText={
|
|
||||||
<>
|
|
||||||
<i className="fa fa-plus" />
|
|
||||||
{t('Create a new chart')}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
buttonAction={() => {
|
|
||||||
window.location.assign('/chart/add');
|
|
||||||
}}
|
|
||||||
image="chart.svg"
|
|
||||||
/>
|
|
||||||
</DashboardEmptyStateContainer>
|
</DashboardEmptyStateContainer>
|
||||||
)}
|
)}
|
||||||
<div className="dashboard-grid" ref={this.setGridRef}>
|
<div className="dashboard-grid" ref={this.setGridRef}>
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { styled } from '@superset-ui/core';
|
import { bindActionCreators } from 'redux';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { styled, t } from '@superset-ui/core';
|
||||||
|
|
||||||
|
import { EmptyStateMedium } from 'src/components/EmptyState';
|
||||||
|
import { setEditMode } from 'src/dashboard/actions/dashboardState';
|
||||||
import DashboardComponent from '../../containers/DashboardComponent';
|
import DashboardComponent from '../../containers/DashboardComponent';
|
||||||
import DragDroppable from '../dnd/DragDroppable';
|
import DragDroppable from '../dnd/DragDroppable';
|
||||||
import EditableTitle from '../../../components/EditableTitle';
|
import EditableTitle from '../../../components/EditableTitle';
|
||||||
@ -40,6 +44,7 @@ const propTypes = {
|
|||||||
renderType: PropTypes.oneOf([RENDER_TAB, RENDER_TAB_CONTENT]).isRequired,
|
renderType: PropTypes.oneOf([RENDER_TAB, RENDER_TAB_CONTENT]).isRequired,
|
||||||
onDropOnTab: PropTypes.func,
|
onDropOnTab: PropTypes.func,
|
||||||
editMode: PropTypes.bool.isRequired,
|
editMode: PropTypes.bool.isRequired,
|
||||||
|
canEdit: PropTypes.bool.isRequired,
|
||||||
filters: PropTypes.object.isRequired,
|
filters: PropTypes.object.isRequired,
|
||||||
|
|
||||||
// grid related
|
// grid related
|
||||||
@ -53,6 +58,7 @@ const propTypes = {
|
|||||||
handleComponentDrop: PropTypes.func.isRequired,
|
handleComponentDrop: PropTypes.func.isRequired,
|
||||||
updateComponents: PropTypes.func.isRequired,
|
updateComponents: PropTypes.func.isRequired,
|
||||||
setDirectPathToChild: PropTypes.func.isRequired,
|
setDirectPathToChild: PropTypes.func.isRequired,
|
||||||
|
setEditMode: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
@ -85,7 +91,7 @@ const renderDraggableContentTop = dropProps =>
|
|||||||
<div className="drop-indicator drop-indicator--top" />
|
<div className="drop-indicator drop-indicator--top" />
|
||||||
);
|
);
|
||||||
|
|
||||||
export default class Tab extends React.PureComponent {
|
class Tab extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.handleChangeText = this.handleChangeText.bind(this);
|
this.handleChangeText = this.handleChangeText.bind(this);
|
||||||
@ -143,8 +149,11 @@ export default class Tab extends React.PureComponent {
|
|||||||
onResizeStop,
|
onResizeStop,
|
||||||
editMode,
|
editMode,
|
||||||
isComponentVisible,
|
isComponentVisible,
|
||||||
|
canEdit,
|
||||||
|
setEditMode,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const shouldDisplayEmptyState = tabComponent.children.length === 0;
|
||||||
return (
|
return (
|
||||||
<div className="dashboard-component-tabs-content">
|
<div className="dashboard-component-tabs-content">
|
||||||
{/* Make top of tab droppable */}
|
{/* Make top of tab droppable */}
|
||||||
@ -162,6 +171,43 @@ export default class Tab extends React.PureComponent {
|
|||||||
{renderDraggableContentTop}
|
{renderDraggableContentTop}
|
||||||
</DragDroppable>
|
</DragDroppable>
|
||||||
)}
|
)}
|
||||||
|
{shouldDisplayEmptyState && (
|
||||||
|
<EmptyStateMedium
|
||||||
|
title={
|
||||||
|
editMode
|
||||||
|
? t('Drag and drop components to this tab')
|
||||||
|
: t('There are no components added to this tab')
|
||||||
|
}
|
||||||
|
description={
|
||||||
|
canEdit &&
|
||||||
|
(editMode ? (
|
||||||
|
<span>
|
||||||
|
{t('You can')}{' '}
|
||||||
|
<a
|
||||||
|
href="/chart/add"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{t('create a new chart')}
|
||||||
|
</a>{' '}
|
||||||
|
{t('or use existing ones from the panel on the right')}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
{t('You can add the components in the')}{' '}
|
||||||
|
<span
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={() => setEditMode(true)}
|
||||||
|
>
|
||||||
|
{t('edit mode')}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
image="chart.svg"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{tabComponent.children.map((componentId, componentIndex) => (
|
{tabComponent.children.map((componentId, componentIndex) => (
|
||||||
<DashboardComponent
|
<DashboardComponent
|
||||||
key={componentId}
|
key={componentId}
|
||||||
@ -262,3 +308,20 @@ export default class Tab extends React.PureComponent {
|
|||||||
|
|
||||||
Tab.propTypes = propTypes;
|
Tab.propTypes = propTypes;
|
||||||
Tab.defaultProps = defaultProps;
|
Tab.defaultProps = defaultProps;
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
canEdit: state.dashboardInfo.dash_edit_perm,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return bindActionCreators(
|
||||||
|
{
|
||||||
|
setEditMode,
|
||||||
|
},
|
||||||
|
dispatch,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Tab);
|
||||||
|
@ -23,6 +23,7 @@ import { render, screen } from 'spec/helpers/testing-library';
|
|||||||
import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
|
import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
|
||||||
import EditableTitle from 'src/components/EditableTitle';
|
import EditableTitle from 'src/components/EditableTitle';
|
||||||
import DragDroppable from 'src/dashboard/components/dnd/DragDroppable';
|
import DragDroppable from 'src/dashboard/components/dnd/DragDroppable';
|
||||||
|
import { setEditMode } from 'src/dashboard/actions/dashboardState';
|
||||||
|
|
||||||
import Tab from './Tab';
|
import Tab from './Tab';
|
||||||
|
|
||||||
@ -54,8 +55,13 @@ jest.mock('src/dashboard/components/dnd/DragDroppable', () =>
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
jest.mock('src/dashboard/actions/dashboardState', () => ({
|
||||||
|
setEditMode: jest.fn(() => ({
|
||||||
|
type: 'SET_EDIT_MODE',
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
const creteProps = () => ({
|
const createProps = () => ({
|
||||||
id: 'TAB-YT6eNksV-',
|
id: 'TAB-YT6eNksV-',
|
||||||
parentId: 'TABS-L-d9eyOE-b',
|
parentId: 'TABS-L-d9eyOE-b',
|
||||||
depth: 2,
|
depth: 2,
|
||||||
@ -98,7 +104,7 @@ beforeEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Render tab (no content)', () => {
|
test('Render tab (no content)', () => {
|
||||||
const props = creteProps();
|
const props = createProps();
|
||||||
props.renderType = 'RENDER_TAB';
|
props.renderType = 'RENDER_TAB';
|
||||||
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
||||||
expect(screen.getByText('🚀 Aspiring Developers')).toBeInTheDocument();
|
expect(screen.getByText('🚀 Aspiring Developers')).toBeInTheDocument();
|
||||||
@ -107,7 +113,7 @@ test('Render tab (no content)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Render tab (no content) editMode:true', () => {
|
test('Render tab (no content) editMode:true', () => {
|
||||||
const props = creteProps();
|
const props = createProps();
|
||||||
props.editMode = true;
|
props.editMode = true;
|
||||||
props.renderType = 'RENDER_TAB';
|
props.renderType = 'RENDER_TAB';
|
||||||
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
||||||
@ -117,7 +123,7 @@ test('Render tab (no content) editMode:true', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Edit table title', () => {
|
test('Edit table title', () => {
|
||||||
const props = creteProps();
|
const props = createProps();
|
||||||
props.editMode = true;
|
props.editMode = true;
|
||||||
props.renderType = 'RENDER_TAB';
|
props.renderType = 'RENDER_TAB';
|
||||||
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
||||||
@ -131,7 +137,7 @@ test('Edit table title', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Render tab (with content)', () => {
|
test('Render tab (with content)', () => {
|
||||||
const props = creteProps();
|
const props = createProps();
|
||||||
props.isFocused = true;
|
props.isFocused = true;
|
||||||
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
||||||
expect(DashboardComponent).toBeCalledTimes(2);
|
expect(DashboardComponent).toBeCalledTimes(2);
|
||||||
@ -174,8 +180,39 @@ test('Render tab (with content)', () => {
|
|||||||
expect(DragDroppable).toBeCalledTimes(0);
|
expect(DragDroppable).toBeCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Render tab content with no children', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.component.children = [];
|
||||||
|
render(<Tab {...props} />, {
|
||||||
|
useRedux: true,
|
||||||
|
useDnd: true,
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
screen.getByText('There are no components added to this tab'),
|
||||||
|
).toBeVisible();
|
||||||
|
expect(screen.getByAltText('empty')).toBeVisible();
|
||||||
|
expect(screen.queryByText('edit mode')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render tab content with no children, canEdit: true', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.component.children = [];
|
||||||
|
render(<Tab {...props} />, {
|
||||||
|
useRedux: true,
|
||||||
|
useDnd: true,
|
||||||
|
initialState: {
|
||||||
|
dashboardInfo: {
|
||||||
|
dash_edit_perm: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(screen.getByText('edit mode')).toBeVisible();
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'edit mode' }));
|
||||||
|
expect(setEditMode).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
test('Render tab (with content) editMode:true', () => {
|
test('Render tab (with content) editMode:true', () => {
|
||||||
const props = creteProps();
|
const props = createProps();
|
||||||
props.isFocused = true;
|
props.isFocused = true;
|
||||||
props.editMode = true;
|
props.editMode = true;
|
||||||
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
||||||
@ -220,7 +257,7 @@ test('Render tab (with content) editMode:true', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should call "handleDrop" and "handleTopDropTargetDrop"', () => {
|
test('Should call "handleDrop" and "handleTopDropTargetDrop"', () => {
|
||||||
const props = creteProps();
|
const props = createProps();
|
||||||
props.isFocused = true;
|
props.isFocused = true;
|
||||||
props.editMode = true;
|
props.editMode = true;
|
||||||
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
render(<Tab {...props} />, { useRedux: true, useDnd: true });
|
||||||
@ -233,3 +270,29 @@ test('Should call "handleDrop" and "handleTopDropTargetDrop"', () => {
|
|||||||
expect(props.onDropOnTab).toBeCalledTimes(1);
|
expect(props.onDropOnTab).toBeCalledTimes(1);
|
||||||
expect(props.handleComponentDrop).toBeCalledTimes(2);
|
expect(props.handleComponentDrop).toBeCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Render tab content with no children, editMode: true, canEdit: true', () => {
|
||||||
|
const props = createProps();
|
||||||
|
props.editMode = true;
|
||||||
|
// props.canEdit = true;
|
||||||
|
props.component.children = [];
|
||||||
|
render(<Tab {...props} />, {
|
||||||
|
useRedux: true,
|
||||||
|
useDnd: true,
|
||||||
|
initialState: {
|
||||||
|
dashboardInfo: {
|
||||||
|
dash_edit_perm: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
screen.getByText('Drag and drop components to this tab'),
|
||||||
|
).toBeVisible();
|
||||||
|
expect(screen.getByAltText('empty')).toBeVisible();
|
||||||
|
expect(
|
||||||
|
screen.getByRole('link', { name: 'create a new chart' }),
|
||||||
|
).toBeVisible();
|
||||||
|
expect(
|
||||||
|
screen.getByRole('link', { name: 'create a new chart' }),
|
||||||
|
).toHaveAttribute('href', '/chart/add');
|
||||||
|
});
|
||||||
|
@ -24,11 +24,12 @@ import {
|
|||||||
handleComponentDrop,
|
handleComponentDrop,
|
||||||
resizeComponent,
|
resizeComponent,
|
||||||
} from '../actions/dashboardLayout';
|
} from '../actions/dashboardLayout';
|
||||||
import { setDirectPathToChild } from '../actions/dashboardState';
|
import { setDirectPathToChild, setEditMode } from '../actions/dashboardState';
|
||||||
|
|
||||||
function mapStateToProps({ dashboardState }) {
|
function mapStateToProps({ dashboardState, dashboardInfo }) {
|
||||||
return {
|
return {
|
||||||
editMode: dashboardState.editMode,
|
editMode: dashboardState.editMode,
|
||||||
|
canEdit: dashboardInfo.dash_edit_perm,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ function mapDispatchToProps(dispatch) {
|
|||||||
handleComponentDrop,
|
handleComponentDrop,
|
||||||
resizeComponent,
|
resizeComponent,
|
||||||
setDirectPathToChild,
|
setDirectPathToChild,
|
||||||
|
setEditMode,
|
||||||
},
|
},
|
||||||
dispatch,
|
dispatch,
|
||||||
);
|
);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only top-level tabs have popover, give it more padding to match header + tabs */
|
/* only top-level tabs have popover, give it more padding to match header + tabs */
|
||||||
|
Loading…
Reference in New Issue
Block a user