Skip to content

Commit

Permalink
Fix #2754 Add map widget layer's editing (#2767)
Browse files Browse the repository at this point in the history
  • Loading branch information
offtherailz authored Mar 26, 2018
1 parent 3e1a10e commit 47463ac
Show file tree
Hide file tree
Showing 58 changed files with 1,613 additions and 125 deletions.
57 changes: 32 additions & 25 deletions web/client/components/TOC/enhancers/tocItemsSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* LICENSE file in the root directory of this source tree.
*/

const {isNil, isEqual} = require('lodash');
const {withState, withHandlers, compose, lifecycle} = require('recompose');
const { isNil, isEqual } = require('lodash');
const { withState, withHandlers, compose, lifecycle } = require('recompose');

/**
* Enhancer for settings state needed in TOCItemsSettings plugin
Expand Down Expand Up @@ -39,37 +39,44 @@ const settingsState = compose(
*/
const settingsLifecycle = compose(
withHandlers({
onUpdateParams: props => (newParams, update = true) => {
let originalSettings = {...props.originalSettings};
onUpdateParams: ({
settings = {},
initialSettings = {},
originalSettings: orig,
onUpdateOriginalSettings = () => {},
onUpdateSettings = () => {},
onUpdateNode = () => {}
}) => (newParams, update = true) => {
let originalSettings = { ...(orig || {}) };
// TODO one level only storage of original settings for the moment
Object.keys(newParams).forEach((key) => {
originalSettings[key] = props.initialSettings[key];
originalSettings[key] = initialSettings && initialSettings[key];
});
props.onUpdateOriginalSettings(originalSettings);
props.onUpdateSettings(newParams);
onUpdateOriginalSettings(originalSettings);
onUpdateSettings(newParams);
if (update) {
props.onUpdateNode(
props.settings.node,
props.settings.nodeType,
{...props.settings.options, ...newParams}
onUpdateNode(
settings.node,
settings.nodeType,
{ ...settings.options, ...newParams }
);
}
},
onClose: ({onUpdateNode, originalSettings, settings, onHideSettings, onShowAlertModal}) => forceClose => {
const originalOptions = Object.keys(settings.options).reduce((options, key) => ({...options, [key]: key === 'opacity' && !originalSettings[key] && 1.0 || originalSettings[key]}), {});
onClose: ({ onUpdateNode, originalSettings, settings, onHideSettings, onShowAlertModal }) => forceClose => {
const originalOptions = Object.keys(settings.options).reduce((options, key) => ({ ...options, [key]: key === 'opacity' && !originalSettings[key] && 1.0 || originalSettings[key] }), {});
if (!isEqual(originalOptions, settings.options) && !forceClose) {
onShowAlertModal(true);
} else {
onUpdateNode(
settings.node,
settings.nodeType,
{...settings.options, ...originalSettings}
{ ...settings.options, ...originalSettings }
);
onHideSettings();
onShowAlertModal(false);
}
},
onSave: ({onHideSettings = () => {}, onShowAlertModal = () => {}}) => () => {
onSave: ({ onHideSettings = () => { }, onShowAlertModal = () => { } }) => () => {
onHideSettings();
onShowAlertModal(false);
}
Expand All @@ -78,19 +85,19 @@ const settingsLifecycle = compose(
componentWillMount() {
const {
element = {},
onUpdateOriginalSettings = () => {},
onUpdateInitialSettings = () => {}
onUpdateOriginalSettings = () => { },
onUpdateInitialSettings = () => { }
} = this.props;

onUpdateOriginalSettings({...element});
onUpdateInitialSettings({...element});
onUpdateOriginalSettings({ ...element });
onUpdateInitialSettings({ ...element });
},
componentWillReceiveProps(newProps) {
// an empty description does not trigger the single layer getCapabilites,
// it does only for missing description
const {
settings = {},
onRetrieveLayerData = () => {}
onRetrieveLayerData = () => { }
} = this.props;

if (!settings.expanded && newProps.settings && newProps.settings.expanded && isNil(newProps.element.description) && newProps.element.type === "wms") {
Expand All @@ -100,15 +107,15 @@ const settingsLifecycle = compose(
componentWillUpdate(newProps) {
const {
settings = {},
onUpdateOriginalSettings = () => {},
onUpdateInitialSettings = () => {},
onSetTab = () => {}
onUpdateOriginalSettings = () => { },
onUpdateInitialSettings = () => { },
onSetTab = () => { }
} = this.props;

if (!settings.expanded && newProps.settings && newProps.settings.expanded) {
// update initial and original settings
onUpdateOriginalSettings({...newProps.element});
onUpdateInitialSettings({...newProps.element});
onUpdateOriginalSettings({ ...newProps.element });
onUpdateInitialSettings({ ...newProps.element });
onSetTab('general');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 onMapViewChanges = require('../onMapViewChanges');

describe('onMapViewChanges 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('onMapViewChanges rendering with defaults', () => {
const Sink = onMapViewChanges(createSink( props => {
expect(props.eventHandlers.onMapViewChanges).toExist();
setTimeout(props.eventHandlers.onMapViewChanges("CENTER", "ZOOM", { bbox: { x: 2 } }, "SIZE", "mapStateSource", "projection"));

}));
const actions = {
onMapViewChanges: () => {}
};
const spy = expect.spyOn(actions, 'onMapViewChanges');
ReactDOM.render(<Sink map={{ bbox: { x: 1, y: 1 }, test: "TEST" }} onMapViewChanges={actions.onMapViewChanges} />, document.getElementById("container"));
expect(spy).toHaveBeenCalled();
const map = spy.calls[0].arguments[0];
expect(map).toExist();
expect(map.center).toExist();
expect(map.zoom).toExist();
expect(map.bbox).toExist();
expect(map.size).toExist();
expect(map.mapStateSource).toExist();
expect(map.projection).toExist();
});

});
8 changes: 1 addition & 7 deletions web/client/components/map/enhancers/autoResize.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ module.exports = (debounceTime = 0) => compose(
resize: 0
}),
{
onResize: ({resize = 0, map}) => ({width, height} = {}) => ({
map: {
...map,
size: {
width, height
}
},
onResize: ({resize = 0}) => () => ({
resize: resize + 1
})
}
Expand Down
41 changes: 41 additions & 0 deletions web/client/components/map/enhancers/onMapViewChanges.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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 {compose, withHandlers, withPropsOnChange} = require('recompose');

/**
* Enhance map to add the `onMapViewChanges` handler passed as prop to the list of event handlers.
* The handler is called with only one parameter (the map) that is the result of the merge of
* original callback (where center, zoom, bbox, size, mapStateSource and projection are separated) with the current `map` prop
*/
module.exports = compose(
withHandlers({
onMapViewChanges: ({ map = {}, onMapViewChanges = () => {}}) => (center, zoom, bbox, size, mapStateSource, projection) => {
onMapViewChanges({
...map,
center,
bbox: {
...map.bbox,
...bbox
},
zoom,
size,
mapStateSource,
projection
});
}
}),
withPropsOnChange(
['onMapViewChanges', 'eventHandlers'],
({ onMapViewChanges = () => {}, eventHandlers ={} } = {}) => ({
eventHandlers: {
...eventHandlers,
onMapViewChanges
}
})
)
);
2 changes: 1 addition & 1 deletion web/client/components/map/plugins/cesium.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ module.exports = () => {
return {
Map: require('../cesium/Map'),
Layer: require('../cesium/Layer'),
Feature: createSink()
Feature: createSink(() => {})
};
};
18 changes: 18 additions & 0 deletions web/client/components/map/plugins/sink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright 2016, 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 { createSink } = require('recompose');
/**
* Dummy implementation of mapType for tests
*/
module.exports = () => {
return {
Map: createSink(() => {}),
Layer: createSink(() => {}),
Feature: createSink(() => {})
};
};
4 changes: 2 additions & 2 deletions web/client/components/widgets/builder/wizard/ChartWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ const dependenciesToFilter = require('../../enhancers/dependenciesToFilter');
const emptyChartState = require('../../enhancers/emptyChartState');
const errorChartState = require('../../enhancers/errorChartState');
const {compose, lifecycle} = require('recompose');
const enhanchePreview = compose(
const enhancePreview = compose(
dependenciesToFilter,
wpsChart,
loadingState,
errorChartState,
emptyChartState
);
const PreviewChart = enhanchePreview(require('../../../charts/SimpleChart'));
const PreviewChart = enhancePreview(require('../../../charts/SimpleChart'));
const SampleChart = sampleData(require('../../../charts/SimpleChart'));

const sampleProps = {
Expand Down
27 changes: 24 additions & 3 deletions web/client/components/widgets/builder/wizard/MapWizard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,42 @@ const WidgetOptions = require('./common/WidgetOptions');
const {wizardHandlers} = require('../../../misc/wizard/enhancers');
const Wizard = wizardHandlers(require('../../../misc/wizard/WizardContainer'));

const MapOptions = require('./map/MapOptions');
const Preview = require('./map/PreviewMap');


module.exports = ({
onChange = () => {}, onFinish = () => {}, setPage= () => {},
step=0,
editorData = {}
selectedNodes=[],
onNodeSelect = () => {},
editorData = {},
editNode,
setEditNode = () => {},
closeNodeEditor = () => {}
} = {}) => (
<Wizard
step={step}
setPage={setPage}
onFinish={onFinish}
hideButtons>
<MapOptions
editNode={editNode}
setEditNode={setEditNode}
closeNodeEditor={closeNodeEditor}
onNodeSelect={onNodeSelect}
selectedNodes={selectedNodes}
onChange={onChange}
preview={<Preview
onChange={onChange}
layers={editorData.map && editorData.map.layers}
map={editorData.map}
options={{ style: { margin: 10, height: 'calc(100% - 20px)' } }} /> }
map={editorData.map}
/>
<WidgetOptions
key="widget-options"
data={editorData}
onChange={onChange}
/>
</Wizard>
);
</Wizard>);
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 PropTypes = require('prop-types');
const { withContext } = require('recompose');
const expect = require('expect');

const mockStore = withContext({
store: PropTypes.any
}, ({store = {}} = {}) => ({
store: {
dispatch: () => { },
subscribe: () => { },
getState: () => ({}),
...store
}
}));
const MapWizard = mockStore(require('../MapWizard'));
describe('MapWizard component', () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
});
afterEach((done) => {
ReactDOM.unmountComponentAtNode(document.getElementById("container"));
document.body.innerHTML = '';
setTimeout(done);
});
it('MapWizard rendering with map', () => {
// mock the store for empty map type
const store = {
getState: () => ({
maptype: {
mapType: 'sink'
}
})
};
const map = { groups: [{ id: 'GGG' }], layers: [{ id: "LAYER", name: "Layer", group: "GGG", options: {} }] };
ReactDOM.render(<MapWizard store={store} editorData={{ map }} />, document.getElementById("container"));
const container = document.getElementById('container');
const el = container.querySelector('.ms-wizard');
expect(el).toExist();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ module.exports = ({data = {}, onChange = () => {}, sampleChart}) => (<Row>
<FormControl value={data.title} type="text" onChange={ e => onChange("title", e.target.value)} />
</Col>
</FormGroup>

<FormGroup controlId="aggregationAttribute">
<Col componentClass={ControlLabel} sm={6}>
<Message msgId={`widgets.description`} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = ({canProceed, selected, onProceed = () => {}} = {}) => (<Toolba
buttons={[{
onClick: onProceed,
disabled: !canProceed,
tooltipId: "widgets.useTheSelectedLayer",
tooltipId: "widgets.builder.wizard.useTheSelectedLayer",
visible: selected,
glyph: "arrow-right"
}]} />);
Loading

0 comments on commit 47463ac

Please sign in to comment.