Skip to content

Commit

Permalink
Fix #2662. Add widget connections and colors (#2793)
Browse files Browse the repository at this point in the history
  • Loading branch information
offtherailz authored Apr 5, 2018
1 parent 78b0a41 commit dce2b1f
Show file tree
Hide file tree
Showing 31 changed files with 1,486 additions and 53 deletions.
5 changes: 4 additions & 1 deletion web/client/actions/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
const SET_EDITOR_AVAILABLE = "DASHBOARD:SET_AVAILABLE";
const SET_EDITING = "DASHBOARD:SET_EDITING";
const SHOW_CONNECTIONS = "DASHBOARD:SHOW_CONNECTIONS";
module.exports = {
SET_EDITING,
setEditing: (editing) => ({type: SET_EDITING, editing }),
SET_EDITOR_AVAILABLE,
setEditorAvailable: available => ({type: SET_EDITOR_AVAILABLE, available})
setEditorAvailable: available => ({type: SET_EDITOR_AVAILABLE, available}),
SHOW_CONNECTIONS,
triggerShowConnections: show => ({ type: SHOW_CONNECTIONS, show})
};
4 changes: 2 additions & 2 deletions web/client/components/dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ module.exports =
({widgets = []} = {}) => widgets.length === 0,
() => ({
glyph: "dashboard",
title: <Message msgId="dashboard.emptyTitle" /> // TODO i18n
title: <Message msgId="dashboard.emptyTitle" />
})
),
defaultProps({
isWidgetSelectable: ({}) => true // TODO: filter widgets
isWidgetSelectable: ({}) => true
}),
withSelection
)(require('../widgets/view/WidgetsView'));
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const nodeEditor = require('./enhancers/nodeEditor');
const Editor = nodeEditor(require('./NodeEditor'));

module.exports = ({ preview, map = {}, onChange = () => { }, selectedNodes = [], onNodeSelect = () => { }, editNode, closeNodeEditor = () => { } }) => (<div>
<StepHeader title={<Message msgId={`Preview`} />} />
<StepHeader title={<Message msgId={`widgets.builder.wizard.preview`} />} />
<div key="sample" >
<div style={{ width: "100%", height: "200px"}}>
{preview}
Expand Down
18 changes: 18 additions & 0 deletions web/client/components/widgets/enhancers/withGroupColor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2018, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
const {withProps} = require('recompose');
const {get, head} = require('lodash');
const getGroupColor = groups => get(head(groups, ({ color }) => color), 'color');
/**
* get the first color found in widget groups array.
*/
module.exports = withProps(({ groups, showGroupColor, headerStyle = {borderTop: "3px solid rgba(0,0,0,0)", transition: "border-color .5s ease-out"} }) => ({
headerStyle: showGroupColor && groups && getGroupColor(groups)
? { ...headerStyle, borderTop: `3px solid ${getGroupColor(groups)}` }
: headerStyle
}));
10 changes: 8 additions & 2 deletions web/client/components/widgets/view/WidgetsView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
const React = require('react');

const { pure } = require('recompose');

const { find } = require('lodash');
/*
react-grid-layout-resize-prevent-collision is a fork of react-grid-layout deployed on npmjs.org to fix https://github.com/STRML/react-grid-layout/issues/655
You can install and use react-grid-layout again when the issue is fixed
*/
const { Responsive, WidthProvider: widthProvider } = require('react-grid-layout-resize-prevent-collision');
const ResponsiveReactGridLayout = widthProvider(Responsive);
const DefaultWidget = require('../widget/DefaultWidget');
const withGroupColor = require('../enhancers/withGroupColor');
const DefaultWidget = withGroupColor(require('../widget/DefaultWidget'));
const getWidgetGroups = (groups = [], w) => groups.filter(g => find(g.widgets, id => id === w.id));
require('react-grid-layout-resize-prevent-collision/css/styles.css');

module.exports = pure(({
Expand All @@ -28,6 +30,8 @@ module.exports = pure(({
widgets = [],
layouts,
dependencies,
showGroupColor,
groups = [],
getWidgetClass = () => { },
onWidgetClick = () => { },
updateWidgetProperty = () => { },
Expand All @@ -54,6 +58,8 @@ module.exports = pure(({
data-grid={w.dataGrid}
{...actions}
{...w}
groups={getWidgetGroups(groups, w)}
showGroupColor={showGroupColor}
dependencies={dependencies}
updateProperty={(...args) => updateWidgetProperty(w.id, ...args)}
onDelete={() => deleteWidget(w)}
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/widgets/widget/ChartWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module.exports = ({
id,
title,
description,
headerStyle,
data = [],
series = [],
loading,
Expand All @@ -45,6 +46,7 @@ module.exports = ({
...props}) =>
(<WidgetContainer
id={`widget-chart-${id}`}
headerStyle={headerStyle}
title={title}
topLeftItems={renderHeaderLeftTopItem({loading, title, description, showTable, toggleTableView})}
confirmDelete={confirmDelete}
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/widgets/widget/CounterWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module.exports = ({
width,
height,
confirmDelete= false,
headerStyle,
toggleTableView= () => {},
toggleDeleteConfirm= () => {},
onEdit= () => {},
Expand All @@ -48,6 +49,7 @@ module.exports = ({
confirmDelete={confirmDelete}
onDelete={onDelete}
toggleDeleteConfirm = {toggleDeleteConfirm}
headerStyle={headerStyle}
topRightItems={showTable
? null : <ButtonToolbar>
<DropdownButton pullRight bsStyle="default" className="widget-menu" title={<Glyphicon glyph="option-vertical" />} noCaret id="dropdown-no-caret">
Expand Down
5 changes: 3 additions & 2 deletions web/client/components/widgets/widget/MapWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ module.exports = ({
map,
mapStateSource,
confirmDelete = false,
onDelete = () => {}
onDelete = () => {},
headerStyle
} = {}) =>
(<WidgetContainer id={`widget-text-${id}`} title={title} confirmDelete={confirmDelete} onDelete={onDelete} toggleDeleteConfirm={toggleDeleteConfirm}
(<WidgetContainer id={`widget-text-${id}`} title={title} confirmDelete={confirmDelete} onDelete={onDelete} toggleDeleteConfirm={toggleDeleteConfirm} headerStyle={headerStyle}
topLeftItems={renderHeaderLeftTopItem({ loading, title, description })}
topRightItems={<ButtonToolbar>
<DropdownButton pullRight bsStyle="default" className="widget-menu" title={<Glyphicon glyph="option-vertical" />} noCaret id="dropdown-no-caret">
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/widgets/widget/TableWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ module.exports = ({
description,
loading,
confirmDelete = false,
headerStyle,
toggleTableView = () => { },
toggleDeleteConfirm = () => { },
onEdit = () => { },
Expand All @@ -54,6 +55,7 @@ module.exports = ({
(<WidgetContainer
id={`widget-chart-${id}`}
title={title}
headerStyle={headerStyle}
topLeftItems={renderHeaderLeftTopItem({ loading, title, description, toggleTableView })}
confirmDelete={confirmDelete}
onDelete={onDelete}
Expand Down
3 changes: 2 additions & 1 deletion web/client/components/widgets/widget/TextWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ module.exports = ({
onEdit = () => {},
toggleDeleteConfirm = () => {},
id, title, text,
headerStyle,
confirmDelete= false,
onDelete=() => {}
} = {}) =>
(<WidgetContainer id={`widget-text-${id}`} title={title} confirmDelete={confirmDelete} onDelete={onDelete} toggleDeleteConfirm={toggleDeleteConfirm}
(<WidgetContainer id={`widget-text-${id}`} title={title} confirmDelete={confirmDelete} onDelete={onDelete} toggleDeleteConfirm={toggleDeleteConfirm} headerStyle={headerStyle}
topRightItems={<ButtonToolbar>
<DropdownButton pullRight bsStyle="default" className="widget-menu" title={<Glyphicon glyph="option-vertical" />} noCaret id="dropdown-no-caret">
<MenuItem onClick={() => onEdit()} eventKey="3"><Glyphicon glyph="pencil"/>&nbsp;<Message msgId="widgets.widget.menu.edit" /></MenuItem>
Expand Down
3 changes: 2 additions & 1 deletion web/client/components/widgets/widget/WidgetContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ module.exports = ({
onDelete=() => {},
topLeftItems,
topRightItems,
headerStyle = {},
children
}) =>
(<div className="mapstore-widget-card" id={id}>
<BorderLayout header={(<div className={`mapstore-widget-info ${handle ? handle : ""}`}>
<BorderLayout header={(<div style={headerStyle} className={`mapstore-widget-info ${handle ? handle : ""}`}>
<div className="mapstore-widget-header">
{topLeftItems}
<span className="widget-title">{title}</span>
Expand Down
11 changes: 8 additions & 3 deletions web/client/plugins/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ const {connect} = require('react-redux');
const { compose, withProps, withHandlers } = require('recompose');
const {createSelector} = require('reselect');
const {mapIdSelector} = require('../selectors/map');
const { getDashboardWidgets, dependenciesSelector, getDashboardWidgetsLayout, isWidgetSelectionActive, getEditingWidget} = require('../selectors/widgets');
const { getDashboardWidgets, dependenciesSelector, getDashboardWidgetsLayout, isWidgetSelectionActive, getEditingWidget, getWidgetsDependenciesGroups} = require('../selectors/widgets');
const { editWidget, updateWidgetProperty, deleteWidget, changeLayout, exportCSV, exportImage, selectWidget} = require('../actions/widgets');
const {showConnectionsSelector} = require('../selectors/dashboard');
const ContainerDimensions = require('react-container-dimensions').default;

const PropTypes = require('prop-types');
Expand All @@ -26,13 +27,17 @@ const WidgetsView = compose(
dependenciesSelector,
isWidgetSelectionActive,
(state) => get(getEditingWidget(state), "id"),
(id, widgets, layouts, dependencies, selectionActive, editingWidgetId) => ({
getWidgetsDependenciesGroups,
showConnectionsSelector,
(id, widgets, layouts, dependencies, selectionActive, editingWidgetId, groups, showGroupColor) => ({
id,
widgets,
layouts,
dependencies,
selectionActive,
editingWidgetId
editingWidgetId,
groups,
showGroupColor
})
), {
editWidget,
Expand Down
53 changes: 36 additions & 17 deletions web/client/plugins/DashboardEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,48 @@ const {createSelector} = require('reselect');
const {connect} = require('react-redux');
const PropTypes = require('prop-types');

const {isDashboardEditing} = require('../selectors/dashboard');
const { isDashboardEditing} = require('../selectors/dashboard');
const {dashboardSelector} = require('./widgetbuilder/commons');
const { createWidget, toggleConnection } = require('../actions/widgets');
const { triggerShowConnections } = require('../actions/dashboard');
const { showConnectionsSelector } = require('../selectors/dashboard');
const Builder =
compose(
connect(dashboardSelector, {toggleConnection}),
connect(dashboardSelector, { toggleConnection, triggerShowConnections}),
withProps(({ availableDependencies = []}) => ({
availableDependencies: availableDependencies.filter(d => d !== "map")
})),
)(require('./widgetbuilder/WidgetTypeBuilder'));
const Toolbar = require('../components/misc/toolbar/Toolbar');

const Toolbar = compose(
connect(
createSelector(
showConnectionsSelector,
showConnections => ({showConnections})
),
{
onShowConnections: triggerShowConnections,
onAddWidget: createWidget
}
),
withProps(({
onAddWidget = () => {},
showConnections, onShowConnections = () => { }
}) => ({
buttons: [{
glyph: 'plus',
tooltipId: 'dashboard.editor.addACardToTheDashboard',
bsStyle: 'primary',
visible: true,
onClick: () => onAddWidget()
}, {
glyph: showConnections ? 'bulb-on' : 'bulb-off',
tooltipId: showConnections ? 'dashboard.editor.hideConnections' : 'dashboard.editor.showConnections',
bsStyle: showConnections ? 'success' : 'primary',
onClick: () => onShowConnections(!showConnections)
}]
}))
)(require('../components/misc/toolbar/Toolbar'));


const {setEditing, setEditorAvailable} = require('../actions/dashboard');
Expand All @@ -40,7 +71,6 @@ class DashboardEditorComponent extends React.Component {
onMount: PropTypes.func,
onUnmount: PropTypes.func,
setEditing: PropTypes.func,
onAddWidget: PropTypes.func,
dimMode: PropTypes.string,
src: PropTypes.string,
style: PropTypes.object
Expand All @@ -56,7 +86,6 @@ class DashboardEditorComponent extends React.Component {
position: "left",
onMount: () => {},
onUnmount: () => {},
onAddWidget: () => {},
setEditing: () => {}
};
componentDidMount() {
Expand All @@ -67,21 +96,12 @@ class DashboardEditorComponent extends React.Component {
this.props.onUnmount();
}
render() {
const buttons = [{
glyph: 'plus',
tooltipId: 'dashboard.editor.addACardToTheDashboard',
bsStyle: 'primary',
tooltipPosition: 'right',
visible: true,
onClick: () => {
this.props.onAddWidget();
}
}];


return this.props.editing
? <div className="dashboard-editor de-builder"><Builder enabled={this.props.editing} onClose={() => this.props.setEditing(false)} catalog={this.props.catalog}/></div>
: (<div className="ms-vertical-toolbar dashboard-editor de-toolbar" id={this.props.id}>
<Toolbar btnGroupProps={{vertical: true}} btnDefaultProps={{ className: 'square-button-md', bsStyle: 'primary'}} buttons={buttons}/>
<Toolbar transitionProps={false} btnGroupProps={{vertical: true}} btnDefaultProps={{ tooltipPosition: 'right', className: 'square-button-md', bsStyle: 'primary'}} />
</div>);
}
}
Expand All @@ -92,7 +112,6 @@ const Plugin = connect(
editing => ({editing})
), {
setEditing,
onAddWidget: createWidget,
onMount: () => setEditorAvailable(true),
onUnmount: () => setEditorAvailable(false)
}
Expand Down
5 changes: 4 additions & 1 deletion web/client/plugins/widgetbuilder/commons.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
const {createSelector} = require('reselect');
const { getEditingWidget, dependenciesSelector, getEditorSettings, getWidgetLayer, availableDependenciesSelector} = require('../../selectors/widgets');
const { showConnectionsSelector } = require('../../selectors/dashboard');

const wizardStateToProps = ( stateProps = {}, dispatchProps = {}, ownProps = {}) => ({
...ownProps,
Expand All @@ -32,10 +33,12 @@ const wizardSelector = createSelector(
);
const dashboardSelector = createSelector(
getEditingWidget,
showConnectionsSelector,
dependenciesSelector,
availableDependenciesSelector,
({ layer }, dependencies, dependencyConnectProps) => ({
({ layer }, showConnections, dependencies, dependencyConnectProps) => ({
layer,
showConnections,
dependencies,
...dependencyConnectProps
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = (showCondition = () => true) => compose(
? "widgets.builder.wizard.clearConnection"
: availableDependencies.length === 1
? "widgets.builder.wizard.connectToTheMap"
: "widgets.builder.wizard.connectToAMap" // TODO: "widgets.builder.wizard.connectToAMap"
: "widgets.builder.wizard.connectToAMap"
}, ...stepButtons
]
}))
Expand Down
31 changes: 31 additions & 0 deletions web/client/reducers/__tests__/dashboard-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2018, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
const expect = require('expect');
const { setEditorAvailable, setEditing, triggerShowConnections } = require('../../actions/dashboard');
const { insertWidget, updateWidget, deleteWidget } = require('../../actions/widgets');
const dashboard = require('../dashboard');
describe('Test the dashboard reducer', () => {
it('setEditorAvailable action', () => {
const state = dashboard({}, setEditorAvailable( true ));
expect(state.editor.available).toBe(true);
});
it('setEditing', () => {
const state = dashboard({}, setEditing(true));
expect(state.editing).toBe(true);
});
it('disable editing on insert/update/delete', () => {
expect(dashboard({ editing: true }, insertWidget({})).editing).toBeFalsy();
expect(dashboard({ editing: true }, updateWidget({})).editing).toBeFalsy();
expect(dashboard({ editing: true }, deleteWidget({})).editing).toBeFalsy();
});
it('triggerShowConnections', () => {
const state = dashboard({}, triggerShowConnections(true));
expect(state.showConnections).toBe(true);
});

});
4 changes: 3 additions & 1 deletion web/client/reducers/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/

const {SET_EDITING, SET_EDITOR_AVAILABLE} = require('../actions/dashboard');
const { SET_EDITING, SET_EDITOR_AVAILABLE, SHOW_CONNECTIONS} = require('../actions/dashboard');
const {INSERT, UPDATE, DELETE} = require('../actions/widgets');
const {set} = require('../utils/ImmutableUtils');
function dashboard(state = {}, action) {
Expand All @@ -21,6 +21,8 @@ function dashboard(state = {}, action) {
case INSERT:
case DELETE:
return set("editing", action.editing, state);
case SHOW_CONNECTIONS:
return set("showConnections", action.show, state);
default:
return state;
}
Expand Down
Loading

0 comments on commit dce2b1f

Please sign in to comment.