Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect to #2662 Geodashboard map to map sync #2783

Merged
merged 1 commit into from
Mar 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions web/client/components/widgets/builder/wizard/map/Toolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const getSaveTooltipId = (step, { id } = {}) => {
return "widgets.builder.wizard.addToTheMap";
};

module.exports = ({ step = 0, buttons, tocButtons = [], editorData = {}, setPage = () => { }, onFinish = () => { }, toggleLayerSelector = () => { } } = {}) => (<Toolbar btnDefaultProps={{
module.exports = ({ step = 0, buttons, tocButtons = [], stepButtons = [], editorData = {}, setPage = () => { }, onFinish = () => { }, toggleLayerSelector = () => { } } = {}) => (<Toolbar btnDefaultProps={{
bsStyle: "primary",
bsSize: "sm"
}}
Expand All @@ -31,7 +31,7 @@ module.exports = ({ step = 0, buttons, tocButtons = [], editorData = {}, setPage
visible: step === 1,
glyph: "arrow-left",
tooltipId: "widgets.builder.wizard.configureMapOptions"
}, {
}, ...stepButtons, {
onClick: () => setPage(Math.min(step + 1, 2)),
visible: step === 0,
glyph: "arrow-right",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 React = require('react');
const ReactDOM = require('react-dom');
const {createSink} = require('recompose');
const expect = require('expect');
const dependenciesToMapProp = require('../dependenciesToMapProp');

describe('dependenciesToMapProp enhancer', () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});
afterEach((done) => {
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
document.body.innerHTML = '';
setTimeout(done);
});
it('dependenciesToMapProp rendering with defaults', (done) => {
const Sink = dependenciesToMapProp('center')(createSink( props => {
expect(props.map.center.x).toBe(1);
expect(props.map.center.y).toBe(1);
done();
}));
ReactDOM.render(<Sink map={{center: {x: 1, y: 1}}} dependencies={{center: {x: 2, y: 2}}}/>, document.getElementById("container"));
});
it('dependenciesToMapProp rendering with mapSync', (done) => {
const Sink = dependenciesToMapProp('center')(createSink(props => {
expect(props.map.center.x).toBe(2);
expect(props.map.center.y).toBe(2);
done();
}));
ReactDOM.render(<Sink mapSync map={{ center: { x: 1, y: 1 } }} dependencies={{ center: { x: 2, y: 2 } }} />, document.getElementById("container"));
});
});
24 changes: 24 additions & 0 deletions web/client/components/widgets/enhancers/dependenciesToMapProp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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 {set} = require('../../../utils/ImmutableUtils');
const {shallowEqual, branch, withPropsOnChange} = require('recompose');
/**
* Syncs map center
*/
module.exports = (prop) => branch(
(({mapSync} = {}) => mapSync),
withPropsOnChange(
({ mapSync, dependencies = {} } = {}, { mapSync: newMapSync, dependencies: newDependencies }) =>
newDependencies && shallowEqual(dependencies[prop], newDependencies[prop])
|| mapSync === newMapSync,
({ map, mapSync, dependencies = {} }) => ({
mapStateSource: "__dependency_system__",
map: dependencies[prop] && mapSync ? set(prop, dependencies[prop], map) : map
})
)
);
8 changes: 7 additions & 1 deletion web/client/components/widgets/widget/DefaultWidget.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,20 @@ const wpsChart = require('../enhancers/wpsChart');
const {compose} = require('recompose');
const dependenciesToFilter = require('../enhancers/dependenciesToFilter');
const dependenciesToWidget = require('../enhancers/dependenciesToWidget');
const dependenciesToMapProp = require('../enhancers/dependenciesToMapProp');
const ChartWidget = compose(
dependenciesToWidget,
dependenciesToFilter,
wpsChart,
enhanceChartWidget
)(require('./ChartWidget'));
const TextWidget = deleteWidget(require('./TextWidget'));
const MapWidget = deleteWidget(require('./MapWidget'));
const MapWidget = compose(
dependenciesToWidget,
dependenciesToMapProp('center'),
dependenciesToMapProp('zoom'),
deleteWidget
)(require('./MapWidget'));
const TableWidget = compose(
dependenciesToWidget,
dependenciesToFilter,
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 @@ -8,7 +8,7 @@
const React = require('react');
const WidgetContainer = require('./WidgetContainer');
const InfoPopover = require('./InfoPopover');

const { omit } = require('lodash');
const Message = require('../../I18N/Message');
const {withHandlers} = require('recompose');
const MapView = withHandlers({
Expand All @@ -33,6 +33,7 @@ module.exports = ({
toggleDeleteConfirm = () => { },
id, title, loading, description,
map,
mapStateSource,
confirmDelete = false,
onDelete = () => {}
} = {}) =>
Expand All @@ -45,5 +46,5 @@ module.exports = ({
</DropdownButton>
</ButtonToolbar>}
>
<MapView updateProperty={updateProperty} id={id} map={map} layers={map && map.layers} options={{ style: { margin: 10, height: 'calc(100% - 20px)' }}}/>
<MapView updateProperty={updateProperty} id={id} map={omit(map, 'mapStateSource')} mapStateSource={mapStateSource} layers={map && map.layers} options={{ style: { margin: 10, height: 'calc(100% - 20px)' }}}/>
</WidgetContainer>);
25 changes: 23 additions & 2 deletions web/client/epics/__tests__/widgets-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ var expect = require('expect');
const { testEpic, addTimeoutEpic, TEST_TIMEOUT } = require('./epicTestUtils');

const {
clearWidgetsOnLocationChange
clearWidgetsOnLocationChange,
alignDependenciesToWidgets
} = require('../widgets');
const {
CLEAR_WIDGETS
CLEAR_WIDGETS,
insertWidget,
LOAD_DEPENDENCIES
} = require('../../actions/widgets');
const {
savingMap,
Expand Down Expand Up @@ -126,4 +129,22 @@ describe('widgets Epics', () => {
};
});
});
it('alignDependenciesToWidgets triggered on insertWidget', (done) => {
const checkActions = actions => {
expect(actions.length).toBe(1);
const action = actions[0];
expect(action.type).toBe(LOAD_DEPENDENCIES);
expect(action.dependencies).toExist();
expect(action.dependencies.center).toBe("map.center");
expect(action.dependencies.viewport).toBe("map.bbox");
expect(action.dependencies.zoom).toBe("map.zoom");
done();
};
testEpic(alignDependenciesToWidgets,
1,
[insertWidget({id: 'test'})],
checkActions,
{});
});

});
3 changes: 2 additions & 1 deletion web/client/epics/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ module.exports = {
.map((maps=[]) => loadDependencies(maps.reduce( (deps, m) => ({
...deps,
[m === "map" ? "viewport" : `${m}.viewport`]: `${m}.bbox`, // {viewport: "map.bbox"} or {"widgets[ID_W].viewport": "widgets[ID_W].bbox"}
[m === "map" ? "center" : `${m}.center`]: `${m}.center` // {center: "map.center"} or {"widgets[ID_W].center": "widgets[ID_W].center"}
[m === "map" ? "center" : `${m}.center`]: `${m}.center`, // {center: "map.center"} or {"widgets[ID_W].center": "widgets[ID_W].center"}
[m === "map" ? "zoom" : `${m}.zoom`]: `${m}.zoom`
}), {}))
),
clearWidgetsOnLocationChange: (action$, {getState = () => {}} = {}) =>
Expand Down
2 changes: 1 addition & 1 deletion web/client/plugins/widgetbuilder/ChartBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const chooseLayerEnhancer = compose(
)
);

module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, availableDependencies = {}, dependencies, ...props} = {}) =>
module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, availableDependencies = [], dependencies, ...props} = {}) =>

(<BorderLayout
header={<BuilderHeader onClose={onClose}><Toolbar availableDependencies={availableDependencies} onClose={onClose}/></BuilderHeader>}
Expand Down
2 changes: 1 addition & 1 deletion web/client/plugins/widgetbuilder/CounterBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const chooseLayerEnhancer = compose(
)
);

module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, availableDependencies={}, dependencies, ...props } = {}) =>
module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, availableDependencies=[], dependencies, ...props } = {}) =>

(<BorderLayout
header={<BuilderHeader onClose={onClose}><Toolbar availableDependencies={availableDependencies} onClose={onClose} /></BuilderHeader>}
Expand Down
15 changes: 7 additions & 8 deletions web/client/plugins/widgetbuilder/MapBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
const React = require('react');
const {connect} = require('react-redux');
const {onEditorChange} = require('../../actions/widgets');
const { wizardSelector, wizardStateToProps, availableDependenciesSelector} = require('./commons');
const { wizardSelector, wizardStateToProps} = require('./commons');
const layerSelector = require('./enhancers/layerSelector');
const manageLayers = require('./enhancers/manageLayers');
const mapToolbar = require('./enhancers/mapToolbar');
Expand Down Expand Up @@ -63,17 +63,16 @@ const mapBuilder = compose(
map: editorData.map
})),
handleNodeSelection,
handleNodeEditing,
connect(availableDependenciesSelector)
handleNodeEditing
);


module.exports = mapBuilder(({
enabled, onClose = () => {},
toggleLayerSelector = () => {},
editNode, setEditNode, closeNodeEditor, selectedGroups=[], selectedLayers=[], selectedNodes, onNodeSelect = () => {} } = {},
availableDependencies = []
) =>
enabled, onClose = () => {},
toggleLayerSelector = () => {},
editNode, setEditNode, closeNodeEditor, selectedGroups=[], selectedLayers=[], selectedNodes, onNodeSelect = () => {},
availableDependencies =[]
} = {}) =>
(<BorderLayout
className = "map-selector"
header={(<BuilderHeader onClose={onClose}>
Expand Down
2 changes: 1 addition & 1 deletion web/client/plugins/widgetbuilder/TableBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const chooseLayerEnhancer = compose(
)
);

module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, editorData = {}, availableDependencies = {}, dependencies, ...props } = {}) =>
module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, editorData = {}, availableDependencies = [], dependencies, ...props } = {}) =>

(<BorderLayout
header={
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* 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 { withHandlers, withProps, compose } = require('recompose');
const { omit } = require('lodash');

/**
* Provides proper handlers and variables to connect a widget to a map viewport in the toolbar or other builders
* requires:
* - editorData object
* - onChange: function to change widget properties
* - toggleDependencySelector function in case of multiple maps
*
*/
module.exports = compose(
withProps(({ availableDependencies = [], editorData = {}} = {}) => ({
availableDependencies: availableDependencies.filter(d => !(editorData.id && d.indexOf(editorData.id) >= 0))
})),
withProps(({ editorData = {} }) => ({
canConnect: true,
connected: editorData.mapSync
})),
withHandlers({
toggleConnection: ({ onChange = () => { }, editorData = {} }) => (widget, id) => {
onChange('mapSync', !editorData.mapSync);
const center =
!editorData.mapSync
? id === 'map'
? 'center'
: `${id}.center`
: undefined;
const zoom =
!editorData.mapSync
? id === 'map'
? 'zoom'
: `${id}.zoom`
: undefined;
const { dependenciesMap = {} } = editorData;
onChange('dependenciesMap', !editorData.mapSync && center && zoom !== undefined
? { ...dependenciesMap, center, zoom } :
omit(dependenciesMap, ['center', 'zoom']));


}
}),
withHandlers({
toggleConnection: ({ toggleConnection = () => { }, toggleDependencySelector = () => { }, widget, editorData = {} }) =>
(available = []) => available.length === 1 || editorData.mapSync
? toggleConnection(widget, available[0])
: toggleDependencySelector()
})
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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, compose } = require('recompose');
/**
* Returns an enhancer that add `stepButtons` for viewport connection to a wizard toolbar
* @param {function} showCondition parses props to allow visualization of the buttons (if other connect condition are satisfied)
*/
module.exports = (showCondition = () => true) => compose(
withProps(({
stepButtons = [],
toggleConnection = () => { },
availableDependencies = [],
canConnect,
connected,
...props
}) => ({
stepButtons: [{
onClick: () => toggleConnection(availableDependencies),
disabled: availableDependencies.length > 1, // TODO: remove when support multi map
visible: showCondition(props) && canConnect && availableDependencies.length > 0,
bsStyle: connected ? "success" : "primary",
glyph: connected ? "plug" : "unplug",
tooltipId: connected
? "widgets.builder.wizard.clearConnection"
: availableDependencies.length === 1
? "widgets.builder.wizard.connectToTheMap"
: "connection to multiple maps not supported yet" // TODO: "widgets.builder.wizard.connectToAMap"
}, ...stepButtons
]
}))
);
10 changes: 7 additions & 3 deletions web/client/plugins/widgetbuilder/enhancers/mapToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
*/
const { compose, branch, withProps, withHandlers} = require('recompose');
const {connect} = require('react-redux');
const { insertWidget, setPage} = require('../../../actions/widgets');
const { insertWidget, setPage, onEditorChange} = require('../../../actions/widgets');
const manageLayers = require('./manageLayers');
const handleNodeEditing = require('./handleNodeEditing');
const { wizardSelector, wizardStateToProps } = require('../commons');

const withConnectButton = require('./connection/withConnectButton');
const mapPositionConnect = require('./connection/mapPositionConnect');
module.exports = compose(
connect(wizardSelector, {
setPage,
onChange: onEditorChange,
insertWidget
},
wizardStateToProps
Expand Down Expand Up @@ -49,6 +51,8 @@ module.exports = compose(
tooltipId: "toc.toolTrashLayerTooltip"
}]
}))
)
),
mapPositionConnect,
withConnectButton(({step}) => step === 0)

);
6 changes: 6 additions & 0 deletions web/client/reducers/__tests__/widgets-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ describe('Test the widgets reducer', () => {
it('initial state', () => {
const state = widgets(undefined, {type: "START"});
expect(state.containers).toExist();
expect(state.dependencies.key).toBeFalsy();
expect(state.dependencies.viewport).toBe("map.bbox");
expect(state.dependencies.center).toBe("map.center");
expect(state.dependencies.zoom).toBe("map.zoom");
});
it('editNewWidget', () => {
const state = widgets(undefined, editNewWidget({a: "A"}, {step: 0}));
Expand Down Expand Up @@ -121,5 +125,7 @@ describe('Test the widgets reducer', () => {
expect(state).toExist();
expect(state.dependencies.key).toBeFalsy();
expect(state.dependencies.viewport).toBe("map.bbox");
expect(state.dependencies.center).toBe("map.center");
expect(state.dependencies.zoom).toBe("map.zoom");
});
});
3 changes: 2 additions & 1 deletion web/client/reducers/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const {arrayUpsert, arrayDelete} = require('../utils/ImmutableUtils');
const emptyState = {
dependencies: {
viewport: "map.bbox",
center: "map.center"
center: "map.center",
zoom: "map.zoom"
},
containers: {
floating: {
Expand Down