From f9bea27384f8004f4cd89633d94e7c5a8b636448 Mon Sep 17 00:00:00 2001 From: Lorenzo Natali Date: Thu, 3 Nov 2016 11:30:33 +0100 Subject: [PATCH 1/4] Fix #1194. First commits --- web/client/actions/catalog.js | 1 - web/client/actions/layers.js | 13 +++-- web/client/api/WMS.js | 1 - web/client/components/TOC/DefaultLayer.jsx | 3 ++ .../TOC/fragments/SettingsModal.jsx | 36 ++++++++++--- .../TOC/fragments/settings/WMSStyle.jsx | 54 +++++++++++++++++++ web/client/components/catalog/RecordItem.jsx | 2 + web/client/plugins/TOC.jsx | 6 ++- 8 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 web/client/components/TOC/fragments/settings/WMSStyle.jsx diff --git a/web/client/actions/catalog.js b/web/client/actions/catalog.js index 0f9c96f602..ce7a49045d 100644 --- a/web/client/actions/catalog.js +++ b/web/client/actions/catalog.js @@ -16,7 +16,6 @@ const RECORD_LIST_LOAD_ERROR = 'RECORD_LIST_LOAD_ERROR'; const CHANGE_CATALOG_FORMAT = 'CHANGE_CATALOG_FORMAT'; const ADD_LAYER_ERROR = 'ADD_LAYER_ERROR'; const CATALOG_RESET = 'CATALOG_RESET'; - function recordsLoaded(options, result) { return { type: RECORD_LIST_LOADED, diff --git a/web/client/actions/layers.js b/web/client/actions/layers.js index 4e1dedeea1..d8d497866e 100644 --- a/web/client/actions/layers.js +++ b/web/client/actions/layers.js @@ -185,7 +185,7 @@ function getDescribeLayer(url, layer, options) { } function getLayerCapabilities(layer, options) { - // geoserver's specific. + // geoserver's specific. TODO parse layer.capabilitiesURL. let reqUrl = layer.url; let urlParts = reqUrl.split("/geoserver/"); if (urlParts.length === 2) { @@ -193,7 +193,6 @@ function getLayerCapabilities(layer, options) { if (layerParts.length === 2) { reqUrl = urlParts[0] + "/geoserver/" + layerParts [0] + "/" + layerParts[1] + "/" + urlParts[1]; } - } return (dispatch) => { // TODO, look ad current cached capabilities; @@ -202,9 +201,9 @@ function getLayerCapabilities(layer, options) { let layerCapability; layerCapability = _.head(layers.filter( ( capability ) => { - if (layer.name.split(":").length === 2 && capability.name.split(":").length === 2 ) { + if (layer.name.split(":").length === 2 && capability.name && capability.name.split(":").length === 2 ) { return layer.name === capability.name; - } else if (capability.name.split(":").length === 2) { + } else if (capability.name && capability.name.split(":").length === 2) { return (layer.name === capability.name.split(":")[1]); } else if (layer.name.split(":").length === 2) { return layer.name.split(":")[1] === capability.name; @@ -212,7 +211,11 @@ function getLayerCapabilities(layer, options) { return layer.name === capability.name; })); if (layerCapability) { - dispatch(updateNode(layer.id, "id", {capabilities: layerCapability, boundingBox: layerCapability.latLonBoundingBox})); + dispatch(updateNode(layer.id, "id", { + capabilities: layerCapability, + boundingBox: layerCapability.latLonBoundingBox, + availableStyles: Array.isArray(layerCapability.style) ? layerCapability.style : [layerCapability.style] + })); } // return dispatch(updateNode(layer.id, "id", {capabilities: capabilities || {"error": "no describe Layer found"}})); diff --git a/web/client/api/WMS.js b/web/client/api/WMS.js index 49cf4b032f..095fb91c93 100644 --- a/web/client/api/WMS.js +++ b/web/client/api/WMS.js @@ -67,7 +67,6 @@ const Api = { resolve(axios.get(parseUrl(getCapabilitiesUrl)).then((response) => { let json = unmarshaller.unmarshalString(response.data); return json && json.value; - })); }); }); diff --git a/web/client/components/TOC/DefaultLayer.jsx b/web/client/components/TOC/DefaultLayer.jsx index c9b3d8559e..25767f74af 100644 --- a/web/client/components/TOC/DefaultLayer.jsx +++ b/web/client/components/TOC/DefaultLayer.jsx @@ -23,6 +23,7 @@ var DefaultLayer = React.createClass({ node: React.PropTypes.object, settings: React.PropTypes.object, propertiesChangeHandler: React.PropTypes.func, + retrieveLayerData: React.PropTypes.func, onToggle: React.PropTypes.func, onZoom: React.PropTypes.func, onSettings: React.PropTypes.func, @@ -56,6 +57,7 @@ var DefaultLayer = React.createClass({ onToggle: () => {}, onZoom: () => {}, onSettings: () => {}, + retrieveLayerData: () => {}, activateRemoveLayer: false, activateLegendTool: false, activateSettingsTool: false, @@ -106,6 +108,7 @@ var DefaultLayer = React.createClass({ tools.push( {}, updateNode: () => {}, removeNode: () => {}, + retrieveLayerData: () => {}, asModal: true, buttonSize: "large", closeGlyph: "", @@ -98,22 +101,39 @@ const SettingsModal = React.createClass({ ); this.props.hideSettings(); }, - render() { - const general = (); - const display = ( this.updateParams({[key]: value}, this.props.realtimeUpdate)} />); + }, + renderDisplay() { + return ( this.updateParams({[key]: value}, this.props.realtimeUpdate)} />); + }, + renderStyleTab() { + if (this.props.element.type === "wms") { + return (); + } + }, + render() { + const general = this.renderGeneral(); + const display = this.renderDisplay(); + const style = this.renderStyleTab(); const tabs = ( }>{general} }>{display} - } disabled>Tab 3 content + } disabled={!style} >{style} ); const footer = ( {this.props.includeCloseButton ? : } diff --git a/web/client/components/TOC/fragments/settings/WMSStyle.jsx b/web/client/components/TOC/fragments/settings/WMSStyle.jsx new file mode 100644 index 0000000000..e404d5f60b --- /dev/null +++ b/web/client/components/TOC/fragments/settings/WMSStyle.jsx @@ -0,0 +1,54 @@ +/** + * 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. + */ + +var React = require('react'); +// const Message = require('../../../I18N/Message'); +const Select = require('react-select'); +const {Button, Glyphicon} = require('react-bootstrap'); + +/** + * General Settings form for layer + */ +const WMSStyle = React.createClass({ + propTypes: { + retrieveLayerData: React.PropTypes.func, + updateSettings: React.PropTypes.func, + element: React.PropTypes.object, + groups: React.PropTypes.array + }, + getDefaultProps() { + return { + element: {}, + retrieveLayerData: () => {}, + updateSettings: () => {} + }; + }, + render() { + return (
+ { return {label: item.title || item.name, value: item.name}; }))} value={this.props.element.style || ""} onChange={(selected) => { - this.updateEntry("style", {target: {value: selected.value || ""}}); + this.updateEntry("style", {target: {value: (selected && selected.value) || ""}}); }} />
+ {this.renderLegend()} + {this.renderError()}
); From 334bc3068f0a20c701638a7b7f4c9817797ae5b3 Mon Sep 17 00:00:00 2001 From: Lorenzo Natali Date: Fri, 4 Nov 2016 17:40:47 +0100 Subject: [PATCH 3/4] Add manual edit style. Add translations and tests --- package.json | 2 +- web/client/actions/__tests__/layers-test.js | 24 ++- web/client/actions/layers.js | 6 +- .../TOC/fragments/settings/WMSStyle.jsx | 39 +++-- .../settings/__tests__/WMSStyle-test.jsx | 122 +++++++++++++ web/client/plugins/Save.jsx | 3 + web/client/plugins/SaveAs.jsx | 3 + .../geoserver/testworkspace/testlayer/wms | 165 ++++++++++++++++++ web/client/translations/data.de-DE | 3 + web/client/translations/data.en-US | 3 + web/client/translations/data.fr-FR | 3 + web/client/translations/data.it-IT | 3 + 12 files changed, 359 insertions(+), 17 deletions(-) create mode 100644 web/client/components/TOC/fragments/settings/__tests__/WMSStyle-test.jsx create mode 100644 web/client/test-resources/geoserver/testworkspace/testlayer/wms diff --git a/package.json b/package.json index 224ddd0f79..84b44f4b9d 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "react-motion": "0.4.4", "react-router": "2.4.0", "react-router-redux": "2.1.0", - "react-select": "1.0.0-beta14", + "react-select": "1.0.0-rc.1", "react-transform-catch-errors": "1.0.2", "redbox-react": "1.2.4", "redux-devtools": "3.1.1", diff --git a/web/client/actions/__tests__/layers-test.js b/web/client/actions/__tests__/layers-test.js index 937d5f4d8f..3fc4c94c24 100644 --- a/web/client/actions/__tests__/layers-test.js +++ b/web/client/actions/__tests__/layers-test.js @@ -33,7 +33,8 @@ var { removeLayer, showSettings, hideSettings, - updateSettings + updateSettings, + getLayerCapabilities } = require('../layers'); describe('Test correctness of the layers actions', () => { @@ -167,4 +168,25 @@ describe('Test correctness of the layers actions', () => { expect(action.type).toBe(UPDATE_SETTINGS); expect(action.options).toEqual({opacity: 0.5, size: 500}); }); + it('get layer capabilities', (done) => { + const layer = { + id: "TEST_ID", + name: 'testworkspace:testlayer', + title: 'Layer', + visibility: true, + storeIndex: 9, + type: 'shapefile', + url: 'base/web/client/test-resources/geoserver/wms' + }; + const actionCall = getLayerCapabilities(layer); + expect(actionCall).toExist(); + actionCall((action)=> { + expect(action).toExist(); + expect(action.options).toExist(); + expect(action.type === UPDATE_NODE); + if (action.options.capabilities) { + done(); + } + }); + }); }); diff --git a/web/client/actions/layers.js b/web/client/actions/layers.js index 36e6d1f98f..7f6358e381 100644 --- a/web/client/actions/layers.js +++ b/web/client/actions/layers.js @@ -196,6 +196,9 @@ function getLayerCapabilities(layer, options) { } return (dispatch) => { // TODO, look ad current cached capabilities; + dispatch(updateNode(layer.id, "id", { + capabilitiesLoading: true + })); return WMS.getCapabilities(reqUrl, options).then((capabilities) => { let layers = _.get(capabilities, "capability.layer.layer"); let layerCapability; @@ -213,6 +216,7 @@ function getLayerCapabilities(layer, options) { if (layerCapability) { dispatch(updateNode(layer.id, "id", { capabilities: layerCapability, + capabilitiesLoading: null, boundingBox: layerCapability.latLonBoundingBox, availableStyles: layerCapability.style && (Array.isArray(layerCapability.style) ? layerCapability.style : [layerCapability.style]) })); @@ -220,7 +224,7 @@ function getLayerCapabilities(layer, options) { // return dispatch(updateNode(layer.id, "id", {capabilities: capabilities || {"error": "no describe Layer found"}})); }).catch((error) => { - dispatch(updateNode(layer.id, "id", {capabilities: {error: "error getting capabilities", details: error}} )); + dispatch(updateNode(layer.id, "id", {capabilitiesLoading: null, capabilities: {error: "error getting capabilities", details: error}} )); // return dispatch(updateNode(layer.id, "id", {capabilities: capabilities || {"error": "no describe Layer found"}})); diff --git a/web/client/components/TOC/fragments/settings/WMSStyle.jsx b/web/client/components/TOC/fragments/settings/WMSStyle.jsx index 146a1ae574..e2543d60e4 100644 --- a/web/client/components/TOC/fragments/settings/WMSStyle.jsx +++ b/web/client/components/TOC/fragments/settings/WMSStyle.jsx @@ -7,7 +7,7 @@ */ var React = require('react'); -// const Message = require('../../../I18N/Message'); +const Message = require('../../../I18N/Message'); const Select = require('react-select'); const {Button, Glyphicon, Alert} = require('react-bootstrap'); @@ -29,28 +29,39 @@ const WMSStyle = React.createClass({ }; }, renderLegend() { - if (this.props.element && this.props.element.availableStyles) { - let i = this.props.element.availableStyles.findIndex((item) => item.name === this.props.element.style); - if (i >= 0) { - let style = this.props.element.availableStyles[i]; - let legendUrl = style.legendURL && style.legendURL[0]; - } - } + // legend can not added because of this issue + // https://github.com/highsource/ogc-schemas/issues/183 + return null; }, renderError() { if (this.props.element && this.props.element.capabilities && this.props.element && this.props.element.capabilities.error) { - return There was an error getting layer's style list; + return ; } }, render() { + let options = [{label: "Default Style", value: ""}].concat((this.props.element.availableStyles || []).map((item) => { + return {label: item.title || item.name, value: item.name}; + })); + let currentStyleIndex = this.props.element.style && this.props.element.availableStyles && this.props.element.availableStyles.findIndex( el => el.name === this.props.element.style); + if (!(currentStyleIndex >= 0) && this.props.element.style) { + options.push({label: this.props.element.style, value: this.props.element.style }); + } return (
-