From c2b0d5408a39cbe3355d05d30057bfb181972ac5 Mon Sep 17 00:00:00 2001 From: allyoucanmap Date: Mon, 24 Jun 2024 16:16:09 +0200 Subject: [PATCH 1/4] #4675 Remove unused code --- .../actions/__tests__/rasterstyler-test.js | 34 - web/client/actions/__tests__/styler-test.js | 29 - web/client/actions/rasterstyler.js | 25 - web/client/actions/styler.js | 54 - web/client/actions/vectorstyler.js | 55 - web/client/api/WFS3.js | 144 --- web/client/api/__tests__/WFS3-test.js | 252 ---- .../map/leaflet/FeatureCollection.jsx | 31 - .../map/openlayers/__tests__/Layer-test.jsx | 73 -- .../map/openlayers/plugins/WFS3Layer.js | 136 --- .../map/openlayers/plugins/index.js | 1 - .../mapcontrols/annotations/Annotations.jsx | 429 ------- .../annotations/AnnotationsConfig.js | 116 -- .../annotations/AnnotationsEditor.jsx | 900 --------------- .../annotations/DropdownFeatureType.jsx | 91 -- .../mapcontrols/annotations/FeaturesList.jsx | 257 ----- .../annotations/SelectAnnotationsFile.jsx | 100 -- .../annotations/__tests__/Annotations-test.js | 245 ---- .../__tests__/AnnotationsEditor-test.js | 587 ---------- .../__tests__/DropdownFeatureType-test.js | 123 -- .../annotations/__tests__/FeatureList-test.js | 308 ----- .../__tests__/SelectAnnotationsFile-test.js | 86 -- web/client/components/style/BandSelector.jsx | 128 --- web/client/components/style/CircleStyler.jsx | 123 -- web/client/components/style/ColorMapGrid.jsx | 122 -- .../ColorPickerRenderer.jsx | 98 -- .../ColorMapGridComponents/NumberRenderer.jsx | 113 -- .../ReactCellRendererFactoryParams.jsx | 25 - .../ColorMapGridComponents/colorenderer.css | 28 - .../ColorMapGridComponents/numberpicker.css | 7 - .../components/style/ColorRampSelector.jsx | 72 -- .../components/style/ColorRangeSelector.jsx | 79 -- web/client/components/style/EqualInterval.jsx | 204 ---- .../EqualIntervalComponents/ColorRamp.js | 17 - .../EqualIntervalComponents/ColorRampItem.jsx | 37 - .../ExtendColorBrewer.js | 69 -- .../__tests__/ColorRampItem-test.jsx | 54 - .../components/style/MarkerPropertyPicker.jsx | 72 -- web/client/components/style/OpacityPicker.jsx | 50 - web/client/components/style/PolygonStyler.jsx | 127 --- .../components/style/PolylineStyler.jsx | 111 -- .../components/style/PseudoColorSettings.jsx | 108 -- .../style/RasterStyleTypePicker.jsx | 51 - .../components/style/ScaleDenominator.jsx | 98 -- web/client/components/style/TextStyler.jsx | 244 ---- .../style/__tests__/BandSelector-test.jsx | 41 - .../style/__tests__/ColorMapGrid-test.jsx | 41 - .../style/__tests__/EqualInterval-test.jsx | 33 - .../style/__tests__/OpacityPicker-test.jsx | 31 - .../__tests__/PseudoColorSettings-test.jsx | 43 - .../__tests__/RasterStyleTypePicker-test.jsx | 31 - .../style/__tests__/ScaleDenominator-test.jsx | 37 - web/client/components/style/opacitypicker.css | 22 - .../style/thumbGeoms/CircleThumb.jsx | 54 - .../components/style/thumbGeoms/LineThumb.jsx | 51 - .../style/thumbGeoms/MultiGeomThumb.jsx | 101 -- .../style/thumbGeoms/PolygonThumb.jsx | 62 - .../thumbGeoms/__tests__/LineThumb-test.js | 40 - .../__tests__/MultiGeomThumb-test.js | 81 -- .../thumbGeoms/__tests__/PolygonThumb-test.js | 43 - web/client/components/style/vector/Fill.jsx | 82 -- .../components/style/vector/Manager.jsx | 237 ---- web/client/components/style/vector/Stroke.jsx | 133 --- web/client/components/style/vector/Text.jsx | 229 ---- .../style/vector/marker/MarkerGlyph.jsx | 164 --- .../style/vector/marker/MarkerType.jsx | 66 -- .../style/vector/marker/SymbolLayout.jsx | 200 ---- .../components/style/vector/marker/sample.xml | 7 - web/client/libs/openlayers.js | 8 - web/client/plugins/FeatureGrid.jsx | 60 - web/client/plugins/MeasurePanel.jsx | 65 -- web/client/plugins/MeasureResults.jsx | 71 -- web/client/plugins/RasterStyler.jsx | 278 ----- web/client/plugins/ShapeFile.jsx | 107 -- web/client/plugins/Styler.jsx | 355 ------ web/client/plugins/VectorStyler.jsx | 294 ----- web/client/plugins/omnibar/OmniBarMenu.jsx | 58 - web/client/plugins/rasterstyler/index.js | 72 -- .../plugins/rasterstyler/rasterstyler.css | 7 - web/client/plugins/styler/styler.css | 29 - web/client/plugins/vectorstyler/index.js | 36 - .../plugins/vectorstyler/vectorstyler.css | 7 - .../product/assets/img/rasterstyler.jpg | Bin 56611 -> 0 bytes .../reducers/__tests__/rasterstyler-test.js | 34 - web/client/reducers/rasterstyler.js | 65 -- web/client/reducers/styler.js | 32 - web/client/reducers/vectorstyler.js | 136 --- web/client/selectors/vectorstyler.js | 18 - web/client/utils/LegacyAnnotationsUtils.js | 739 ------------ web/client/utils/SLDUtils.js | 244 ---- .../__tests__/LegacyAnnotationsUtils-test.js | 1010 ----------------- web/client/utils/__tests__/SLDUtils-test.js | 89 -- 92 files changed, 11756 deletions(-) delete mode 100644 web/client/actions/__tests__/rasterstyler-test.js delete mode 100644 web/client/actions/__tests__/styler-test.js delete mode 100644 web/client/actions/rasterstyler.js delete mode 100644 web/client/actions/styler.js delete mode 100644 web/client/actions/vectorstyler.js delete mode 100644 web/client/api/WFS3.js delete mode 100644 web/client/api/__tests__/WFS3-test.js delete mode 100644 web/client/components/map/leaflet/FeatureCollection.jsx delete mode 100644 web/client/components/map/openlayers/plugins/WFS3Layer.js delete mode 100644 web/client/components/mapcontrols/annotations/Annotations.jsx delete mode 100644 web/client/components/mapcontrols/annotations/AnnotationsConfig.js delete mode 100644 web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx delete mode 100644 web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx delete mode 100644 web/client/components/mapcontrols/annotations/FeaturesList.jsx delete mode 100644 web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx delete mode 100644 web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js delete mode 100644 web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js delete mode 100644 web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js delete mode 100644 web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js delete mode 100644 web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js delete mode 100644 web/client/components/style/BandSelector.jsx delete mode 100644 web/client/components/style/CircleStyler.jsx delete mode 100644 web/client/components/style/ColorMapGrid.jsx delete mode 100644 web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx delete mode 100644 web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx delete mode 100644 web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx delete mode 100644 web/client/components/style/ColorMapGridComponents/colorenderer.css delete mode 100644 web/client/components/style/ColorMapGridComponents/numberpicker.css delete mode 100644 web/client/components/style/ColorRampSelector.jsx delete mode 100644 web/client/components/style/ColorRangeSelector.jsx delete mode 100644 web/client/components/style/EqualInterval.jsx delete mode 100644 web/client/components/style/EqualIntervalComponents/ColorRamp.js delete mode 100644 web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx delete mode 100644 web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js delete mode 100644 web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx delete mode 100644 web/client/components/style/MarkerPropertyPicker.jsx delete mode 100644 web/client/components/style/OpacityPicker.jsx delete mode 100644 web/client/components/style/PolygonStyler.jsx delete mode 100644 web/client/components/style/PolylineStyler.jsx delete mode 100644 web/client/components/style/PseudoColorSettings.jsx delete mode 100644 web/client/components/style/RasterStyleTypePicker.jsx delete mode 100644 web/client/components/style/ScaleDenominator.jsx delete mode 100644 web/client/components/style/TextStyler.jsx delete mode 100644 web/client/components/style/__tests__/BandSelector-test.jsx delete mode 100644 web/client/components/style/__tests__/ColorMapGrid-test.jsx delete mode 100644 web/client/components/style/__tests__/EqualInterval-test.jsx delete mode 100644 web/client/components/style/__tests__/OpacityPicker-test.jsx delete mode 100644 web/client/components/style/__tests__/PseudoColorSettings-test.jsx delete mode 100644 web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx delete mode 100644 web/client/components/style/__tests__/ScaleDenominator-test.jsx delete mode 100644 web/client/components/style/opacitypicker.css delete mode 100644 web/client/components/style/thumbGeoms/CircleThumb.jsx delete mode 100644 web/client/components/style/thumbGeoms/LineThumb.jsx delete mode 100644 web/client/components/style/thumbGeoms/MultiGeomThumb.jsx delete mode 100644 web/client/components/style/thumbGeoms/PolygonThumb.jsx delete mode 100644 web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js delete mode 100644 web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js delete mode 100644 web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js delete mode 100644 web/client/components/style/vector/Fill.jsx delete mode 100644 web/client/components/style/vector/Manager.jsx delete mode 100644 web/client/components/style/vector/Stroke.jsx delete mode 100644 web/client/components/style/vector/Text.jsx delete mode 100644 web/client/components/style/vector/marker/MarkerGlyph.jsx delete mode 100644 web/client/components/style/vector/marker/MarkerType.jsx delete mode 100644 web/client/components/style/vector/marker/SymbolLayout.jsx delete mode 100644 web/client/components/style/vector/marker/sample.xml delete mode 100644 web/client/libs/openlayers.js delete mode 100644 web/client/plugins/FeatureGrid.jsx delete mode 100644 web/client/plugins/MeasurePanel.jsx delete mode 100644 web/client/plugins/MeasureResults.jsx delete mode 100644 web/client/plugins/RasterStyler.jsx delete mode 100644 web/client/plugins/ShapeFile.jsx delete mode 100644 web/client/plugins/Styler.jsx delete mode 100644 web/client/plugins/VectorStyler.jsx delete mode 100644 web/client/plugins/omnibar/OmniBarMenu.jsx delete mode 100644 web/client/plugins/rasterstyler/index.js delete mode 100644 web/client/plugins/rasterstyler/rasterstyler.css delete mode 100644 web/client/plugins/styler/styler.css delete mode 100644 web/client/plugins/vectorstyler/index.js delete mode 100644 web/client/plugins/vectorstyler/vectorstyler.css delete mode 100644 web/client/product/assets/img/rasterstyler.jpg delete mode 100644 web/client/reducers/__tests__/rasterstyler-test.js delete mode 100644 web/client/reducers/rasterstyler.js delete mode 100644 web/client/reducers/styler.js delete mode 100644 web/client/reducers/vectorstyler.js delete mode 100644 web/client/selectors/vectorstyler.js delete mode 100644 web/client/utils/LegacyAnnotationsUtils.js delete mode 100644 web/client/utils/SLDUtils.js delete mode 100644 web/client/utils/__tests__/LegacyAnnotationsUtils-test.js delete mode 100644 web/client/utils/__tests__/SLDUtils-test.js diff --git a/web/client/actions/__tests__/rasterstyler-test.js b/web/client/actions/__tests__/rasterstyler-test.js deleted file mode 100644 index 2abeb2ee40..0000000000 --- a/web/client/actions/__tests__/rasterstyler-test.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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. - */ - -import expect from 'expect'; - -import { - SET_RASTERSTYLE_PARAMETER, - SET_RASTER_LAYER, - setRasterStyleParameter, - setRasterLayer -} from '../rasterstyler'; - -describe('Test correctness of the rasterstyle actions', () => { - - it('setRasterStyleParameter', () => { - const retVal = setRasterStyleParameter('cmp', 'property', 'val'); - expect(retVal).toExist(); - expect(retVal.type).toBe(SET_RASTERSTYLE_PARAMETER); - expect(retVal.component).toBe('cmp'); - expect(retVal.property).toBe('property'); - expect(retVal.value).toBe('val'); - }); - it('setRasterLayer', () => { - const retVal = setRasterLayer('layer'); - expect(retVal).toExist(); - expect(retVal.type).toBe(SET_RASTER_LAYER); - expect(retVal.layer).toBe('layer'); - }); -}); diff --git a/web/client/actions/__tests__/styler-test.js b/web/client/actions/__tests__/styler-test.js deleted file mode 100644 index f4565831de..0000000000 --- a/web/client/actions/__tests__/styler-test.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright 20167, 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. - */ - -import expect from 'expect'; - -import { STYLER_RESET, SET_STYLER_LAYER, setStylerLayer, reset } from '../styler'; - -describe('Test correctness of the rasterstyle actions', () => { - - it('setStylerLayer', () => { - const layer = {name: "TEST"}; - const retVal = setStylerLayer(layer); - expect(retVal).toExist(); - expect(retVal.type).toBe(SET_STYLER_LAYER); - expect(retVal.layer).toBe(layer); - }); - it('setRasterLayer', () => { - const layer = {name: "TEST"}; - const retVal = reset(layer); - expect(retVal).toExist(); - expect(retVal.type).toBe(STYLER_RESET); - expect(retVal.layer).toBe(layer); - }); -}); diff --git a/web/client/actions/rasterstyler.js b/web/client/actions/rasterstyler.js deleted file mode 100644 index cbca1700c1..0000000000 --- a/web/client/actions/rasterstyler.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * 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. - */ - -export const SET_RASTERSTYLE_PARAMETER = 'SET_RASTERSTYLE_PARAMETER'; -export const SET_RASTER_LAYER = 'SET_RASTER_LAYER'; - -export function setRasterStyleParameter(component, property, value) { - return { - type: SET_RASTERSTYLE_PARAMETER, - component, - property, - value - }; -} -export function setRasterLayer(layer) { - return { - type: SET_RASTER_LAYER, - layer - }; -} diff --git a/web/client/actions/styler.js b/web/client/actions/styler.js deleted file mode 100644 index 673f4dbd2a..0000000000 --- a/web/client/actions/styler.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * 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. - */ - -export const STYLE_SAVED = 'STYLER_STYLE_SAVED'; -export const SET_STYLER_LAYER = 'SET_STYLER_LAYER'; -export const STYLE_SAVE_ERROR = 'STYLE_SAVE_ERROR'; -export const STYLER_RESET = 'STYLER_RESET'; - -import Layers from '../api/geoserver/Layers'; -import { saveStyle } from '../api/geoserver/Styles'; - -export function setStylerLayer(layer) { - return { - type: SET_STYLER_LAYER, - layer - }; -} -export function styleSaved(name, style) { - return { - type: STYLE_SAVED, - name, - style - }; -} -export function styleSaveError(layer, style, error) { - return { - type: STYLE_SAVE_ERROR, - layer, - style, - error - }; -} -export function reset(layer) { - return { - type: STYLER_RESET, - layer - }; -} -export function saveLayerDefaultStyle(geoserverBaseUrl, layerName, style) { - return (dispatch) => { - return Layers.getLayer(geoserverBaseUrl, layerName).then((layer) => { - saveStyle(geoserverBaseUrl, layer.defaultStyle && layer.defaultStyle.name, style).then(()=> { - dispatch(styleSaved(layer.defaultStyle.name, style)); - }).catch((e) => {styleSaveError(layerName, layer.defaultStyle, e); }); - - }).catch((e) => {styleSaveError(layerName, null, e); }); - - }; -} diff --git a/web/client/actions/vectorstyler.js b/web/client/actions/vectorstyler.js deleted file mode 100644 index 44bea603ee..0000000000 --- a/web/client/actions/vectorstyler.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * 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. - */ -import uuid from 'uuid'; - -export const SET_VECTOR_RULE_PARAMETER = 'SET_VECTOR_RULE_PARAMETER'; -export const NEW_VECTOR_RULE = 'NEW_VECTOR_RULE'; -export const REMOVE_VECTOR_RULE = 'REMOVE_VECTOR_RULE'; -export const SELECT_VECTOR_RULE = 'SELECT_VECTOR_RULE'; -export const SET_VECTORSTYLE_PARAMETER = 'SET_VECTORSTYLE_PARAMETER'; -export const SET_VECTOR_LAYER = 'SET_VECTOR_LAYER'; - -export function setVectorStyleParameter(component, property, value) { - return { - type: SET_VECTORSTYLE_PARAMETER, - component, - property, - value - }; -} -export function setVectorRuleParameter(property, value) { - return { - type: SET_VECTOR_RULE_PARAMETER, - property, - value - }; -} -export function setVectorLayer(layer) { - return { - type: SET_VECTOR_LAYER, - layer - }; -} -export function newVectorRule() { - return { - type: NEW_VECTOR_RULE, - id: uuid.v1() - }; -} -export function removeVectorRule(id) { - return { - type: REMOVE_VECTOR_RULE, - id - }; -} -export function selectVectorRule(id) { - return { - type: SELECT_VECTOR_RULE, - id - }; -} diff --git a/web/client/api/WFS3.js b/web/client/api/WFS3.js deleted file mode 100644 index b3d5aff87d..0000000000 --- a/web/client/api/WFS3.js +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2019, 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. - */ - -import axios from 'axios'; -import head from 'lodash/head'; -import isString from 'lodash/isString'; -import ConfigUtils from '../utils/ConfigUtils'; - -const capabilitiesCache = {}; - -const collectionToLayer = (collection) => { - const { name, title, extent, links } = collection; - const spatial = extent && extent.spatial || [-180, -90, 180, 90]; - const { href: layerUrl, type: format } = head((links || []).filter(({ rel }) => rel === 'tiles')) || {}; - const { href: tilingSchemes } = head((links || []).filter(({ rel }) => rel === 'tilingSchemes')) || {}; - const { href: tilingScheme } = head((links || []).filter(({ rel }) => rel === 'tilingScheme')) || {}; - return { - name, - title, - type: 'wfs3', - visibility: true, - url: layerUrl, - format, - tilingScheme, - tilingSchemes, - bbox: { - crs: 'EPSG:4326', - bounds: { - minx: spatial[0], - miny: spatial[1], - maxx: spatial[2], - maxy: spatial[3] - } - } - }; -}; - -const searchAndPaginate = (json = {}, startPosition, maxRecords, text, url) => { - const { collections } = json; - const filteredLayers = collections - .filter((layer = {}) => !text - || layer.name && layer.name.toLowerCase().indexOf(text.toLowerCase()) !== -1 - || layer.title && layer.title.toLowerCase().indexOf(text.toLowerCase()) !== -1); - return { - numberOfRecordsMatched: filteredLayers.length, - numberOfRecordsReturned: Math.min(maxRecords, filteredLayers.length), - nextRecord: startPosition + Math.min(maxRecords, filteredLayers.length) + 1, - records: filteredLayers - .filter((layer, index) => index >= startPosition - 1 && index < startPosition - 1 + maxRecords) - .map((collection) => ({ - ...collection, - ...collectionToLayer(collection), - capabilitiesUrl: url - })) - }; -}; - -const parseUrl = function(url) { - const serviceUrl = (url || '').split(/\/wfs3\//)[0]; - return `${serviceUrl}/wfs3/collections`; -}; - -export const getRecords = function(url, startPosition, maxRecords, text) { - const cached = capabilitiesCache[url]; - if (cached && new Date().getTime() < cached.timestamp + (ConfigUtils.getConfigProp('cacheExpire') || 60) * 1000) { - return new Promise((resolve) => { - resolve(searchAndPaginate(cached.data, startPosition, maxRecords, text, url)); - }); - } - return axios.get(parseUrl(url)) - .then(({ data }) => { - capabilitiesCache[url] = { - timestamp: new Date().getTime(), - data - }; - return searchAndPaginate(data, startPosition, maxRecords, text, url); - }); -}; - -export const textSearch = function(url, startPosition, maxRecords, text) { - return getRecords(url, startPosition, maxRecords, text); -}; - -export const getTilingSchemes = (layer) => { - const { tilingSchemes, tilingScheme } = layer; - if (isString(tilingSchemes)) { - return axios.get(tilingSchemes) - .then(({ data }) => { - return data && data.tilingSchemes && data.tilingSchemes.length > 0 - ? axios.all( - data.tilingSchemes.map((tilingSchemeId) => - axios.get(tilingScheme.replace('{tilingSchemeId}', tilingSchemeId)) - .then(({ data: scheme }) => scheme) - .catch(() => null) - ) - ) - .then((schemes) => ({ - tilingSchemes: { - url: tilingSchemes, - schemes: schemes.filter(scheme => scheme) - }, - allowedSRS: schemes - .filter(scheme => scheme) - .reduce((acc, { supportedCRS }) => { - return { - ...acc, - [supportedCRS]: true - }; - }, {}) - })) - : { - tilingSchemes: { - url: tilingSchemes, - schemes: null - }, - allowedSRS: {} - }; - }); - } - return new Promise((resolve) => resolve(tilingSchemes)); -}; - -export const getLayerFromId = (serviceUrl, collectionId) => { - return axios.get(`${parseUrl(serviceUrl)}/${collectionId}`) - .then(({ data: collection }) => { - const layer = collectionToLayer(collection); - return getTilingSchemes(layer) - .then((params) => ({ - ...layer, - ...params - })); - }); -}; - -export const reset = () => { - Object.keys(capabilitiesCache).forEach(key => { - delete capabilitiesCache[key]; - }); -}; diff --git a/web/client/api/__tests__/WFS3-test.js b/web/client/api/__tests__/WFS3-test.js deleted file mode 100644 index c3b28b5ba3..0000000000 --- a/web/client/api/__tests__/WFS3-test.js +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright 2019, 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. - */ - -import expect from 'expect'; -import { - getTilingSchemes, - getLayerFromId, - textSearch, - reset -} from '../WFS3'; -import MockAdapter from 'axios-mock-adapter'; -import axios from '../../libs/ajax'; - -let mockAxios; - -describe('Test WFS3 API', () => { - - beforeEach(done => { - mockAxios = new MockAdapter(axios); - setTimeout(done); - }); - - afterEach(done => { - mockAxios.restore(); - setTimeout(done); - reset(); - }); - - it('test getTilingSchemes', (done) => { - - const TILING_SCHEMES_URL = '/geoserver/wfs3/collections/layer_name/tiles'; - const TILING_SCHEMES_ID = 'GoogleMapsCompatible'; - const TILING_SCHEME = { - type: 'TileMatrixSet', - identifier: 'GoogleMapsCompatible', - title: 'GoogleMapsCompatible', - supportedCRS: 'EPSG:3857', - tileMatrix: [{ - matrixHeight: 1, - matrixWidth: 1, - tileHeight: 256, - tileWidth: 256, - identifier: '0', - scaleDenominator: 559082263.9508929, - topLeftCorner: [ - -20037508.34, - 20037508 - ], - type: 'TileMatrix' - }], - boundingBox: { - crs: 'http://www.opengis.net/def/crs/EPSG/0/3857', - lowerCorner: [ - -20037508.34, - -20037508.34 - ], - upperCorner: [ - 20037508.34, - 20037508.34 - ], - type: 'BoundingBox' - }, - wellKnownScaleSet: 'http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible' - }; - - mockAxios.onGet(TILING_SCHEMES_URL).reply(() => { - return [ 200, { tilingSchemes: [ TILING_SCHEMES_ID ] }]; - }); - - mockAxios.onGet(`${TILING_SCHEMES_URL}/${TILING_SCHEMES_ID}`).reply(() => { - return [ 200, TILING_SCHEME]; - }); - - const layer = { - tilingScheme: `${TILING_SCHEMES_URL}/{tilingSchemeId}`, - tilingSchemes: TILING_SCHEMES_URL - }; - - getTilingSchemes(layer) - .then(({ tilingSchemes, allowedSRS }) => { - expect(allowedSRS).toEqual({ 'EPSG:3857': true }); - expect(tilingSchemes).toEqual({ - url: TILING_SCHEMES_URL, - schemes: [ TILING_SCHEME ] - }); - done(); - }); - }); - - it('test getLayerFromId', (done) => { - const SERVICE_URL = '/geoserver/wfs3/collections/'; - const COLLECTIONS_ID = 'layer_name'; - const TILING_SCHEMES_URL = '/geoserver/wfs3/collections/layer_name/tiles'; - const TILING_SCHEMES_ID = 'GoogleMapsCompatible'; - const COLLECTION = { - name: COLLECTIONS_ID, - title: 'Layer Title', - extent: { - spatial: [-180, -90, 180, 90] - }, - links: [ - { - href: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}/{level}/{row}/{col}', - rel: 'tiles', - type: 'application/vnd.mapbox-vector-tile' - }, - { - href: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}', - rel: 'tilingScheme', - type: 'application/json', - title: '...' - }, - { - href: TILING_SCHEMES_URL, - rel: 'tilingSchemes', - type: 'application/json', - title: '...' - } - ] - }; - - const TILING_SCHEME = { - type: 'TileMatrixSet', - identifier: 'GoogleMapsCompatible', - title: 'GoogleMapsCompatible', - supportedCRS: 'EPSG:3857', - tileMatrix: [{ - matrixHeight: 1, - matrixWidth: 1, - tileHeight: 256, - tileWidth: 256, - identifier: '0', - scaleDenominator: 559082263.9508929, - topLeftCorner: [ - -20037508.34, - 20037508 - ], - type: 'TileMatrix' - }], - boundingBox: { - crs: 'http://www.opengis.net/def/crs/EPSG/0/3857', - lowerCorner: [ - -20037508.34, - -20037508.34 - ], - upperCorner: [ - 20037508.34, - 20037508.34 - ], - type: 'BoundingBox' - }, - wellKnownScaleSet: 'http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible' - }; - - mockAxios.onGet(`${SERVICE_URL}${COLLECTIONS_ID}`).reply(() => { - return [ 200, COLLECTION]; - }); - - mockAxios.onGet(TILING_SCHEMES_URL).reply(() => { - return [ 200, { tilingSchemes: [ TILING_SCHEMES_ID ] }]; - }); - - mockAxios.onGet(`${TILING_SCHEMES_URL}/${TILING_SCHEMES_ID}`).reply(() => { - return [ 200, TILING_SCHEME]; - }); - - getLayerFromId(SERVICE_URL, COLLECTIONS_ID) - .then((layer) => { - expect(layer).toEqual({ - name: COLLECTIONS_ID, - title: 'Layer Title', - type: 'wfs3', - visibility: true, - url: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}/{level}/{row}/{col}', - format: 'application/vnd.mapbox-vector-tile', - tilingScheme: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}', - tilingSchemes: { - url: TILING_SCHEMES_URL, - schemes: [ TILING_SCHEME ] - }, - allowedSRS: { 'EPSG:3857': true }, - bbox: { - crs: 'EPSG:4326', - bounds: { - minx: -180, - miny: -90, - maxx: 180, - maxy: 90 - } - }}); - done(); - }); - }); - it('test textSearch', (done) => { - const TILING_SCHEMES_URL = '/geoserver/wfs3/collections'; - const START_POSITION = 1; - const MAX_RECORDS = 1; - const TEXT = ''; - const COLLECTIONS = [ - { - name: 'layer_name_01', - title: 'layer title 01', - extent: { - spatial: [-180, -90, 180, 90] - }, - links: [] - }, - { - name: 'layer_name_02', - title: 'layer title 02', - extent: { - spatial: [-180, -90, 180, 90] - }, - links: [] - } - ]; - - mockAxios.onGet(TILING_SCHEMES_URL) - .reply(() => { - return [ 200, { collections: COLLECTIONS }]; - }); - textSearch(TILING_SCHEMES_URL, START_POSITION, MAX_RECORDS, TEXT) - .then((res) => { - expect(res).toEqual({ - numberOfRecordsMatched: 2, - numberOfRecordsReturned: 1, - nextRecord: 3, - records: [{ - name: 'layer_name_01', - title: 'layer title 01', - extent: { spatial: [ -180, -90, 180, 90 ] }, - links: [], - type: 'wfs3', - visibility: true, - url: undefined, - format: undefined, - tilingScheme: undefined, - tilingSchemes: undefined, - bbox: { crs: 'EPSG:4326', bounds: { minx: -180, miny: -90, maxx: 180, maxy: 90 } }, - capabilitiesUrl: '/geoserver/wfs3/collections' - }] - }); - done(); - }); - }); -}); - diff --git a/web/client/components/map/leaflet/FeatureCollection.jsx b/web/client/components/map/leaflet/FeatureCollection.jsx deleted file mode 100644 index 2017a56782..0000000000 --- a/web/client/components/map/leaflet/FeatureCollection.jsx +++ /dev/null @@ -1,31 +0,0 @@ -var PropTypes = require('prop-types'); -/** - * Copyright 2015, 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'); - - -class Feature extends React.Component { - static propTypes = { - type: PropTypes.string, - container: PropTypes.object, // TODO it must be a L.GeoJSON - geometry: PropTypes.object - }; - - componentDidMount() { - } - - componentWillUnmount() { - } - - render() { - return null; - } -} - -module.exports = Feature; diff --git a/web/client/components/map/openlayers/__tests__/Layer-test.jsx b/web/client/components/map/openlayers/__tests__/Layer-test.jsx index 00886485a3..e6f8a26af4 100644 --- a/web/client/components/map/openlayers/__tests__/Layer-test.jsx +++ b/web/client/components/map/openlayers/__tests__/Layer-test.jsx @@ -23,7 +23,6 @@ import '../plugins/GraticuleLayer'; import '../plugins/OverlayLayer'; import '../plugins/TMSLayer'; import '../plugins/WFSLayer'; -import '../plugins/WFS3Layer'; import '../plugins/ElevationLayer'; import '../plugins/ArcGISLayer'; @@ -2878,78 +2877,6 @@ describe('Openlayers layer', () => { expect(layer.layer.getSource()).toBeTruthy(); }); - it('test render a wfs3 layer', () => { - - const options = { - id: 'layer_id', - name: 'layer_name', - title: 'Layer Title', - type: 'wfs3', - visibility: true, - url: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}/{level}/{row}/{col}', - format: 'application/vnd.mapbox-vector-tile', - tilingScheme: '/geoserver/wfs3/collections/layer_name/tiles/{tilingSchemeId}', - tilingSchemes: { - url: '/geoserver/wfs3/collections/layer_name/tiles', - schemes: [ - { - type: 'TileMatrixSet', - identifier: 'GoogleMapsCompatible', - title: 'GoogleMapsCompatible', - supportedCRS: 'EPSG:3857', - tileMatrix: [{ - matrixHeight: 1, - matrixWidth: 1, - tileHeight: 256, - tileWidth: 256, - identifier: '0', - scaleDenominator: 559082263.9508929, - topLeftCorner: [ - -20037508.34, - 20037508 - ], - type: 'TileMatrix' - }], - boundingBox: { - crs: 'http://www.opengis.net/def/crs/EPSG/0/3857', - lowerCorner: [ - -20037508.34, - -20037508.34 - ], - upperCorner: [ - 20037508.34, - 20037508.34 - ], - type: 'BoundingBox' - }, - wellKnownScaleSet: 'http://www.opengis.net/def/wkss/OGC/1.0/GoogleMapsCompatible' - } - ] - }, - bbox: { - crs: 'EPSG:4326', - bounds: { - minx: -156.2575, - miny: -90, - maxx: 123.33333333333333, - maxy: 46.5475 - } - }, - allowedSRS: { - 'EPSG:3857': true - } - }; - let layer = ReactDOM.render(, document.getElementById("container")); - - expect(layer).toBeTruthy(); - expect(map.getLayers().getLength()).toBe(1); - expect(layer.layer.constructor.name).toBe('VectorTileLayer'); - expect(layer.layer.getSource().format_.constructor.name).toBe('MVT'); - }); - it('should apply native ol min and max resolution on wms layer', () => { const minResolution = 1222; // ~ zoom 7 Web Mercator const maxResolution = 39135; // ~ zoom 2 Web Mercator diff --git a/web/client/components/map/openlayers/plugins/WFS3Layer.js b/web/client/components/map/openlayers/plugins/WFS3Layer.js deleted file mode 100644 index fa1aec492c..0000000000 --- a/web/client/components/map/openlayers/plugins/WFS3Layer.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * 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. - */ - -import head from 'lodash/head'; -import urlParser from 'url'; - -import CoordinatesUtils from '../../../../utils/CoordinatesUtils'; -import MapUtils from '../../../../utils/MapUtils'; -import Layers from '../../../../utils/openlayers/Layers'; -import {addAuthenticationParameter} from '../../../../utils/SecurityUtils'; - -import {get, getTransform} from 'ol/proj'; -import {applyTransform} from 'ol/extent'; -import TileGrid from 'ol/tilegrid/TileGrid'; -import VectorTileLayer from 'ol/layer/VectorTile'; -import VectorTile from 'ol/source/VectorTile'; -import MVT from 'ol/format/MVT'; - -import { isVectorFormat } from '../../../../utils/VectorTileUtils'; -import { OL_VECTOR_FORMATS, applyStyle } from '../../../../utils/openlayers/VectorTileUtils'; - -const createLayer = (options) => { - - const srs = CoordinatesUtils.normalizeSRS(options.srs || 'EPSG:3857', options.allowedSRS); - const projection = get(srs); - const metersPerUnit = projection.getMetersPerUnit(); - - const tilingScheme = head(options.tilingSchemes - && options.tilingSchemes.schemes - && options.tilingSchemes.schemes.filter(({ supportedCRS }) => supportedCRS === srs)); - - const { identifier: tilingSchemeId, tileMatrix, boundingBox } = tilingScheme || {}; - const scales = tileMatrix && tileMatrix.map(({ scaleDenominator }) => scaleDenominator); - const mapResolutions = MapUtils.getResolutions(); - - const scaleToResolution = s => s * 0.28E-3 / metersPerUnit; - const matrixResolutions = options.resolutions || scales && scales.map(scaleToResolution); - const resolutions = matrixResolutions || mapResolutions; - - const switchOriginXY = projection.getAxisOrientation().substr(0, 2) === 'ne'; - const origins = tileMatrix && tileMatrix - .map(({ topLeftCorner } = {}) => topLeftCorner) - .map(([ x, y ] = []) => switchOriginXY ? [y, x] : [x, y]); - - const tileSizes = tileMatrix && tileMatrix - .map(({tileWidth, tileHeight}) => [tileWidth, tileHeight]); - - const bbox = options.bbox; - - const extent = bbox - ? applyTransform([ - parseFloat(bbox.bounds.minx), - parseFloat(bbox.bounds.miny), - parseFloat(bbox.bounds.maxx), - parseFloat(bbox.bounds.maxy) - ], getTransform(bbox.crs, options.srs)) - : null; - - const tileGridExtent = boundingBox && boundingBox.lowerCorner && boundingBox.upperCorner - ? [ - ...boundingBox.lowerCorner, - ...boundingBox.upperCorner - ] - : null; - - const tileGrid = new TileGrid({ - extent: tileGridExtent, - minZoom: 0, - origins, - origin: !origins ? [20037508.3428, -20037508.3428] : undefined, - resolutions, - tileSizes, - tileSize: !tileSizes ? [256, 256] : undefined - }); - - let url = (options.url || '') - .replace(/\{tilingSchemeId\}/, tilingSchemeId) - .replace(/\{level\}/, '{z}') - .replace(/\{row\}/, '{y}') - .replace(/\{col\}/, '{x}'); - - let queryParameters = { }; - addAuthenticationParameter(url, queryParameters, options.securityToken); - - const layerUrl = decodeURI(url); - const queryParametersString = urlParser.format({ query: { ...queryParameters } }); - - const Format = isVectorFormat(options.format) && OL_VECTOR_FORMATS[options.format] || MVT; - - const source = new VectorTile({ - format: new Format({ - dataProjection: srs, - layerName: '_layer_' - }), - tileGrid, - url: layerUrl + queryParametersString - }); - - const layer = new VectorTileLayer({ - extent, - msId: options.id, - source: source, - visible: options.visibility !== false, - zIndex: options.zIndex, - minResolution: options.minResolution, - maxResolution: options.maxResolution - }); - - applyStyle(options.vectorStyle, layer); - - return layer; -}; -Layers.registerType('wfs3', { - create: createLayer, - update: (layer, newOptions, oldOptions) => { - if (oldOptions.securityToken !== newOptions.securityToken - || oldOptions.srs !== newOptions.srs) { - return createLayer(newOptions); - } - if (oldOptions.minResolution !== newOptions.minResolution) { - layer.setMinResolution(newOptions.minResolution === undefined ? 0 : newOptions.minResolution); - } - if (oldOptions.maxResolution !== newOptions.maxResolution) { - layer.setMaxResolution(newOptions.maxResolution === undefined ? Infinity : newOptions.maxResolution); - } - return null; - }, - render: () => { - return null; - } -}); diff --git a/web/client/components/map/openlayers/plugins/index.js b/web/client/components/map/openlayers/plugins/index.js index 028fd239f3..5fc479405d 100644 --- a/web/client/components/map/openlayers/plugins/index.js +++ b/web/client/components/map/openlayers/plugins/index.js @@ -17,7 +17,6 @@ export default { TileProviderLayer: require('./TileProviderLayer').default, VectorLayer: require('./VectorLayer').default, WFSLayer: require('./WFSLayer').default, - WFS3Layer: require('./WFS3Layer').default, WMSLayer: require('./WMSLayer').default, WMTSLayer: require('./WMTSLayer').default, COGLayer: require('./COGLayer').default, diff --git a/web/client/components/mapcontrols/annotations/Annotations.jsx b/web/client/components/mapcontrols/annotations/Annotations.jsx deleted file mode 100644 index e9e0d60591..0000000000 --- a/web/client/components/mapcontrols/annotations/Annotations.jsx +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright 2017, 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. - */ - -import bbox from '@turf/bbox'; -import { countBy, head, isUndefined, keys, values } from 'lodash'; -import assign from 'object-assign'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Glyphicon } from 'react-bootstrap'; -import uuidv1 from 'uuid/v1'; - -import { getGeometryGlyphInfo } from '../../../utils/LegacyAnnotationsUtils'; -import { getMessageById } from '../../../utils/LocaleUtils'; -import Message from '../../I18N/Message'; -import BorderLayout from '../../layout/BorderLayout'; -import SideGrid from '../../misc/cardgrids/SideGrid'; -import Filter from '../../misc/Filter'; -import Loader from '../../misc/Loader'; -import Toolbar from '../../misc/toolbar/Toolbar'; -import defaultConfig from './AnnotationsConfig'; -import SelectAnnotationsFile from './SelectAnnotationsFile'; -import Button from '../../misc/Button'; - -/** - * Annotations panel component. - * It can be in different modes: - * - list: when showing the current list of annotations on the map - * - detail: when showing a detail of a specific annotation - * - editing: when editing an annotation - * When in list mode, the list of current map annotations is shown, with: - * - summary card for each annotation, with full detail show on click - * - upload annotations Button - * - new annotation Button - * - download annotations Button - * - filtering widget - * When in detail mode the configured editor is shown on the selected annotation, in viewer mode. - * When in editing mode the configured editor is shown on the selected annotation, in editing mode. - * - * It also handles removal confirmation modals - * @memberof components.mapControls.annotations - * @class - * @prop {string} id id of the borderlayout Component - * @prop {boolean} closing user asked for closing panel when editing - * @prop {boolean} styling flag to state status of styling during editing - * @prop {boolean} showUnsavedChangesModal flag to state status of UnsavedChangesModal - * @prop {boolean} showUnsavedStyleModal flag to state status of UnsavedStyleModal - * @prop {object} editing annotation object currently under editing (null if we are not in editing mode) - * @prop {function} toggleControl triggered when the user closes the annotations panel - * @prop {object} removing object to remove, it is also a flag that means we are currently asking for removing an annotation / geometry. Toggles visibility of the confirm dialog - * @prop {string} mode current mode of operation (list, editing, detail) - * @prop {object} editor editor component, used in detail and editing modes - * @prop {object[]} annotations list of annotations objects to list - * @prop {string} current id of the annotation currently shown in the editor (when not in list mode) - * @prop {object} config configuration object, where overridable stuff is stored (fields config for annotations, marker library, etc.) {@link #components.mapControls.annotations.AnnotationsConfig} - * @prop {string} filter current filter entered by the user - * @prop {function} onToggleUnsavedChangesModal toggles the view of the UnsavedChangesModal - * @prop {function} onToggleUnsavedStyleModal toggles the view of the UnsavedStyleModal - * @prop {function} onCancelRemove triggered when the user cancels removal - * @prop {function} onCancelEdit triggered when the user cancels any changes to the properties or geometry - * @prop {function} onCancelStyle triggered when the user cancels any changes to the style - * @prop {function} onConfirmRemove triggered when the user confirms removal - * @prop {function} onCancelClose triggered when the user cancels closing - * @prop {function} onConfirmClose triggered when the user confirms closing - * @prop {function} onAdd triggered when the user clicks on the new annotation button - * @prop {function} onEdit triggered when the user clicks on the annotation card into annotation viewer - * @prop {function} onZoom triggered when the user zooms to an annotation - * @prop {function} onHighlight triggered when the mouse hovers an annotation card - * @prop {function} onCleanHighlight triggered when the mouse is out of any annotation card - * @prop {function} onDetail triggered when the user clicks on an annotation card - * @prop {function} onFilter triggered when the user enters some text in the filtering widget - * @prop {function} classNameSelector optional selector to assign custom a CSS class to annotations, based on - * @prop {function} onSetErrorSymbol set a flag in the state to say if the default symbols exists - * @prop {function} onDownload triggered when the user clicks on the download annotations button - * @prop {function} onUpdateSymbols triggered when user click on refresh icon of the symbols addon - * @prop {function} onToggleVisibility triggered when user click on annotation visibility icon - * @prop {boolean} symbolErrors errors related to the symbols - * @prop {object[]} lineDashOptions list of options for dashed lines - * @prop {string} symbolsPath path to the svg folder - * @prop {object[]} symbolList list of symbols - * @prop {string} defaultShape default Shape - * @prop {number} maxZoom max zoom for annotation (default 18) - * @prop {string} defaultShapeStrokeColor default symbol stroke color - * @prop {string} defaultShapeFillColor default symbol fill color - * @prop {string} defaultShapeSize default symbol shape size in px - * @prop {object} defaultStyles object with default symbol styles - * @prop {number} textRotationStep rotation step of text styler - * @prop {boolean} geodesic draw geodesic annotation (Currently applicable only for Circle annotation) - * - * the annotation's attributes. - */ -class Annotations extends React.Component { - static propTypes = { - id: PropTypes.string, - styling: PropTypes.bool, - toggleControl: PropTypes.func, - loading: PropTypes.bool, - closing: PropTypes.bool, - showUnsavedChangesModal: PropTypes.bool, - showUnsavedStyleModal: PropTypes.bool, - editing: PropTypes.object, - removing: PropTypes.object, - onCancelRemove: PropTypes.func, - onConfirmRemove: PropTypes.func, - onCancelClose: PropTypes.func, - onToggleUnsavedChangesModal: PropTypes.func, - onToggleUnsavedStyleModal: PropTypes.func, - onResetCoordEditor: PropTypes.func, - onAddNewFeature: PropTypes.func, - onToggleUnsavedGeometryModal: PropTypes.func, - onConfirmClose: PropTypes.func, - onCancelEdit: PropTypes.func, - onCancelStyle: PropTypes.func, - onAdd: PropTypes.func, - onZoom: PropTypes.func, - onHighlight: PropTypes.func, - onCleanHighlight: PropTypes.func, - onDetail: PropTypes.func, - mode: PropTypes.string, - editor: PropTypes.func, - annotations: PropTypes.array, - current: PropTypes.string, - config: PropTypes.object, - filter: PropTypes.string, - onFilter: PropTypes.func, - classNameSelector: PropTypes.func, - width: PropTypes.number, - onDownload: PropTypes.func, - onLoadAnnotations: PropTypes.func, - onUpdateSymbols: PropTypes.func, - onSetErrorSymbol: PropTypes.func, - onToggleVisibility: PropTypes.func, - onEdit: PropTypes.func, - symbolErrors: PropTypes.array, - lineDashOptions: PropTypes.array, - symbolList: PropTypes.array, - defaultShape: PropTypes.string, - symbolsPath: PropTypes.string, - maxZoom: PropTypes.number, - defaultShapeSize: PropTypes.number, - defaultShapeFillColor: PropTypes.string, - defaultShapeStrokeColor: PropTypes.string, - defaultStyles: PropTypes.object, - onLoadDefaultStyles: PropTypes.func, - textRotationStep: PropTypes.number, - measurementAnnotationEdit: PropTypes.bool, - geodesic: PropTypes.bool - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - mode: 'list', - config: defaultConfig, - classNameSelector: () => '', - toggleControl: () => {}, - onUpdateSymbols: () => {}, - onSetErrorSymbol: () => {}, - onLoadAnnotations: () => {}, - annotations: [], - maxZoom: 18, - onLoadDefaultStyles: () => {} - }; - state = { - selectFile: false - } - - componentDidMount() { - this.props.onLoadDefaultStyles(this.props.defaultShape, this.props.defaultShapeSize, this.props.defaultShapeFillColor, this.props.defaultShapeStrokeColor, - this.props.symbolsPath); - } - - getConfig = () => { - return assign({}, defaultConfig, this.props.config); - }; - - getGeomsThumbnail(geometry) { - let glyph; - const geoms = geometry?.features.reduce((p, c) => { - if (c.properties && c.properties.isCircle) { - return {...p, "Circle": true}; - } - if (c.properties && c.properties.isText) { - return {...p, "Text": true}; - } - return {...p, [c.geometry.type]: true}; - }, {"Circle": false, "Text": false}); - - if (countBy(values(geoms))?.true > 1) { - glyph = "geometry-collection"; - } else { - const type = keys(geoms).find(key => geoms[key] === true); - glyph = getGeometryGlyphInfo(type)?.glyph; - } - - return ; - } - - renderField = (field, annotation) => { - return (
- {this.renderFieldValue(field, annotation)} -
); - }; - - renderFieldValue = (field, annotation) => { - const fieldValue = annotation.properties[field.name] || ''; - if (field.type === 'html') { - // Return the text content of the first child of the html string (to prevent collating all texts into a single word) - return (new DOMParser).parseFromString(fieldValue, "text/html").documentElement.lastElementChild - ?.firstChild - ?.textContent || ''; - } - return fieldValue; - }; - - renderThumbnail = ({featureType, geometry, properties = {}}) => { - if (properties?.type === "Measure") { - return ( - - ); - } else if (featureType === "LineString" || featureType === "MultiLineString" ) { - return ( - ; - ); - } - if (featureType === "Polygon" || featureType === "MultiPolygon" ) { - return ( - ; - ); - } - if (featureType === "Circle") { - return ( - ; - ); - } - if (featureType === "GeometryCollection" || featureType === "FeatureCollection") { - return ( - {(!!(geometry.geometries || geometry.features || []).filter(f => f.type !== "MultiPoint").length || (properties.textValues && properties.textValues.length)) && (this.getGeomsThumbnail(geometry))} - ); - } - return ( - ; - ); - }; - - renderItems = (annotation) => { - const {features: aFeatures, properties} = annotation; - const cardActions = { - onMouseEnter: () => {this.props.onHighlight(properties.id); }, - onMouseLeave: this.props.onCleanHighlight, - onClick: () => this.props.onEdit(properties.id) - }; - const annotationVisibility = properties && !isUndefined(properties.visibility) ? properties.visibility : true; - return { - ...this.getConfig().fields.reduce( (p, c)=> { - return assign({}, p, {[c.name]: this.renderField(c, annotation)}); - }, {}), - preview: this.renderThumbnail({featureType: "FeatureCollection", geometry: {features: aFeatures}, properties }), - tools: { - event.stopPropagation(); - const extent = bbox(annotation); - this.props.onZoom(extent, 'EPSG:4326', this.props.maxZoom); - } - }, - { - glyph: annotationVisibility ? 'eye-open' : 'eye-close', - tooltipId: annotationVisibility ? "annotations.hide" : "annotations.show", - onClick: (event) => { - event.stopPropagation(); - this.props.onToggleVisibility(properties?.id); - } - } - - ]}/>, - ...cardActions - }; - }; - - renderCards = () => { - if (this.props.loading) { - return ( -
- -
- ); - } - if (this.props.mode === 'list') { - const annotationsPresent = !!this.props.annotations.length; - return ( - <> -
- , - visible: this.props.mode === "list", - onClick: () => { this.setState(() => ({selectFile: true})); } - }, - { - glyph: 'plus', - tooltip: , - visible: this.props.mode === "list", - onClick: () => { this.props.onAdd(); } - }, - { - glyph: 'download', - disabled: !(annotationsPresent), - tooltip: , - visible: this.props.mode === "list", - onClick: () => { this.props.onDownload(); } - } - ]}/> -
-
- -
-
- {!annotationsPresent && } - { annotationsPresent && - this.renderItems(a))}/> - } -
- - ); - } - const annotation = this.props.annotations && head(this.props.annotations.filter(a => a.properties.id === this.props.current)); - const Editor = this.props.editor; - if (this.props.mode === 'detail') { - return (); - } - // mode = editing - return this.props.editing && ; - }; - - renderHeader() { - return ( -
-
-
- -
-
-

-
-
- -
-
-
- ); - } - - render() { - let body; - if (this.state.selectFile) { - body = ( - } - onFileChoosen={this.props.onLoadAnnotations} - show={this.state.selectFile} - disableOvveride={!(this.props.annotations && this.props.annotations.length > 0)} - onClose={() => this.setState(() => ({selectFile: false}))} - />); - - - } else { - body = ( {this.renderCards()} ); - } - return ( - {body} - ); - - } - - applyFilter = (annotation) => { - return !this.props.filter || this.getConfig().fields.reduce((previous, field) => { - return (annotation.properties[field.name] || '').toUpperCase().indexOf(this.props.filter.toUpperCase()) !== -1 || previous; - }, false); - }; -} - -export default Annotations; diff --git a/web/client/components/mapcontrols/annotations/AnnotationsConfig.js b/web/client/components/mapcontrols/annotations/AnnotationsConfig.js deleted file mode 100644 index 00ee466e56..0000000000 --- a/web/client/components/mapcontrols/annotations/AnnotationsConfig.js +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2017, 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. - */ - -import MarkerUtils from '../../../utils/MarkerUtils'; - -const defaultIcon = MarkerUtils.markers.extra.icons[0]; -const defaultMarkers = MarkerUtils.markers.extra.getGrid(); -const glyphPrefix = 'fa'; - -/** - * Annotations configuration object. - * Stores overridable configuration. - * - * The default configuration is the following: - * - 2 fields (title and description) - * - extra markers library {@link https://github.com/coryasilva/Leaflet.ExtraMarkers} - * - font awesome glyphs for markers - * - multiGeometry enabled - * - * To (partially) override the configuration use initialState in localConfig.json: - * @example - * Only overrides the list of fields - * { - * ... - * "initialState": { - * "defaultState": { - * "annotations": { - * "config": { - * "fields": [{ - * "name": "myattribute", - * "editable": true - * "validator": "value.indexOf('fake') === -1", - * "validateError": "annotations.error.fake" - * }] - * } - * } - * } - * } - * } - * - * @memberof components.mapControls.annotations - * @class AnnotationsConfig - */ -export default { - /** - * Available annotation fields. - * A list of object specifying: - * - name: the field synthetic name - * - type: type of value for the field (text or html) - * - validator: (optional) rule for validation - * - validationError: (optional) id for the translations file containing the validation error message - * - showLabel: whether to show or not the label of the field in the viewer / editor - * - editable: whether the field can be edited or not in editing mode - */ - fields: [ - { - name: 'title', - type: 'text', - validator: (val) => val, - validateError: 'annotations.mandatory', - showLabel: true, - editable: true - }, - { - name: 'description', - type: 'html', - showLabel: true, - editable: true - } - ], - /** - * Grid of markers used to style annotations. - */ - markers: defaultMarkers, - /** - * Markers icon sprite resource. - */ - markerIcon: defaultIcon, - /** - * Markers used to style annotations configuration object. - */ - markersConfig: MarkerUtils.markers.extra, - /** - * Allow multiGeometry or not (MultiPoint on a single annotation). - */ - multiGeometry: false, - /** - * Available glyphs list (used by the markers styler). - */ - glyphs: Object.keys(MarkerUtils.getGlyphs('fontawesome')), - /** - * Returns a CSS classname usable to draw a glyph for the given style (iconGlyph), - * using the default glyphs library (font-awesome). - * @param {string} style style object - * @return {string} classname to draw the glyph - */ - getGlyphClassName: (style) => { - return glyphPrefix + " " + glyphPrefix + "-" + style.iconGlyph; - }, - /** - * Returns a marker configuration object for the given style, using the default (extra) - * markers library. - * - * @param {string} style style object - * @return {object} marker config object - */ - getMarkerFromStyle: (style) => { - return defaultMarkers.filter(m => m.name === style.iconShape)[0] - .markers.filter(m2 => m2.name === style.iconColor)[0]; - } -}; diff --git a/web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx b/web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx deleted file mode 100644 index 1c9fdc1997..0000000000 --- a/web/client/components/mapcontrols/annotations/AnnotationsEditor.jsx +++ /dev/null @@ -1,900 +0,0 @@ -/* - * 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. -*/ - -import { head, isEmpty, isFunction, isUndefined } from 'lodash'; -import assign from 'object-assign'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { - Checkbox, - Col, - ControlLabel, - FormControl, - FormGroup, - Glyphicon, - Grid, - Nav, - NavItem, - Row -} from 'react-bootstrap'; -import ReactQuill from '../../../libs/quill/react-quill-suspense'; - -import { - coordToArray, - getComponents, - getGeometryGlyphInfo, - getGeometryType, - validateCoords -} from '../../../utils/LegacyAnnotationsUtils'; -import { MEASURE_TYPE } from '../../../utils/MeasurementUtils'; -import { handleExpression } from '../../../utils/PluginsUtils'; -import Message from '../../I18N/Message'; -import ConfirmDialog from '../../misc/ConfirmDialog'; -import Portal from '../../misc/Portal'; -import Toolbar from '../../misc/toolbar/Toolbar'; -import Manager from '../../style/vector/Manager'; -import defaultConfig from './AnnotationsConfig'; -import FeaturesList from './FeaturesList'; -import GeometryEditor from '../../../plugins/Annotations/components/GeometryEditor'; -import { getApi } from '../../../api/userPersistedStorage'; - -/** - * (Default) Viewer / Editor for Annotations. - * @memberof components.mapControls.annotations - * @class - * @prop {string} id identifier of the current annotation feature - * @prop {function} onChangeFormat triggered every format change - * @prop {string} format decimal or aeronautical degree for coordinates - * @prop {string} mapProjection crs of the map - * @prop {object} config configuration object, where overridable stuff is stored (fields config for annotations, marker library, etc.) {@link #components.mapControls.annotations.AnnotationsConfig} - * @prop {object} editing feature object of the feature under editing (when editing mode is enabled, null otherwise) - * @prop {boolean} drawing flag to state status of drawing during editing - * @prop {boolean} styling flag to state status of styling during editing - * @prop {object} errors key/value set of validation errors (field_name: error_id) - * @prop {object} feature object with the annotation properties - * @prop {bool} showBack shows / hides the back button in the view mode - * @prop {bool} showEdit shows / hides the edit button in the view mode - * @prop {function} onEdit triggered when the user clicks on the edit button - * @prop {function} onCancelEdit triggered when the user cancels current editing session - * @prop {function} onCancelStyle triggered when the user cancels style selection - * @prop {function} onCancel triggered when the user cancels the addition/changes made to the annotation - * @prop {function} onCleanHighlight triggered when the user exits 'details' mode - * @prop {function} onHighlight triggered when the user hover the infoviewer card - * @prop {function} onConfirmDeleteFeature triggered when the user confirms deletion of a feature - * @prop {function} onAddText triggered when the user adds new Text geometry to the feature - * @prop {function} onToggleUnsavedChangesModal toggles the view of the UnsavedChangesModal - * @prop {function} onToggleUnsavedStyleModal toggles the view of the UnsavedStyleModal - * @prop {function} onToggleUnsavedGeometryModal toggles the view of the UnsavedGeometryModal - * @prop {function} onSetUnsavedChanges triggered when the user changes the value of any field, it sets a flag used to trigger the view of the UnsavedChangesModal - * @prop {function} onAddNewFeature triggered when user click on save icon of the coordinate editor, this will add the feature being drawn to the list of features of the ft coll of the annotation - * @prop {function} onChangeProperties triggered when the user changes the value of any field - * @prop {function} onSetUnsavedStyle triggered when the user changes the style , it sets a flag used to trigger the view of the UnsavedStyleModal - * @prop {function} onConfirmRemove triggered when the user confirms removal - * @prop {function} onCancelRemove triggered when the user cancels removal - * @prop {function} onCancelClose triggered when the user cancels closing - * @prop {function} onConfirmClose triggered when the user confirms closing - * @prop {function} onStartDrawing triggered before the user starts the drawing process - * @prop {object} editedFields fields of the annotation - * @prop {object} drawingText it contains info of the text annotation, 'drawing' if being added or 'show' used to show the modal to add the relative value - * @prop {boolean} unsavedChanges flag used to trigger changes of showUnsavedChangesModal - * @prop {boolean} unsavedStyle flag used to trigger changes of showUnsavedChangesModal - * @prop {boolean} closing user asked for closing panel when editing - * @prop {string} stylerType selected styler to be shown as body - * @prop {boolean} showUnsavedStyleModal flag used to show the UnsavedChangesModal - * @prop {boolean} showUnsavedChangesModal flag used to show the UnsavedStyleModal - * @prop {boolean} showUnsavedGeometryModal flag used to display the modal after user clicks on back and has changed something in the coord editor - * @prop {boolean} showDeleteFeatureModal flag used to display the modal after deleting a feature for confirmation - * @prop {boolean} unsavedGeometry flag used to say if something has changed when coord editor is open - * @prop {string} mode current mode of operation (list, editing, detail) - * @prop {function} onRemove triggered when the user clicks on the remove button - * @prop {function} onSave triggered when the user clicks on the save button - * @prop {function} onSaveStyle triggered when the user saves changes to the style - * @prop {function} onError triggered when a validation error occurs - * @prop {function} onAddGeometry triggered when the user clicks on the add point button TODO FIX THIS - * @prop {function} onDeleteGeometry triggered when the user clicks on the remove points button - * @prop {function} onStyleGeometry triggered when the user clicks on the style button - * @prop {function} onSetStyle triggered when the user changes a style property - * @prop {function} onChangeSelected triggered when the user changes a value(lat or lon) of a coordinate in the coordinate editor - * @prop {function} onChangeRadius triggered when the user changes the radius of the Circle in its coordinate editor - * @prop {function} onChangeText triggered when the user changes the text of the Text Annotation in its coordinate editor - * @prop {function} onSetInvalidSelected triggered when the user insert an invalid coordinate or remove a valid one i.e. "" - * @prop {function} onHighlightPoint triggered when mouse goes over/off a CoordinatesRow - * @prop {function} onResetCoordEditor triggered when the user goes back from the coordinate editor, it will open a dialog for unsaved changes - * @prop {function} onZoom triggered when the user zooms to an annotation - * @prop {function} onDownload triggered when the user exports - * @prop {function} onChangeGeometryTitle triggered when the user changes geometry title in coordinate editor panel - * @prop {function} onSelectFeature triggered when the user clicks on a geometry card - * @prop {boolean} coordinateEditorEnabled triggered when the user zooms to an annotation - * @prop {object} selected Feature containing the geometry and the properties used for the coordinated editor - * @prop {object} aeronauticalOptions options for aeronautical format (seconds decimals and step) - * @prop {number} maxZoom max zoome the for annotation (default 18) - * @prop {function} onDeleteFeature triggered when user click on trash icon of the coordinate editor - * @prop {function} onUpdateSymbols triggered when user click on refresh icon of the symbols addon - * @prop {function} onSetErrorSymbol set a flag in the state to say if the default symbols exists - * @prop {number} width of the annotation panel - * @prop {string} pointType the type of the point, values are "marker" or "symbol" - * @prop {object[]} lineDashOptions list of options for dashed lines - * @prop {object[]} symbolList list of symbols - * @prop {string} symbolsPath path to the svg folder - * @prop {string} defaultShape default shape for symbol - * @prop {string} defaultShapeStrokeColor default symbol stroke color - * @prop {string} defaultShapeFillColor default symbol fill color - * @prop {string} defaultShapeSize default symbol shape size in px - * @prop {object} defaultStyles object with default symbol styles - * @prop {number} textRotationStep rotation step of text styler - * @prop {function} onSetAnnotationMeasurement triggered on click of edit measurement button when annotation is of type 'Measure' - * @prop {function} onFilterMarker triggered when marker/glyph name is specified for filtering - * @prop {object[]} annotations list of annotations - * @prop {boolean} measurementAnnotationEdit flag for measurement specific annotation features - * @prop {boolean} geodesic enable to draw a geodesic geometry (supported only for Circle) - * @prop {function} onHideMeasureWarning triggered when warning is ignored with "Don't show again" flag - * @prop {boolean} showAgain flag for checkbox on the measure annotation popup warning - * @prop {boolean} showPopupWarning flag to show warning modal on navigating to measurement panel from annotation - * @prop {function} onToggleShowAgain triggered when interacting with the checkbox on measure annotation warning popup - * @prop {function} onInitPlugin triggered when annotation editor is mounted - * @prop {function} onGeometryHighlight triggered onMouseEnter and onMouseLeave of the geometry card - * @prop {function} onUnSelectFeature triggered on unselecting a geometry card - * - * In addition, as the Identify viewer interface mandates, every feature attribute is mapped as a component property (in addition to the feature object). - */ -class AnnotationsEditor extends React.Component { - static displayName = 'AnnotationsEditor'; - - static propTypes = { - id: PropTypes.string, - onEdit: PropTypes.func, - onCancelEdit: PropTypes.func, - onCancelStyle: PropTypes.func, - onCleanHighlight: PropTypes.func, - onHighlight: PropTypes.func, - onAddText: PropTypes.func, - onCancel: PropTypes.func, - onConfirmDeleteFeature: PropTypes.func, - onRemove: PropTypes.func, - onSave: PropTypes.func, - onSaveStyle: PropTypes.func, - onError: PropTypes.func, - onAddGeometry: PropTypes.func, - onToggleUnsavedChangesModal: PropTypes.func, - onToggleUnsavedGeometryModal: PropTypes.func, - onToggleUnsavedStyleModal: PropTypes.func, - onToggleDeleteFtModal: PropTypes.func, - onSetUnsavedChanges: PropTypes.func, - onSetUnsavedStyle: PropTypes.func, - onChangeProperties: PropTypes.func, - onChangeSelected: PropTypes.func, - onConfirmClose: PropTypes.func, - onCancelRemove: PropTypes.func, - onConfirmRemove: PropTypes.func, - onChangeRadius: PropTypes.func, - onChangeText: PropTypes.func, - onChangeGeometryTitle: PropTypes.func, - onCancelClose: PropTypes.func, - onSetInvalidSelected: PropTypes.func, - onDeleteGeometry: PropTypes.func, - onAddNewFeature: PropTypes.func, - onStyleGeometry: PropTypes.func, - onResetCoordEditor: PropTypes.func, - onHighlightPoint: PropTypes.func, - onSetStyle: PropTypes.func, - onStartDrawing: PropTypes.func, - onZoom: PropTypes.func, - editing: PropTypes.object, - editedFields: PropTypes.object, - drawingText: PropTypes.object, - drawing: PropTypes.bool, - unsavedChanges: PropTypes.bool, - unsavedGeometry: PropTypes.bool, - unsavedStyle: PropTypes.bool, - mouseHoverEvents: PropTypes.bool, - coordinateEditorEnabled: PropTypes.bool, - styling: PropTypes.bool, - closing: PropTypes.bool, - removing: PropTypes.bool, - errors: PropTypes.object, - stylerType: PropTypes.string, - featureType: PropTypes.string, - showBack: PropTypes.bool, - showEdit: PropTypes.bool, - showUnsavedChangesModal: PropTypes.bool, - showUnsavedStyleModal: PropTypes.bool, - showDeleteFeatureModal: PropTypes.bool, - showUnsavedGeometryModal: PropTypes.bool, - config: PropTypes.object, - feature: PropTypes.object, - features: PropTypes.object, - selected: PropTypes.object, - mode: PropTypes.string, - maxZoom: PropTypes.number, - width: PropTypes.number, - onDownload: PropTypes.func, - onChangeFormat: PropTypes.func, - onSelectFeature: PropTypes.func, - mapProjection: PropTypes.string, - format: PropTypes.string, - aeronauticalOptions: PropTypes.object, - onDeleteFeature: PropTypes.func, - pointType: PropTypes.string, - symbolsPath: PropTypes.string, - onUpdateSymbols: PropTypes.func, - onSetErrorSymbol: PropTypes.func, - symbolErrors: PropTypes.array, - lineDashOptions: PropTypes.array, - symbolList: PropTypes.array, - defaultShape: PropTypes.string, - defaultShapeSize: PropTypes.number, - defaultShapeFillColor: PropTypes.string, - defaultShapeStrokeColor: PropTypes.string, - defaultStyles: PropTypes.object, - textRotationStep: PropTypes.number, - onSetAnnotationMeasurement: PropTypes.func, - onFilterMarker: PropTypes.func, - annotations: PropTypes.array, - measurementAnnotationEdit: PropTypes.bool, - geodesic: PropTypes.bool, - onHideMeasureWarning: PropTypes.func, - showAgain: PropTypes.bool, - showPopupWarning: PropTypes.bool, - onToggleShowAgain: PropTypes.func, - onInitPlugin: PropTypes.func, - onGeometryHighlight: PropTypes.func, - onUnSelectFeature: PropTypes.func, - onValidateFeature: PropTypes.func - }; - - static defaultProps = { - config: defaultConfig, - errors: {}, - selected: null, - editedFields: {}, - showBack: false, - showEdit: true, - coordinateEditorEnabled: false, - feature: {}, - maxZoom: 18, - format: "decimal", - pointType: "marker", - stylerType: "marker", - annotations: [], - measurementAnnotationEdit: false, - geodesic: true, - onInitPlugin: () => {} - }; - /** - @prop {object} removing object to remove, it is also a flag that means we are currently asking for removing an annotation / geometry. Toggles visibility of the confirm dialog - */ - state = { - editedFields: {}, - removing: null, - textValue: "", - tabValue: "coordinates", - showPopupWarning: false - }; - - componentDidMount() { - this.props.onInitPlugin(); - } - - getConfig = () => { - return {...defaultConfig, ...this.props.config, onFilterMarker: this.props.onFilterMarker}; - }; - - getBodyItems = (editing) => { - return this.getConfig().fields - .filter((field) => !editing || field.editable) - .map((field) => { - const isError = editing && this.props.errors[field.name]; - const additionalCls = isError ? 'field-error' : ''; - return ( -
- {field.showLabel ? : null} - {isError ? this.renderErrorOn(field.name) : ''} - {this.renderProperty(field, this.props[field.name] || field.value, editing)} -
- ); - }); - }; - - - getValidator = (validator) => { - if (isFunction(validator)) { - return validator; - } - return handleExpression({}, {}, '{(function(value) {return ' + validator + ';})}'); - }; - - renderViewButtons = () => { - return ( - - - - { - this.props.onCancelEdit(this.props?.feature?.properties); - this.props.onCancel(); this.props.onCleanHighlight(); - } - }, { - glyph: "pencil", - tooltipId: "annotations.edit", - visible: this.props.showEdit, - multiGeometry: this.props.config.multiGeometry, - onClick: () => { this.props.onEdit(this.props.id); }, - disabled: !this.props.config.multiGeometry && this.props.editing && this.props.editing.features && this.props.editing.features.length, - bsStyle: this.props.drawing ? "success" : "primary" - }, { - glyph: 'trash', - tooltipId: "annotations.remove", - visible: true, - onClick: () => { - this.setState({removing: this.props.id}); - } - }, { - glyph: 'download', - tooltip: , - visible: true, - onClick: () => { this.props.onDownload(this.props.features); } - } - ]} /> - - - ); - }; - - renderEditingCoordButtons = () => { - const areAllFeaturesValid = this.validateFeatures(); - return ( - - - { - if (this.props.styling && this.isMeasureEditDisabled()) { - if (this.props.unsavedStyle) { - this.props.onToggleUnsavedStyleModal(); - } else { - this.props.onCancelStyle(); - } - } else if (this.props.unsavedGeometry) { - this.props.onToggleUnsavedGeometryModal(); - } else if (this.props.unsavedChanges) { - this.props.onToggleUnsavedChangesModal(); - } else { - this.props.onResetCoordEditor(); - this.props.onCancelEdit(this.props.editing?.properties); - // Reset geometry editor tab - this.setState({...this.state, tabValue: 'coordinates'}); - } - - } - }, { - glyph: 'trash', - tooltipId: "annotations.remove", - tooltipPosition: 'bottom', - disabled: !this.props.annotations.length, - visible: !this.props.selected, - onClick: () => { - this.setState({removing: this.props.id}); - } - }, { - glyph: 'floppy-disk', - tooltipPosition: 'bottom', - tooltipId: !areAllFeaturesValid ? "annotations.annotationSaveGeometryError" : !isEmpty(this.props.selected) ? "annotations.saveGeometry" : "annotations.save", - disabled: (this.props.selected && this.props.selected.properties && !this.props.selected.properties.isValidFeature) || !areAllFeaturesValid, - onClick: () => this.save() - }, - { - glyph: 'download', - tooltip: , - tooltipPosition: 'bottom', - disabled: Object.keys(this.validate()).length !== 0 || this.props.unsavedChanges, - visible: !this.props.selected, - onClick: () => { - const {newFeature, ...features} = this.props.editing; - this.props.onDownload(features); - } - } - ]} /> - - - ); - }; - - renderButtons = (editing) => { - let toolbar; - if (editing) { - toolbar = this.renderEditingCoordButtons(); - } else { - toolbar = this.renderViewButtons(); - } - return (
{toolbar}
); - }; - - renderProperty = (field, prop, editing) => { - const fieldValue = this.props.editedFields[field.name] === undefined ? prop : this.props.editedFields[field.name]; - if (editing) { - switch (field.type) { - case 'html': - return ( { this.change(field.name, val); if (!this.props.unsavedChanges) { this.props.onSetUnsavedChanges(true); } }} - />); - case 'component': - const Component = fieldValue; - return } onChange={(e) => { this.change(field.name, e.target.value); if (!this.props.unsavedChanges) { this.props.onSetUnsavedChanges(true); } }} />; - default: - return { this.change(field.name, e.target.value); if (!this.props.unsavedChanges) { this.props.onSetUnsavedChanges(true); } }} />; - } - - } - switch (field.type) { - case 'html': - return ; - case 'component': - const Component = fieldValue; - return ; - default: - return (

{fieldValue}

); - } - }; - - renderErrorOn = (field) => { - return
; - }; - - renderMarkers = (markers, prefix = '') => { - return markers.map((marker) => { - if (marker.markers) { - return (
- {this.renderMarkers(marker.markers, marker.name + '-')} -
); - } - return ( -
this.selectStyle(marker)} - className={"mapstore-annotations-info-viewer-marker mapstore-annotations-info-viewer-marker-" + prefix + marker.name + - (this.isCurrentStyle(marker) ? " mapstore-annotations-info-viewer-marker-selected" : "")} style={marker.thumbnailStyle} />); - }); - }; - - renderBody = (editing) => { - const items = this.getBodyItems(editing); - if (items.length === 0) { - return null; - } - - return (
-
- {items} - {editing && - } -
-
); - }; - - renderError = (editing) => { - return editing ? (Object.keys(this.props.errors) - .filter(field => this.getConfig().fields.filter(f => f.name === field).length === 0).map(field => this.renderErrorOn(field))) : null; - }; - - renderModals = () => { - if (this.props.closing) { - return ( this.props.onConfirmClose(this.props.editing?.properties)} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showUnsavedChangesModal) { - return ( { - this.props.selected && this.props.onResetCoordEditor(); - this.props.onCancelEdit(this.props.editing?.properties); this.props.onToggleUnsavedChangesModal(); - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showUnsavedGeometryModal) { - return ( { - this.props.onResetCoordEditor(); - this.props.onCancelEdit(this.props.editing?.properties); - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - title={} - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showUnsavedStyleModal) { - return ( { - this.props.onCancelStyle(); - this.props.onToggleUnsavedStyleModal(); - if (this.isMeasureEditDisabled()) { - this.setTabValue('coordinates'); - } else { - this.setTabValue('style'); - } - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.props.showDeleteFeatureModal) { - return ( { this.props.onConfirmDeleteFeature(); this.props.onToggleDeleteFtModal(); }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - - ); - } else if (this.state.removing || this.props.removing) { - return ({ - this.state.removing && this.setState({removing: null}); - this.props.onCancelRemove(); - }} - focusConfirm={this.props.removing} - onConfirm={() => { - if (this.state.removing) { - this.setState({removing: null}); - this.props.onConfirmRemove(this.state.removing, "features"); - } else { - this.props.onConfirmRemove(this.props.removing, "geometry"); - } - }} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - {this.props.mode === 'editing' ? : - } - ); - } else if (this.state.showPopupWarning && this.props.showPopupWarning) { - return (} - onClose={this.hideWarning} - onConfirm={this.setAnnotationMeasurement} - confirmButtonBSStyle="default" - closeGlyph="1-close" - confirmButtonContent={} - closeText={}> - -

-

- - - -

-
-
); - } - - return null; - } - - render() { - const editing = this.props.editing && (this.props.editing.properties.id === this.props.id); - let mouseHoverEvents = this.props.mouseHoverEvents ? { - onMouseEnter: () => { - this.props.onHighlight(this.props.id); - }, - onMouseLeave: () => { - this.props.onCleanHighlight(); - } - } : {}; - const type = this.props.selected ? getGeometryType(this.props.selected) : ""; - const {glyph = "", label = ""} = isEmpty(type) ? {} : getGeometryGlyphInfo(type); - return ( -
-
- {this.renderButtons(editing)} - {this.renderError(editing)} - {this.renderModals()} - {this.renderBody(editing)} -
- {!isEmpty(this.props.selected) && -
-
- -
- { - const valueText = e.target.value.trim(); - this.props.onChangeGeometryTitle(valueText ? valueText : label); - }} - type="text"/> -
-
- {this.props.selected?.properties?.isText &&
- - - - { - const valueText = e.target.value; - const components = this.props?.selected?.geometry?.coordinates?.length ? - getComponents(this.props.selected.geometry) : []; - if (this.validateText(components, valueText )) { - this.props.onChangeText(valueText, components.map(coordToArray)); - } else if (valueText !== "") { - this.props.onChangeText(valueText, components.map(coordToArray)); - } else { - this.props.onChangeText("", components.map(coordToArray)); - this.props.onSetInvalidSelected("text", components.map(coordToArray)); - } - }} - type="text"/> - - -
} - -
- {this.state.tabValue === 'coordinates' && - - } - {this.state.tabValue === 'style' && - { - this.props.onSetStyle(style); - this.props.onSetUnsavedStyle(true); - this.props.onSetUnsavedChanges(true); - }} - pointType={this.props.pointType} - style={this.props.selected && this.props.selected.style || this.props.editing.style} - width={this.props.width} - symbolsPath={this.props.symbolsPath} - onSetErrorSymbol={this.props.onSetErrorSymbol} - symbolErrors={this.props.symbolErrors} - onUpdateSymbols={this.props.onUpdateSymbols} - symbolList={this.props.symbolList} - defaultShape={this.props.defaultShape} - defaultShapeSize={this.props.defaultShapeSize} - defaultShapeFillColor={this.props.defaultShapeFillColor} - defaultShapeStrokeColor={this.props.defaultShapeStrokeColor} - defaultStyles={this.props.defaultStyles} - lineDashOptions={this.props.lineDashOptions} - markersOptions={this.getConfig()} - textRotationStep={this.props.textRotationStep} - /> - } -
-
- } -
- ); - } - - validateFeatures = () => { - let areAllGeometriesValid = true; - if (Array.isArray(this.props?.editing?.features)) { - areAllGeometriesValid = this.props.editing.features.every(feature => feature?.properties?.isValidFeature); - } - return areAllGeometriesValid; - }; - - change = (field, value) => { - this.props.onChangeProperties(field, value); - }; - - isCurrentStyle = (m) => { - return this.getConfig().markersConfig.matches(this.props.editing.style.MultiPoint, m.style); - }; - - selectStyle = (marker) => { - return this.props.onSetStyle(assign({}, { - "Point": { - ...this.getConfig().markersConfig.getStyle(marker.style), - iconGlyph: this.props.editing.style.Point && this.props.editing.style.Point.iconGlyph - }, - "MultiPoint": { - ...this.getConfig().markersConfig.getStyle(marker.style), - iconGlyph: this.props.editing.style.MultiPoint && this.props.editing.style.MultiPoint.iconGlyph - } - })); - }; - - selectGlyph = (option) => { - return this.props.onSetStyle( - assign({}, this.props.editing.style, { - "Point": { - ...this.props.editing.style.Point, - iconGlyph: option && option.value || "" - }, - "MultiPoint": { - ...this.props.editing.style.MultiPoint, - iconGlyph: option && option.value || "" - } - })); - }; - - validate = () => { - return assign(this.getConfig().fields.filter(field => field.editable).reduce((previous, field) => { - const value = this.props.editedFields[field.name] === undefined ? this.props[field.name] : this.props.editedFields[field.name]; - if (field.validator && !this.getValidator(field.validator)(value)) { - return assign(previous, { - [field.name]: field.validateError - }); - } - return previous; - }, {}), this.props.editing.features && this.props.editing.features.length ? {} : { - geometry: 'annotations.emptygeometry' - }); - - }; - - validateText = (components, valueText) => { - if (components && components.length) { - const cmp = head(components); - return !!valueText && validateCoords(cmp); - } - return false; - } - - save = () => { - if (!isEmpty(this.props.selected)) { - this.props.onAddNewFeature(); - } else { - const errors = this.validate(); - if (Object.keys(errors).length === 0) { - this.props.onError({}); - this.props.onSave(this.props.id, assign({}, this.props.editedFields), - this.props.editing.features, this.props.editing.style, this.props.editing.newFeature || false, { - ...this.props.editing.properties, - visibility: !isUndefined(this.props.editing.properties.visibility) - ? this.props.editing.properties.visibility - : this.props.editing.visibility - } - ); - } else { - this.props.onError(errors); - } - } - }; - - setTabValue = (tabValue) =>{ - if (this.state.tabValue !== tabValue) { - this.setState({...this.state, tabValue}); - } - } - - setPopupWarning = (showPopupWarning) =>{ - this.setState({...this.state, showPopupWarning}); - } - - isMeasureEditDisabled = () => { - const isMeasureAnnotation = this.props.editing?.properties?.type === MEASURE_TYPE || false; - return !this.props.measurementAnnotationEdit || !isMeasureAnnotation; - } - - setAnnotationMeasurement = () => { - // Excluding geometry types not supported by measurement - this.props.onSetAnnotationMeasurement(this.props.editing.features.filter(f=> f.geometry.type !== 'Point' && !f.properties.isCircle), this.props.editing?.properties); - this.hideWarning(); - } - - hideWarning = () => { - if (this.props.showAgain) { - try { - getApi().setItem("showPopupWarning", false); - } catch (e) { - console.error(e); - } - this.props.onHideMeasureWarning(); - } - this.setPopupWarning(false); - } -} - -export default AnnotationsEditor; diff --git a/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx b/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx deleted file mode 100644 index a7c4b76823..0000000000 --- a/web/client/components/mapcontrols/annotations/DropdownFeatureType.jsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. -*/ -import { Glyphicon, DropdownButton, MenuItem } from 'react-bootstrap'; - -import tooltip from '../../misc/enhancers/tooltip'; -import { DEFAULT_ANNOTATIONS_STYLES, getStartEndPointsForLinestring } from '../../../utils/LegacyAnnotationsUtils'; -import React from 'react'; -import uuidv1 from 'uuid/v1'; -import assign from 'object-assign'; - - -const DropdownButtonT = tooltip(DropdownButton); -const DropdownFeatureType = ({ - onClick = () => {}, - onStartDrawing = () => {}, - onAddText = () => {}, - onSetStyle = () => {}, - defaultStyles = {}, - defaultPointType = 'marker', - titles = {}, - glyph = "", - bsStyle = "primary", - ...props -} = {}) => ( - } - disabled={!!props.disabled} - noCaret> - - { - onClick("Point"); - onSetStyle([{ ...defaultStyles.POINT?.[defaultPointType], highlight: true, id: uuidv1()}]); - onStartDrawing(); - }}> - {titles.marker} - - - { - onClick("LineString"); - onSetStyle( - [{ ...DEFAULT_ANNOTATIONS_STYLES.LineString, highlight: true, id: uuidv1()}] - .concat(getStartEndPointsForLinestring())); - onStartDrawing(); - }}> - {titles.line} - - - { - onClick("Polygon"); - onSetStyle([ - {...DEFAULT_ANNOTATIONS_STYLES.Polygon, highlight: true, id: uuidv1()} - ]); - onStartDrawing(); - }}> - {titles.polygon} - - - { - onClick("Text"); - onAddText(); - onSetStyle([ - assign({}, {...DEFAULT_ANNOTATIONS_STYLES.Text, highlight: true, type: "Text", title: "Text Style", id: uuidv1()}) - ]); - onStartDrawing(); - }}> - {titles.text} - - - { - onClick("Circle"); - onSetStyle([ - assign({}, {...DEFAULT_ANNOTATIONS_STYLES.Circle, highlight: true, type: "Circle", title: "Circle Style", id: uuidv1()} ), - {...DEFAULT_ANNOTATIONS_STYLES.Point, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "Center Style", filtering: false, geometry: "centerPoint", id: uuidv1()} - ]); - onStartDrawing(); - }}> - {titles.circle} - - -); - -export default DropdownFeatureType; diff --git a/web/client/components/mapcontrols/annotations/FeaturesList.jsx b/web/client/components/mapcontrols/annotations/FeaturesList.jsx deleted file mode 100644 index c69fa022c3..0000000000 --- a/web/client/components/mapcontrols/annotations/FeaturesList.jsx +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2020, 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. -*/ -import React from 'react'; -import {Glyphicon, ControlLabel, Tooltip } from 'react-bootstrap'; -import uuidv1 from 'uuid/v1'; -import bbox from '@turf/bbox'; -import Toolbar from '../../misc/toolbar/Toolbar'; -import OverlayTrigger from '../../misc/OverlayTrigger'; -import cs from 'classnames'; -import Message from '../../I18N/Message'; -import {get} from 'lodash'; -import {DEFAULT_ANNOTATIONS_STYLES, getStartEndPointsForLinestring, getGeometryGlyphInfo, getGeometryType} from '../../../utils/LegacyAnnotationsUtils'; - -/** - * Feature List component for Annotation Viewer. - * @memberof components.mapControls.annotations - * @function - * -*/ -const FeaturesList = (props) => { - const { - editing, - onAddGeometry, - onSetStyle, - onStartDrawing, - onAddText, - onStyleGeometry, - setTabValue, - isMeasureEditDisabled, - onSetAnnotationMeasurement, - showPopupWarning, - setPopupWarning, - geodesic, - defaultStyles, - defaultPointType, - onValidateFeature, - validateFeatures - } = props; - const {features = []} = editing || {}; - const isValidFeature = get(props, "selected.properties.isValidFeature", true); - const areAllFeaturesValid = validateFeatures(); - - const onClickGeometry = (type, style) => { - onStyleGeometry(false); - onAddGeometry(type); - type === "Text" && onAddText(); - onSetStyle(style); - onStartDrawing({geodesic}); - setTabValue('coordinates'); - onValidateFeature(); - }; - const circleCenterStyles = defaultPointType === "symbol" ? defaultStyles.POINT?.[defaultPointType] : DEFAULT_ANNOTATIONS_STYLES.Point; - - const linePointStyles = defaultPointType === "symbol" ? [{...defaultStyles.POINT?.[defaultPointType], highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "StartPoint Style", geometry: "startPoint", filtering: false, id: uuidv1()}, - {...defaultStyles.POINT?.[defaultPointType], highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "EndPoint Style", geometry: "endPoint", filtering: false, id: uuidv1()}] : getStartEndPointsForLinestring(); - - return ( - <> -
- - { - showPopupWarning ? setPopupWarning(true) : onSetAnnotationMeasurement(); - }, - tooltip: - }, - { - glyph: 'point-plus', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [{ ...defaultStyles.POINT?.[defaultPointType], highlight: true, id: uuidv1()}]; - onClickGeometry("Point", style); - }, - tooltip: - }, - { - glyph: 'polyline-plus', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [{ ...DEFAULT_ANNOTATIONS_STYLES.LineString, highlight: true, id: uuidv1()}] - .concat(linePointStyles); - onClickGeometry("LineString", style); - }, - tooltip: - }, - { - glyph: 'polygon-plus', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [ - {...DEFAULT_ANNOTATIONS_STYLES.Polygon, highlight: true, id: uuidv1()}]; - onClickGeometry("Polygon", style); - }, - tooltip: - }, - { - glyph: 'font-add', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [ - {...DEFAULT_ANNOTATIONS_STYLES.Text, highlight: true, type: "Text", title: "Text Style", id: uuidv1()}]; - onClickGeometry("Text", style); - }, - tooltip: - }, - { - glyph: '1-circle-add', - visible: isMeasureEditDisabled, - disabled: !isValidFeature, - onClick: () => { - const style = [ - {...DEFAULT_ANNOTATIONS_STYLES.Circle, highlight: true, type: "Circle", title: "Circle Style", id: uuidv1()}, - { ...circleCenterStyles, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "Center Style", filtering: false, geometry: "centerPoint", id: uuidv1()} - ]; - onClickGeometry("Circle", style); - }, - tooltip: - } - ]} - /> -
- {features && features.length === 0 &&
} - {features?.map((feature, key) => { - return ( - - ); - })} - - ); -}; - -/** - * Feature or Geometry card component for FeatureList. - * @function - * - */ -const FeatureCard = ({ - feature, - selected, - disabled, - onDeleteGeometry, - onZoom, - maxZoom, - onSelectFeature, - onUnselectFeature, - setTabValue, - isMeasureEditDisabled, - onStyleGeometry, - onGeometryHighlight, - onValidateFeature -}) => { - const type = getGeometryType(feature); - const {properties} = feature; - const {glyph, label} = getGeometryGlyphInfo(type); - const isSelected = selected?.properties?.id === properties?.id; - - const selectedIsValidFeature = get(selected, "properties.isValidFeature", true); - const isValidFeature = properties?.isValidFeature; - const allowCardMouseEvent = !isSelected && selectedIsValidFeature; - - const overlayWrapper = (content) => ( - }> - {content} - - ); - - const content = ( -
allowCardMouseEvent && onGeometryHighlight(properties.id)} - onMouseLeave={() => allowCardMouseEvent && onGeometryHighlight(properties.id, false)} - onClick={() =>{ - - if (isSelected && isValidFeature) { - onUnselectFeature(); - onGeometryHighlight(properties.id); - } else if (!disabled) { - onSelectFeature([feature]); - setTabValue(isMeasureEditDisabled ? 'coordinates' : 'style'); - onStyleGeometry(!isMeasureEditDisabled); - } - onValidateFeature(); - } } - > -
- -
-
-
{properties?.geometryTitle || label || properties?.id}
-
- , - onClick: (event) => { - event.stopPropagation(); - const extent = bbox(feature); - onZoom(extent, 'EPSG:4326', maxZoom); - } - }, - { - glyph: 'trash', - className: cs({'inactive': disabled && !isSelected, 'square-button-md no-border': true}), - tooltip: , - onClick: (event) => { - event.stopPropagation(); - onDeleteGeometry(properties?.id); - } - } - ]} - /> -
- ); - - return disabled && !isSelected ? overlayWrapper(content) : content; -}; - -FeaturesList.defaultProps = { - onAddGeometry: () => {}, - onSetStyle: () => {}, - onStartDrawing: () => {}, - onAddText: () => {}, - onStyleGeometry: () => {}, - onSetAnnotationMeasurement: () => {}, - onSelectFeature: () => {}, - setTabValue: () => {}, - isMeasureEditDisabled: true, - defaultPointType: 'marker', - defaultStyles: {}, - onValidateFeature: () => {}, - validateFeatures: () => { return true; } -}; - -export default FeaturesList; diff --git a/web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx b/web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx deleted file mode 100644 index 6eb6595d60..0000000000 --- a/web/client/components/mapcontrols/annotations/SelectAnnotationsFile.jsx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2017, 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. - */ - -import { Promise } from 'es6-promise'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Checkbox } from 'react-bootstrap'; -import Dropzone from 'react-dropzone'; -import Spinner from 'react-spinkit'; - -import { ANNOTATION_TYPE } from '../../../plugins/Annotations/utils/AnnotationsUtils'; -import { readGeoJson } from '../../../utils/FileUtils'; -import Message from '../../I18N/Message'; -import ResizableModal from '../../misc/ResizableModal'; - -class SelectAnnotationsFile extends React.Component { - static propTypes = { - show: PropTypes.bool, - text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - onFileChoosen: PropTypes.func, - error: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), - errorMessage: PropTypes.string, - onClose: PropTypes.func, - title: PropTypes.node, - closeGlyph: PropTypes.string, - disableOvveride: PropTypes.bool - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - show: false, - text: , - onFileChoosen: () => {}, - onClose: () => {}, - closeGlyph: "", - errorMessage: "annotations.loaderror", - title: , - disableOvveride: false - }; - state = { - override: false, - loading: false - } - renderError = () => ( -
-
- -
-
) - render() { - return ( - -
- {this.state.error && this.renderError()} - -
{this.state.loading && }{this.props.text}
-
-
- this.setState(() => ({override: !this.state.override}))}> - - -
-
-
- ); - } - setError = () => { - this.setState(() => ({error: this.props.errorMessage, loading: false})); - } - // Modificare per accettare file json ma non devono per forza avere ext.json - // inoltre può accettare qualsiasi collezione di features inoltre filtrare le features che hanno medesimo id - checkfile = (files) => { - this.setState(() => ({loading: true})); - Promise.all(files.map(file => readGeoJson(file))).then((contents) => { - if (this.state.error) { - this.setState(() => ({error: null})); - } - // Get only features - const annotations = contents.filter(({geoJSON, errors = []}) => errors.length === 0 || geoJSON.type === ANNOTATION_TYPE).reduce((acc, {geoJSON}) => acc.concat(geoJSON.features || geoJSON), []); - if (annotations.length === 0) { - throw new Error(); - } - this.props.onFileChoosen(annotations, this.state.override); - this.setState(() => ({loading: false})); - this.props.onClose(); - }).catch(() => { - this.setError(); - }); - }; -} - -export default SelectAnnotationsFile; diff --git a/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js b/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js deleted file mode 100644 index 5eb466e541..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/Annotations-test.js +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2015-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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import Annotations from '../Annotations'; -import TestUtils from 'react-dom/test-utils'; - -describe("test the Annotations Panel", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test default properties', () => { - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toBeTruthy(); - }); - - it('test removing annotations', () => { - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toBeTruthy(); - }); - - it('test rendering detail mode', () => { - const annotationsList = [{ - properties: { - id: '1', - title: 'a', - description: 'b' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }, { - properties: { - id: '2', - title: 'a', - description: 'b' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }]; - - const Editor = () =>
; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor").length).toBe(1); - }); - - it('test rendering editing mode', () => { - const Editor = () =>
; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor").length).toBe(1); - }); - - it('test rendering custom class', () => { - const annotationsList = [{ - properties: { - title: 'a', - description: 'b' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue', - iconGlyph: 'comment' - } - }, { - properties: { - external: true, - title: 'c', - description: 'd' - }, - geometry: { - type: "MultiPoint" - }, - style: { - iconShape: 'square', - iconColor: 'blue', - iconGlyph: 'comment' - } - }]; - - const classNameSelector = (annotation) => { - if (annotation && annotation.properties && annotation.properties.external) { - return 'external'; - } - return ''; - }; - - const annotations = ReactDOM.render(, document.getElementById("container")); - - expect(annotations).toBeTruthy(); - - /* - TODO verify the external properties - const cardsExternal = TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card external"); - expect(cardsExternal.length).toBe(1);*/ - }); - - it('test custom editor', () => { - const annotationsList = [{ - properties: { - id: '1', - title: 'a', - description: 'b' - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }, { - properties: { - id: '2', - title: 'a', - description: 'b' - }, - style: { - iconShape: 'square', - iconColor: 'blue' - } - }]; - - const Editor = (props) => { - return This is my editor; - }; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toBeTruthy(); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "mapstore-annotations-panel-card").length).toBe(0); - expect(TestUtils.scryRenderedDOMComponentsWithClass(annotations, "myeditor1").length).toBe(1); - }); - - it('test annotation card', ()=> { - const actions = { - onZoom: () => {}, - onToggleVisibility: () => {}, - onHighlight: () => {} - }; - const spyOnToggleVisibility = expect.spyOn(actions, 'onToggleVisibility'); - const spyOnHighlight = expect.spyOn(actions, 'onHighlight'); - const spyOnZoom = expect.spyOn(actions, 'onZoom'); - const annotations = [{ - "type": "FeatureCollection", - "properties": { - "id": "819b4120-aa2c-11ea-95b6-c74060290256", - "title": "Poly", - "description": "

Description

Next Line

", - "visibility": true - }, - "features": [ - { - "type": "Feature", - "geometry": { - "coordinates": [[[-121.07812513411045, 42.11778385718358], - [ -116.2265622317791, 44.72175879125132], - [ -115.87499973177908, 40.773885871584866], - [ -114.96093589067458, 42.68889580392076], - [ -121.07812513411045, 42.11778385718358]] - ], - "type": "Polygon" - }, - "properties": { - "id": "829d47d0-aa2c-11ea-95b6-c74060290256", - "isValidFeature": true, - "canEdit": false, - "geometryTitle": "Polygon-test" - } - } - ] - }]; - const container = ReactDOM.render(, document.getElementById("container")); - expect(container).toBeTruthy(); - - const sideCard = TestUtils.scryRenderedDOMComponentsWithClass(container, "mapstore-side-card"); - expect(sideCard).toBeTruthy(); - expect(sideCard.length).toBe(1); - const sideCardTitle = TestUtils.scryRenderedDOMComponentsWithClass(container, "mapstore-annotations-panel-card-title"); - expect(sideCardTitle[0].innerText).toBe('Poly'); - const sideCardDescription = TestUtils.scryRenderedDOMComponentsWithClass(container, "mapstore-annotations-panel-card-description"); - expect(sideCardDescription[0].innerText).toBe('Description'); - const sideCardTools = document.querySelectorAll('.mapstore-side-card-tool .btn-group'); - expect(sideCardTools).toBeTruthy(); - const cardButtons = sideCardTools[0].querySelectorAll('button'); - expect(cardButtons.length).toBe(2); - - // Zoom to annotation - const zoomBtn = cardButtons[0]; - TestUtils.Simulate.click(zoomBtn); - expect(spyOnZoom).toHaveBeenCalled(); - - // Toggle annotations visibility - const visibilityBtn = cardButtons[1]; - TestUtils.Simulate.click(visibilityBtn); - expect(spyOnToggleVisibility).toHaveBeenCalled(); - - // Toggle annotation highlight - TestUtils.Simulate.mouseEnter(sideCard[0]); - expect(spyOnHighlight).toHaveBeenCalled(); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js b/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js deleted file mode 100644 index 6759f77098..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/AnnotationsEditor-test.js +++ /dev/null @@ -1,587 +0,0 @@ -/** - * Copyright 2015-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. - */ -import expect from 'expect'; -import React from 'react'; -import { DragDropContext as dragDropContext } from 'react-dnd'; -import html5Backend from 'react-dnd-html5-backend'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import AnnotationsEditorComp from '../AnnotationsEditor'; - -const AnnotationsEditor = dragDropContext(html5Backend)(AnnotationsEditorComp); - -const actions = { - onChangeProperties: () => {}, - onSetUnsavedChanges: () => {}, - onEdit: () => {}, - onCancelEdit: () => {}, - onSetUnsavedStyle: () => {}, - onError: () => {}, - onSetAnnotationMeasurement: () => {}, - onDownload: () => {}, - onHideMeasureWarning: () => {}, - onSelectFeature: () => {}, - onUnSelectFeature: () => {}, - onValidateFeature: () => {} -}; -describe("test the AnnotationsEditor Panel", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test default properties', () => { - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode).toExist(); - }); - - it('test display annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode).toExist(); - expect(viewerNode.innerText.indexOf('mytitle') !== -1).toBe(true); - expect(viewerNode.innerHTML.indexOf('desc') !== -1).toBe(true); - }); - - it('test display annotation with component field', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - const MyComponent = (props) => { - return my feature: {props.annotation.id}; - }; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode).toExist(); - expect(viewerNode.innerText.indexOf('my feature: 1') !== -1).toBe(true); - }); - - it('test editing annotation', () => { - const properties = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - expect(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "input").length).toEqual(1); - expect(TestUtils.scryRenderedDOMComponentsWithClass(viewer, "quill").length).toEqual(1); - }); - - it('test click remove annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onRemoveHandler: () => { } - }; - - const spyRemove = expect.spyOn(testHandlers, 'onRemoveHandler'); - - let viewer = ReactDOM.render({}} onSetUnsavedChanges={()=>{}} - onConfirmRemove={testHandlers.onRemoveHandler}/>, document.getElementById("container")); - expect(viewer).toExist(); - let btnGroup = document.querySelector(".mapstore-annotations-info-viewer-buttons"); - let toolBarButtons = btnGroup.querySelectorAll('button'); - let removeBtn = toolBarButtons[1]; - expect(toolBarButtons.length).toBe(4); - expect(removeBtn).toExist(); - TestUtils.Simulate.click(removeBtn); - const dialog = document.getElementById("confirm-dialog"); - expect(dialog).toExist(); - const confirm = dialog.querySelectorAll('button')[1]; - TestUtils.Simulate.click(confirm); - expect(spyRemove).toHaveBeenCalled(); - - // Disable remove button when no annotations present except for the unsaved new annotation - viewer = ReactDOM.render({}} onSetUnsavedChanges={()=>{}} - onConfirmRemove={testHandlers.onRemoveHandler}/>, document.getElementById("container")); - expect(viewer).toExist(); - btnGroup = document.querySelector(".mapstore-annotations-info-viewer-buttons"); - toolBarButtons = btnGroup.querySelectorAll('button'); - removeBtn = toolBarButtons[1]; - expect(toolBarButtons.length).toBe(4); - expect(removeBtn.classList.contains('disabled')).toBe(true); - - }); - - it('test click save annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onCancelHandler: (id) => { return id; }, - onToggleGeometryEditHandler: (flag) => { return flag; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyCancel = expect.spyOn(testHandlers, 'onCancelHandler'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[2]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - expect(spySave.calls.length).toEqual(1); - expect(spySave.calls[0].arguments[0]).toEqual(1); - expect(spySave.calls[0].arguments[5]).toEqual({...feature, visibility: true}); - expect(spyCancel.calls.length).toEqual(0); - }); - - it('test click save annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onAddNewFeature: () => {} - }; - - const spySaveGeometry = expect.spyOn(testHandlers, 'onAddNewFeature'); - const defaultStyles = {POINT: { - marker: ["Test marker"], - symbol: ["Test symbol"] - }}; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[1]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - expect(spySaveGeometry).toHaveBeenCalled(); - }); - - it('test click cancel', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc', - visibility: false - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onCancelHandler: (id) => { return id; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyCancel = expect.spyOn(testHandlers, 'onCancelHandler'); - - const viewer = ReactDOM.render(null}/>, document.getElementById("container")); - expect(viewer).toExist(); - - let cancelButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[0]); - - expect(cancelButton).toExist(); - TestUtils.Simulate.click(cancelButton); - - expect(spySave.calls.length).toEqual(0); - expect(spyCancel.calls.length).toEqual(1); - const properties = spyCancel.calls[0].arguments[0]; - expect(Object.keys(properties).length > 0).toBe(true); - expect(spyCancel.calls[0].arguments[0].id).toBe('1'); - expect(spyCancel.calls[0].arguments[0].visibility).toBe(false); - }); - - it('test click cancel trigger UnsavedChangesModal', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onToggleUnsavedChangesModal: (id) => { return id; } - }; - - const spyUnsavedModal = expect.spyOn(testHandlers, 'onToggleUnsavedChangesModal'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let cancelButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[0]); - - expect(cancelButton).toExist(); - TestUtils.Simulate.click(cancelButton); - - expect(spyUnsavedModal.calls.length).toEqual(1); - }); - - it('test click save validate title error', () => { - const feature = { - id: "1", - title: '', - description: 'desc' - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onErrorHandler: (msg) => { return msg; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyError = expect.spyOn(testHandlers, 'onErrorHandler'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[2]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - - expect(spySave.calls.length).toEqual(0); - expect(spyError.calls.length).toEqual(1); - expect(spyError.calls[0].arguments[0].title).toBe('annotations.mandatory'); - }); - - it('test click save validate geometry error', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const testHandlers = { - onSaveHandler: (id) => { return id; }, - onErrorHandler: (msg) => { return msg; } - }; - - const spySave = expect.spyOn(testHandlers, 'onSaveHandler'); - const spyError = expect.spyOn(testHandlers, 'onErrorHandler'); - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - let saveButton = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "button")[2]); - - expect(saveButton).toExist(); - TestUtils.Simulate.click(saveButton); - - expect(spySave.calls.length).toEqual(0); - expect(spyError.calls.length).toEqual(1); - expect(spyError.calls[0].arguments[0].geometry).toBe('annotations.emptygeometry'); - }); - - it('test edit field', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - const testHandlers = { - onChangeProperties: (id) => { return id; } - }; - const spyChangeProperties = expect.spyOn(testHandlers, 'onChangeProperties'); - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - - const titleField = ReactDOM.findDOMNode(TestUtils.scryRenderedDOMComponentsWithTag(viewer, "input")[0]); - titleField.value = 'anothertitle'; - TestUtils.Simulate.change(titleField); - expect(spyChangeProperties.calls.length).toEqual(2); - - }); - - it('test errors', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.innerText.indexOf('myerror') !== -1).toBe(true); - }); - - it('test styling', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - const stylerPanel = TestUtils.findRenderedDOMComponentWithClass(viewer, "mapstore-annotations-info-viewer-styler"); - expect(stylerPanel).toExist(); - }); - - it('test Measurement annotation', () => { - const feature = { - id: "1", - title: 'Measure Length', - description: 'Description', - type: "Measure", - iconGlyph: "1-measure-length" - }; - const spyOnSetAnnotationMeasurement = expect.spyOn(actions, "onSetAnnotationMeasurement"); - const spyOnHideMeasureWarning = expect.spyOn(actions, "onHideMeasureWarning"); - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toBeTruthy(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - const annotationInfoViewer = TestUtils.findRenderedDOMComponentWithClass(viewer, "mapstore-annotations-info-viewer-items"); - const geometriesToolbar = document.querySelector('.geometries-toolbar'); - const geometryCard = document.querySelectorAll('.geometry-card'); - expect(annotationInfoViewer).toBeTruthy(); - expect(geometriesToolbar).toBeTruthy(); - - const geomButton = geometriesToolbar.children[1].getElementsByTagName('button'); - expect(geomButton.length).toBe(1); - const editMeasureButton = geomButton[0]; - expect(editMeasureButton.children[0].className).toContain(feature.iconGlyph); - expect(geometryCard.length).toBe(2); - - // Edit measurement - TestUtils.Simulate.click(editMeasureButton); - expect(spyOnSetAnnotationMeasurement).toHaveBeenCalled(); - expect(spyOnHideMeasureWarning).toHaveBeenCalled(); - expect(spyOnSetAnnotationMeasurement.calls[0].arguments).toBeTruthy(); - expect(spyOnSetAnnotationMeasurement.calls[0].arguments.length).toBe(2); - const features = spyOnSetAnnotationMeasurement.calls[0].arguments[0]; - const properties = spyOnSetAnnotationMeasurement.calls[0].arguments[1]; - expect(features.length).toBe(1); - expect(features[0].geometry.type).toBe('LineString'); - expect(properties).toBeTruthy(); - expect(Object.keys(properties).length > 0).toBe(true); - }); - - it('test Measurement geometry', () => { - const properties = { - id: "1", - title: 'Measure Length', - description: 'Description', - type: "Measure", - iconGlyph: "1-measure-length" - }; - const feature = { - properties, - features: [{ - type: 'Feature', - geometry: {type: "LineString"}, - properties: { - id: 1, - values: [{ - value: '1511', - formattedValues: "1,511 m", - position: [1, 1], - type: 'length' - }] - } - }, - {type: 'Feature', geometry: {type: "Point"}}], - style: [{}] - }; - const viewer = ReactDOM.render(, document.getElementById("container")); - expect(viewer).toBeTruthy(); - const viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - const annotationInfoViewer = TestUtils.findRenderedDOMComponentWithClass(viewer, "mapstore-annotations-info-viewer-items"); - const geometryCard = document.querySelectorAll('.geometry-card'); - expect(annotationInfoViewer).toBeTruthy(); - expect(geometryCard.length).toBe(2); - - // Onclick of measurement geometry - TestUtils.Simulate.click(geometryCard[0]); - const navTabs = document.querySelector('.nav-tabs'); - expect(navTabs.children.length).toBe(1); - const styleTab = navTabs.children[0].childNodes[0].textContent; - expect(styleTab).toContain('Style'); - }); - - it('test onDownload annotation', () => { - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const spyOnDownload = expect.spyOn(actions, 'onDownload'); - let viewer = ReactDOM.render(, document.getElementById("container")); - - expect(viewer).toExist(); - let viewerNode = ReactDOM.findDOMNode(viewer); - expect(viewerNode.className).toBe('mapstore-annotations-info-viewer'); - - let buttonsRow = viewerNode.querySelector('.mapstore-annotations-info-viewer-buttons .noTopMargin'); - expect(buttonsRow).toBeTruthy(); - - let buttons = buttonsRow.querySelectorAll('button'); - expect(buttons.length).toBe(4); - - let downloadCurrentAnnotation = buttons[3]; - expect(downloadCurrentAnnotation.classList.contains('disabled')).toBe(false); - - TestUtils.Simulate.click(downloadCurrentAnnotation); - expect(spyOnDownload).toHaveBeenCalled(); - expect(spyOnDownload.calls[0].arguments[0]).toEqual({features: [{id: "1"}], properties: feature}); - }); - it('test onDownload when unsavedChanges', ()=>{ - const feature = { - id: "1", - title: 'mytitle', - description: 'desc' - }; - - const viewer = ReactDOM.render(, document.getElementById("container")); - - expect(viewer).toExist(); - const viewerNode = ReactDOM.findDOMNode(viewer); - const buttonsRow = viewerNode.querySelector('.mapstore-annotations-info-viewer-buttons .noTopMargin'); - const buttons = buttonsRow.querySelectorAll('button'); - const downloadCurrentAnnotation = buttons[3]; - expect(downloadCurrentAnnotation.classList.contains('disabled')).toBe(true); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js b/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js deleted file mode 100644 index ab9aadfa37..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/DropdownFeatureType-test.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2019, 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. -*/ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import DropdownFeatureType from '../DropdownFeatureType'; - -const titles = { - marker: "marker", - line: "line", - polygon: "polygon", - circle: "circle", - text: "text" -}; - -const testSpies = (spies, button) => { - expect(button).toExist(); - button.click(); - spies.forEach(spy => { - expect(spy).toHaveBeenCalled(); - }); -}; - -const resetSpies = (spies) => { - spies.forEach(spy => { - spy.restore(); - }); -}; - -describe("test the DropdownFeatureType Panel", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('DropdownFeatureType rendering with defaults', () => { - ReactDOM.render( - , document.getElementById("container") - ); - const items = document.getElementsByTagName("li"); - expect(items).toExist(); - expect(items.length).toBe(5); - const spans = document.getElementsByTagName("span"); - expect(spans).toExist(); - expect(spans.length).toBe(6); - expect(spans[0].className).toBe("glyphicon glyphicon-pencil-add"); - expect(spans[1].className).toBe("glyphicon glyphicon-point"); - expect(spans[2].className).toBe("glyphicon glyphicon-line"); - expect(spans[3].className).toBe("glyphicon glyphicon-polygon"); - expect(spans[4].className).toBe("glyphicon glyphicon-text-colour"); - expect(spans[5].className).toBe("glyphicon glyphicon-1-circle"); - }); - - it('DropdownFeatureType testing the actions', () => { - - const testHandlers = { - onClick: () => {}, - onStartDrawing: () => {}, - onSetStyle: () => {}, - onAddText: () => {} - }; - - const spyOnClick = expect.spyOn(testHandlers, 'onClick'); - const spyOnSetStyle = expect.spyOn(testHandlers, 'onSetStyle'); - const spyOnStartDrawing = expect.spyOn(testHandlers, 'onStartDrawing'); - const spyOnAddText = expect.spyOn(testHandlers, 'onAddText'); - - const spies = [spyOnClick, spyOnSetStyle, spyOnStartDrawing]; - ReactDOM.render( - , document.getElementById("container") - ); - const buttons = document.getElementsByTagName("a"); - - const marker = buttons[0]; - testSpies(spies, marker); - expect(spyOnClick).toHaveBeenCalledWith("Point"); - resetSpies(spies); - - const line = buttons[1]; - testSpies(spies, line); - expect(spyOnClick).toHaveBeenCalledWith("LineString"); - resetSpies(spies); - - const polygon = buttons[2]; - testSpies(spies, polygon); - expect(spyOnClick).toHaveBeenCalledWith("Polygon"); - resetSpies(spies); - - const text = buttons[3]; - testSpies([...spies, spyOnAddText], text); - expect(spyOnClick).toHaveBeenCalledWith("Text"); - resetSpies(spies); - - const circle = buttons[4]; - testSpies(spies, circle); - expect(spyOnClick).toHaveBeenCalledWith("Circle"); - resetSpies(spies); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js b/web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js deleted file mode 100644 index 6ed0274547..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/FeatureList-test.js +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2020, 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. - */ - -import React from 'react'; -import ReactDOM from 'react-dom'; -import expect from 'expect'; -import FeaturesList from '../FeaturesList'; - -import TestUtils from 'react-dom/test-utils'; - -describe("test FeatureList component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test render FeaturesList', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - }); - - it('test render with default properties', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - const labels = container.querySelectorAll(".control-label"); - expect(labels[0].innerText).toBe('annotations.geometries'); - const buttons = container.querySelectorAll("button"); - expect(buttons.length).toBe(5); - expect(container.innerText).toContain('annotations.addGeometry'); - }); - - it('test render with measurement annotation properties', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - const buttons = container.querySelectorAll("button"); - expect(buttons.length).toBe(1); - }); - it('test geometries toolbar', () => { - const editing = { - features: [{ - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }; - const actions = { - onAddGeometry: () => {}, - onSetStyle: () => {}, - onStyleGeometry: () => {}, - onStartDrawing: () => {}, - onAddText: () => {} - }; - const defaultStyle = {POINT: { - marker: ["Test marker"], - symbol: ["Test symbol"] - }}; - const spyOnAddGeometry = expect.spyOn(actions, "onAddGeometry"); - const spyOnSetStyle = expect.spyOn(actions, "onSetStyle"); - const spyOnStyleGeometry = expect.spyOn(actions, "onStyleGeometry"); - const spyOnStartDrawing = expect.spyOn(actions, "onStartDrawing"); - const spyOnAddText = expect.spyOn(actions, "onAddText"); - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const geometriesToolbar = document.querySelector('.geometries-toolbar'); - const buttons = geometriesToolbar.children[1].getElementsByTagName('button'); - [...buttons].forEach((btn, index)=>{ - TestUtils.Simulate.click(btn); - expect(spyOnSetStyle).toHaveBeenCalled(); - if (index === 0) { - const [style] = spyOnSetStyle.calls[0].arguments[0]; - expect(style["0"]).toEqual('Test symbol'); - } - index === 3 && expect(spyOnAddText).toHaveBeenCalled(); - expect(spyOnAddGeometry).toHaveBeenCalled(); - expect(spyOnStartDrawing).toHaveBeenCalled(); - expect(spyOnStyleGeometry).toHaveBeenCalled(); - }); - }); - it('test render with feature card', () => { - const editing = { - features: [{ - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }; - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const cardContainer = document.getElementsByClassName('geometry-card'); - expect(cardContainer).toBeTruthy(); - - const previewIcon = document.querySelector('.glyphicon-polygon'); - expect(previewIcon).toBeTruthy(); - - const cardTitle = document.querySelector('.geometry-card-label'); - expect(cardTitle.innerText).toBe('Polygon'); - - const glyphIcons = document.querySelectorAll('.btn-group .glyphicon'); - expect(glyphIcons.length).toBe(7); - expect(glyphIcons[5].className).toContain('zoom-to'); - expect(glyphIcons[6].className).toContain('trash'); - }); - - it('test actions on feature card', () => { - const editing = { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon", coordinates: [ - [ - [-121.07812513411045, 42.11778385718358], - [-116.2265622317791, 44.72175879125132], - [-115.87499973177908, 40.773885871584866], - [-114.96093589067458, 42.68889580392076], - [-121.07812513411045, 42.11778385718358] - ] - ]} - }] - }; - const testHandlers = { - onSelectFeature: () => {}, - onUnselectFeature: () => {}, - onStyleGeometry: () => {}, - onZoom: () => {}, - onDeleteGeometry: () => {}, - setTabValue: () => {} - }; - const spyOnSelectFeature = expect.spyOn(testHandlers, "onSelectFeature"); - const spyOnZoom = expect.spyOn(testHandlers, "onZoom"); - const spyOnDeleteGeometry = expect.spyOn(testHandlers, "onDeleteGeometry"); - const spyOnStyleGeometry = expect.spyOn(testHandlers, "onStyleGeometry"); - ReactDOM.render( - , document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - const buttons = document.querySelectorAll('button'); - - // OnSelectFeature - TestUtils.Simulate.click(featureCard[0]); - expect(spyOnSelectFeature).toHaveBeenCalled(); - expect(spyOnSelectFeature.calls[0].arguments[0]).toEqual(editing.features); - expect(spyOnStyleGeometry).toHaveBeenCalled(); - expect(spyOnStyleGeometry.calls[0].arguments[0]).toBe(false); - - // OnZoomGeometry - TestUtils.Simulate.click(buttons[5]); - expect(spyOnZoom).toHaveBeenCalled(); - expect(spyOnZoom.calls[0].arguments[1]).toBe("EPSG:4326"); - - // OnDeleteGeometry - TestUtils.Simulate.click(buttons[6]); - expect(spyOnDeleteGeometry).toHaveBeenCalled(); - expect(spyOnDeleteGeometry.calls[0].arguments[0]).toBe("1"); - }); - - it('test unselect a geometry', () => { - const props = { - editing: { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }, - selected: {properties: {id: '1'}} - }; - const testHandlers = { - onUnselectFeature: () => {}, - onGeometryHighlight: () => {} - }; - const spyOnUnselectFeature = expect.spyOn(testHandlers, "onUnselectFeature"); - const spyOnGeometryHighlight = expect.spyOn(testHandlers, "onGeometryHighlight"); - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - - const featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - // OnUnSelectFeature - TestUtils.Simulate.click(featureCard[0]); - expect(spyOnUnselectFeature).toHaveBeenCalled(); - expect(spyOnGeometryHighlight).toHaveBeenCalled(); - expect(spyOnGeometryHighlight.calls[0].arguments[0]).toBe('1'); - }); - - it('test geometry highlight', () => { - let props = { - editing: { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: true, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }, - selected: {properties: {id: '1'}} - }; - const testHandlers = { - onGeometryHighlight: () => {} - }; - const spyOnGeometryHighlight = expect.spyOn(testHandlers, "onGeometryHighlight"); - ReactDOM.render(, document.getElementById("container")); - let container = document.getElementById('container'); - expect(container).toBeTruthy(); - - let featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - TestUtils.Simulate.mouseEnter(featureCard[0]); - expect(spyOnGeometryHighlight).toNotHaveBeenCalled(); - - // When geometry card is not selected - props = {...props, selected: {...props.selected, properties: {id: 2}}}; - ReactDOM.render(, document.getElementById("container")); - container = document.getElementById('container'); - featureCard = document.getElementsByClassName('geometry-card'); - // OnMouseEnter - TestUtils.Simulate.mouseEnter(featureCard[0]); - expect(spyOnGeometryHighlight).toHaveBeenCalled(); - expect(spyOnGeometryHighlight.calls[0].arguments[0]).toBe('1'); - - // OnMouseLeave - TestUtils.Simulate.mouseLeave(featureCard[0]); - expect(spyOnGeometryHighlight).toHaveBeenCalled(); - expect(spyOnGeometryHighlight.calls[1].arguments[0]).toBe('1'); - expect(spyOnGeometryHighlight.calls[1].arguments[1]).toBe(false); - }); - - it('test geometry highlight limitations', () => { - let props = { - editing: { - features: [{ - type: "Feature", - properties: {id: '1', isValidFeature: false, geometryTitle: 'Polygon'}, - geometry: {type: "Polygon"} - }] - }, - selected: {properties: {id: '2', isValidFeature: false}} - }; - const testHandlers = { - onGeometryHighlight: () => {} - }; - const spyOnGeometryHighlight = expect.spyOn(testHandlers, "onGeometryHighlight"); - ReactDOM.render(, document.getElementById("container")); - let container = document.getElementById('container'); - expect(container).toBeTruthy(); - - let featureCard = document.getElementsByClassName('geometry-card'); - expect(featureCard).toBeTruthy(); - - ReactDOM.render(, document.getElementById("container")); - container = document.getElementById('container'); - featureCard = document.getElementsByClassName('geometry-card'); - // OnMouseEnter - TestUtils.Simulate.mouseEnter(featureCard[0]); - expect(spyOnGeometryHighlight).toNotHaveBeenCalled(); - - // OnMouseLeave - TestUtils.Simulate.mouseLeave(featureCard[0]); - expect(spyOnGeometryHighlight).toNotHaveBeenCalled(); - }); - - it('test render defaults with defaultPointType as symbol', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - expect(container).toBeTruthy(); - const labels = container.querySelectorAll(".control-label"); - expect(labels[0].innerText).toBe('annotations.geometries'); - const buttons = container.querySelectorAll("button"); - expect(buttons.length).toBe(5); - expect(container.innerText).toContain('annotations.addGeometry'); - }); -}); diff --git a/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js b/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js deleted file mode 100644 index e4b228d7a2..0000000000 --- a/web/client/components/mapcontrols/annotations/__tests__/SelectAnnotationsFile-test.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import SelectAnnotationsFile from '../SelectAnnotationsFile'; - - -describe("test the SelectAnnotationsFile modal", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.body); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('test default properties', () => { - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toExist(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toNotExist(); - }); - it('test file selected', (done) => { - const jsonFile = new File([`{ "coordinates": [ - 4.6142578125, - 45.67548217560647 - ], - "type": "Point" - }` - ], "file.json", { - type: "application/json" - }); - const onFileChoosen = (features, override) => { - expect(features instanceof Array).toBe(true); - expect(features.length).toBe(1); - expect(override).toBe(false); - done(); - }; - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toExist(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toExist(); - annotations.checkfile([jsonFile]); - }); - - it('test file selected to fail', (done) => { - const jsonFile = new File([`[{ - "geometry": { - "type": "MultiPolygon" - }, - "properties": { - "id": "25cbbbb0-1625-11e8-a091-639e3ca0149f", - "title": "Pino" - }, - "style": { - "highlight": false - }, - "type": "Feature" - }]` - ], "file.txt", { - type: "text/plain" - }); - const annotations = ReactDOM.render(, document.getElementById("container")); - expect(annotations).toExist(); - const annotationsNode = ReactDOM.findDOMNode(annotations); - expect(annotationsNode).toExist(); - annotations.componentDidUpdate = () => { - if (annotations.state.error) { - expect(annotations.state.error).toExist(); - done(); - } - }; - annotations.checkfile([jsonFile]); - }); - -}); diff --git a/web/client/components/style/BandSelector.jsx b/web/client/components/style/BandSelector.jsx deleted file mode 100644 index da5722df1e..0000000000 --- a/web/client/components/style/BandSelector.jsx +++ /dev/null @@ -1,128 +0,0 @@ -/** - * 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. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import { Col, Grid, Row } from 'react-bootstrap'; -import { Combobox, NumberPicker } from 'react-widgets'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -import { getMessageById } from '../../utils/LocaleUtils'; -import Message from '../I18N/Message'; - -numberLocalizer(); - - -class BandSelector extends React.Component { - static propTypes = { - band: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - bands: PropTypes.array, - min: PropTypes.number, - max: PropTypes.number, - contrast: PropTypes.oneOf(['none', 'Normalize', 'Histogram', 'GammaValue']), - algorithm: PropTypes.oneOf(['none', 'StretchToMinimumMaximum', 'ClipToMinimumMaximum', 'ClipToZero']), - gammaValue: PropTypes.number, - onChange: PropTypes.func, - bandsComboOptions: PropTypes.object - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - band: '1', - contrast: "none", - algorithm: "none", - gammaValue: 1, - min: 0, - max: 255, - bandsComboOptions: {}, - onChange: () => {}, - bands: ['1', '2', '3'] - }; - - render() { - return ( - - - - - {this.props.contrast === "GammaValue" ? : null } - {this.props.contrast === "Normalize" ? : null } - - - - this.props.onChange("band", v)} - {...this.props.bandsComboOptions}/> - - - this.props.onChange("contrast", v.value)}/> - - { this.props.contrast === "GammaValue" ? - this.props.onChange("gammaValue", v)}/> : null} - { this.props.contrast === "Normalize" ? - - this.props.onChange("algorithm", v.value)}/> - - : null} - - {this.props.contrast === "Normalize" && this.props.algorithm !== "none" ? - - - - : null } - {this.props.contrast === "Normalize" && this.props.algorithm !== "none" ? - - - this.props.onChange("min", v)} - /> - - this.props.onChange("max", v)} - /> - : null } - ); - } -} - -export default BandSelector; diff --git a/web/client/components/style/CircleStyler.jsx b/web/client/components/style/CircleStyler.jsx deleted file mode 100644 index bcf6b74aa8..0000000000 --- a/web/client/components/style/CircleStyler.jsx +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import assign from 'object-assign'; -import { Grid, Row, Col } from 'react-bootstrap'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import Slider from 'react-nouislider'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import { isNil } from 'lodash'; -import Message from '../I18N/Message'; -import tinycolor from 'tinycolor2'; - -class StylePolygon extends React.Component { - static propTypes = { - shapeStyle: PropTypes.object, - width: PropTypes.number, - setStyleParameter: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - shapeStyle: {}, - setStyleParameter: () => {} - }; - - render() { - const styleType = "Circle"; - const style = this.props.shapeStyle[styleType] || this.props.shapeStyle; // in case of old version of style. - return ( - - -
- -
- -
- - - - - - { - if (!isNil(c)) { - const fillColor = tinycolor(c).toHexString(); - const fillOpacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {fillColor, fillOpacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{min: 1, max: 15}} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {weight}) - }); - this.props.setStyleParameter(newStyle); - }} - /> -
- -
-
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default StylePolygon; diff --git a/web/client/components/style/ColorMapGrid.jsx b/web/client/components/style/ColorMapGrid.jsx deleted file mode 100644 index d9208978c3..0000000000 --- a/web/client/components/style/ColorMapGrid.jsx +++ /dev/null @@ -1,122 +0,0 @@ -/** - * 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. - */ - -import React from 'react'; - -import { isEqual } from 'lodash'; -import { AgGridReact } from 'ag-grid-react'; -import PropTypes from 'prop-types'; -import reactCellRendererFactory from './ColorMapGridComponents/ReactCellRendererFactoryParams'; -import ColorPickerRenderer from './ColorMapGridComponents/ColorPickerRenderer'; -import assign from 'object-assign'; -import NumberRenderer from './ColorMapGridComponents/NumberRenderer'; -import { getMessageById } from '../../utils/LocaleUtils'; -import 'ag-grid-community/dist/styles/ag-grid.css'; -import 'ag-grid-community/dist/styles/ag-theme-blue.css'; - -class ColorMapGrid extends React.Component { - static propTypes = { - entries: PropTypes.array, - style: PropTypes.object, - selectEntry: PropTypes.func, - valueChanged: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - entries: [], - style: {height: "200px"}, - selectEntry: () => {}, - valueChanged: () => {} - }; - - shouldComponentUpdate(nextProps) { - return !isEqual(nextProps.entries, this.props.entries); - } - - componentDidUpdate() { - this.api.sizeColumnsToFit(); - } - - onGridReady = (params) => { - this.api = params.api; - this.api.sizeColumnsToFit(); - this.columnApi = params.columnApi; - }; - - render() { - return ( -
- -
); - } - - selectEntry = (row) => { - if (row) { - this.props.selectEntry(row.node.childIndex); - } - }; - - valueChanged = () => { - let newData = []; - this.api.getModel().forEachNode((node) => {newData.push(node.data); }); - this.props.valueChanged(newData); - }; - - changeColor = (node, colorOpacity) => { - let newData = []; - this.api.getModel().forEachNode((n, idx) => { - let data = idx === node.childIndex ? assign({}, n.data, colorOpacity) : n.data; - newData.push(data); - }); - this.props.valueChanged(newData); - }; - - changeQuantity = (node, value) => { - let newData = []; - this.api.getModel().forEachNode((n, idx) => { - let data = idx === node.childIndex ? assign({}, n.data, {quantity: value}) : n.data; - newData.push(data); - }); - this.props.valueChanged(newData); - }; -} - -export default ColorMapGrid; diff --git a/web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx b/web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx deleted file mode 100644 index bc175b5877..0000000000 --- a/web/client/components/style/ColorMapGridComponents/ColorPickerRenderer.jsx +++ /dev/null @@ -1,98 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * 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. - */ -import React from 'react'; - -import { SketchPicker } from 'react-color'; -import './colorenderer.css'; -import { getWindowSize } from '../../../utils/AgentUtils'; - -class ColorPickerRenderer extends React.Component { - static propTypes = { - params: PropTypes.object, - onChangeColor: PropTypes.func, - disabled: PropTypes.bool - }; - - static defaultProps = { - disabled: false, - onChangeColor: () => {} - }; - - state = { - displayColorPicker: false - }; - - onChangeColor = () => { - if ( this.state.color) { - let opacity = this.state.color.rgb.a !== 1 ? this.state.color.rgb.a : undefined; - let color = this.state.color.hex.indexOf("#") === 0 ? this.state.color.hex : "#" + this.state.color.hex; - this.props.onChangeColor( this.props.params.node, {color: color, opacity: opacity}); - } - }; - - getBackgroundColor = (data) => { - let color = 'blue'; - if ( data && data.color) { - let rgb = this.hexToRgb(data.color); - let opacity = data.opacity !== undefined ? data.opacity : 1; - color = rgb ? `rgba(${ rgb.r }, ${ rgb.g }, ${ rgb.b }, ${ opacity })` : 'blue'; - } - return color; - }; - - render() { - let data = this.props.params.data; - let colorValue = data && data.color ? this.hexToRgb(data.color) : {r: 0, g: 0, b: 255}; - colorValue.a = data.opacity !== undefined ? data.opacity : 1; - let bkgColor = this.getBackgroundColor(data); - return ( -
-
{ - if (!this.props.disabled) { - this.setState({ - displayColorPicker: !this.state.displayColorPicker, - y: e.pageY - }); - } - }} - /> - { this.state.displayColorPicker ? -
-
{ - this.setState({ displayColorPicker: false}); - this.onChangeColor(); - }}/> - { this.setState({ color: color }); }} /> -
- : null } -
- ); - } - - calculateTop = (y) => { - let h = getWindowSize().maxHeight; - return (y + 300 > h ? h - 305 : y ) - 300; - }; - - hexToRgb = (hex) => { - const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); - return result ? { - r: parseInt(result[1], 16), - g: parseInt(result[2], 16), - b: parseInt(result[3], 16) - } : null; - }; -} - -export default ColorPickerRenderer; diff --git a/web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx b/web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx deleted file mode 100644 index 6573d3e796..0000000000 --- a/web/client/components/style/ColorMapGridComponents/NumberRenderer.jsx +++ /dev/null @@ -1,113 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * 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. - */ - -import React from 'react'; - -import { findDOMNode } from 'react-dom'; -import { Popover, Label, Overlay } from 'react-bootstrap'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import { NumberPicker } from 'react-widgets'; -import './numberpicker.css'; - -class NumberRenderer extends React.Component { - static propTypes = { - params: PropTypes.object, - onChangeValue: PropTypes.func, - errorMessage: PropTypes.string - }; - - static defaultProps = { - onChangeValue: () => {}, - errorMessage: "Value not valid" - }; - - state = { - displayNumberPicker: false, - showError: false - }; - - componentDidMount() { - this.props.params.api.addEventListener('cellClicked', this.cellClicked); - } - - componentWillUnmount() { - this.props.params.api.removeEventListener('cellClicked', this.cellClicked); - } - - getRange = () => { - let data = []; - this.props.params.api.forEachNode((node) => {data.push(node.data); }); - let idx = this.props.params.node.childIndex; - let min = data[idx - 1] ? data[idx - 1].quantity + 0.01 : -Infinity; - let max = data[idx + 1] ? data[idx + 1].quantity - 0.01 : Infinity; - return {min: min, max: max}; - }; - - render() { - - return ( -
{ - if (!this.state.displayNumberPicker) { - this.setState({displayNumberPicker: !this.state.displayNumberPicker}); - } - } } - > - { this.state.displayNumberPicker ? -
-
-
{e.stopPropagation(); }}> - - findDOMNode(this.refs.colorMapNumberPicker)} - show={this.state.showError} placement="top" > - - - - -
-
: - {this.props.params.value.toFixed ? this.props.params.value.toFixed(2) : this.props.params.value} } -
- ); - } - - cellClicked = (e) => { - if (this.props.params.value !== e.value && this.state.displayNumberPicker) { - this.stopEditing(); - } - }; - - stopEditing = () => { - let range = this.getRange(); - let newValue = this.state.value === undefined ? this.props.params.value : this.state.value; - if (range.min < newValue && newValue < range.max) { - this.setState({ displayNumberPicker: false, showError: false}); - if (newValue !== this.props.params.value) { - this.props.onChangeValue(this.props.params.node, newValue); - } - } else { - this.setState({showError: true}); - } - - }; - - changeNumber = (value) => { - this.setState({value: value, showError: false}); - }; -} - -export default NumberRenderer; diff --git a/web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx b/web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx deleted file mode 100644 index c6ab15917f..0000000000 --- a/web/client/components/style/ColorMapGridComponents/ReactCellRendererFactoryParams.jsx +++ /dev/null @@ -1,25 +0,0 @@ -/** - * 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. - */ -import React from 'react'; - -import ReactDOM from 'react-dom'; -function reactCellRendererFactoryParams(ReactComponent, compParams) { - return function(params) { - if (params.eParentOfValue.addElementAttachedListener) { - params.eParentOfValue.addElementAttachedListener(function(eCell) { - ReactDOM.render(, eCell); - params.api.addVirtualRowListener('virtualRowRemoved', params.rowIndex, function() { - ReactDOM.unmountComponentAtNode(eCell); - }); - }); - } - // return null to the grid, as we don't want it responsible for rendering - return null; - }; -} -export default reactCellRendererFactoryParams; diff --git a/web/client/components/style/ColorMapGridComponents/colorenderer.css b/web/client/components/style/ColorMapGridComponents/colorenderer.css deleted file mode 100644 index 702fc25e97..0000000000 --- a/web/client/components/style/ColorMapGridComponents/colorenderer.css +++ /dev/null @@ -1,28 +0,0 @@ -.cpr-color - { - box-sizing: border-box; - width: 100%; - min-height: 28px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - padding: 2px; - -} -.cpe-popover -{ - white-space: normal; - position: fixed; - z-index: 1000; -} -.cpe-cover -{ - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; -} -.cpe-popover > div > div { - position: relative; -} diff --git a/web/client/components/style/ColorMapGridComponents/numberpicker.css b/web/client/components/style/ColorMapGridComponents/numberpicker.css deleted file mode 100644 index 85f3585a0a..0000000000 --- a/web/client/components/style/ColorMapGridComponents/numberpicker.css +++ /dev/null @@ -1,7 +0,0 @@ -.numberpicker { - font-size: small; - -ms-transform: scaleY(0.9) translateY(-2px); /* IE 9 */ - -webkit-transform: scaleY(0.9) translateY(-2px); /* Chrome, Safari, Opera */ - transform: scaleY(0.9) translateY(-2px); - -} \ No newline at end of file diff --git a/web/client/components/style/ColorRampSelector.jsx b/web/client/components/style/ColorRampSelector.jsx deleted file mode 100644 index 10314f00a5..0000000000 --- a/web/client/components/style/ColorRampSelector.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import colorsSchema from './EqualIntervalComponents/ColorRamp'; -import ColorRampItem from './EqualIntervalComponents/ColorRampItem'; -import colors from './EqualIntervalComponents/ExtendColorBrewer'; -import { Combobox } from 'react-widgets'; - -class ColorRampSelector extends React.Component { - - static propTypes = { - colorsSchema: PropTypes.array, - colors: PropTypes.object, - classes: PropTypes.number, - ramp: PropTypes.string - }; - - static defaultProps = { - colorsSchema, - colors, - classes: 5, - ramp: 'Blues' - }; - - UNSAFE_componentWillMount() { - this.setState({ - ramp: this.props.ramp - }); - } - - getColorsSchema = () => { - return this.props.classes ? - this.props.colorsSchema.filter((c) => { - return c.max >= this.props.classes; - }, this) : this.props.colorsSchema; - }; - - getRampValue = () => { - let ramp = this.state.ramp; - if (!this.props.colors[this.state.ramp][this.props.classes]) { - ramp = this.props.colorsSchema.filter((color) => { return color.max >= this.props.classes; }, this)[0].name; - } - return ramp; - }; - - getRamp = () => { - return this.props.colors[this.state.ramp] ? ( - this.props.colors[this.state.ramp][5].map(c => { - return
; - }) - ) : null; - } - - render() { - return (
-
- {this.getRamp()} -
- { - this.setState({ - ramp: ramp.name - }); - }}/> -
); - } -} - -export default ColorRampSelector; diff --git a/web/client/components/style/ColorRangeSelector.jsx b/web/client/components/style/ColorRangeSelector.jsx deleted file mode 100644 index cab4a35ba4..0000000000 --- a/web/client/components/style/ColorRangeSelector.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { sameToneRangeColors } from '../../utils/ColorUtils'; -import ColorRampItem from './EqualIntervalComponents/ColorRampItem'; -import { DropdownList } from 'react-widgets'; -import { head } from 'lodash'; - -class ColorRangeSelector extends React.Component { - - static propTypes = { - value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - samples: PropTypes.number, - onChange: PropTypes.func, - items: PropTypes.array, - rampFunction: PropTypes.func, - disabled: PropTypes.bool - }; - static contextTypes = { - messages: PropTypes.object - }; - static defaultProps = { - samples: 5, - onChange: () => {}, - items: [{ - name: 'global.colors.blue', - schema: 'sequencial', - options: {base: 190, range: 20} - }, { - name: 'global.colors.red', - schema: 'sequencial', - options: {base: 10, range: 4} - }, { - name: 'global.colors.green', - schema: 'sequencial', - options: {base: 120, range: 4} - }, { - name: 'global.colors.brown', - schema: 'sequencial', - options: {base: 30, range: 4, s: 1, v: 0.5} - }, { - name: 'global.colors.purple', - schema: 'sequencial', - options: {base: 300, range: 4} - }, { - name: 'global.colors.random', - schema: 'qualitative', - options: {base: 190, range: 340, options: {base: 10, range: 360, s: 0.67, v: 0.67}} - }], - disabled: false - }; - getValue = () => { - return head(this.getItems().filter( (i = {}) => i === this.props.value || i.name === (this.props.value && this.props.value.name))); - } - getItems = () => { - return this.props.items.map(({options = {}, ...item}) => ({ - ...item, - options, - ramp: this.props.rampFunction ? this.props.rampFunction(item, options) : (sameToneRangeColors(options.base, options.range, this.props.samples + 1, options.options) || ["#AAA"]).splice(1) - })); - } - - render() { - const items = this.getItems(); - return ( - } - itemComponent={ColorRampItem} - value={this.getValue()} - onChange={(ramp) => { - this.props.onChange(ramp); - }}/> - ); - } -} - -export default ColorRangeSelector; diff --git a/web/client/components/style/EqualInterval.jsx b/web/client/components/style/EqualInterval.jsx deleted file mode 100644 index cda76103f3..0000000000 --- a/web/client/components/style/EqualInterval.jsx +++ /dev/null @@ -1,204 +0,0 @@ - -/** - * 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. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import { Col, Grid, Label, Overlay, Popover, Row } from 'react-bootstrap'; -import { findDOMNode } from 'react-dom'; -import { Combobox, NumberPicker } from 'react-widgets'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -import Message from '../I18N/Message'; -import colorsSchema from './EqualIntervalComponents/ColorRamp'; -import ColorRampItem from './EqualIntervalComponents/ColorRampItem'; -import colors from './EqualIntervalComponents/ExtendColorBrewer'; -import Button from '../misc/Button'; - -numberLocalizer(); - - -class EqualInterval extends React.Component { - static propTypes = { - min: PropTypes.number, - max: PropTypes.number, - classes: PropTypes.number, - onChange: PropTypes.func, - onClassify: PropTypes.func, - ramp: PropTypes.string, - error: PropTypes.object - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - min: 0, - max: 100, - classes: 5, - ramp: "Blues", - onChange: () => {}, - onClassify: () => {}, - error: null - }; - - shouldComponentUpdate() { - return true; - } - - getColorsSchema = () => { - return this.props.classes ? - colorsSchema.filter((c) => { - return c.max >= this.props.classes; - }, this) : colorsSchema; - }; - - getRampValue = () => { - let ramp = this.props.ramp; - if (!colors[this.props.ramp][this.props.classes]) { - ramp = colorsSchema.filter((color) => { return color.max >= this.props.classes; }, this)[0].name; - } - return ramp; - }; - - renderErrorPopOver = () => { - return ( - findDOMNode(this.refs[this.props.error.type])} - show placement="top" > - - - - - ); - }; - - render() { - return ( - - - - - - - - - {this.props.error && this.props.error.type === 'min' ? this.renderErrorPopOver() : null} - - - - - - - - - {this.props.error && this.props.error.type === 'max' ? this.renderErrorPopOver() : null} - - - - - - - - - - - this.props.onChange("classes", number)} - precision={0} min={3} max={12} step={1} - value={this.props.classes} - /> - - - - - - - - - - - this.props.onChange("ramp", value.name)} - textField="name" - itemComponent={ColorRampItem} value={this.getRampValue()}/> - - - - - - - - - - ); - } - - classifyDisabled = () => { - return this.props.error && this.props.error.type ? true : false; - }; - - generateEqualIntervalRamp = () => { - let ramp = colors[this.getRampValue()][this.props.classes]; - let min = this.props.min; - let max = this.props.max; - let step = (max - min) / this.props.classes; - let colorRamp = ramp.map((color, idx) => { - return {color: color, quantity: min + idx * step}; - }); - this.props.onClassify("colorRamp", colorRamp); - }; - - changeMin = (value) => { - if (value < this.props.max) { - if (this.props.error) { - this.props.onChange("error", {}); - } - this.props.onChange("min", value); - } else { - this.props.onChange("error", { - type: "min", - msg: "equalinterval.minerror" - }); - } - - }; - - changeMax = (value) => { - if (value > this.props.min) { - if (this.props.error) { - this.props.onChange("error", {}); - } - this.props.onChange("max", value); - } else { - this.props.onChange("error", { - type: "max", - msg: "equalinterval.maxerror" - }); - } - }; -} - -export default EqualInterval; diff --git a/web/client/components/style/EqualIntervalComponents/ColorRamp.js b/web/client/components/style/EqualIntervalComponents/ColorRamp.js deleted file mode 100644 index 5d04aa786a..0000000000 --- a/web/client/components/style/EqualIntervalComponents/ColorRamp.js +++ /dev/null @@ -1,17 +0,0 @@ -const colorsSchema = [ - {name: "BuGn", schema: "Sequential", max: 9}, {name: "BuPu", schema: "Sequential", max: 9}, {name: "GnBu", schema: "Sequential", max: 9}, - {name: "OrRd", schema: "Sequential", max: 9}, {name: "PuBu", schema: "Sequential", max: 9}, {name: "PuBuGn", schema: "Sequential", max: 9}, - {name: "PuRd", schema: "Sequential", max: 9}, {name: "RdPu", schema: "Sequential", max: 9}, {name: "YlGn", schema: "Sequential", max: 9}, - {name: "YlGnBu", schema: "Sequential", max: 9}, {name: "YlOrBr", schema: "Sequential", max: 9}, {name: "YlOrRd", schema: "Sequential", max: 9}, - {name: "Blues", schema: "Singlehue", max: 9}, {name: "Greens", schema: "Singlehue", max: 9}, {name: "Greys", schema: "Singlehue", max: 9}, - {name: "Oranges", schema: "Singlehue", max: 9}, {name: "Purples", schema: "Singlehue", max: 9}, {name: "Reds", schema: "Singlehue", max: 9}, - {name: "BrBG", schema: "Diverging", max: 11}, {name: "PiYG", schema: "Diverging", max: 11}, {name: "PRGn", schema: "Diverging", max: 11}, - {name: "PuOr", schema: "Diverging", max: 11}, {name: "RdBu", schema: "Diverging", max: 11}, {name: "RdGy", schema: "Diverging", max: 11}, - {name: "RdYlBu", schema: "Diverging", max: 11}, {name: "RdYlGn", schema: "Diverging", max: 11}, {name: "Spectral", schema: "Diverging", max: 11}, - {name: "Accent", schema: "Qualitative", max: 8}, {name: "Dark2", schema: "Qualitative", max: 8}, {name: "Paired", schema: "Qualitative", max: 12}, - {name: "Pastel1", schema: "Qualitative", max: 9}, {name: "Pastel2", schema: "Qualitative", max: 8}, {name: "Set1", schema: "Qualitative", max: 9}, - {name: "Set2", schema: "Qualitative", max: 8}, {name: "Set3", schema: "Qualitative", max: 12}, {name: "Earth", schema: "Dem", max: 12}, - {name: "Land", schema: "Dem", max: 12}, {name: "Water", schema: "Dem", max: 12}, {name: "CDA", schema: "Dem", max: 12}, - {name: "Simple", schema: "Dem", max: 7}]; - -export default colorsSchema; diff --git a/web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx b/web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx deleted file mode 100644 index e7b78d4f7f..0000000000 --- a/web/client/components/style/EqualIntervalComponents/ColorRampItem.jsx +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright 2019, 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. - */ - -import React from 'react'; - -import PropTypes from 'prop-types'; -import colors from './ExtendColorBrewer'; -import Message from '../../I18N/Message'; - -/** - * @name ColorRampItem - * @description Simple component to display color label - */ -const ColorRampItem = ({ item }) => { - let ramp = item && (item.ramp || colors[item.name] && colors[item.name][5]) || []; - return ( -
- {ramp.map(cell =>
)} -
- {item && ( item.label || item.name ) - ? - : item} -
-
- ); -}; - -ColorRampItem.propTypes = { - item: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) -}; - -export default ColorRampItem; diff --git a/web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js b/web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js deleted file mode 100644 index b539a09ebe..0000000000 --- a/web/client/components/style/EqualIntervalComponents/ExtendColorBrewer.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright 2017, 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 extendColorBrewer = { - Earth: { - 3: ["#3e2f8d", "#d3e1b2", "#f1e8dd"], - 4: ["#3e2f8d", "#a4cef4", "#676c52", "#f1e8dd"], - 5: ["#3e2f8d", "#87b2f1", "#d3e1b2", "#615742", "#f1e8dd"], - 6: ["#3e2f8d", "#739cd3", "#cbe1da", "#8e9f79", "#7e6d4f", "#f1e8dd"], - 7: ["#3e2f8d", "#6a8dc7", "#a4cef4", "#d3e1b2", "#676c52", "#89795d", "#f1e8dd"], - 8: ["#3e2f8d", "#6783c7", "#94c0fb", "#e1e9ca", "#a3b990", "#524d3d", "#908169", "#f1e8dd"], - 9: ["#3e2f8d", "#657bc7", "#87b2f1", "#b9dae8", "#d3e1b2", "#7b8965", "#615742", "#948671", "#f1e8dd"], - 10: ["#3e2f8d", "#6375c7", "#7ca6e0", "#a4cef4", "#eceec1", "#afc79c", "#676c52", "#716349", "#988b78", "#f1e8dd"], - 11: ["#3e2f8d", "#6271c7", "#739cd3", "#99c4f9", "#cbe1da", "#d3e1b2", "#8e9f79", "#585743", "#7e6d4f", "#9b8f7e", "#f1e8dd"], - 12: ["#3e2f8d", "#616dc7", "#6c93c7", "#8fbcfe", "#aed6f1", "#f1f0be", "#bbd5a9", "#788562", "#504a3b", "#847252", "#9b8f7e", "#f1e8dd"] - }, - Land: { - 3: ["#c3e2df", "#2f412c", "#e7e9dd"], - 4: ["#c3e2df", "#5d7a65", "#3f3633", "#e7e9dd"], - 5: ["#c3e2df", "#868f65", "#2f412c", "#5c4e4b", "#e7e9dd"], - 6: ["#c3e2df", "#979f72", "#446553", "#302f26", "#6e5d56", "#e7e9dd"], - 7: ["#c3e2df", "#a5ac7d", "#5d7a65", "#2f412c", "#3f3633", "#7b695a", "#e7e9dd"], - 8: ["#c3e2df", "#b0b788", "#768562", "#3c5a46", "#2d3123", "#4f4342", "#84715c", "#e7e9dd"], - 9: ["#c3e2df", "#b8c091", "#868f65", "#4b6e5f", "#2f412c", "#322d28", "#5c4e4b", "#8c775d", "#e7e9dd"], - 10: ["#c3e2df", "#bfc697", "#8f986c", "#5d7a65", "#37553e", "#2b3221", "#3f3633", "#665651", "#917c5e", "#e7e9dd"], - 11: ["#c3e2df", "#c4cc9d", "#979f72", "#6f8263", "#446553", "#2f412c", "#302f26", "#4a3f3d", "#6e5d56", "#96805f", "#e7e9dd"], - 12: ["#c3e2df", "#c8d0a1", "#9ea576", "#7d8861", "#4e7265", "#35513a", "#2a3320", "#352e2a", "#534745", "#756359", "#9d896a", "#e7e9dd"] - }, - Water: { - 3: ["#1f373d", "#4cc1b2", "#dee2b6"], - 4: ["#1f373d", "#309590", "#85dfce", "#dee2b6"], - 5: ["#1f373d", "#2a8180", "#4cc1b2", "#a1f3dc", "#dee2b6"], - 6: ["#1f373d", "#2f6f79", "#30a8a2", "#76d1c6", "#c1fdf6", "#dee2b6"], - 7: ["#1f373d", "#306573", "#309590", "#4cc1b2", "#85dfce", "#c8f3dc", "#dee2b6"], - 8: ["#1f373d", "#305f6b", "#2a8b86", "#2fb2aa", "#6eccbd", "#8deccd", "#c8e6bb", "#dee2b6"], - 9: ["#1f373d", "#2f5b66", "#2a8180", "#32a09a", "#4cc1b2", "#7dd5ce", "#a1f3dc", "#c8dda3", "#dee2b6"], - 10: ["#1f373d", "#2f5862", "#2d777c", "#309590", "#2eb8af", "#69cab8", "#85dfce", "#b3f8eb", "#c8d690", "#dee2b6"], - 11: ["#1f373d", "#2f555f", "#2f6f79", "#2c8e89", "#30a8a2", "#4cc1b2", "#76d1c6", "#8ae8cd", "#c1fdf6", "#c8d181", "#dee2b6"], - 12: ["#1f373d", "#2f535c", "#306977", "#298883", "#329c97", "#30bab1", "#66c8b4", "#80d7cf", "#92efd0", "#c8faf0", "#cad285", "#dee2b6"] - }, - CDA: { - 3: ["#18c6ca", "#fed873", "#ffffff"], - 4: ["#18c6ca", "#fffbc3", "#e3ce9b", "#ffffff"], - 5: ["#18c6ca", "#e9feb4", "#fed873", "#d0c6b0", "#ffffff"], - 6: ["#18c6ca", "#cffea9", "#fef5af", "#efd28b", "#c8c2b6", "#ffffff"], - 7: ["#18c6ca", "#bafea1", "#fffbc3", "#fed873", "#e3ce9b", "#ccc8c1", "#ffffff"], - 8: ["#18c6ca", "#affe9d", "#f0feb8", "#fef3a8", "#f3d486", "#d8c9a8", "#d3d0ca", "#ffffff"], - 9: ["#18c6ca", "#affe9d", "#e9feb4", "#fef7b5", "#fed873", "#e7cf96", "#d0c6b0", "#dad8d2", "#ffffff"], - 10: ["#18c6ca", "#a3fe9a", "#d8feac", "#fffbc3", "#feee9b", "#f7d580", "#e3ce9b", "#ccc4b3", "#dad8d2", "#ffffff"], - 11: ["#18c6ca", "#97fe96", "#cffea9", "#f7febb", "#fef5af", "#fed873", "#efd28b", "#dccaa4", "#c8c2b6", "#e1dfdb", "#ffffff"], - 12: ["#18c6ca", "#97fe96", "#c5fea5", "#f0feb8", "#fef9bc", "#feee9b", "#f7d580", "#e7cf96", "#d8c9a8", "#c4c1b9", "#e1dfdb", "#ffffff"] - }, - Simple: { - 3: ["#000000", "#7fff00", "#bf7f3f"], - 4: ["#000000", "#38ff38", "#ffd400", "#bf7f3f"], - 5: ["#000000", "#7fff7f", "#7fff00", "#ff9f00", "#bf7f3f"], - 6: ["#000000", "#aaffaa", "#00ff00", "#ffff00", "#ff7f00", "#bf7f3f"], - 7: ["#000000", "#8dd48d", "#38ff38", "#7fff00", "#ffd400", "#f47f0a", "#bf7f3f"] - } -}; - -import assign from 'object-assign'; - -export default assign({}, require("colorbrewer"), extendColorBrewer); diff --git a/web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx b/web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx deleted file mode 100644 index 2c503c8b91..0000000000 --- a/web/client/components/style/EqualIntervalComponents/__tests__/ColorRampItem-test.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright 2019, 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. - */ - -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; - -import ColorRampItem from '../ColorRampItem'; - -describe("Test the ColorRampItem", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates colorRamp with defaults', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('.color-ramp-item'); - expect(colorRamp).toExist(); - }); - it('ColorRampItem with string item equal to blue', () => { - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('.colorname-cell'); - expect(colorRamp.innerHTML).toEqual('blue'); - }); - it('ColorRampItem with object item contain name', () => { - const color = 'global.colors.blue'; - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('span'); - expect(colorRamp.innerHTML).toEqual(color); - }); - it('ColorRampItem with object item contain label', () => { - const name = 'blue'; - const label = 'global.colors.blue'; - ReactDOM.render(, document.getElementById("container")); - const container = document.getElementById('container'); - const colorRamp = container.querySelector('span'); - expect(colorRamp.innerHTML).toEqual(label); - }); -}); diff --git a/web/client/components/style/MarkerPropertyPicker.jsx b/web/client/components/style/MarkerPropertyPicker.jsx deleted file mode 100644 index 109862ab80..0000000000 --- a/web/client/components/style/MarkerPropertyPicker.jsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020, 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. -*/ - -import React from 'react'; -import PropTypes from 'prop-types'; -import Popover from '../styleeditor/Popover'; -function MarkerPropertyPicker({ - disabled, - containerNode, - onOpen, - placement, - children, - triggerNode -}) { - - const disabledClassName = disabled ? ' ms-disabled' : ''; - - return ( - onOpen(isOpen)} - content={ -
- {children} -
- } - > -
-
- {triggerNode} -
-
-
- ); -} - -MarkerPropertyPicker.propTypes = { - value: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.shape({r: PropTypes.number, g: PropTypes.number, b: PropTypes.number, a: PropTypes.number}) - ]), - format: PropTypes.string, - onChangeColor: PropTypes.func, - text: PropTypes.string, - line: PropTypes.bool, - disabled: PropTypes.bool, - pickerProps: PropTypes.object, - containerNode: PropTypes.node, - onOpen: PropTypes.function, - placement: PropTypes.string -}; - -MarkerPropertyPicker.defaultProps = { - disabled: false, - line: false, - onChangeColor: () => {}, - pickerProps: {}, - onOpen: () => {} -}; - -export default MarkerPropertyPicker; diff --git a/web/client/components/style/OpacityPicker.jsx b/web/client/components/style/OpacityPicker.jsx deleted file mode 100644 index 3b2538a791..0000000000 --- a/web/client/components/style/OpacityPicker.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * 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. - */ - -import React from 'react'; - -import Slider from 'react-nouislider'; -import 'react-nouislider/example/nouislider.css'; -import './opacitypicker.css'; - -class OpacityPicker extends React.Component { - static propTypes = { - opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - onChange: PropTypes.func, - disabled: PropTypes.bool - }; - - static defaultProps = { - opacity: "1", - onChange: () => {}, - disabled: false - }; - - render() { - return ( -
- this.props.onChange("opacity", (v / 100).toFixed(2))} - connect="lower" - tooltips={[ { - to: function( value ) { - return Math.round(value) + '%'; - } - } - ]} - /> -
); - } -} - -export default OpacityPicker; diff --git a/web/client/components/style/PolygonStyler.jsx b/web/client/components/style/PolygonStyler.jsx deleted file mode 100644 index d16aedaaa7..0000000000 --- a/web/client/components/style/PolygonStyler.jsx +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import assign from 'object-assign'; -import { Grid, Row, Col } from 'react-bootstrap'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import Slider from 'react-nouislider'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import Message from '../I18N/Message'; -import { isNil } from 'lodash'; -import tinycolor from 'tinycolor2'; - -class StylePolygon extends React.Component { - static propTypes = { - shapeStyle: PropTypes.object, - width: PropTypes.number, - setStyleParameter: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - shapeStyle: {}, - setStyleParameter: () => {} - }; - - render() { - const styleType = !!this.props.shapeStyle.MultiPolygon ? "MultiPolygon" : "Polygon"; - const otherStyleType = !this.props.shapeStyle.MultiPolygon ? "MultiPolygon" : "Polygon"; - const style = this.props.shapeStyle[styleType] || this.props.shapeStyle; // in case of old version of style. - return ( - - -
- -
- -
- - - - - - { - if (!isNil(c)) { - const fillColor = tinycolor(c).toHexString(); - const fillOpacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {fillColor, fillOpacity}), - [otherStyleType]: assign({}, style, {fillColor, fillOpacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {color, opacity}), - [otherStyleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{min: 1, max: 15}} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {weight}), - [otherStyleType]: assign({}, style, {weight}) - }); - this.props.setStyleParameter(newStyle); - }} - /> -
- -
-
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default StylePolygon; diff --git a/web/client/components/style/PolylineStyler.jsx b/web/client/components/style/PolylineStyler.jsx deleted file mode 100644 index 50e3757ccd..0000000000 --- a/web/client/components/style/PolylineStyler.jsx +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Grid, Row, Col } from 'react-bootstrap'; -import assign from 'object-assign'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import Slider from 'react-nouislider'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import Message from '../I18N/Message'; -import { isNil } from 'lodash'; -import tinycolor from 'tinycolor2'; - -class StylePolyline extends React.Component { - static propTypes = { - width: PropTypes.number, - shapeStyle: PropTypes.object, - setStyleParameter: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - shapeStyle: {}, - setStyleParameter: () => {} - }; - - render() { - const styleType = !!this.props.shapeStyle.MultiLineString ? "MultiLineString" : "LineString"; - const otherStyleType = !this.props.shapeStyle.MultiLineString ? "MultiLineString" : "LineString"; - const style = this.props.shapeStyle[styleType]; - return ( - - -
- -
- -
- - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {color, opacity}), - [otherStyleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - } - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{min: 1, max: 15}} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - const newStyle = assign({}, this.props.shapeStyle, { - [styleType]: assign({}, style, {weight}), - [otherStyleType]: assign({}, style, {weight}) - }); - this.props.setStyleParameter(newStyle); - }} - /> -
- -
-
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default StylePolyline; diff --git a/web/client/components/style/PseudoColorSettings.jsx b/web/client/components/style/PseudoColorSettings.jsx deleted file mode 100644 index 191b79ef70..0000000000 --- a/web/client/components/style/PseudoColorSettings.jsx +++ /dev/null @@ -1,108 +0,0 @@ - -/** - * 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. - */ - -import PropTypes from 'prop-types'; -import React from 'react'; -import { Grid, Row, Col} from 'react-bootstrap'; -import { Combobox } from 'react-widgets'; - -import Button from '../misc/Button'; -import ColorMapGrid from './ColorMapGrid'; -import Message from '../I18N/Message'; - -class PseudoColorSettings extends React.Component { - static propTypes = { - type: PropTypes.oneOf(['ramp', 'intervals', 'values']), - opacity: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - selected: PropTypes.number, - colorMapEntry: PropTypes.array, - onChange: PropTypes.func, - extended: PropTypes.bool - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - type: 'ramp', - opacity: "1", - selected: null, - colorMapEntry: [], - onChange: () => {}, - extended: false - }; - - render() { - return ( - - - - - - - - this.props.onChange("type", v)} /> - - -    this.props.onChange("extended", e.target.checked)} checked={this.props.extended} /> - - - - - - this.props.onChange("colorMapEntry", colorMap)} - entries={this.props.colorMapEntry}/> - - - - - - - - - - - - - ); - } - - addEntry = () => { - let colorMapEntry = this.props.colorMapEntry ? this.props.colorMapEntry.slice() : []; - let quantity = colorMapEntry.length > 0 ? colorMapEntry[colorMapEntry.length - 1].quantity + 0.01 : 0; - let label = quantity.toFixed ? quantity.toFixed(2) : quantity; - colorMapEntry.push({color: '#AA34FF', quantity: quantity, label: label }); - this.props.onChange("colorMapEntry", colorMapEntry); - }; - - removeEntry = () => { - let colorMapEntry = this.props.colorMapEntry.filter((e, idx) => { - return idx !== this.props.selected; - }); - this.props.onChange("selected", null); - this.props.onChange("colorMapEntry", colorMapEntry); - }; - - selectEntry = (id) => { - if ( id !== this.props.selected) { - this.props.onChange("selected", id); - } - }; -} - -export default PseudoColorSettings; diff --git a/web/client/components/style/RasterStyleTypePicker.jsx b/web/client/components/style/RasterStyleTypePicker.jsx deleted file mode 100644 index 2ab2610588..0000000000 --- a/web/client/components/style/RasterStyleTypePicker.jsx +++ /dev/null @@ -1,51 +0,0 @@ -/** - * 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. - */ - -import React from 'react'; - -import { Combobox } from 'react-widgets'; -import PropTypes from 'prop-types'; -import { getMessageById } from '../../utils/LocaleUtils'; - -class RasterStyleTypePicker extends React.Component { - static propTypes = { - styletype: PropTypes.oneOf(['rgb', 'gray', 'pseudo']), - onChange: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object - }; - - render() { - return ( - this.props.onChange("styletype", v.value)} - value={this.props.styletype} /> - ); - } -} - -export default RasterStyleTypePicker; diff --git a/web/client/components/style/ScaleDenominator.jsx b/web/client/components/style/ScaleDenominator.jsx deleted file mode 100644 index 3f59de5317..0000000000 --- a/web/client/components/style/ScaleDenominator.jsx +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 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. - */ - -import React from 'react'; - -import PropTypes from 'prop-types'; -import { getGoogleMercatorScales } from '../../utils/MapUtils'; -import { findDOMNode } from 'react-dom'; -import { DropdownList } from 'react-widgets'; -import { Row, Col, Overlay, Popover, Label } from 'react-bootstrap'; -import { getMessageById } from '../../utils/LocaleUtils'; -import Message from '../I18N/Message'; - -class ScaleDenominator extends React.Component { - static propTypes = { - minValue: PropTypes.number, - maxValue: PropTypes.number, - onChange: PropTypes.func.isRequired - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - minValue: null, - maxValue: null, - onChange: () => null - }; - - state = {error: false}; - - UNSAFE_componentWillMount() { - let scales = getGoogleMercatorScales(0, 21); - this.scales = [{value: null, text: getMessageById(this.context.messages, "scaledenominator.none") || 'None'}, ...scales.map((v) => ({value: v, text: `${v.toFixed(0)}`}))]; - } - - onChange = (t, {value: v}) => { - if (t === 'minDenominator' && this.props.maxValue && v >= this.props.maxValue) { - this.setState({error: {type: t, msg: "scaledenominator.minerror"}}); - } else if (t === 'maxDenominator' && this.props.minValue && v <= this.props.minValue) { - this.setState({error: {type: t, msg: "scaledenominator.maxerror"}}); - } else { - if (this.state.error) { - this.setState({error: false}); - } - this.props.onChange(t, v); - } - }; - - renderErrorPopOver = () => { - return ( - findDOMNode(this.refs[this.state.error.type])} - show placement="top" > - - - - - ); - }; - - render() { - return ( - - - this.onChange("minDenominator", v)} - /> - - - - this.onChange("maxDenominator", v)} - /> - - {(this.state.error) ? this.renderErrorPopOver() : null} - ) - ; - } -} - -export default ScaleDenominator; diff --git a/web/client/components/style/TextStyler.jsx b/web/client/components/style/TextStyler.jsx deleted file mode 100644 index 67bc560ec6..0000000000 --- a/web/client/components/style/TextStyler.jsx +++ /dev/null @@ -1,244 +0,0 @@ -/* - * 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. -*/ - -import React from 'react'; - -import PropTypes from 'prop-types'; -import { Grid, Row, Col } from 'react-bootstrap'; -import { Combobox } from 'react-widgets'; -import assign from 'object-assign'; -import ColorSelector from './ColorSelector'; -import StyleCanvas from './StyleCanvas'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -numberLocalizer(); -import { getMessageById } from '../../utils/LocaleUtils'; -import { createFont } from '../../utils/LegacyAnnotationsUtils'; -import Message from '../I18N/Message'; -import tinycolor from 'tinycolor2'; -import IntlNumberFormControl from '../I18N/IntlNumberFormControl'; - -class TextStyler extends React.Component { - static propTypes = { - width: PropTypes.number, - uomValues: PropTypes.array, - alignValues: PropTypes.array, - fontStyleValues: PropTypes.array, - fontWeightValues: PropTypes.array, - fontFamilyValues: PropTypes.array, - shapeStyle: PropTypes.object, - setStyleParameter: PropTypes.func, - styleType: PropTypes.String - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - styleType: "Text", - uomValues: [{value: "px"}, {value: "em"}], - fontWeightValues: [{value: "normal"}, {value: "bold"}], - alignValues: [{value: "start", label: "left"}, {value: "center", label: "center"}, {value: "end", label: "right"}], - fontStyleValues: [{value: "normal"}, {value: "italic"}], - fontFamilyValues: [{value: "Arial"}, {value: "Helvetica"}, {value: "sans-serif"}, {value: "Courier"}], - shapeStyle: {}, - setStyleParameter: () => {} - }; - - state = { - fontFamily: "Arial" - }; - - render() { - const messages = { - emptyList: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyList"), - open: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.open"), - emptyFilter: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyFilter") - }; - const {styleType, shapeStyle} = this.props; - const style = shapeStyle[styleType]; - return ( - - -
- {} -
- -
- - - - - - { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {color, opacity}) - }); - this.props.setStyleParameter(newStyle); - }}/> - - - - - - - - { - let fontFamily = e.value ? e.value : e; - if (fontFamily === "") { - fontFamily = "Arial"; - } - this.setState({fontFamily}); - const font = createFont({...style, fontFamily}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontFamily, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - const fontSize = val; - const font = createFont({...style, fontSize}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontSize, font}) - }); - this.props.setStyleParameter(newStyle); - }} - type="number"/> - - - { - let fontSizeUom = e.value ? e.value : e; - if (this.props.uomValues.map(f => f.value).indexOf(fontSizeUom) === -1) { - fontSizeUom = "px"; - } - const font = createFont({...style, fontSizeUom}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontSizeUom, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - let textAlign = e.value ? e.value : e; - if (this.props.alignValues.map(f => f.value).indexOf(textAlign) === -1) { - textAlign = "center"; - } - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {textAlign}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - let fontStyle = e.value ? e.value : e; - if (this.props.fontStyleValues.map(f => f.value).indexOf(fontStyle) === -1) { - fontStyle = style.fontStyle; - } - const font = createFont({...style, fontStyle}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontStyle, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - - - - - - - { - let fontWeight = e.value ? e.value : e; - if (this.props.fontWeightValues.map(f => f.value).indexOf(fontWeight) === -1) { - fontWeight = style.fontWeight; - } - const font = createFont({...style, fontWeight}); - const newStyle = assign({}, shapeStyle, { - [styleType]: assign({}, style, {fontWeight, font}) - }); - this.props.setStyleParameter(newStyle); - }} - /> - - -
); - } - addOpacityToColor = (color, opacity) => { - return assign({}, color, { - a: opacity - }); - } -} - -export default TextStyler; diff --git a/web/client/components/style/__tests__/BandSelector-test.jsx b/web/client/components/style/__tests__/BandSelector-test.jsx deleted file mode 100644 index f582a69472..0000000000 --- a/web/client/components/style/__tests__/BandSelector-test.jsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import BandSelector from '../BandSelector'; - -describe("Test the BandSelector component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.props.onChange(); - }); - - it('creates component contrast', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('creates component algorithm', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - -}); diff --git a/web/client/components/style/__tests__/ColorMapGrid-test.jsx b/web/client/components/style/__tests__/ColorMapGrid-test.jsx deleted file mode 100644 index b7c0adb0a2..0000000000 --- a/web/client/components/style/__tests__/ColorMapGrid-test.jsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import ColorMap from '../ColorMapGrid'; - -describe("Test the ColorMap component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - - it('creates component with element', (done) => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.selectEntry({node: {childIndex: 0}}); - setTimeout(() => { - cmp.valueChanged(); - done(); - }, 0); - }); - -}); diff --git a/web/client/components/style/__tests__/EqualInterval-test.jsx b/web/client/components/style/__tests__/EqualInterval-test.jsx deleted file mode 100644 index 3f92bb353e..0000000000 --- a/web/client/components/style/__tests__/EqualInterval-test.jsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import EqualInterval from '../EqualInterval'; - -describe("Test the EqualInterval component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.generateEqualIntervalRamp(); - cmp.props.onChange(); - }); - -}); diff --git a/web/client/components/style/__tests__/OpacityPicker-test.jsx b/web/client/components/style/__tests__/OpacityPicker-test.jsx deleted file mode 100644 index 293865afb3..0000000000 --- a/web/client/components/style/__tests__/OpacityPicker-test.jsx +++ /dev/null @@ -1,31 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import OpacityPicker from '../OpacityPicker'; - -describe("Test the OpacityPicker component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - -}); diff --git a/web/client/components/style/__tests__/PseudoColorSettings-test.jsx b/web/client/components/style/__tests__/PseudoColorSettings-test.jsx deleted file mode 100644 index 43a7d60bb6..0000000000 --- a/web/client/components/style/__tests__/PseudoColorSettings-test.jsx +++ /dev/null @@ -1,43 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import PseudoColorSettings from '../PseudoColorSettings'; - -describe("Test the PseudoColorSettings component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - - it('creates component add entry', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.addEntry(); - }); - it('creates component remove entry', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - cmp.removeEntry(); - cmp.selectEntry(2); - }); - -}); diff --git a/web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx b/web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx deleted file mode 100644 index dfaa5f2692..0000000000 --- a/web/client/components/style/__tests__/RasterStyleTypePicker-test.jsx +++ /dev/null @@ -1,31 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import RasterStyleTypePicker from '../RasterStyleTypePicker'; - -describe("Test the RasterStyleTypePicker component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('creates component with defaults', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - -}); diff --git a/web/client/components/style/__tests__/ScaleDenominator-test.jsx b/web/client/components/style/__tests__/ScaleDenominator-test.jsx deleted file mode 100644 index 3bcc501149..0000000000 --- a/web/client/components/style/__tests__/ScaleDenominator-test.jsx +++ /dev/null @@ -1,37 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import React from 'react'; -import ReactDOM from 'react-dom'; -import ScaleDenominator from '../ScaleDenominator'; - -describe('ScaleDenominator', () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - it('create component with defaults', () => { - const sb = ReactDOM.render(, document.getElementById("container")); - expect(sb).toExist(); - const domNode = ReactDOM.findDOMNode(sb); - expect(domNode).toExist(); - - const comboItems = sb.scales; - expect(comboItems.length).toBe(23); - sb.onChange("minDenominator", {value: 1000}); - sb.onChange("minDenominator", {value: 100000}); - sb.onChange("maxDenominator", {value: 100}); - }); -}); diff --git a/web/client/components/style/opacitypicker.css b/web/client/components/style/opacitypicker.css deleted file mode 100644 index eeda0d82a0..0000000000 --- a/web/client/components/style/opacitypicker.css +++ /dev/null @@ -1,22 +0,0 @@ -.opacity-picker .noUi-tooltip { - display: block; - position: absolute; - border: 1px solid #D9D9D9; - border-radius: 3px; - background: #fff; - padding: 5px; - left: -1px; - text-align: center; - width: 34px; - font-style: normal; - font-variant: normal; - font-weight: 700; - font-stretch: normal; - font-size: 10px; - line-height: 12px; - font-family: Arial; - } - -.opacity-picker .noUi-handle-lower .noUi-tooltip { - top: 28px; -} diff --git a/web/client/components/style/thumbGeoms/CircleThumb.jsx b/web/client/components/style/thumbGeoms/CircleThumb.jsx deleted file mode 100644 index 43f3e55c85..0000000000 --- a/web/client/components/style/thumbGeoms/CircleThumb.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. -*/ - -import React from 'react'; - -import PropTypes from 'prop-types'; - -class CircleThumb extends React.Component { - - static propTypes = { - linecap: PropTypes.string, - linejoin: PropTypes.string, - stroke: PropTypes.string, - fillColor: PropTypes.string, - strokeWidth: PropTypes.number, - styleRect: PropTypes.object - }; - - static defaultProps = { - styleRect: {}, - linecap: 'round', // butt round square - linejoin: 'round', // miter round bevel - strokeWidth: 3, - stroke: '#ffcc33', - fillColor: '#FFFFFF' - }; - - render() { - const {color, weight, fillColor} = this.props.styleRect; - return ( -
- - - - - /* - */ -
- ); - } -} - -export default CircleThumb; diff --git a/web/client/components/style/thumbGeoms/LineThumb.jsx b/web/client/components/style/thumbGeoms/LineThumb.jsx deleted file mode 100644 index 57a004c907..0000000000 --- a/web/client/components/style/thumbGeoms/LineThumb.jsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. -*/ - -import React from 'react'; - -import PropTypes from 'prop-types'; - -class LineThumb extends React.Component { - - static propTypes = { - linecap: PropTypes.string, - linejoin: PropTypes.string, - stroke: PropTypes.string, - fillColor: PropTypes.string, - strokeWidth: PropTypes.number, - style: PropTypes.object - }; - - static defaultProps = { - style: {}, - linecap: 'round', // butt round square - linejoin: 'round', // miter round bevel - strokeWidth: 3, - stroke: '#ffcc33', - fillColor: '#FFFFFF' - }; - - render() { - const {color, weight, fillColor} = this.props.style; - return ( -
- - - -
- ); - } -} - -export default LineThumb; diff --git a/web/client/components/style/thumbGeoms/MultiGeomThumb.jsx b/web/client/components/style/thumbGeoms/MultiGeomThumb.jsx deleted file mode 100644 index 08ca532679..0000000000 --- a/web/client/components/style/thumbGeoms/MultiGeomThumb.jsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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. -*/ - -import React from 'react'; - -import PropTypes from 'prop-types'; -import markerIcon from '../../map/openlayers/img/marker-icon.png'; - -class MultiGeomThumb extends React.Component { - - static propTypes = { - linecap: PropTypes.string, - linejoin: PropTypes.string, - stroke: PropTypes.string, - strokeWidth: PropTypes.number, - styleMultiGeom: PropTypes.object, - geometry: PropTypes.object, - properties: PropTypes.object - }; - - static defaultProps = { - linecap: 'round', // butt round square - linejoin: 'round', // miter round bevel - stroke: '#ffcc33', - strokeWidth: 3, - styleMultiGeom: {}, - geometry: { - features: [] - }, - properties: {} - }; - - getGeoms() { - return this.props.geometry && this.props.geometry.features.reduce((p, c) => { - if (c.properties && c.properties.isCircle) { - return {...p, "Circle": true}; - } - if (c.properties && c.properties.isText) { - return {...p, "Text": true}; - } - return {...p, [c.geometry.type]: true}; - }, {"Circle": false, "Text": false}); - } - render() { - let geoms = this.getGeoms(); - const stroke = {color: "#ffcc33", opacity: 1, weight: 2 }; - const fill = {fillColor: "#FFFFFF", fillOpacity: 0 }; - let textPresent = geoms.Text; - let circlePresent = geoms.Circle; - let polygonPresent = geoms.Polygon || geoms.MultiPolygon; - let lineStringPresent = geoms.LineString || geoms.MultiLineString; - let pointPresent = geoms.Point || geoms.MultiPoint; // this can be a symbol tho.. - - let styleLine = {...stroke}; - let stylePolygon = {...stroke, ...fill}; - let styleCircle = {...stroke, ...fill}; - let styleText = textPresent ? { - fontStyle: 'normal', - fontSize: '14', - fontSizeUom: 'px', - fontFamily: 'Arial', - fontWeight: 'normal', - font: "14px Arial", - textAlign: 'center', - ...stroke, ...fill} : {}; - return ( -
- - {styleLine && lineStringPresent && () - } - {stylePolygon && polygonPresent && () } - {textPresent && T} - {circlePresent && } - - {pointPresent && } -
- ); - } -} - -export default MultiGeomThumb; diff --git a/web/client/components/style/thumbGeoms/PolygonThumb.jsx b/web/client/components/style/thumbGeoms/PolygonThumb.jsx deleted file mode 100644 index 085d10df15..0000000000 --- a/web/client/components/style/thumbGeoms/PolygonThumb.jsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. -*/ - -import React from 'react'; - -import PropTypes from 'prop-types'; - -class PolygonThumb extends React.Component { - - static propTypes = { - stroke: PropTypes.string, - fill: PropTypes.string, - fillOpacity: PropTypes.number, - strokeWidth: PropTypes.number, - opacity: PropTypes.number, - styleRect: PropTypes.object, - viewBox: PropTypes.string, - rectParams: PropTypes.object - }; - - static defaultProps = { - stroke: '#ffcc33', - fill: '#FFFFFF', - fillOpacity: 0.2, - strokeWidth: 3, - opacity: 1, - styleRect: {}, - viewBox: "0 0 100 100", - rectParams: { - height: "50", - width: "50", - x: "25", - y: "25" - } - }; - - render() { - const {color, weight, fillColor, fillOpacity, opacity} = this.props.styleRect; - const {height, width, x, y} = this.props.rectParams; - return ( -
- - - -
- ); - } -} - -export default PolygonThumb; diff --git a/web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js b/web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js deleted file mode 100644 index 77011584ee..0000000000 --- a/web/client/components/style/thumbGeoms/__tests__/LineThumb-test.js +++ /dev/null @@ -1,40 +0,0 @@ -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import {DEFAULT_ANNOTATIONS_STYLES} from '../../../../plugins/Annotations/utils/AnnotationsUtils'; -import LineThumb from '../LineThumb'; - -describe("Test the LineThumb component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('create component with default', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('create component with default style from annotation utils', () => { - const style = DEFAULT_ANNOTATIONS_STYLES.LineString; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const path = TestUtils.findRenderedDOMComponentWithTag(cmp, 'path'); - expect(path).toExist(); - expect(path.attributes.d.value).toBe("M25 75 L50 50 L75 75 L100 75"); - expect(path.attributes["stroke-linecap"].value).toBe("round"); - expect(path.attributes["stroke-linejoin"].value).toBe("round"); - expect(path.attributes["stroke-width"].value).toBe(style.weight.toString()); - expect(path.attributes.stroke.value).toBe(style.color.toString()); - - }); - - -}); diff --git a/web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js b/web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js deleted file mode 100644 index 15dfba7b1a..0000000000 --- a/web/client/components/style/thumbGeoms/__tests__/MultiGeomThumb-test.js +++ /dev/null @@ -1,81 +0,0 @@ -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import {DEFAULT_ANNOTATIONS_STYLES} from '../../../../utils/LegacyAnnotationsUtils'; -import MultiGeomThumb from '../MultiGeomThumb'; - -describe("Test the MultiGeomThumb component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('create component with default', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('create component with only Polygon', () => { - const style = DEFAULT_ANNOTATIONS_STYLES; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const rect = TestUtils.findRenderedDOMComponentWithTag(cmp, 'rect'); - const svg = TestUtils.findRenderedDOMComponentWithTag(cmp, 'svg'); - expect(rect).toExist(); - const path = TestUtils.scryRenderedDOMComponentsWithTag(cmp, 'path'); - expect(path.length).toBe(0); - expect(rect.attributes.width.value).toBe("50"); - expect(rect.attributes.height.value).toBe("50"); - expect(rect.attributes.x.value).toBe("20"); - expect(rect.attributes.y.value).toBe("15"); - expect(svg.attributes.xmlns.value).toBe("http://www.w3.org/2000/svg"); - expect(svg.attributes.viewBox.value).toBe("0 0 100 100"); - - }); - it('create component with only MultiPolygon LineString', () => { - - const stroke = {color: "#ffcc33", opacity: 1, weight: 2 }; - const fill = {fillColor: "#FFFFFF", fillOpacity: 0 }; - const style = {...stroke, ...fill}; - - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const rect = TestUtils.findRenderedDOMComponentWithTag(cmp, 'rect'); - - const svg = TestUtils.findRenderedDOMComponentWithTag(cmp, 'svg'); - expect(rect).toExist(); - expect(rect.attributes.width.value).toBe("50"); - expect(rect.attributes.height.value).toBe("50"); - expect(rect.attributes.x.value).toBe("40"); - expect(rect.attributes.y.value).toBe("15"); - expect(svg.attributes.xmlns.value).toBe("http://www.w3.org/2000/svg"); - expect(svg.attributes.viewBox.value).toBe("0 0 100 100"); - - }); - it('create component with only Circle', () => { - const style = DEFAULT_ANNOTATIONS_STYLES; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const circle = TestUtils.findRenderedDOMComponentWithTag(cmp, 'circle'); - - expect(circle).toExist(); - expect(circle.attributes.cx.value).toBe("50"); - expect(circle.attributes.cy.value).toBe("50"); - expect(circle.attributes.r.value).toBe("25"); - expect(circle.attributes.stroke.value).toBe("#ffcc33"); - expect(circle.attributes.fill.value).toBe("#FFFFFF"); - expect(circle.attributes.opacity.value).toBe("1"); - expect(circle.attributes["stroke-width"].value).toBe("2"); - expect(circle.attributes["fill-opacity"].value).toBe("0"); - - }); - - -}); diff --git a/web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js b/web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js deleted file mode 100644 index 93691d931f..0000000000 --- a/web/client/components/style/thumbGeoms/__tests__/PolygonThumb-test.js +++ /dev/null @@ -1,43 +0,0 @@ -import expect from 'expect'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import TestUtils from 'react-dom/test-utils'; - -import {DEFAULT_ANNOTATIONS_STYLES} from '../../../../plugins/Annotations/utils/AnnotationsUtils'; -import PolygonThumb from '../PolygonThumb'; - -describe("Test the PolygonThumb component", () => { - beforeEach((done) => { - document.body.innerHTML = '
'; - setTimeout(done); - }); - - afterEach((done) => { - ReactDOM.unmountComponentAtNode(document.getElementById("container")); - document.body.innerHTML = ''; - setTimeout(done); - }); - - it('create component with default', () => { - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - }); - it('create component with default style from annotation utils', () => { - const style = DEFAULT_ANNOTATIONS_STYLES; - const featureType = "MultiPolygon"; - const cmp = ReactDOM.render(, document.getElementById("container")); - expect(cmp).toExist(); - const rect = TestUtils.findRenderedDOMComponentWithTag(cmp, 'rect'); - const svg = TestUtils.findRenderedDOMComponentWithTag(cmp, 'svg'); - expect(rect).toExist(); - expect(rect.attributes.width.value).toBe("50"); - expect(rect.attributes.height.value).toBe("50"); - expect(rect.attributes.x.value).toBe("25"); - expect(rect.attributes.y.value).toBe("25"); - expect(svg.attributes.xmlns.value).toBe("http://www.w3.org/2000/svg"); - expect(svg.attributes.viewBox.value).toBe("0 0 100 100"); - - }); - - -}); diff --git a/web/client/components/style/vector/Fill.jsx b/web/client/components/style/vector/Fill.jsx deleted file mode 100644 index 917114d6d4..0000000000 --- a/web/client/components/style/vector/Fill.jsx +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Row, Col } from 'react-bootstrap'; -import { isNil } from 'lodash'; -import tinycolor from 'tinycolor2'; - -// number localizer? -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -// not sure this is needed, TODO check! -numberLocalizer(); - -import Message from '../../I18N/Message'; -import OpacitySlider from '../../../plugins/TOC/components/OpacitySlider'; -import ColorSelector from '../ColorSelector'; -import { addOpacityToColor } from '../../../utils/VectorStyleUtils'; - -/** - * Styler for the stroke properties of a vector style -*/ -class Fill extends React.Component { - static propTypes = { - style: PropTypes.object, - defaultColor: PropTypes.string, - onChange: PropTypes.func, - width: PropTypes.number - }; - - static defaultProps = { - style: {}, - onChange: () => {} - }; - - render() { - const {style} = this.props; - return (
- - - - - - - - - - - { - if (!isNil(c)) { - const fillColor = tinycolor(c).toHexString(); - const fillOpacity = c.a; - this.props.onChange(style.id, {fillColor, fillOpacity}); - } - }}/> - - - - - - - - { - this.props.onChange(style.id, {fillOpacity}); - }}/> - - -
); - } -} - -export default Fill; diff --git a/web/client/components/style/vector/Manager.jsx b/web/client/components/style/vector/Manager.jsx deleted file mode 100644 index 1e072d1224..0000000000 --- a/web/client/components/style/vector/Manager.jsx +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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. -*/ - -import axios from 'axios'; -import { castArray, filter, find, findIndex, isNil } from 'lodash'; -import assign from 'object-assign'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Grid } from 'react-bootstrap'; -import tinycolor from 'tinycolor2'; -import uuidv1 from 'uuid/v1'; - -import { DEFAULT_PATH, DEFAULT_SHAPE, checkSymbolsError } from '../../../utils/LegacyAnnotationsUtils'; -import { arrayUpdate } from '../../../utils/ImmutableUtils'; -import { - addOpacityToColor, - createSvgUrl, - fetchStyle, - getStylerTitle, - hashAndStringify, - isFillStyle, - isMarkerStyle, - isStrokeStyle, - isSymbolStyle, - isTextStyle, - registerStyle -} from '../../../utils/VectorStyleUtils'; -import SwitchPanel from '../../misc/switch/SwitchPanel'; -import StyleCanvas from '../StyleCanvas'; -import Fill from './Fill'; -import MarkerGlyph from './marker/MarkerGlyph'; -import MarkerType from './marker/MarkerType'; -import SymbolLayout from './marker/SymbolLayout'; -import Stroke from './Stroke'; -import Text from './Text'; - -class Manager extends React.Component { - static propTypes = { - style: PropTypes.object, - switchPanelOptions: PropTypes.array, - lineDashOptions: PropTypes.array, - onChangeStyle: PropTypes.func, - pointType: PropTypes.string, - onUpdateSymbols: PropTypes.func, - onSetErrorSymbol: PropTypes.func, - width: PropTypes.number, - symbolsPath: PropTypes.string, - defaultShape: PropTypes.string, - defaultShapeSize: PropTypes.number, - defaultShapeFillColor: PropTypes.string, - defaultShapeStrokeColor: PropTypes.string, - defaultStyles: PropTypes.object, - symbolList: PropTypes.array, - symbolErrors: PropTypes.array, - defaultSymbol: PropTypes.object, - defaultMarker: PropTypes.object, - markersOptions: PropTypes.object, - textRotationStep: PropTypes.number - }; - - static defaultProps = { - style: {}, - defaultShape: DEFAULT_SHAPE, - symbolsPath: DEFAULT_PATH, - defaultShapeSize: 64, - defaultShapeFillColor: '#000000', - defaultShapeStrokeColor: '#000000', - symbolErrors: [], - onChangeStyle: () => {}, - onUpdateSymbols: () => {}, - defaultStyles: {}, - switchPanelOptions: [] - }; - - state = {} - - - UNSAFE_componentWillMount() { - // we assume that the default symbols shape is correctly configured - - const styles = castArray(this.props.style); - const expanded = styles.map((s, i) => i === 0 || s.filtering ); - const locked = styles.map((s, i) => i === 0 ); - this.setState({expanded, locked}); - styles.filter(({type}) => type === 'Point').forEach(style => { - this.checkSymbolUrl({...this.props, style}); - }); - } - - /** - * it renders a switch panel styler - * @prop {object} style - * @prop {object} switchPanelOptions - */ - renderPanelStyle = (style = {}, switchPanelOptions = {}, i) => { - - const stylerProps = { - style, - onChange: this.change, - width: this.props.width - }; - - /* getting pieces to render in the styler - // only for marker there is no preview - // TODO move into separate functions the checks for showing the various pieces of styler - */ - const isTextOrSymbol = isTextStyle(style) || isSymbolStyle(style); - const preview = !(isMarkerStyle(style) || isSymbolStyle(style) && (checkSymbolsError(this.props.symbolErrors) || - checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape))) && (
- -
); - // TODO improve conditions to show the stroke and fill - const stroke = isStrokeStyle(style) && isSymbolStyle(style) && - (checkSymbolsError(this.props.symbolErrors) || - checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape)) - ? null : isStrokeStyle(style) ? : null; - const fill = isFillStyle(style) && isSymbolStyle(style) && - (checkSymbolsError(this.props.symbolErrors) || - checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape)) - ? null : isFillStyle(style) && || null; - const text = isTextStyle(style) && || null; - const markerType = (isMarkerStyle(style) || isSymbolStyle(style)) && || null; - const markerGlyph = isMarkerStyle(style) && || null; - const symbolLayout = isSymbolStyle(style) && ( - { - this.props.onUpdateSymbols(symbols); - }} - options={this.props.symbolList} - symbolErrors={this.props.symbolErrors} - onLoadingError={this.props.onSetErrorSymbol}/>) || null; - const separator =
; - - const sections = [markerType, preview, symbolLayout, markerGlyph, text, fill, stroke]; - - return ( - - { - /* adding the separator between sections */ - sections.reduce((prev, curr, k) => [prev, prev && curr && {separator}, curr]) - } - - ); - } - - render() { - const styles = castArray(this.props.style); - return (
{styles.map((style, i) => this.renderPanelStyle( - {...style, id: style.id || uuidv1()}, - { - expanded: this.state.expanded[i], - locked: this.state.locked[i], - onSwitch: () => { - this.setState(() => { - const expanded = this.state.expanded.map((e, k) => i === k ? !this.state.expanded[i] : this.state.expanded[k]); - return {expanded}; - }); - let newStyles = styles.map((s, k) => k === i ? {...s, "filtering": !this.state.expanded[i]} : s); - this.props.onChangeStyle(newStyles); - }, - title: style.title || getStylerTitle(style) + " Style"}, - i))}
); - } - change = (id, values) => { - const styles = castArray(this.props.style); - let styleChanged = {...find(styles, { 'id': id }), ...values}; - - if (isSymbolStyle(styleChanged)) { - if (!fetchStyle(hashAndStringify(styleChanged))) { - createSvgUrl(styleChanged, styleChanged.symbolUrl) - .then(symbolUrlCustomized => { - this.updateStyles(id, {...styleChanged, symbolUrlCustomized}, styles, true); - }); - } else { - this.updateStyles(id, fetchStyle(hashAndStringify(styleChanged)), styles, true); - } - } else { - this.updateStyles(id, styleChanged, styles, true); - } - } - updateStyles = (id, style, styles, register = true) => { - if (register) { - registerStyle(hashAndStringify(style), style); - } - let newStyles = arrayUpdate(false, style, { 'id': id }, styles ); - this.props.onChangeStyle(newStyles); - } - changeSymbolType = (id, pointType) => { - this.updateStylesAndType(id, pointType, this.props.defaultStyles.POINT?.[pointType]); - } - - updateStylesAndType = (id, pointType, pointStyle) => { - const styles = castArray(this.props.style); - const styleChangedIndex = findIndex(styles, { 'id': id}); - if (styleChangedIndex !== -1) { - let newStyles = styles.map((s, k) => k === styleChangedIndex ? {...pointStyle, id: s.id, title: s.title, geometry: s.geometry, filtering: s.filtering} : s); - this.props.onChangeStyle(newStyles); - } - } - checkSymbolUrl = ({style, symbolErrors, onLoadingError = this.props.onSetErrorSymbol}) => { - axios.get(style.symbolUrl) - .then(() => { - if (!checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape )) { - const errors = filter(symbolErrors, s => s !== "loading_symbol" + style.shape); - onLoadingError(errors); - } - }) - .catch(() => { - if (!checkSymbolsError(this.props.symbolErrors, "loading_symbol" + style.shape )) { - onLoadingError(symbolErrors.concat(["loading_symbol" + style.shape])); - } - }); - } -} - -export default Manager; diff --git a/web/client/components/style/vector/Stroke.jsx b/web/client/components/style/vector/Stroke.jsx deleted file mode 100644 index dab70b50ab..0000000000 --- a/web/client/components/style/vector/Stroke.jsx +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Row, Col } from 'react-bootstrap'; -import { isNil, isEqual } from 'lodash'; -import tinycolor from 'tinycolor2'; -import Slider from 'react-nouislider'; - -// number localizer? -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; - -// not sure this is needed, TODO check! -numberLocalizer(); -import Message from '../../I18N/Message'; -import OpacitySlider from '../../../plugins/TOC/components/OpacitySlider'; -import ColorSelector from '../ColorSelector'; -import DashArray from './DashArray'; -import { addOpacityToColor } from '../../../utils/VectorStyleUtils'; - -/** - * Styler for the stroke properties of a vector style -*/ -class Stroke extends React.Component { - static propTypes = { - style: PropTypes.object, - defaultColor: PropTypes.string, - lineDashOptions: PropTypes.array, - onChange: PropTypes.func, - width: PropTypes.number, - constraints: PropTypes.object - }; - - static defaultProps = { - style: {}, - constraints: { - maxWidth: 15, - minWidth: 1 - }, - onChange: () => {} - }; - - shouldComponentUpdate(nextProps) { - return !isEqual(this.props.style, nextProps.style) - || !isEqual(this.props.lineDashOptions, nextProps.lineDashOptions); - } - render() { - const {style} = this.props; - return (
- - - - - - - - - - - { - this.props.onChange(style.id, {dashArray}); - }} - /> - - - - - - - - { - if (!isNil(c)) { - const color = tinycolor(c).toHexString(); - const opacity = c.a; - this.props.onChange(style.id, {color, opacity}); - } - }}/> - - - - - - - - { - this.props.onChange(style.id, {opacity}); - }}/> - - - - - - - -
- Math.round(value), - to: value => Math.round(value) + ' px' - }} - range={{ - min: isNil(this.props.constraints && this.props.constraints.minWidth) ? 1 : this.props.constraints.maxWidth, - max: this.props.constraints && this.props.constraints.maxWidth || 15 - }} - onChange={(values) => { - const weight = parseInt(values[0].replace(' px', ''), 10); - this.props.onChange(style.id, {weight}); - }} - /> -
- -
-
); - } -} - -export default Stroke; diff --git a/web/client/components/style/vector/Text.jsx b/web/client/components/style/vector/Text.jsx deleted file mode 100644 index d131df60d6..0000000000 --- a/web/client/components/style/vector/Text.jsx +++ /dev/null @@ -1,229 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Combobox } from 'react-widgets'; -import Slider from 'react-nouislider'; -import IntlNumberFormControl from '../../I18N/IntlNumberFormControl'; -import numberLocalizer from 'react-widgets/lib/localizers/simple-number'; -// not sure this is needed, TODO check! -numberLocalizer(); - -import Message from '../../I18N/Message'; -import { getMessageById } from '../../../utils/LocaleUtils'; -import { createFont } from '../../../utils/LegacyAnnotationsUtils'; - -/** - * Styler for the stroke properties of a vector style -*/ -class Text extends React.Component { - static propTypes = { - style: PropTypes.object, - onChange: PropTypes.func, - addOpacityToColor: PropTypes.func, - width: PropTypes.number, - uomValues: PropTypes.array, - alignValues: PropTypes.array, - fontStyleValues: PropTypes.array, - fontWeightValues: PropTypes.array, - fontFamilyValues: PropTypes.array, - shapeStyle: PropTypes.object, - rotationStep: PropTypes.number - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - style: {}, - onChange: () => {}, - uomValues: [{value: "px"}, {value: "em"}], - fontWeightValues: [{value: "normal"}, {value: "bold"}], - alignValues: [{value: "start", label: "left"}, {value: "center", label: "center"}, {value: "end", label: "right"}], - fontStyleValues: [{value: "normal"}, {value: "italic"}], - fontFamilyValues: [{value: "Arial"}, {value: "Helvetica"}, {value: "sans-serif"}, {value: "Courier"}], - shapeStyle: {}, - rotationStep: 5 - }; - - state = { - fontFamily: "Arial" - }; - - render() { - const messages = { - emptyList: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyList"), - open: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.open"), - emptyFilter: getMessageById(this.context.messages, "queryform.attributefilter.autocomplete.emptyFilter") - }; - const {style} = this.props; - return (
-
- -
-
-
- -
-
- { - let fontFamily = e.value ? e.value : e; - if (fontFamily === "") { - fontFamily = "Arial"; - } - this.setState({fontFamily}); - const font = createFont({...style, fontFamily}); - this.props.onChange(style.id, {fontFamily, font}); - }} - /> -
-
-
-
- -
-
-
- { - const fontSize = val || 14; - const font = createFont({...style, fontSize}); - this.props.onChange(style.id, {fontSize, font}); - }} - type="number"/> -
- { - let fontSizeUom = e.value ? e.value : e; - if (this.props.uomValues.map(f => f.value).indexOf(fontSizeUom) === -1) { - fontSizeUom = "px"; - } - const font = createFont({...style, fontSizeUom}); - this.props.onChange(style.id, {fontSizeUom, font}); - }} - /> -
-
-
-
- -
-
- { - let fontStyle = e.value ? e.value : e; - if (this.props.fontStyleValues.map(f => f.value).indexOf(fontStyle) === -1) { - fontStyle = style.fontStyle; - } - const font = createFont({...style, fontStyle}); - this.props.onChange(style.id, {fontStyle, font}); - }} - /> -
-
-
-
- -
-
- { - let fontWeight = e.value ? e.value : e; - if (this.props.fontWeightValues.map(f => f.value).indexOf(fontWeight) === -1) { - fontWeight = style.fontWeight; - } - const font = createFont({...style, fontWeight}); - this.props.onChange(style.id, {fontWeight, font}); - }} - /> -
-
-
-
- -
-
-
-
- -
-
- { - let textAlign = e.value ? e.value : e; - if (this.props.alignValues.map(f => f.value).indexOf(textAlign) === -1) { - textAlign = "center"; - } - this.props.onChange(style.id, {textAlign}); - }} - /> -
-
-
-
- -
-
-
- Math.round(parseFloat(value)), - to: value => Math.round(value) + ' °' - }} - range={{ - min: 0, - max: 359 - }} - onChange={(values) => { - const rotationDeg = parseInt(values[0].replace(' °', ''), 10); - this.props.onChange(style.id, {textRotationDeg: rotationDeg}); - }} - /> -
-
-
-
); - } -} - -export default Text; diff --git a/web/client/components/style/vector/marker/MarkerGlyph.jsx b/web/client/components/style/vector/marker/MarkerGlyph.jsx deleted file mode 100644 index ba268bfc45..0000000000 --- a/web/client/components/style/vector/marker/MarkerGlyph.jsx +++ /dev/null @@ -1,164 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import Filter from '../../../misc/Filter'; -import MarkerPropertyPicker from '../../MarkerPropertyPicker'; -import Message from '../../../I18N/Message'; - -/** - * Styler for the glyph, color and shape -*/ -class MarkerGlyph extends React.Component { - static propTypes = { - style: PropTypes.object, - markersOptions: PropTypes.object, - onChange: PropTypes.func, - width: PropTypes.number - }; - - static defaultProps = { - style: {}, - onChange: () => {} - }; - - // eslint-disable-next-line no-unused-vars - renderMarkers = (markers, prefix = '') => { - return markers.map((marker) => { - if (marker.markers) { - return this.renderMarkers(marker.markers, marker.name + '-'); - } - return ( -
this.selectStyle(marker)} - className={this.isCurrentStyle(marker) ? 'ms-marker-selected' : ''} - style={{ - ...marker.thumbnailStyle - }} - />); - }); - }; - - render() { - const selectedMarker = this.props.markersOptions.markers.reduce((acc, { markers }) => [...acc, ...markers], []).find((marker) => this.isCurrentStyle(marker)) || {}; - return ( -
-
-
- -
-
- - -
- }> -
-
- -
-
- {this.props.markersOptions.glyphs.map(glyph => { - if (this.filterMarkerGlyph(glyph)) { - return ( -
{ - this.props.onChange(this.props.style.id, {iconGlyph: glyph}); - }}> - -
- ); - } - return null; - })} -
-
- -
-
- -
-
- -
-
- - }> -
- {this.renderMarkers(this.props.markersOptions.markers)} -
-
-
-
-
- ); - } - - isCurrentStyle = (m) => { - // TODO change this - return this.props.markersOptions.markersConfig.matches(this.props.style, m.style); - } - - selectStyle = (marker) => { - return this.props.onChange(this.props.style.id, {...this.props.markersOptions.markersConfig.getStyle(marker.style)}); - }; - - filterMarkerGlyph = (marker) =>{ - return marker && marker.toLowerCase().indexOf(this.props.markersOptions?.filter?.toLowerCase() || '') !== -1; - }; -} - -export default MarkerGlyph; diff --git a/web/client/components/style/vector/marker/MarkerType.jsx b/web/client/components/style/vector/marker/MarkerType.jsx deleted file mode 100644 index 0e2591ab94..0000000000 --- a/web/client/components/style/vector/marker/MarkerType.jsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. -*/ - -import PropTypes from 'prop-types'; - -import React from 'react'; -import { Row, Col } from 'react-bootstrap'; -import Select from 'react-select'; -import Message from '../../../I18N/Message'; - -/** - * Styler for the gliph, color and shape -*/ -class MarkerType extends React.Component { - static propTypes = { - style: PropTypes.object, - pointType: PropTypes.string, - options: PropTypes.array, - onChangeType: PropTypes.func, - width: PropTypes.number - }; - - static defaultProps = { - style: {}, - options: [{ - label: 'Marker', - value: 'marker' - }, { - label: 'Symbol', - value: 'symbol' - }], - pointType: "marker", - onChangeType: () => {} - }; - - render() { - return ( -
- - - - - - list - const iconRenderer = (option) => { - return (
- - {option.label}
); - }; - // checking if default shape exists - const shapeDefault = this.props.options && this.props.options.length ? find(this.props.options, (s) => s.value === this.props.defaultShape) && this.props.defaultShape : DEFAULT_SHAPE; - return ( -
- - - - - - { // managing misconfigruation of symbols.json (symbolsPath) - checkSymbolsError(this.props.symbolErrors) ? ( - - - - - - - - - - - ) : ( -
- - - - - - - - - - - - - - ); - }; - - renderAvancedRule = () => { - return ()} eventKey="3"> - - - - ); - }; - - renderSelector = () => { - return ( - - {!this.props.hideLayerSelector ? ( - - this.props.selectLayer(value)} - valueField={"id"} - textField={"title"} /> - ) : null} - {this.props.layer ? ( - - this.props.selectRule(value.id)} - valueField={"id"} - textField={"name"} /> ) : null} - {this.props.rule ? ( - - - this.props.setRuleParameter('name', ev.target.value)} value={this.props.rule.name}/> - ) : null} - - ); - }; - - renderVectorStyler = () => { - return this.props.layer ? - - - {this.props.rule ? this.renderSymbolStyler() : null} - {this.props.rule ? this.renderAvancedRule() : null} - - : null; - }; - - renderApplyBtn = () => { - let disabled = !this.props.rule; - return ( - - - - - - - - ); - }; - - renderBody = () => { - - return ( - {this.renderError()} - {this.renderSelector()} - {this.renderVectorStyler()} - {this.props.layer ? this.renderApplyBtn() : null} - ); - }; - - render() { - if (this.props.forceOpen || this.props.open) { - return this.props.withContainer ? - }> - {this.renderBody()} - : this.renderBody(); - } - return null; - } - - apply = () => { - let style = vecStyleToSLD({rules: this.props.rules, layer: this.props.layer}); - this.props.changeLayerProperties(this.props.layer.id, { params: assign({}, this.props.layer.params, {SLD_BODY: style})}); - }; -} - -const selector = createSelector([ - (state) => state.controls.toolbar && state.controls.toolbar.active === 'vectorstyler', - ruleselctor, - (state) => state.vectorstyler && state.vectorstyler.rules, - (state) => state.vectorstyler && state.vectorstyler.layer, - layersSelector -], (open, rule, rules, layer, layers) => ({ - open, - rule, - rules, - layer, - layers: layers.filter((l) => { return l.group !== 'background'; }) -})); - -const VectorStylerPlugin = connect(selector, { - setVectorStyleParameter: setVectorStyleParameter, - selectLayer: setVectorLayer, - addRule: newVectorRule, - removeRule: removeVectorRule, - selectRule: selectVectorRule, - changeLayerProperties: changeLayerProperties, - setRuleParameter: setVectorRuleParameter -})(VectorStyler); - -export default { - VectorStylerPlugin: assign( VectorStylerPlugin, - { - Toolbar: { - name: 'vectorstyler', - help: , - tooltip: "vectorstyler.tooltip", - icon: , - position: 9, - panel: true, - exclusive: true - } - }), - reducers: { - vectorstyler: vectorstylerReducers - } -}; diff --git a/web/client/plugins/omnibar/OmniBarMenu.jsx b/web/client/plugins/omnibar/OmniBarMenu.jsx deleted file mode 100644 index b8b697a828..0000000000 --- a/web/client/plugins/omnibar/OmniBarMenu.jsx +++ /dev/null @@ -1,58 +0,0 @@ - -/** - * 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. - */ - -import React from 'react'; -import PropTypes from 'prop-types'; - -import { NavDropdown, Glyphicon, MenuItem } from 'react-bootstrap'; -import { connect } from 'react-redux'; -import { partial } from 'lodash'; -import Message from '../locale/Message'; -import Button from '../../components/misc/Button'; - -class OmniBarMenu extends React.Component { - static propTypes = { - dispatch: PropTypes.func, - items: PropTypes.array, - title: PropTypes.node, - onItemClick: PropTypes.func - }; - - static contextTypes = { - messages: PropTypes.object, - router: PropTypes.object - }; - - static defaultProps = { - items: [], - onItemClick: () => {}, - title: - }; - - renderNavItem = (tool) => { - return ( { - e.preventDefault(); - if (tool.action) { - this.props.dispatch(partial(tool.action, this.context)); - } else { - this.props.onItemClick(tool); - } - }}>{tool.icon} {tool.text}); - }; - - render() { - return (} > - {this.props.title} - {this.props.items.sort((a, b) => a.position - b.position).map(this.renderNavItem)} - ) - ; - } -} - -export default connect()(OmniBarMenu); diff --git a/web/client/plugins/rasterstyler/index.js b/web/client/plugins/rasterstyler/index.js deleted file mode 100644 index 2bb17c9d37..0000000000 --- a/web/client/plugins/rasterstyler/index.js +++ /dev/null @@ -1,72 +0,0 @@ -/** -* 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. -*/ - -import { connect } from 'react-redux'; - -import { setRasterStyleParameter } from '../../actions/rasterstyler'; -import BandSelectorComp from '../../components/style/BandSelector'; -import EqualIntervalComp from '../../components/style/EqualInterval'; -import OpacityPickerComp from '../../components/style/OpacityPicker'; -import PseudoColorSettingsComp from '../../components/style/PseudoColorSettings'; -import RasterStyleTypePickerComp from '../../components/style/RasterStyleTypePicker'; - -export const RedBandSelector = connect((state) => { return state.rasterstyler.redband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'redband') - })(BandSelectorComp); - -export const BlueBandSelector = connect((state) => { return state.rasterstyler.blueband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'blueband') - })(BandSelectorComp); - -export const GreenBandSelector = connect((state) => { return state.rasterstyler.greenband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'greenband') - })(BandSelectorComp); - -export const GrayBandSelector = connect((state) => { return state.rasterstyler.grayband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'grayband') - })(BandSelectorComp); -export const PseudoBandSelector = connect((state) => { return state.rasterstyler.pseudoband || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'pseudoband') - })(BandSelectorComp); - -export const RasterStyleTypePicker = connect((state) => { return state.rasterstyler.typepicker || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'typepicker') - })(RasterStyleTypePickerComp); - -export const OpacityPicker = connect((state) => { return state.rasterstyler.opacitypicker || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'opacitypicker') - })(OpacityPickerComp); - -export const EqualInterval = connect((state) => { return state.rasterstyler.equalinterval || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'equalinterval') - })(EqualIntervalComp); - -export const PseudoColor = connect((state) => { return state.rasterstyler.pseudocolor || {}; }, - { - onChange: setRasterStyleParameter.bind(null, 'pseudocolor') - })(PseudoColorSettingsComp); - -export default { - RedBandSelector, - BlueBandSelector, - GreenBandSelector, - GrayBandSelector, - PseudoBandSelector, - RasterStyleTypePicker, - EqualInterval, - PseudoColor, - OpacityPicker -}; diff --git a/web/client/plugins/rasterstyler/rasterstyler.css b/web/client/plugins/rasterstyler/rasterstyler.css deleted file mode 100644 index 106a0c5b89..0000000000 --- a/web/client/plugins/rasterstyler/rasterstyler.css +++ /dev/null @@ -1,7 +0,0 @@ -.mapstore-rasterstyler-panel { - width: 600px; - position: absolute; - top: 10px; - right: 60px; - z-index: 1000; -} \ No newline at end of file diff --git a/web/client/plugins/styler/styler.css b/web/client/plugins/styler/styler.css deleted file mode 100644 index 3509847bc4..0000000000 --- a/web/client/plugins/styler/styler.css +++ /dev/null @@ -1,29 +0,0 @@ -.mapstore-styler-panel { - width: 600px; - position: absolute; - top: 10px; - right: 60px; - z-index: 1000; -} -.mapstore-styler-panel button{ - font-size:14px !important; - border-radius: 4px; - height: 30px; - padding-bottom: 5px; -} -.mapstore-styler-panel button:disabled{ - color:white; -} -.mapstore-styler-panel .panel-heading{ - background-color: #078AA3 !important; - color:white !important; -} - -.mapstore-styler-panel .form-control{ - height: 32px !important; - -} - -.mapstore-styler-panel, .panel, .panel-default{ - overflow: visible !important; -} diff --git a/web/client/plugins/vectorstyler/index.js b/web/client/plugins/vectorstyler/index.js deleted file mode 100644 index 0895c29230..0000000000 --- a/web/client/plugins/vectorstyler/index.js +++ /dev/null @@ -1,36 +0,0 @@ -/** -* 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. -*/ - -import { connect } from 'react-redux'; - -import { setVectorStyleParameter } from '../../actions/vectorstyler'; -import ScaleDenominatorComp from '../../components/style/ScaleDenominator'; -import StylePointComp from '../../components/style/StylePoint'; -import StylePolygonComp from '../../components/style/StylePolygon'; -import StylePolylineComp from '../../components/style/StylePolyline'; -import { symbolselector } from '../../selectors/vectorstyler'; - -export const StylePolygon = connect(symbolselector, { - setStyleParameter: setVectorStyleParameter.bind(null, 'symbol') -})(StylePolygonComp); - -export const StylePoint = connect(symbolselector, { - setStyleParameter: setVectorStyleParameter.bind(null, 'symbol') -})(StylePointComp); - -export const StylePolyline = connect(symbolselector, { - setStyleParameter: setVectorStyleParameter.bind(null, 'symbol') -})(StylePolylineComp); -export const ScaleDenominator = ScaleDenominatorComp; - -export default { - StylePolygon, - StylePolyline, - StylePoint, - ScaleDenominator -}; diff --git a/web/client/plugins/vectorstyler/vectorstyler.css b/web/client/plugins/vectorstyler/vectorstyler.css deleted file mode 100644 index 83d8cfd50e..0000000000 --- a/web/client/plugins/vectorstyler/vectorstyler.css +++ /dev/null @@ -1,7 +0,0 @@ -.mapstore-vectorstyler-panel { - width: 600px; - position: absolute; - top: 10px; - right: 60px; - z-index: 1000; -} \ No newline at end of file diff --git a/web/client/product/assets/img/rasterstyler.jpg b/web/client/product/assets/img/rasterstyler.jpg deleted file mode 100644 index 65f7b1184ad82842c1ffd49c84a732fae370711b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56611 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 H>VN;)Nj=qE diff --git a/web/client/reducers/__tests__/rasterstyler-test.js b/web/client/reducers/__tests__/rasterstyler-test.js deleted file mode 100644 index 258fba70af..0000000000 --- a/web/client/reducers/__tests__/rasterstyler-test.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import rasterstyler from '../rasterstyler'; -import { SET_RASTERSTYLE_PARAMETER, SET_RASTER_LAYER } from '../../actions/rasterstyler'; - -describe('Test the rasterstyler reducer', () => { - it('set a rasterstyle parameter', () => { - const state = rasterstyler(undefined, { - type: SET_RASTERSTYLE_PARAMETER, - component: 'testComponent', - property: 'testProperty', - value: 'testValue' - }); - expect(state.testComponent).toExist(); - expect(state.testComponent.testProperty).toExist(); - expect(state.testComponent.testProperty).toBe('testValue'); - }); - - it('set a rasterstyle layer', () => { - const state = rasterstyler(undefined, { - type: SET_RASTER_LAYER, - layer: 'testLayer' - }); - expect(state.layer).toBe('testLayer'); - }); - -}); diff --git a/web/client/reducers/rasterstyler.js b/web/client/reducers/rasterstyler.js deleted file mode 100644 index 2f0fc27a15..0000000000 --- a/web/client/reducers/rasterstyler.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * 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. - */ - -import { SET_RASTERSTYLE_PARAMETER, SET_RASTER_LAYER } from '../actions/rasterstyler'; - -import assign from 'object-assign'; -import { STYLER_RESET } from '../actions/styler'; - -const initialSpec = { - pseudoband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - redband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - blueband: {band: '3', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - greenband: {band: '2', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - grayband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - pseudocolor: {colorMapEntry: [], type: 'ramp', selected: null, opacity: '1.00', activepanel: "1"}, - equalinterval: {classes: 6, max: 255, min: 0, ramp: "Blues"} -}; - -function setBaseOptions(describe = {}) { - let newInit = {}; - Object.keys(initialSpec).reduce((pr, next) => { - pr[next] = assign({}, initialSpec[next]); - return pr; - }, newInit); - if (describe.bands && describe.bands.length > 0) { - newInit.pseudoband.band = describe.bands[0]; - newInit.redband.band = describe.bands[0]; - newInit.greenband.band = describe.bands.length > 1 ? describe.bands[1] : describe.bands[0]; - newInit.blueband.band = describe.bands.length > 2 ? describe.bands[2] : describe.bands[0]; - newInit.grayband.band = describe.bands[0]; - } - if (describe.range) { - newInit.equalinterval.min = describe.range.min; - newInit.equalinterval.max = describe.range.max; - } - return newInit; -} - -function rasterstyler(state = initialSpec, action) { - switch (action.type) { - case SET_RASTERSTYLE_PARAMETER: { - return assign({}, state, { - [action.component]: assign({}, state[action.component], { - [action.property]: action.value - }) - }); - } - case SET_RASTER_LAYER: { - - return assign({}, setBaseOptions(action.layer.describeLayer), { layer: action.layer}); - } - case STYLER_RESET: { - return initialSpec; - } - default: - return state; - } -} - -export default rasterstyler; diff --git a/web/client/reducers/styler.js b/web/client/reducers/styler.js deleted file mode 100644 index c96f2b4bbe..0000000000 --- a/web/client/reducers/styler.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * 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. - */ - -import { SET_VECTOR_LAYER } from '../actions/vectorstyler'; - -import { SET_RASTER_LAYER } from '../actions/rasterstyler'; -import { SET_STYLER_LAYER, STYLER_RESET } from '../actions/styler'; -function styler(state = {}, action) { - switch (action.type) { - case SET_VECTOR_LAYER: { - return {...state, layer: action.layer, type: "vector"}; - } - case SET_RASTER_LAYER: { - return {...state, layer: action.layer, type: "raster"}; - } - case STYLER_RESET: { - return {}; - } - case SET_STYLER_LAYER: { - return {...state, layer: action.layer}; - } - default: - return state; - } -} - -export default styler; diff --git a/web/client/reducers/vectorstyler.js b/web/client/reducers/vectorstyler.js deleted file mode 100644 index f99e78a72f..0000000000 --- a/web/client/reducers/vectorstyler.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * 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. - */ - -import { - NEW_VECTOR_RULE, - SELECT_VECTOR_RULE, - REMOVE_VECTOR_RULE, - SET_VECTORSTYLE_PARAMETER, - SET_VECTOR_LAYER, - SET_VECTOR_RULE_PARAMETER -} from '../actions/vectorstyler'; - -import { STYLER_RESET } from '../actions/styler'; -import assign from 'object-assign'; -import { isObject, findIndex } from 'lodash'; -const baseStyle = { - Point: { - type: "Point", - color: { r: 0, g: 0, b: 255, a: 1 }, - width: 3, - fill: { r: 0, g: 0, b: 255, a: 0.1 }, - radius: 10, - marker: false, - markName: "circle" - }, - Line: { - type: "Line", - color: { r: 0, g: 0, b: 255, a: 1 }, - width: 3 - }, - Polygon: { - type: "Polygon", - color: { r: 0, g: 0, b: 255, a: 1 }, - width: 3, - fill: { r: 0, g: 0, b: 255, a: 0.1 } - } - -}; - -const initialSpec = { - rules: [] -}; -function getType(layer) { - switch (layer.describeLayer.geometryType) { - case 'Polygon': - case 'MultiPolygon': { - return "Polygon"; - } - case 'MultiLineString': - case 'LineString': { - return "Line"; - } - case 'Point': - case 'MultiPoint': { - return "Point"; - } - default: { - return "Polygon"; - } - } -} - -function getBaseSymbol(type = "Polygon") { - let newSymbol = {}; - let symbol = baseStyle[type]; - Object.keys(symbol).reduce((pr, next) => { - pr[next] = isObject(symbol[next]) ? assign({}, symbol[next]) : symbol[next]; - return pr; - }, newSymbol); - return newSymbol; -} - -function getRuleIdx(rules, id) { - return findIndex(rules, (r) => {return r.id === id; }); -} - -function vectorstyler(state = initialSpec, action) { - switch (action.type) { - case NEW_VECTOR_RULE: { - const newRule = { - id: action.id, - symbol: getBaseSymbol(getType(state.layer)), - name: 'New Rule' - }; - - return assign({}, state, {rule: newRule.id, rules: state.rules ? [...state.rules, newRule] : [newRule]}); - - } - case SELECT_VECTOR_RULE: { - return assign({}, state, {rule: action.id}); - - } - case REMOVE_VECTOR_RULE: { - const idx = getRuleIdx(state.rules, action.id); - let newSelected = state.rules[idx - 1] ? state.rules[idx - 1].id : undefined; - if (newSelected === undefined) { - newSelected = state.rules[idx + 1] ? state.rules[idx + 1].id : undefined; - } - return assign({}, state, {rule: newSelected, rules: state.rules.filter((rule) => rule.id !== action.id)}); - } - case SET_VECTOR_RULE_PARAMETER: { - let newRules = state.rules.slice(); - const ruleIdx = getRuleIdx(newRules, state.rule); - const activeRule = newRules[ruleIdx]; - newRules[ruleIdx] = assign({}, activeRule, {[action.property]: action.value}); - return assign({}, state, {rules: newRules}); - } - case SET_VECTORSTYLE_PARAMETER: { - let newRules = state.rules.slice(); - const ruleIdx = getRuleIdx(newRules, state.rule); - const activeRule = newRules[ruleIdx]; - newRules[ruleIdx] = assign( {}, activeRule, { - [action.component]: assign({}, activeRule[action.component], { - [action.property]: action.value - }) - }); - return assign({}, state, {rules: newRules}); - - } - case SET_VECTOR_LAYER: { - return assign({}, initialSpec, { layer: action.layer}); - } - case STYLER_RESET: { - return initialSpec; - } - default: - return state; - } -} - -export default vectorstyler; diff --git a/web/client/selectors/vectorstyler.js b/web/client/selectors/vectorstyler.js deleted file mode 100644 index 0d1ea3f60f..0000000000 --- a/web/client/selectors/vectorstyler.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * 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. - */ - -import { createSelector } from 'reselect'; - -import { head } from 'lodash'; - -export const ruleselctor = (state) => state.vectorstyler && state.vectorstyler.rule && head(state.vectorstyler.rules.filter((r) => {return r.id === state.vectorstyler.rule; })); - -export const symbolselector = createSelector([ruleselctor], - (rule) => ({ - shapeStyle: rule && rule.symbol || {} - })); diff --git a/web/client/utils/LegacyAnnotationsUtils.js b/web/client/utils/LegacyAnnotationsUtils.js deleted file mode 100644 index c9509717d6..0000000000 --- a/web/client/utils/LegacyAnnotationsUtils.js +++ /dev/null @@ -1,739 +0,0 @@ -/* - * 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. -*/ - -import uuidv1 from 'uuid/v1'; - -import {getMessageById} from './LocaleUtils'; -import MarkerUtils from './MarkerUtils'; -import { geometryFunctions, fetchStyle, hashAndStringify } from './VectorStyleUtils'; -import { set } from './ImmutableUtils'; -import { values, isNil, slice, head, castArray, last, isArray, findIndex, isString, get, includes } from 'lodash'; -import uuid from 'uuid'; -import turfCenter from '@turf/center'; -import assign from 'object-assign'; -let AnnotationsUtils = {}; - -export const STYLE_CIRCLE = { - color: '#ffcc33', - opacity: 1, - weight: 3, - fillColor: '#ffffff', - fillOpacity: 0.2 -}; -export const STYLE_POINT_MARKER = { - iconGlyph: 'comment', - iconShape: 'square', - iconColor: 'blue' -}; -export const STYLE_POINT_SYMBOL = { - iconAnchor: [0.5, 0.5], - anchorXUnits: 'fraction', - anchorYUnits: 'fraction', - color: "#000000", - fillColor: "#000000", - opacity: 1, - size: 64, - fillOpacity: 1 -}; -export const STYLE_TEXT = { - fontStyle: 'normal', - fontSize: '14', - fontSizeUom: 'px', - fontFamily: 'Arial', - fontWeight: 'normal', - font: "14px Arial", - textAlign: 'center', - color: '#000000', - opacity: 1, - fillColor: '#000000', - fillOpacity: 1 -}; -export const STYLE_LINE = { - color: '#ffcc33', - opacity: 1, - weight: 3, - editing: { - fill: 1 - } -}; -export const STYLE_POLYGON = { - color: '#ffcc33', - opacity: 1, - weight: 3, - fillColor: '#ffffff', - fillOpacity: 0.2, - editing: { - fill: 1 - } -}; -/** - * some defaults for the style -*/ -export const DEFAULT_ANNOTATIONS_STYLES = { - "Text": STYLE_TEXT, - "Point": STYLE_POINT_MARKER, - "Circle": STYLE_CIRCLE, - "MultiPoint": STYLE_POINT_MARKER, - "LineString": STYLE_LINE, - "MultiLineString": STYLE_LINE, - "Polygon": STYLE_POLYGON, - "MultiPolygon": STYLE_POLYGON -}; -/** - * The constant for annotation type - */ -export const ANNOTATION_TYPE = "ms2-annotations"; - -/** - * The constant for annotations - */ -export const ANNOTATIONS = "annotations"; - -/** - * return two styles object for start and end point. - * usually added to a LineString - * @return {object[]} the two styles -*/ -export const getStartEndPointsForLinestring = () => { - return [{...DEFAULT_ANNOTATIONS_STYLES.Point, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "StartPoint Style", geometry: "startPoint", filtering: false, id: uuidv1()}, - {...DEFAULT_ANNOTATIONS_STYLES.Point, highlight: true, iconAnchor: [0.5, 0.5], type: "Point", title: "EndPoint Style", geometry: "endPoint", filtering: false, id: uuidv1()}]; -}; - -export const rgbaTorgb = (rgba = "") => { - return rgba.indexOf("rgba") !== -1 ? `rgb${rgba.slice(rgba.indexOf("("), rgba.lastIndexOf(","))})` : rgba; -}; - -export const textAlignTolabelAlign = (a) => (a === "start" && "lm") || (a === "end" && "rm") || "cm"; - -export const getStylesObject = ({type = "Point", features = []} = {}) => { - return type === "FeatureCollection" ? features.reduce((p, c) => { - p[c.geometry.type] = DEFAULT_ANNOTATIONS_STYLES[c.geometry.type]; - return p; - }, {type: "FeatureCollection"}) : {...DEFAULT_ANNOTATIONS_STYLES[type]}; -}; -export const getProperties = (props = {}, messages = {}) => ({title: getMessageById(messages, "annotations.defaulttitle") !== "annotations.defaulttitle" ? getMessageById(messages, "annotations.defaulttitle") : "Default title", id: uuidv1(), ...props}); - -export const getDashArrayFromStyle = dashArray => { - return isString(dashArray) && dashArray || isArray(dashArray) && dashArray.join(" "); -}; - -export const hasOutline = (style) => { - return style.color && style.opacity && style.weight; -}; - -export const annStyleToOlStyle = (type, tempStyle, label = "") => { - let style = tempStyle && tempStyle[type] ? tempStyle[type] : tempStyle; - const s = style ?? {}; - const dashArray = s.dashArray ? getDashArrayFromStyle(s.dashArray) : "solid"; - switch (type) { - case "MultiPolygon": - case "Polygon": - case "Circle": - return { - "strokeColor": rgbaTorgb(s.color), - "strokeOpacity": s.opacity, - "strokeWidth": s.weight, - "fillColor": rgbaTorgb(s.fillColor), - "fillOpacity": s.fillOpacity, - "strokeDashstyle": dashArray - }; - case "LineString": - case "MultiLineString": - return { - "strokeColor": rgbaTorgb(s.color), - "strokeOpacity": s.opacity, - "strokeWidth": s.weight, - "strokeDashstyle": dashArray - }; - case "Text": - const outline = hasOutline(s) ? { - "labelOutlineColor": rgbaTorgb(s.color), - "labelOutlineOpacity": s.opacity, - "labelOutlineWidth": s.weight - } : {}; - return { - "fontStyle": s.fontStyle, - "fontSize": s.fontSize, // in mapfish is in px - "fontFamily": s.fontFamily, - "fontWeight": s.fontWeight, - "labelAlign": textAlignTolabelAlign(s.textAlign), - "fontColor": rgbaTorgb(s.fillColor), - "fontOpacity": s.fillOpacity, - "label": label, - "stroke": true, - "strokeColor": rgbaTorgb(s.color), - "strokeOpacity": s.opacity, - "strokeWidth": s.weight, - "strokeDashstyle": dashArray, - ...outline - }; - case "Point": - case "MultiPoint": { - // TODO TEST THIS - const externalGraphic = s.symbolUrl && fetchStyle(hashAndStringify(s), "base64") || MarkerUtils.extraMarkers.markerToDataUrl(s); - let graphicXOffset = -18; - let graphicYOffset = -46; - if (s.iconAnchor && isArray(s.iconAnchor) && s.size) { - if (s.anchorXUnits === "pixels") { - graphicXOffset = -1 * s.iconAnchor[0]; - } else { - graphicXOffset = -1 * s.size * s.iconAnchor[0]; - } - if (s.anchorYUnits === "pixels") { - graphicYOffset = -1 * s.iconAnchor[1]; - } else { - graphicYOffset = -1 * s.size * s.iconAnchor[1]; - } - } - return externalGraphic ? { - "graphicWidth": s.size || 36, - "graphicHeight": s.size || 46, - externalGraphic, - graphicXOffset, - graphicYOffset, - "display": s.filtering === false && "none" - } : { - "fillColor": "#0000AE", - "fillOpacity": 0.5, - "strokeColor": "#0000FF", - "pointRadius": 10, - "strokeOpacity": 1, - "strokeWidth": 1, - "display": s.filtering === false && "none" - }; - } - default: - return { - "fillColor": "#FF0000", - "fillOpacity": 0, - "strokeColor": "#FF0000", - "pointRadius": 5, - "strokeOpacity": 1, - "strokeDashstyle": dashArray, - "strokeWidth": 1 - }; - } -}; - -/** - * function used to convert a geojson into a internal model. - * if it finds some textValues in the properties it will return this as Text - * otherwise it will return the original geometry type. - * @return {object} a transformed geojson with only geometry types -*/ -export const convertGeoJSONToInternalModel = ({type = "Point", geometries = [], features = []}, textValues = [], circles = []) => { - switch (type) { - case "Point": case "MultiPoint": { - return {type: textValues.length === 1 ? "Text" : type}; - } - case "Polygon": { - return {type: circles.length === 1 ? "Circle" : type}; - } - case "GeometryCollection": { - const onlyPoints = geometries.filter(g => g.type === "Point" || g.type === "MultiPoint"); - const onlyMultiPolygons = geometries.filter(g => g.type === "Polygon"); - let t = 0; - let p = 0; - return {type: "GeometryCollection", geometries: geometries.map(g => { - if (g.type === "Point" || g.type === "MultiPoint") { - if (onlyPoints.length === textValues.length) { - return {type: "Text"}; - } - if (textValues.length === 0) { - return {type: g.type}; - } - if (t === 0) { - t++; - return {type: "Text" }; - } - } - if (g.type === "Polygon") { - if (onlyMultiPolygons.length === circles.length) { - return {type: "Circle"}; - } - if (circles.length === 0) { - return {type: g.type}; - } - if (p === 0) { - p++; - return {type: "Circle" }; - } - } - return {type: g.type}; - })}; - } - case "FeatureCollection" : { - const featuresTypes = features.map(f => { - if (f.properties && f.properties.isCircle) { - return {type: "Circle"}; - } - if (f.properties && f.properties.isText) { - return {type: "Text"}; - } - return {type: f.geometry.type}; - }); - return {type: "FeatureCollection", features: featuresTypes}; - } - default: return {type}; - } -}; -/** - * Retrieves a non duplicated list of stylers - * @return {string[]} it returns the array of available styler from geometry of a feature -*/ -export const getAvailableStyler = ({type = "Point", geometries = [], features = []} = {}) => { - switch (type) { - case "Point": case "MultiPoint": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Symbol": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "LineString": case "MultiLineString": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Polygon": case "MultiPolygon": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Text": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "Circle": { - return [AnnotationsUtils.getRelativeStyler(type)]; - } - case "GeometryCollection": { - return geometries.reduce((p, c) => { - return (p.indexOf(AnnotationsUtils.getRelativeStyler(c.type)) !== -1) ? p : p.concat(AnnotationsUtils.getAvailableStyler(c)); - }, []); - } - case "FeatureCollection": { - return features.reduce((p, c) => { - return (p.indexOf(AnnotationsUtils.getRelativeStyler(c.type)) !== -1) ? p : p.concat(AnnotationsUtils.getAvailableStyler(c)); - }, []); - } - default: return []; - } -}; -/** - * it converts a geometryType to a stylertype - * @return {string} a stylertype -*/ -export const getRelativeStyler = (type) => { - switch (type) { - case "Point": case "MultiPoint": { - return "marker"; - } - case "Symbol": { - return "symbol"; - } - case "Circle": { - return "circle"; - } - case "LineString": case "MultiLineString": { - return "lineString"; - } - case "Polygon": case "MultiPolygon": { - return "polygon"; - } - case "Text": { - return "text"; - } - default: return ""; - } -}; -/** - * it converts some props of a CSS-font into a shorhand form - * @return {string} a CSS-font -*/ -export const createFont = ({fontSize = "14", fontSizeUom = "px", fontFamily = "Arial", fontStyle = "normal", fontWeight = "normal"} = {}) => { - return `${fontStyle} ${fontWeight} ${fontSize}${fontSizeUom} ${fontFamily}`; -}; - -/** - * Converts any feature to a geometry type - * @param {object} feature - * @return {string} a geometry type - */ -export const getGeometryType = (feature) => { - if (feature?.properties?.isCircle) { - return 'Circle'; - } - if (feature?.properties?.isText) { - return 'Text'; - } - return feature?.geometry?.type; -}; -/** - * Converts any geometry type to a glyph - * @param {string} type of geometry - * @return {object} a glyph name and label - */ -export const getGeometryGlyphInfo = (type = 'Point') => { - const glyphs = { - Point: {glyph: 'point', label: 'Point'}, - MultiPoint: {glyph: 'point', label: 'Point'}, - LineString: {glyph: 'polyline', label: 'Line'}, - MultiLineString: {glyph: 'polyline', label: 'Line'}, - Polygon: {glyph: 'polygon', label: 'Polygon'}, - MultiPolygon: {glyph: 'polygon', label: 'Polygon'}, - Text: {glyph: 'font', label: 'Text'}, - Circle: {glyph: '1-circle', label: 'Circle'} - }; - return glyphs[type]; -}; -/** -* it converts any geoJSONObject to an annotation -* Mandatory elements: MUST be a geoJSON type Feature => properties with an ID and a title -* annotation style. -*/ -export const normalizeAnnotation = (ann = {}, messages = {}) => { - const annotation = ann.type === "FeatureCollection" ? {...ann} : {type: "Feature", geometry: ann}; - const style = getStylesObject(annotation); - const properties = getProperties(annotation.properties, messages); - return {style, properties, ...annotation}; -}; -export const removeDuplicate = (annotations) => values(annotations.reduce((p, c) => ({...p, [c.properties.id]: c}), {})); -/** -* Compress circle in a single MultiPolygon feature with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const circlesToMultiPolygon = ({geometries = []}, {circles = []}, style = STYLE_CIRCLE) => { - const coordinates = circles.reduce((coords, cIdx) => coords.concat([geometries[cIdx].coordinates]), []); - return {type: "Feature", geometry: {type: "MultiPolygon", coordinates}, properties: {id: uuidv1(), ms_style: annStyleToOlStyle("Circle", style)}}; -}; -/** -* Transform circle in a single Polygon feature with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const fromCircleToPolygon = (geometry, properties, style = STYLE_CIRCLE) => { - return {type: "Feature", geometry: properties.polygonGeom || geometry, properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle("Circle", style)}}; -}; -/** -* Transform text point to single point with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const fromTextToPoint = (geometry, properties, style = STYLE_TEXT) => { - return {type: "Feature", geometry, properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle("Text", style, properties.valueText)}}; -}; -/** -* Transform LineString to geodesic LineString (with more points) -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object} feature -*/ -export const fromLineStringToGeodesicLineString = (properties, style = STYLE_LINE) => { - return {type: "Feature", geometry: properties.geometryGeodesic, properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle(properties.geometryGeodesic.type, style)}}; -}; -/** -* Flatten text point to single point with style -* @param {object} geometry -* @param {object} properties -* @param {object} style -* @return {object[]} features -*/ -export const textToPoint = ({geometries = []}, {textGeometriesIndexes = [], textValues = []}, style = STYLE_TEXT) => { - return textGeometriesIndexes.map((tIdx, cIdx) => { - return {type: "Feature", geometry: geometries[tIdx], properties: {id: uuidv1(), ms_style: annStyleToOlStyle("Text", style, textValues[cIdx])}}; - }); -}; -/** -* Flatten geometry collection -* @param {object} GeometryCollection An annotation of type geometrycollection -* @return {object[]} an array of features -*/ -export const flattenGeometryCollection = ({geometry, properties, style}) => { - const circles = properties.circles && AnnotationsUtils.circlesToMultiPolygon(geometry, properties, style.Circle) || []; - const texts = properties.textGeometriesIndexes && AnnotationsUtils.textToPoint(geometry, properties, style.Text) || []; - const skeep = (properties.circles || []).concat(properties.textGeometriesIndexes || []); - const features = geometry.geometries.filter((el, idx) => skeep.indexOf(idx) === -1) - .map((geom) => ({ - type: "Feature", - geometry: geom, - properties: {id: uuidv1(), ms_style: annStyleToOlStyle(geom.type, style[geom.type])} - })); - return features.concat(circles, texts); -}; -// for the moment is used with ol functions -export const createGeometryFromGeomFunction = (ft) => { - let type = geometryFunctions[ft.style.geometry] && geometryFunctions[ft.style.geometry].type || ft.geometry.type; - let coordinates = ft.geometry.coordinates || []; - switch (ft.style.geometry ) { - case "startPoint": coordinates = head(coordinates); break; - case "endPoint": coordinates = last(coordinates); break; - case "centerPoint": coordinates = turfCenter(ft).geometry.coordinates; break; - default: break; - } - return {type, coordinates}; -}; -/** -* transform an annotation Feature into a simple geojson feature -* @param {object} feature coming from a ftcoll -* @return {object} a transformed feature -*/ -export const fromAnnotationToGeoJson = ({geometry: ftGeom, properties = {}, style = {}} = {}) => { - let geometry = style.geometry ? AnnotationsUtils.createGeometryFromGeomFunction({geometry: ftGeom, properties, style, type: "Feature"}) : ftGeom; - if (properties.isCircle && geometry.type === "Polygon") { - return AnnotationsUtils.fromCircleToPolygon(geometry, properties, style); - } - if (properties.isText) { - return AnnotationsUtils.fromTextToPoint(geometry, properties, style); - } - if (geometry.type === "LineString" && properties.useGeodesicLines && style.filtering) { - return AnnotationsUtils.fromLineStringToGeodesicLineString(properties, style); - } - return { - type: "Feature", - geometry, - properties: {id: properties.id || uuidv1(), ms_style: annStyleToOlStyle(geometry.type, style)} - }; -}; -/** -* Adapt annotation features to print pdf -* @param {object[]} features -* @param {object} style -* @return {object[]} features -*/ -export const annotationsToPrint = (features = []) => { - return features.reduce((coll, f) => { - if (f.type === "FeatureCollection") { - // takes the style from the feature coll if it is missing from the feature - return coll.concat(f.features.map(ft => { - return castArray(ft.style || f.style || {}).filter(s => isNil(s.filtering) ? true : s.filtering).map(style => AnnotationsUtils.fromAnnotationToGeoJson({...ft, style})); - }).reduce((p, c) => p.concat(c), [])); - } - return f.geometry && f.geometry.type === "GeometryCollection" ? coll.concat(AnnotationsUtils.flattenGeometryCollection(f)) - : coll.concat({type: "Feature", geometry: f.geometry, properties: {...f.properties, ms_style: annStyleToOlStyle(f.geometry.type, f.style)}}); - }, []); -}; -export const formatCoordinates = (coords = [[]]) => { - return coords.map(c => ({lat: c && c[1], lon: c && c[0]})); -}; -export const getBaseCoord = (type) => { - switch (type) { - case "Polygon": case "LineString": case "MultiPoint": return []; - default: return [[{lat: "", lon: ""}]]; - } -}; -export const getComponents = (geometry) => { - const coordinates = get(geometry, 'coordinates', []); - switch (geometry?.type) { - case "Polygon": { - return AnnotationsUtils.isCompletePolygon(coordinates) ? AnnotationsUtils.formatCoordinates(slice(coordinates[0], 0, coordinates[0].length - 1)) : AnnotationsUtils.formatCoordinates(coordinates[0]); - } - case "LineString": case "MultiPoint": { - return AnnotationsUtils.formatCoordinates(coordinates); - } - default: return AnnotationsUtils.formatCoordinates([coordinates]); - } -}; -export const addIds = (features) => { - return features.map(f => { - if (f.properties && f.properties.id) { - return f; - } - return set("properties.id", uuid.v1(), f); - }); -}; -export const COMPONENTS_VALIDATION = { - "Point": {min: 1, add: false, remove: false, validation: "validateCoordinates", notValid: "Add a valid coordinate to complete the Point"}, - "MultiPoint": {min: 2, add: true, remove: true, validation: "validateCoordinates", notValid: "Add 2 valid coordinates to complete the Polyline"}, - "Polygon": {min: 3, add: true, remove: true, validation: "validateCoordinates", notValid: "Add 3 valid coordinates to complete the Polygon"}, - "LineString": {min: 2, add: true, remove: true, validation: "validateCoordinates", notValid: "Add 2 valid coordinates to complete the Polyline"}, - "Circle": {add: false, remove: false, validation: "validateCircle", notValid: "Add a valid coordinate and a radius (m) to complete the Circle"}, - "Text": {add: false, remove: false, validation: "validateText", notValid: "Add a valid coordinate and a Text value"} -}; -export const validateCoords = ({lat, lon} = {}) => !isNaN(parseFloat(lat)) && !isNaN(parseFloat(lon)); -export const validateCoordsArray = ([lon, lat] = []) => !isNaN(parseFloat(lat)) && !isNaN(parseFloat(lon)); -export const validateCoord = (c) => !isNaN(parseFloat(c)); -export const coordToArray = (c = {}) => [c.lon, c.lat]; -export const validateCoordinates = ({components = [], remove = false, type } = {}) => { - if (components && components.length) { - const validComponents = components.filter(AnnotationsUtils.validateCoords); - if (remove) { - return validComponents.length > AnnotationsUtils.COMPONENTS_VALIDATION[type].min && validComponents.length === components.length; - } - return validComponents.length >= AnnotationsUtils.COMPONENTS_VALIDATION[type].min && validComponents.length === components.length; - } - return false; -}; -export const validateCircle = ({components = [], properties = {radius: 0}} = {}) => { - if (components && components.length) { - const cmp = head(components); - return !isNaN(parseFloat(properties.radius)) && AnnotationsUtils.validateCoords(cmp); - } - return false; -}; -export const validateText = ({components = [], properties = {valueText: ""}} = {}) => { - if (components && components.length) { - const cmp = head(components); - return properties && !!properties.valueText && AnnotationsUtils.validateCoords(cmp); - } - return false; -}; -export const validateFeature = ({components = [[]], type, remove = false, properties = {}} = {}) => { - if (isNil(type)) { - return false; - } - if (type === "Text") { - return AnnotationsUtils.validateText({components, properties}); - } - if (type === "Circle") { - return AnnotationsUtils.validateCircle({components, properties}); - } - return AnnotationsUtils.validateCoordinates({components, remove, type}); -}; -export const updateAllStyles = (ftColl = {}, newStyle = {}) => { - if (ftColl.features && ftColl.features.length) { - return { - ...ftColl, - features: ftColl.features.map(f => assign({}, f, { - style: castArray(f.style).map(s => assign({}, s, newStyle))} - ))}; - } - return ftColl; -}; -export const DEFAULT_SHAPE = "triangle"; -export const DEFAULT_PATH = "product/assets/symbols/"; -export const checkSymbolsError = (symbolErrors, error = "loading_symbols_path") => { - return symbolErrors.length && findIndex(symbolErrors, (s) => s === error) !== -1; -}; -export const isAMissingSymbol = (style) => { - return style.symbolUrlCustomized === require('../product/assets/symbols/symbolMissing.svg'); -}; -/** - * it tells if the filtered list of the coordinates is a geojson polygon, - * with the first point = to the last - * @param {number[[[]]]} coords the coordinates of the polygon - * @return {boolean} true if it is a valid polygon, false otherwise -*/ -export const isCompletePolygon = (coords = [[[]]]) => { - if (coords && coords[0]) { - const validCoords = coords[0].filter(AnnotationsUtils.validateCoordsArray); - return validCoords.length > 3 && head(validCoords)[0] === last(validCoords)[0] && head(validCoords)[1] === last(validCoords)[1]; - } - return false; -}; -/** - * utility to check if the GeoJSON has the annotation model structure i.e. {"type": "ms2-annotations", "features": [list of FeatureCollection]} - * or the imported annotation object's name is of "Annotations" - * @param {object} json GeoJSON/plain object - * @returns {boolean} if the GeoJSON passes is a ms2-annotation or if the name property of the object passed is Annotations - */ -export const isAnnotation = (json) => json?.type === ANNOTATION_TYPE || json?.name === "Annotations"; - -/** - * utility to validate and fix coordinates for selected feature and update corresponding entry in editingFeatures object - * @param selectedFeature - * @param editingFeatures - * @returns {{feature, selected: null}|{feature, selected: ({properties}|*)}} - */ -export const modifySelectedInEdited = (selectedFeature, editingFeatures) => { - if (isNil(selectedFeature)) return { selected: selectedFeature, editing: editingFeatures }; - - const featureTypes = ["LineString", "MultiPoint", "Polygon", "Point"]; - let selected = selectedFeature; - let editing = editingFeatures; - let nullGeometryModifier = false; - switch (selected.geometry.type) { - case "Polygon": { - selected = set("geometry.coordinates", [selected.geometry.coordinates[0].filter(validateCoordsArray)], selected); - break; - } - case "LineString": case "MultiPoint": { - selected = set("geometry.coordinates", selected.geometry.coordinates.filter(validateCoordsArray), selected); - break; - } - // point - default: { - selected = set("geometry.coordinates", [selected.geometry.coordinates].filter(validateCoordsArray)[0] || [], selected); - if (!selected.geometry.coordinates.length) nullGeometryModifier = true; - } - } - - if (selected.properties && selected.properties.isCircle) { - selected = set("geometry", selected.properties.polygonGeom, selected); - } - - let selectedIndex = findIndex(editing.features, (f) => f.properties.id === selected.properties.id); - if (selected.properties.isValidFeature || includes(featureTypes, selected.geometry.type)) { - const tempSelected = nullGeometryModifier ? set('geometry', null, selected) : selected; - if (selectedIndex === -1) { - editing = set(`features`, editing.features.concat([tempSelected]), editing); - } else { - editing = set(`features[${selectedIndex}]`, tempSelected, editing); - } - } - if (selectedIndex !== -1 && !selected.properties.isValidFeature && !includes(featureTypes, selected.geometry.type)) { - editing = set(`features`, editing.features.filter((f, i) => i !== selectedIndex ), editing); - } - - return { selected, editing }; -}; - -AnnotationsUtils = { - ANNOTATION_TYPE, - convertGeoJSONToInternalModel, - getAvailableStyler, - getRelativeStyler, - createFont, - DEFAULT_ANNOTATIONS_STYLES, - STYLE_CIRCLE, - STYLE_POINT_MARKER, - STYLE_POINT_SYMBOL, - STYLE_TEXT, - STYLE_LINE, - STYLE_POLYGON, - getGeometryType, - getGeometryGlyphInfo, - normalizeAnnotation, - removeDuplicate, - circlesToMultiPolygon, - fromCircleToPolygon, - fromTextToPoint, - fromLineStringToGeodesicLineString, - textToPoint, - flattenGeometryCollection, - createGeometryFromGeomFunction, - fromAnnotationToGeoJson, - annotationsToPrint, - formatCoordinates, - getBaseCoord, - getComponents, - addIds, - COMPONENTS_VALIDATION, - validateCoords, - validateCoordsArray, - validateCoord, - coordToArray, - validateCoordinates, - validateCircle, - validateText, - validateFeature, - updateAllStyles, - getStartEndPointsForLinestring, - DEFAULT_SHAPE, - DEFAULT_PATH, - checkSymbolsError, - isAMissingSymbol, - isCompletePolygon, - getDashArrayFromStyle, - isAnnotation, - modifySelectedInEdited -}; - -export default AnnotationsUtils; diff --git a/web/client/utils/SLDUtils.js b/web/client/utils/SLDUtils.js deleted file mode 100644 index 54c0310f96..0000000000 --- a/web/client/utils/SLDUtils.js +++ /dev/null @@ -1,244 +0,0 @@ -/** - * 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. - */ -import assign from 'object-assign'; - -/* eslint-disable */ -import { XLink_1_0 } from 'w3c-schemas'; - -import { - WMS_1_3_0, - SMIL_2_0_Language, - SMIL_2_0, - GML_2_1_2, - GML_3_1_1, - OWS_1_0_0, - Filter_1_1_0, - Filter_1_0_0, - SE_1_1_0, -} from 'ogc-schemas'; - -import { SLD_1_0_0 } from 'ogc-schemas/lib/SLD_1_0_0_GeoServer'; -// Normalize miss vendorOption definition in SLD_1_0_Geoserver ogc schema -SLD_1_0_0.tis[4].ps= [ { - n: 'vendorOption', - mno: 0, - col: true, - en: 'VendorOption', - ti: '.VendorOption'}]; -import { Jsonix } from 'jsonix'; - -const context = new Jsonix.Context([ - XLink_1_0, - WMS_1_3_0, - OWS_1_0_0, - SMIL_2_0_Language, - SMIL_2_0, - GML_2_1_2, - GML_3_1_1, - Filter_1_1_0, - Filter_1_0_0, - SE_1_1_0, - SLD_1_0_0], - { - namespacePrefixes: { - "http://www.opengis.net/ogc": 'ogc', - "http://www.opengis.net/gml": "gml", - "http://www.opengis.net/sld": "sld" - }, - mappingStyle: 'simplified' -}); -/* eslint-enable */ - -const marshall = context.createMarshaller(); - -const rgbToHex = function({r, g, b}) { - return `#${r < 16 ? 0 : ''}${r.toString(16)}${g < 16 ? 0 : ''}${g.toString(16)}${b < 16 ? 0 : ''}${b.toString(16)}`; -}; - -const convertOpacity = function(opacity) { - return {TYPE_NAME: "SLD_1_0_0.ParameterValueType", content: [opacity]}; -}; -const convertColorMapEntry = function(colorMapEntry) { - return colorMapEntry.map((entry) => { - return assign({TYPE_NAME: "SLD_1_0_0.ColorMapEntry"}, entry); - }); -}; -const convertColorMap = function(type, extended, colorMapEntry) { - - return {TYPE_NAME: "SLD_1_0_0.ColorMap", type: type, extended: extended, colorMapEntry: convertColorMapEntry(colorMapEntry)}; -}; -const convertChannel = function(channel) { - return {TYPE_NAME: "SLD_1_0_0.SelectedChannelType", - sourceChannelName: channel}; -}; -const convertVendorOption = function(name, value) { - - return {TYPE_NAME: "SLD_1_0_0.VendorOption", name: name, value: "" + value}; -}; -const convertAlgorithm = function(bandConfig) { - return [ - convertVendorOption("algorithm", bandConfig.algorithm), - convertVendorOption("minValue", bandConfig.min), - convertVendorOption("maxValue", bandConfig.max) - ]; -}; -const convertContrast = function(bandConfig) { - let c = {TYPE_NAME: "SLD_1_0_0.ContrastEnhancement"}; - switch (bandConfig.contrast) { - case 'Normalize': { - c.normalize = {TYPE_NAME: "SLD_1_0_0.Normalize"}; - if (bandConfig.algorithm !== 'none') { - c.normalize.vendorOption = convertAlgorithm(bandConfig); - } - break; - } - case 'Histogram': { - c.histogram = {TYPE_NAME: "SLD_1_0_0.Histogram"}; - break; - } - case 'GammaValue': { - c.gammaValue = bandConfig.gammaValue; - break; - } - default: { - break; - } - } - return c; -}; -const convertOneBandChannel = function(bandConfig, channelType) { - let cs = {TYPE_NAME: "SLD_1_0_0.ChannelSelection"}; - let channel = convertChannel(bandConfig.band); - if (bandConfig.contrast !== 'none') { - channel.contrastEnhancement = convertContrast(bandConfig); - } - cs[channelType] = channel; - return cs; -}; -const convertRGBBandChannel = function(redBand, greenBand, blueBand) { - let red = convertOneBandChannel(redBand, "redChannel"); - let green = convertOneBandChannel(greenBand, "greenChannel"); - let blue = convertOneBandChannel(blueBand, "blueChannel"); - assign(red, green, blue); - return red; -}; - -const getSLDObjc = function(layer, rasterSymbolizer) { - return { - "sld:StyledLayerDescriptor": {"TYPE_NAME": "SLD_1_0_0.StyledLayerDescriptor", "version": "1.0.0", - "namedLayerOrUserLayer": [{"TYPE_NAME": "SLD_1_0_0.NamedLayer", "name": layer.name, - "namedStyleOrUserStyle": [{"TYPE_NAME": "SLD_1_0_0.UserStyle", - "featureTypeStyle": [{"TYPE_NAME": "SLD_1_0_0.FeatureTypeStyle", - "rule": [{"TYPE_NAME": "SLD_1_0_0.Rule", "symbolizer": [{"sld:RasterSymbolizer": rasterSymbolizer}]}]}]}]}]}}; - -}; -export const jsonToSLD = function({styletype, opacity = "1.0", state, layer} = {}) { - - let rasterSymbolizer = {TYPE_NAME: "SLD_1_0_0.RasterSymbolizer"}; - rasterSymbolizer.opacity = convertOpacity(opacity); - switch (styletype) { - case 'pseudo': { - rasterSymbolizer.colorMap = convertColorMap(state.pseudocolor.type, state.pseudocolor.extended, state.pseudocolor.colorMapEntry); - if (state.pseudoband.band !== 'none') { - rasterSymbolizer.channelSelection = convertOneBandChannel(state.pseudoband, "grayChannel"); - } - break; - } - case 'gray': { - rasterSymbolizer.channelSelection = convertOneBandChannel(state.grayband, "grayChannel"); - break; - } - case 'rgb': { - rasterSymbolizer.channelSelection = convertRGBBandChannel(state.redband, state.greenband, state.blueband); - break; - } - default: { - break; - } - } - return marshall.marshalString(getSLDObjc(layer, rasterSymbolizer)); -}; -const getStroke = function({a = 1, r = 0, g = 0, b = 255, width = 1} = {}) { - return {cssParameter: [ - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [rgbToHex({r, g, b})], name: "stroke"}, - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [`${a}`], name: "stroke-opacity"}, - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [`${width}`], name: "stroke-width"} - - ] - }; -}; -const getFill = function({a = 1, r = 0, g = 0, b = 255} = {}) { - return {cssParameter: [ - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [rgbToHex({r, g, b})], name: "fill"}, - {"TYPE_NAME": "SLD_1_0_0.CssParameter", content: [`${a}`], name: "fill-opacity"} - ] - }; - -}; -const getSize = function(size) { - return {"TYPE_NAME": "SLD_1_0_0.ParameterValueType", content: [`${size}`]}; -}; -const getWellKnownName = function(markName) { - return {"TYPE_NAME": "SLD_1_0_0.WellKnownName", content: [markName]}; -}; -const getMark = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.Mark", fill: getFill(symbolyzer.fill), stroke: getStroke({...symbolyzer.color, width: symbolyzer.width}), wellKnownName: getWellKnownName(symbolyzer.markName)}; -}; -const getGraphic = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.Graphic", externalGraphicOrMark: [getMark(symbolyzer)], size: getSize(symbolyzer.radius)}; -}; -const getPolygonSymbolyzer = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.PolygonSymbolizer", fill: getFill(symbolyzer.fill), stroke: getStroke({...symbolyzer.color, width: symbolyzer.width})}; -}; -const getLineSymbolyzer = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.LineSymbolizer", stroke: getStroke({...symbolyzer.color, width: symbolyzer.width})}; -}; -const getPointSymbolyzer = function(symbolyzer) { - return {"TYPE_NAME": "SLD_1_0_0.PointSymbolizer", graphic: getGraphic(symbolyzer)}; -}; - -const getSymbolyzer = function(symbolyzer) { - switch (symbolyzer.type) { - case "Point": - return {"PointSymbolizer": getPointSymbolyzer(symbolyzer)}; - case "Line": - return {"LineSymbolizer": getLineSymbolyzer(symbolyzer)}; - case "Polygon": - return {"PolygonSymbolizer": getPolygonSymbolyzer(symbolyzer)}; - default: - return getPolygonSymbolyzer(symbolyzer); - } -}; - -const getRules = function(rules) { - return rules.map((rule) => { - let den = {}; - if (rule.maxDenominator) { - den.maxScaleDenominator = rule.maxDenominator; - } - if (rule.minDenominator) { - den.minScaleDenominator = rule.minDenominator; - } - return { - "TYPE_NAME": "SLD_1_0_0.Rule", - "symbolizer": [getSymbolyzer(rule.symbol)], - ...den - }; - } - ); -}; - -export const vecStyleToSLD = function({rules = [], layer = {}} = {}) { - return marshall.marshalString({ - "sld:StyledLayerDescriptor": {"TYPE_NAME": "SLD_1_0_0.StyledLayerDescriptor", "version": "1.0.0", - "namedLayerOrUserLayer": [{"TYPE_NAME": "SLD_1_0_0.NamedLayer", "name": layer.name, - "namedStyleOrUserStyle": [{"TYPE_NAME": "SLD_1_0_0.UserStyle", - "featureTypeStyle": [{"TYPE_NAME": "SLD_1_0_0.FeatureTypeStyle", - "rule": getRules(rules)}]}]}]}} - ); -}; diff --git a/web/client/utils/__tests__/LegacyAnnotationsUtils-test.js b/web/client/utils/__tests__/LegacyAnnotationsUtils-test.js deleted file mode 100644 index ab2ffc6c0e..0000000000 --- a/web/client/utils/__tests__/LegacyAnnotationsUtils-test.js +++ /dev/null @@ -1,1010 +0,0 @@ -/* - * 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. -*/ -import expect from 'expect'; - -import feature from '../../test-resources/Annotation_geomColl.json'; -import MarkerUtils from '../MarkerUtils'; - - -import { - getAvailableStyler, - getRelativeStyler, - convertGeoJSONToInternalModel, - DEFAULT_ANNOTATIONS_STYLES, - createFont, - circlesToMultiPolygon, - textToPoint, - flattenGeometryCollection, - normalizeAnnotation, - removeDuplicate, - formatCoordinates, - getComponents, - addIds, - validateCoords, - validateCoordsArray, - validateCoord, - getBaseCoord, - validateText, - validateCircle, - validateCoordinates, - coordToArray, - validateFeature, - fromTextToPoint, - fromCircleToPolygon, - fromAnnotationToGeoJson, - annotationsToPrint, - getStartEndPointsForLinestring, - createGeometryFromGeomFunction, - updateAllStyles, - fromLineStringToGeodesicLineString, - isCompletePolygon, - getDashArrayFromStyle, - getGeometryType, - getGeometryGlyphInfo, - modifySelectedInEdited -} from '../LegacyAnnotationsUtils'; - -const featureCollection = { - features: [{ - type: "Feature", - geometry: { - type: "Point", - coordinates: [1, 1] - }, - properties: { - id: 1 - } - }, - { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[1, 1], [2, 2]] - }, - properties: { - id: 2 - } - }, - { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [ - [ - [1, 45], - [2, 45], - [2, 44], - [1, 44], - [1, 45] - ] - ] - }, - properties: { - id: 3 - } - } - ], - type: "FeatureCollection" -}; -const circle1 = { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [[[1, 1], [2, 2], [3, 3], [1, 1]]] - }, - properties: { - isCircle: true, - radius: 200, - id: "circle1" - } -}; -const circle2 = { - type: "Feature", - geometry: { - type: "Point", - coordinates: [1, 1] - }, - properties: { - polygonGeom: { - type: "Polygon", - coordinates: [[[1, 1], [2, 2], [3, 3], [1, 1]]] - }, - isCircle: true, - radius: 200, - id: "circle1" - } -}; -const textFeature = { - geometry: { - type: "Point", - coordinates: [1, 2] - }, - type: "Feature", - properties: {isText: true, valueText: "pino"} -}; -const geodesicLineString = { - geometry: { - type: "LineString", - coordinates: [[1, 2], [2, 2]] - }, - type: "Feature", - properties: { - useGeodesicLines: true, - id: "geodesic.line", - geometryGeodesic: { - type: "LineString", - coordinates: [[]] - } - } -}; - -describe('Test the AnnotationsUtils', () => { - let old = MarkerUtils.extraMarkers.images[1]; - beforeEach((done) => { - // prevent issues with lazy load in karma by faking image and preloading - MarkerUtils.extraMarkers.images[1] = new Image(); - MarkerUtils.extraMarkers.images[1].onload = () => { - done(); - }; - MarkerUtils.extraMarkers.images[1].src = MarkerUtils.extraMarkers.images[0].src; - }); - afterEach(() => { - MarkerUtils.extraMarkers.images[1] = old; - }); - it('getAvailableStyler for point or MultiPoint', () => { - let stylers = getAvailableStyler({type: "Point"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("marker"); - - stylers = getAvailableStyler({type: "MultiPoint"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("marker"); - }); - it('getAvailableStyler for LineString or MultiLineString', () => { - let stylers = getAvailableStyler({type: "LineString"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("lineString"); - - stylers = getAvailableStyler({type: "MultiLineString"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("lineString"); - }); - it('getAvailableStyler for Polygon or MultiPolygon', () => { - let stylers = getAvailableStyler({type: "Polygon"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("polygon"); - - stylers = getAvailableStyler({type: "MultiPolygon"}); - expect(stylers.length).toBe(1); - expect(stylers[0]).toBe("polygon"); - }); - it('getAvailableStyler for GeometryCollection', () => { - let stylers = getAvailableStyler({type: "GeometryCollection", geometries: - [{type: "MultiPolygon"}, {type: "MultiPoint"}]}); - expect(stylers.length).toBe(2); - expect(stylers[0]).toBe("polygon"); - expect(stylers[1]).toBe("marker"); - - stylers = getAvailableStyler({type: "GeometryCollection", geometries: - [{type: "MultiLineString"}, {type: "MultiPoint"}, {type: "MultiPolygon"}]}); - expect(stylers.length).toBe(3); - expect(stylers[0]).toBe("lineString"); - expect(stylers[1]).toBe("marker"); - expect(stylers[2]).toBe("polygon"); - }); - it('getRelativeStyler for simple Geoms and Text', () => { - let styler = getRelativeStyler("Polygon"); - expect(styler).toBe("polygon"); - styler = getRelativeStyler("MultiPolygon"); - expect(styler).toBe("polygon"); - - styler = getRelativeStyler("MultiPoint"); - expect(styler).toBe("marker"); - styler = getRelativeStyler("Point"); - expect(styler).toBe("marker"); - - styler = getRelativeStyler("MultiLineString"); - expect(styler).toBe("lineString"); - styler = getRelativeStyler("LineString"); - expect(styler).toBe("lineString"); - - styler = getRelativeStyler("Text"); - expect(styler).toBe("text"); - }); - it('default styles text', () => { - const numStyles = Object.keys(DEFAULT_ANNOTATIONS_STYLES); - expect(numStyles.length).toBe(8); - - const textParams = Object.keys(DEFAULT_ANNOTATIONS_STYLES.Text); - expect(textParams.length).toBe(11); - - const {font, color, opacity, fontStyle, fontSize, fontSizeUom, textAlign, fontFamily, fontWeight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.Text; - expect(font).toBe("14px Arial"); - expect(fontStyle).toBe("normal"); - expect(fontWeight).toBe("normal"); - expect(fontSize).toBe("14"); - expect(fontFamily).toBe("Arial"); - expect(fontSizeUom).toBe("px"); - expect(textAlign).toBe("center"); - - expect(color).toBe("#000000"); - expect(opacity).toBe(1); - expect(fillColor).toBe("#000000"); - expect(fillOpacity).toBe(1); - }); - it('default styles Point', () => { - let {iconGlyph, iconShape, iconColor} = DEFAULT_ANNOTATIONS_STYLES.Point; - expect(iconGlyph).toBe("comment"); - expect(iconShape).toBe("square"); - expect(iconColor).toBe("blue"); - }); - it('default styles MultiPoint', () => { - let {iconGlyph, iconShape, iconColor} = DEFAULT_ANNOTATIONS_STYLES.MultiPoint; - expect(iconGlyph).toBe("comment"); - expect(iconShape).toBe("square"); - expect(iconColor).toBe("blue"); - }); - it('default styles LineString', () => { - let {color, opacity, weight} = DEFAULT_ANNOTATIONS_STYLES.LineString; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - }); - it('default styles Circle', () => { - let {color, opacity, weight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.Circle; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - expect(fillColor).toBe("#ffffff"); - expect(fillOpacity).toBe(0.2); - }); - it('default styles MultiLineString', () => { - let {color, opacity, weight} = DEFAULT_ANNOTATIONS_STYLES.MultiLineString; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - }); - it('default styles Polygon', () => { - let {color, opacity, weight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.Polygon; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - expect(fillColor).toBe("#ffffff"); - expect(fillOpacity).toBe(0.2); - }); - it('default styles MultiPolygon', () => { - let {color, opacity, weight, fillColor, fillOpacity} = DEFAULT_ANNOTATIONS_STYLES.MultiPolygon; - expect(color).toBe("#ffcc33"); - expect(opacity).toBe(1); - expect(weight).toBe(3); - expect(fillColor).toBe("#ffffff"); - expect(fillOpacity).toBe(0.2); - }); - it('convertGeoJSONToInternalModel simple geoms', () => { - let newGeom = convertGeoJSONToInternalModel({type: "MultiPoint"}, []); - expect(newGeom.type).toBe("MultiPoint"); - newGeom = convertGeoJSONToInternalModel({type: "MultiPoint"}, ["someval"]); - expect(newGeom.type).toBe("Text"); - newGeom = convertGeoJSONToInternalModel({type: "MultiLineString"}, []); - expect(newGeom.type).toBe("MultiLineString"); - newGeom = convertGeoJSONToInternalModel({type: "LineString"}, []); - expect(newGeom.type).toBe("LineString"); - newGeom = convertGeoJSONToInternalModel({type: "MultiPolygon"}, []); - expect(newGeom.type).toBe("MultiPolygon"); - newGeom = convertGeoJSONToInternalModel({type: "Polygon"}, []); - expect(newGeom.type).toBe("Polygon"); - }); - it('convertGeoJSONToInternalModel multi geoms', () => { - let geometries = [{type: "MultiPolygon"}, {type: "MultiPoint"}]; - let newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, []); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(geometries[i].type); - }); - geometries = [{type: "MultiPolygon"}, {type: "MultiPoint"}]; - - let convertedGeometries = [{type: "MultiPolygon"}, {type: "Text"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - geometries = [{type: "MultiPoint"}, {type: "MultiPoint"}]; - convertedGeometries = [{type: "Text"}, {type: "MultiPoint"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - geometries = [{type: "Polygon"}, {type: "MultiPoint"}]; - convertedGeometries = [{type: "Circle"}, {type: "MultiPoint"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, [], ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - geometries = [{type: "MultiPoint"}, {type: "MultiLineString"}, {type: "MultiPoint"}]; - convertedGeometries = [{type: "Text"}, {type: "MultiLineString"}, {type: "MultiPoint"}]; - newGeom = convertGeoJSONToInternalModel({type: "GeometryCollection", geometries}, ["some va"]); - newGeom.geometries.forEach((g, i) => { - expect(g.type).toBe(convertedGeometries[i].type); - }); - }); - it('create font with values', () => { - // with defaults - expect(createFont({})).toBe("normal normal 14px Arial"); - // with values - expect(createFont({fontFamily: "Courier"})).toBe("normal normal 14px Courier"); - expect(createFont({fontSize: "30"})).toBe("normal normal 30px Arial"); - expect(createFont({fontSizeUom: "em"})).toBe("normal normal 14em Arial"); - expect(createFont({fontStyle: "italic"})).toBe("italic normal 14px Arial"); - expect(createFont({fontWeight: "bold"})).toBe("normal bold 14px Arial"); - }); - it('circlesToMultiPolygon', () => { - const {geometry, properties, style} = feature; - const f = circlesToMultiPolygon(geometry, properties, style.Circle); - expect(f).toExist(); - expect(f.type).toBe("Feature"); - expect(f.geometry.type).toBe("MultiPolygon"); - expect(f.properties).toExist(); - expect(f.properties.ms_style).toExist(); - expect(f.properties.ms_style.strokeColor).toBe(style.Circle.color); - }); - it('fromCircleToPolygon', () => { - const {geometry, properties} = circle1; - const {style} = feature; - const ft = fromCircleToPolygon(geometry, properties, style.Circle); - expect(ft).toExist(); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Polygon"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.isCircle).toBe(undefined); - const {geometry: geometry2, properties: properties2} = circle2; - - const ft2 = fromCircleToPolygon(geometry2, properties2, style.Circle); - expect(ft2.geometry.type).toBe("Polygon"); - expect(ft2.properties.isCircle).toBe(undefined); - }); - it('textToPoint', () => { - const {geometry, properties, style} = feature; - const fts = textToPoint(geometry, properties, style.Text); - expect(fts).toExist(); - expect(fts.length).toBe(2); - expect(fts[0].type).toBe("Feature"); - expect(fts[0].geometry.type).toBe("MultiPoint"); - expect(fts[0].properties).toExist(); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.label).toBe("pino"); - - }); - it('fromTextToPoint', () => { - const {geometry, properties} = textFeature; - const {style} = feature; - const ft = fromTextToPoint(geometry, properties, style.Text); - expect(ft).toExist(); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.ms_style.label).toBe("pino"); - - }); - it('fromAnnotationToGeoJson with a circle', () => { - const ft = fromAnnotationToGeoJson(circle1); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Polygon"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.isCircle).toBe(undefined); - }); - it('fromAnnotationToGeoJson with a geodesic LineString', () => { - const ft = fromAnnotationToGeoJson(geodesicLineString); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("LineString"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.geometryGeodesic).toBe(undefined); - }); - it('fromAnnotationToGeoJson with a text', () => { - const ft = fromAnnotationToGeoJson(textFeature); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.isText).toBe(undefined); - }); - it('fromAnnotationToGeoJson with a point', () => { - const ft = fromAnnotationToGeoJson(featureCollection.features[0]); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - }); - it('fromAnnotationToGeoJson with a LineString in origin, but with a style of a startPoint', () => { - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: getStartEndPointsForLinestring()[0] - }; - const ft = fromAnnotationToGeoJson(f); - expect(ft.type).toBe("Feature"); - expect(ft.geometry.type).toBe("Point"); - expect(ft.geometry.coordinates[0]).toBe(0); - expect(ft.geometry.coordinates[1]).toBe(0); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - }); - it('fromAnnotationToGeoJson with a LineString with dashArray', () => { - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: { - dashArray: [1, 3] - } - }; - const ft = fromAnnotationToGeoJson(f); - expect(ft.type).toBe("Feature"); - expect(ft.properties).toExist(); - expect(ft.properties.ms_style).toExist(); - expect(ft.properties.ms_style.strokeDashstyle).toEqual("1 3"); - }); - it('flattenGeometryCollection', () => { - const fts = flattenGeometryCollection(feature); - expect(fts).toExist(); - expect(fts.length).toBe(9); - expect(fts[6].type).toBe("Feature"); - expect(fts[6].geometry.type).toBe("MultiPolygon"); - expect(fts[6].properties.ms_style).toExist(); - expect(fts[6].properties.ms_style.strokeColor).toBe(feature.style.Circle.color); - expect(fts[6].properties).toExist(); - expect(fts[7].type).toBe("Feature"); - expect(fts[7].geometry.type).toBe("MultiPoint"); - expect(fts[7].properties.ms_style).toExist(); - expect(fts[7].properties.ms_style.label).toBe("pino"); - expect(fts[7].properties).toExist(); - }); - - it('test normalizeAnnotation defaults', () => { - let annotation = normalizeAnnotation(); - expect(annotation.geometry.coordinates).toBe(undefined); - expect(annotation.geometry.type).toBe(undefined); - expect(annotation.properties.title).toBe("Default title"); - }); - it('test normalizeAnnotation with Annotation', () => { - let annotation = normalizeAnnotation(featureCollection); - expect(annotation.type).toBe("FeatureCollection"); - expect(annotation.features[0].geometry.type).toBe("Point"); - expect(annotation.features[1].geometry.type).toBe("LineString"); - - }); - it('test removeDuplicate', () => { - const annotations = [{properties: {id: "id1"}}, {properties: {id: "id2"}}, {properties: {id: "id2"}}]; - expect(removeDuplicate(annotations).length).toBe(2); - }); - it('test formatCoordinates defaults and with data', () => { - expect(formatCoordinates().length).toBe(1); - expect(formatCoordinates()[0].lon).toBe(undefined); - expect(formatCoordinates()[0].lat).toBe(undefined); - - const coords = [[1, 2], [3, 4]]; - expect(formatCoordinates(coords).length).toBe(2); - expect(formatCoordinates(coords)[0].lon).toBe(1); - expect(formatCoordinates(coords)[0].lat).toBe(2); - - const coords2 = [[1, undefined]]; - expect(formatCoordinates(coords2).length).toBe(1); - expect(formatCoordinates(coords2)[0].lon).toBe(1); - expect(formatCoordinates(coords2)[0].lat).toBe(undefined); - }); - - it('test getComponents defaults', () => { - const polygonCoords3 = [[[1, 1], [2, 2], [3, 3], [1, 1]]]; - - let polygonGeom = { - type: "Polygon", - coordinates: polygonCoords3 - }; - expect(getComponents(polygonGeom).length).toBe(3); - - const polygonCoords2 = [[[1, 1], [2, undefined], [3, 3]]]; - let polygonGeom2 = { - type: "Polygon", - coordinates: polygonCoords2 - }; - expect(getComponents(polygonGeom2).length).toBe(3); - - let lineString = { - type: "LineString", - coordinates: polygonCoords2[0] - }; - expect(getComponents(lineString).length).toBe(3); - - let point = { - type: "Point", - coordinates: polygonCoords2[0][0] - }; - expect(getComponents(point).length).toBe(1); - expect(getComponents(point)[0].lon).toBe(1); - expect(getComponents(point)[0].lat).toBe(1); - expect(getComponents(null)[0].lat).toBe(undefined); - expect(getComponents(null)[0].lon).toBe(undefined); - }); - it('test addIds defaults', () => { - const features = [{properties: {id: "some id"}}, {properties: {}}]; - expect(addIds(features).length).toBe(2); - expect(addIds(features).map(f => f.properties.id)[0]).toBe("some id"); - }); - it('test validateCoords ', () => { - expect(validateCoords({lat: undefined, lon: 2})).toBe(false); - expect(validateCoords({lat: 4, lon: 2})).toBe(true); - }); - it('test validateCoordsArray', () => { - expect(validateCoordsArray([undefined, 2])).toBe(false); - expect(validateCoordsArray([4, 2])).toBe(true); - }); - it('test validateCoord', () => { - expect(validateCoord(undefined)).toBe(false); - expect(validateCoord(2)).toBe(true); - }); - it('test coordToArray', () => { - expect(coordToArray()[0]).toBe(undefined); - expect(coordToArray()[1]).toBe(undefined); - expect(coordToArray({lon: 2})[0]).toBe(2); - expect(coordToArray({lon: 2})[1]).toBe(undefined); - expect(coordToArray({lon: 2, lat: 1})[0]).toBe(2); - expect(coordToArray({lon: 2, lat: 1})[1]).toBe(1); - }); - it('test getBaseCoord', () => { - expect(getBaseCoord().length).toBe(1); - expect(getBaseCoord()[0].length).toBe(1); - expect(getBaseCoord("Polygon").length).toBe(0); - expect(getBaseCoord("LineString").length).toBe(0); - expect(getBaseCoord("MultiPoint").length).toBe(0); - }); - it('test validateText defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - properties: { - valueText: "valid" - } - }; - expect(validateText(textAnnot)).toBe(true); - - textAnnot.properties.valueText = ""; - expect(validateText(textAnnot)).toBe(false); - - textAnnot.properties.valueText = "asdgf"; - textAnnot.components = [undefined, 4]; - expect(validateText(textAnnot)).toBe(false); - - textAnnot.components = [undefined, 4]; - expect(validateText(textAnnot)).toBe(false); - }); - it('test validateCircle defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - properties: { - radius: 5 - } - }; - expect(validateCircle({})).toBe(false); - expect(validateCircle(textAnnot)).toBe(true); - - textAnnot.properties.radius = ""; - expect(validateCircle(textAnnot)).toBe(false); - - textAnnot.properties.radius = 50; - textAnnot.components = [undefined, 4]; - expect(validateCircle(textAnnot)).toBe(false); - - textAnnot.components = [undefined, 4]; - expect(validateCircle(textAnnot)).toBe(false); - }); - it('test getGeometryType', ()=>{ - let geomFeature = {}; - expect(getGeometryType(geomFeature)).toBeFalsy(); - - geomFeature = {...geomFeature, properties: {isCircle: true}}; - expect(getGeometryType(geomFeature)).toBe('Circle'); - - geomFeature = {properties: {isText: true}}; - expect(getGeometryType(geomFeature)).toBe('Text'); - - geomFeature = {geometry: {type: "Polygon"}}; - expect(getGeometryType(geomFeature)).toBe('Polygon'); - }); - it('test getGeometryGlyphInfo', ()=>{ - let point = ''; - expect(getGeometryGlyphInfo().glyph).toBe('point'); - - point = 'LineString'; - expect(getGeometryGlyphInfo(point).glyph).toBe('polyline'); - - point = 'Text'; - expect(getGeometryGlyphInfo(point).glyph).toBe('font'); - - point = 'Circle'; - expect(getGeometryGlyphInfo(point).glyph).toBe('1-circle'); - }); - it('test validateCoordinates defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - type: "Point" - }; - expect(validateCoordinates({})).toBe(false); - expect(validateCoordinates(textAnnot)).toBe(true); - textAnnot.components = [[undefined, 4]]; - expect(validateCoordinates(textAnnot)).toBe(false); - textAnnot.components = [{lat: 4, lon: 4}]; - expect(validateCoordinates(textAnnot)).toBe(true); - textAnnot.components = [[undefined, 4]]; - expect(validateCoordinates(textAnnot)).toBe(false); - }); - it('test validateFeature defaults', () => { - let components = [{lat: 4, lon: 4}]; - let textAnnot = { - components, - type: "Point" - }; - expect(validateFeature({})).toBe(false); - expect(validateFeature(textAnnot)).toBe(true); - }); - it('test annotationsToPrint from featureCollection', () => { - let fts = annotationsToPrint([featureCollection]); - expect(fts).toExist(); - expect(fts.length).toBe(3); - expect(fts[0].geometry.type).toBe("Point"); - expect(fts[1].geometry.type).toBe("LineString"); - expect(fts[2].geometry.type).toBe("Polygon"); - }); - it('test annotationsToPrint from array of geometryCollection', () => { - let fts = annotationsToPrint([feature]); - expect(fts).toExist(); - expect(fts.length).toBe(9); - expect(fts[0].geometry.type).toBe("MultiPolygon"); - expect(fts[1].geometry.type).toBe("MultiLineString"); - expect(fts[2].geometry.type).toBe("MultiPoint"); - expect(fts[3].geometry.type).toBe("MultiPoint"); - expect(fts[4].geometry.type).toBe("MultiPoint"); - expect(fts[5].geometry.type).toBe("MultiPoint"); - expect(fts[6].geometry.type).toBe("MultiPolygon"); - expect(fts[7].geometry.type).toBe("MultiPoint"); - expect(fts[8].geometry.type).toBe("MultiPoint"); - }); - it('test annotationsToPrint from a lineString', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: [{ - color: "#FF0000" - }].concat(getStartEndPointsForLinestring()) - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); // filter the style not applied - }); - it('getStartEndPointsForLinestring, defaults', () => { - const styles = getStartEndPointsForLinestring(); - expect(styles.length).toBe(2); - expect(styles[0].iconShape).toBe("square"); - expect(styles[0].iconGlyph).toBe("comment"); - expect(styles[0].iconColor).toBe("blue"); - expect(typeof styles[0].id).toBe("string"); - expect(styles[0].geometry).toBe("startPoint"); - expect(styles[0].filtering).toBe(false); - expect(styles[0].highlight).toBe(true); - expect(styles[0].iconAnchor.length).toBe(2); - expect(styles[0].iconAnchor[0]).toBe(0.5); - expect(styles[0].iconAnchor[1]).toBe(0.5); - expect(styles[0].type).toBe("Point"); - expect(styles[0].title).toBe("StartPoint Style"); - - expect(styles[1].iconShape).toBe("square"); - expect(styles[1].iconGlyph).toBe("comment"); - expect(styles[1].iconColor).toBe("blue"); - expect(typeof styles[1].id).toBe("string"); - expect(styles[1].geometry).toBe("endPoint"); - expect(styles[1].filtering).toBe(false); - expect(styles[1].highlight).toBe(true); - expect(styles[1].iconAnchor.length).toBe(2); - expect(styles[1].iconAnchor[0]).toBe(0.5); - expect(styles[1].iconAnchor[1]).toBe(0.5); - expect(styles[1].type).toBe("Point"); - expect(styles[1].title).toBe("EndPoint Style"); - }); - it('createGeometryFromGeomFunction startPoint', () => { - // feature with start point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: getStartEndPointsForLinestring()[0] - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("Point"); - expect(newGeom.coordinates[0]).toBe(0); - expect(newGeom.coordinates[0]).toBe(0); - }); - it('createGeometryFromGeomFunction startPoint', () => { - // feature with end point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: getStartEndPointsForLinestring()[1] - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("Point"); - expect(newGeom.coordinates[0]).toBe(5); - expect(newGeom.coordinates[0]).toBe(5); - }); - it('createGeometryFromGeomFunction centerPoint', () => { - // feature with end point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [5, 5]] - }, - style: {...getStartEndPointsForLinestring()[1], geometry: "centerPoint"} - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("Point"); - expect(newGeom.coordinates[0]).toBe(2.5); - expect(newGeom.coordinates[0]).toBe(2.5); - }); - it('createGeometryFromGeomFunction lineString', () => { - // feature with end point style but with a linestring ad geom - const f = { - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: { - color: "#FF0000" - } - }; - const newGeom = createGeometryFromGeomFunction(f); - expect(newGeom.type).toBe("LineString"); - expect(newGeom.coordinates[0][0]).toBe(0); - expect(newGeom.coordinates[0][1]).toBe(0); - expect(newGeom.coordinates[3][0]).toBe(5); - expect(newGeom.coordinates[3][1]).toBe(5); - }); - it('updateAllStyles, defaults', () => { - const f = { - type: "FeatureCollection", - features: [] - }; - const newFcoll = updateAllStyles(f); - expect(newFcoll.features.length).toBe(0); - }); - it('updateAllStyles, with new props', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: [{ - color: "#FF0000" - }].concat(getStartEndPointsForLinestring()) - }] - }; - const newFcoll = updateAllStyles(f, {highlight: true}); - expect(newFcoll.features.length).toBe(1); - newFcoll.features.map(ft => { - ft.style.map(s => { - expect(s.highlight).toBe(true); - }); - }); - }); - it('fromLineStringToGeodesicLineString', () => { - const geometryGeodesic = { - type: "LineString", - coordinates: [[1, 1], [2, 2]] - }; - const properties = { - geometryGeodesic, - id: "VR46" - }; - const f = fromLineStringToGeodesicLineString(properties, {color: "#12233"}); - expect(f.geometry).toEqual(geometryGeodesic); - expect(f.type).toEqual("Feature"); - expect(f.properties.id).toEqual("VR46"); - expect(f.properties.ms_style).toExist(); - }); - - it('test isCompletePolygon defaults', () => { - const polygonCoords0 = []; - const polygonCoords1 = [[[1, 1]]]; - const polygonCoords2 = [[[1, 1], [2, 2]]]; - const polygonCoords3 = [[[1, 1], [2, 2], [1, 1]]]; - const polygonCoords4 = [[[1, 1], [2, 2], [3, 3], [1, 1]]]; - const polygonCoords5 = [[[1, 1], [2, undefined], [3, 3], [1, 1]]]; - expect(isCompletePolygon()).toBe(false); - expect(isCompletePolygon(polygonCoords0)).toBe(false); - expect(isCompletePolygon(polygonCoords1)).toBe(false); - expect(isCompletePolygon(polygonCoords2)).toBe(false); - expect(isCompletePolygon(polygonCoords3)).toBe(false); - expect(isCompletePolygon(polygonCoords4)).toBe(true); - expect(isCompletePolygon(polygonCoords5)).toBe(false); - }); - it('test getDashArrayFromStyle', () => { - // default - expect(getDashArrayFromStyle()).toEqual(""); - expect(getDashArrayFromStyle("3 4 5")).toEqual("3 4 5"); - expect(getDashArrayFromStyle(["3", "4", "5"])).toEqual("3 4 5"); - }); - it('test annotationsToPrint strokeDashstyle defaults to solid', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "LineString", - coordinates: [[0, 0], [1, 1], [3, 3], [5, 5]] - }, - style: [{ - color: "#FF0000" - }].concat(getStartEndPointsForLinestring()) - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.strokeDashstyle).toBe('solid'); - }); - - it('test annotationsToPrint text without outline', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "Point", - coordinates: [0, 0] - }, - style: { - color: "#000000", - fillColor: "#000000", - fillOpacity: 1, - font: "14px Arial", - fontFamily: "Arial", - fontSize: "14", - fontSizeUom: "px", - fontStyle: "normal", - fontWeight: "normal", - highlight: false, - label: "test", - opacity: 1, - textAlign: "center", - title: "Text Style", - type: "Text" - } - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.labelOutlineColor).toNotExist(); - }); - - it('test annotationsToPrint text with outline', () => { - const f = { - type: "FeatureCollection", - features: [{ - type: "Feature", - geometry: { - type: "Point", - coordinates: [0, 0] - }, - style: { - color: "#000000", - fillColor: "#000000", - fillOpacity: 1, - font: "14px Arial", - fontFamily: "Arial", - fontSize: "14", - fontSizeUom: "px", - fontStyle: "normal", - fontWeight: "normal", - highlight: false, - label: "test", - opacity: 1, - textAlign: "center", - title: "Text Style", - type: "Text", - weight: 2.0 - }, - properties: { - isText: true - } - }] - }; - let fts = annotationsToPrint([f]); - expect(fts).toExist(); - expect(fts.length).toBe(1); - expect(fts[0].properties.ms_style).toExist(); - expect(fts[0].properties.ms_style.labelOutlineColor).toExist(); - }); - - it('test modifySelectedInEdited', () => { - const selectedPoint = { - type: "Feature", - geometry: { - type: "Point", - coordinates: ['', 1] - }, - properties: { - id: 1 - } - }; - const selectedPolygon = { - type: "Feature", - geometry: { - type: "Polygon", - coordinates: [ - [ - [1, 45], - ['', 45], - [2, 44], - [1, 44], - [1, 45] - ] - ] - }, - properties: { - id: 3 - } - }; - - const { selected: pointSelected, editing: editingWithPoint } = modifySelectedInEdited(selectedPoint, featureCollection); - const { selected: nullSelected, editing: editingWithNull } = modifySelectedInEdited(null, featureCollection); - const { selected: polygonSelected, editing: editingWithPolygon } = modifySelectedInEdited(selectedPolygon, featureCollection); - - expect(Array.isArray(pointSelected.geometry.coordinates)).toBe(true); - expect(pointSelected.geometry.coordinates.length).toBe(0); - expect(editingWithPoint.features[0].geometry).toBe(null); - expect(editingWithPoint.features[0].properties.id).toBe(1); - expect(editingWithPoint.features[1].geometry.coordinates.length).toBe(2); - expect(editingWithPoint.features[2].geometry.coordinates[0].length).toBe(5); - - expect(nullSelected).toBe(null); - expect(editingWithNull.features[0].geometry.coordinates.length).toBe(2); - expect(editingWithNull.features[1].geometry.coordinates.length).toBe(2); - expect(editingWithNull.features[2].geometry.coordinates[0].length).toBe(5); - - expect(polygonSelected.geometry.coordinates[0].length).toBe(4); - expect(editingWithPolygon.features[2].geometry.coordinates[0].length).toBe(4); - expect(editingWithPolygon.features[0].geometry.coordinates.length).toBe(2); - expect(editingWithPolygon.features[1].geometry.coordinates.length).toBe(2); - - }); -}); diff --git a/web/client/utils/__tests__/SLDUtils-test.js b/web/client/utils/__tests__/SLDUtils-test.js deleted file mode 100644 index 3afe7d27bb..0000000000 --- a/web/client/utils/__tests__/SLDUtils-test.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * 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. - */ -import expect from 'expect'; - -import { jsonToSLD, vecStyleToSLD } from '../SLDUtils'; - -const rasterstylerstate = { - redband: {band: '1', contrast: 'GammaValue', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - blueband: {band: '3', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - greenband: {band: '2', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - grayband: {band: '1', contrast: 'none', algorithm: "none", gammaValue: 1, min: 1, max: 255}, - pseudocolor: {colorMapEntry: [{color: "#eff3ff", quantity: 0, label: "0.00"}], type: "ramp", opacity: "1.00"}, - pseudoband: {band: "1", contrast: "Normalize", algorithm: "ClipToMinimumMaximum", min: 1, max: 255} -}; -const layer = {name: "sde:HYP_HR_SR_OB_DR"}; - - -describe('SLDUtils', () => { - - it('convert rasterlayer state to sld strings', () => { - let pseudo = jsonToSLD({ - styletype: "pseudo", - opacity: "0.50", - state: rasterstylerstate, - layer: layer}); - expect(pseudo).toExist(); - let rgb = jsonToSLD( - { - styletype: "rgb", - opacity: "0.50", - state: rasterstylerstate, - layer: layer - }); - expect(rgb).toExist(); - let gray = jsonToSLD({ - styletype: "gray", - opacity: "0.50", - state: rasterstylerstate, - layer: layer - }); - expect(gray).toExist(); - }); - it('test vectorlayer state to sld strings', () => { - let rules = [ - { - "id": "bd8587a0-543a-11e6-a812-3f41916af8df", - "symbol": { - "type": "Point", - "color": {"r": 0, "g": 0, "b": 255, "a": 1}, - "width": 3, - "fill": {"r": 0, "g": 0, "b": 255, "a": 0.1}, - "radius": 10, - "marker": false, - "markName": "circle" - }, - "name": "Test Name"}, - { - "id": "dfcce690-543b-11e6-a812-3f41916af8df", - "symbol": { - "type": "Polygon", - "color": {"r": 0, "g": 0, "b": 255, "a": 1}, - "width": 3, - "fill": {"r": 0, "g": 0, "b": 255, "a": 0.1} - }, - "name": "Test Name"}, - { - "id": "406d88b0-543c-11e6-a812-3f41916af8df", - "symbol": { - "type": "Line", - "color": {"r": 0, "g": 0, "b": 255, "a": 1}, - "width": 3 - }, - "name": "Test Name", - "minDenominator": 73957338.86364141, - "maxDenominator": 295829355.45456564} - ]; - let result = `sde:HYP_HR_SR_OB_DRcircle#0000ff0.1#0000ff1310#0000ff0.1#0000ff1373957338.86364141295829355.45456564#0000ff13`; - let sld = vecStyleToSLD({ - rules, - layer}); - expect(sld).toExist(); - expect(sld).toEqual(result); - }); -}); From 927ae59593308f3da30d944f140c6c8ceeaf8df1 Mon Sep 17 00:00:00 2001 From: allyoucanmap Date: Thu, 8 Aug 2024 11:08:25 +0200 Subject: [PATCH 2/4] remove additional code from review --- package.json | 4 - web/client/actions/__tests__/importer-test.js | 315 -------- web/client/actions/__tests__/tasks-test.js | 72 -- web/client/actions/importer.js | 721 ------------------ web/client/actions/share.js | 16 - web/client/actions/tasks.js | 47 -- web/client/api/MapConfigDAO.js | 41 - .../manager/importer/BreadCrumb.jsx | 68 -- .../components/manager/importer/Import.jsx | 170 ----- .../components/manager/importer/Importer.jsx | 263 ------- .../manager/importer/ImportsGrid.jsx | 123 --- .../components/manager/importer/Layer.jsx | 99 --- .../components/manager/importer/Task.jsx | 160 ---- .../manager/importer/TaskProgress.jsx | 56 -- .../components/manager/importer/Transform.jsx | 81 -- .../manager/importer/TransformsGrid.jsx | 78 -- .../components/manager/importer/Workspace.jsx | 115 --- .../manager/importer/style/importer.css | 6 - .../importer/transforms/GdalAddoTransform.jsx | 58 -- .../transforms/GdalTranslateTransform.jsx | 56 -- .../importer/transforms/GdalWarpTransform.jsx | 9 - .../manager/importer/transforms/index.js | 10 - .../search/geocoding/NominatimResult.jsx | 39 - .../search/geocoding/NominatimResultList.jsx | 86 --- .../__tests__/NominatimResult-test.jsx | 60 -- .../__tests__/NominatimResultList-test.jsx | 70 -- web/client/components/maps/MapItem.jsx | 51 -- web/client/components/maps/MapList.jsx | 51 -- .../maps/__tests__/MapItem-test.jsx | 64 -- .../maps/__tests__/MapList-test.jsx | 74 -- web/client/containers/HolyGrail.jsx | 65 -- web/client/observables/ogcDimension.js | 7 - web/client/plugins/manager/Importer.jsx | 208 ----- web/client/reducers/__tests__/tasks-test.js | 62 -- web/client/reducers/importer.js | 408 ---------- web/client/reducers/tasks.js | 49 -- web/client/utils/AgentUtils.js | 20 - 37 files changed, 3882 deletions(-) delete mode 100644 web/client/actions/__tests__/importer-test.js delete mode 100644 web/client/actions/__tests__/tasks-test.js delete mode 100644 web/client/actions/importer.js delete mode 100644 web/client/actions/share.js delete mode 100644 web/client/actions/tasks.js delete mode 100644 web/client/api/MapConfigDAO.js delete mode 100644 web/client/components/manager/importer/BreadCrumb.jsx delete mode 100644 web/client/components/manager/importer/Import.jsx delete mode 100644 web/client/components/manager/importer/Importer.jsx delete mode 100644 web/client/components/manager/importer/ImportsGrid.jsx delete mode 100644 web/client/components/manager/importer/Layer.jsx delete mode 100644 web/client/components/manager/importer/Task.jsx delete mode 100644 web/client/components/manager/importer/TaskProgress.jsx delete mode 100644 web/client/components/manager/importer/Transform.jsx delete mode 100644 web/client/components/manager/importer/TransformsGrid.jsx delete mode 100644 web/client/components/manager/importer/Workspace.jsx delete mode 100644 web/client/components/manager/importer/style/importer.css delete mode 100644 web/client/components/manager/importer/transforms/GdalAddoTransform.jsx delete mode 100644 web/client/components/manager/importer/transforms/GdalTranslateTransform.jsx delete mode 100644 web/client/components/manager/importer/transforms/GdalWarpTransform.jsx delete mode 100644 web/client/components/manager/importer/transforms/index.js delete mode 100644 web/client/components/mapcontrols/search/geocoding/NominatimResult.jsx delete mode 100644 web/client/components/mapcontrols/search/geocoding/NominatimResultList.jsx delete mode 100644 web/client/components/mapcontrols/search/geocoding/__tests__/NominatimResult-test.jsx delete mode 100644 web/client/components/mapcontrols/search/geocoding/__tests__/NominatimResultList-test.jsx delete mode 100644 web/client/components/maps/MapItem.jsx delete mode 100644 web/client/components/maps/MapList.jsx delete mode 100644 web/client/components/maps/__tests__/MapItem-test.jsx delete mode 100644 web/client/components/maps/__tests__/MapList-test.jsx delete mode 100644 web/client/containers/HolyGrail.jsx delete mode 100644 web/client/observables/ogcDimension.js delete mode 100644 web/client/plugins/manager/Importer.jsx delete mode 100644 web/client/reducers/__tests__/tasks-test.js delete mode 100644 web/client/reducers/importer.js delete mode 100644 web/client/reducers/tasks.js delete mode 100644 web/client/utils/AgentUtils.js diff --git a/package.json b/package.json index 84d2d813a8..d22a7d1c18 100644 --- a/package.json +++ b/package.json @@ -153,8 +153,6 @@ "@turf/point-on-surface": "4.1.0", "@turf/polygon-to-linestring": "4.1.0", "@znemz/cesium-navigation": "4.0.0", - "ag-grid-community": "20.2.0", - "ag-grid-react": "20.2.0", "assert": "2.0.0", "axios": "0.28.1", "b64-to-blob": "1.2.19", @@ -168,7 +166,6 @@ "chroma-js": "1.3.7", "classnames": "2.2.5", "codemirror": "5.18.2", - "colorbrewer": "1.0.0", "concurrently": "6.4.0", "connected-react-router": "6.3.2", "create-react-class": "15.6.3", @@ -241,7 +238,6 @@ "react-checkbox-tree": "1.5.1", "react-codemirror2": "4.0.0", "react-color": "2.17.0", - "react-confirm-button": "0.0.2", "react-container-dimensions": "1.4.1", "react-contenteditable": "3.3.2", "react-copy-to-clipboard": "5.0.0", diff --git a/web/client/actions/__tests__/importer-test.js b/web/client/actions/__tests__/importer-test.js deleted file mode 100644 index 8a1d78e058..0000000000 --- a/web/client/actions/__tests__/importer-test.js +++ /dev/null @@ -1,315 +0,0 @@ -/** - * 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. - */ - -import expect from 'expect'; - -import { - IMPORTS_LOADING, - loadImports, - IMPORTS_LIST_LOADED, - loadImport, - IMPORT_LOADED, - createImport, - IMPORT_CREATED, - deleteImport, - IMPORT_DELETE, - runImport, - IMPORT_RUN_SUCCESS, - loadLayer, - LAYER_LOADED, - updateLayer, - loadTask, - IMPORTS_TASK_LOADED, - updateTask, - IMPORTS_TASK_UPDATED, - deleteTask, - IMPORTS_TASK_DELETE, - loadTransform, - IMPORTS_TRANSFORM_LOAD, - updateTransform, - IMPORTS_TRANSFORM_UPDATED, - editTransform, - IMPORTS_TRANSFORM_CHANGE, - deleteTransform, - IMPORTS_TRANSFORM_DELETE, - loadStylerTool, - selectWorkSpace, - loadWorkspaces, - createWorkspace, - IMPORTER_WORKSPACE_LOADED, - IMPORTER_WORKSPACE_SELECTED, - IMPORTER_WORKSPACE_CREATED, - dismissWorkspaceCreationStatus, - IMPORTER_WORKSPACE_STATUS_CHANGE -} from '../importer'; - -import { MAP_CONFIG_LOADED } from '../config'; - -/* This utility function runs a serie of test on an action creator - with multiple dispatch inside - You have to pass an array of functions that tests the action dispatched by - the action creator. TODO evaulate to put in a TestUtils. -*/ -const runAsyncTest = (url, action, tests, done, params = [], state) => { - let count = 0; - action(url, ...params)((actionResult) => { - try { - tests[count](actionResult); - count++; - if (count === tests.length - 1) { - done(); - } - } catch (e) { - done(e); - } - - - }, () => state); -}; -// NOTE use # to skip parameters by the API -describe('Test correctness of the importer actions', () => { - // most common test - const testLoading = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_LOADING); - }; - it('load imports list loading', (done) => { - const testImports = (actionResult) => { - let imports = actionResult && actionResult.imports; - expect(actionResult.type).toBe(IMPORTS_LIST_LOADED); - expect(imports).toExist(); - expect(imports.length).toBe(2); - }; - let url = 'base/web/client/test-resources/importer/imports.json#'; - let tests = [testLoading, testImports, testLoading ]; - runAsyncTest(url, loadImports, tests, done); - }); - it('single import load', (done) => { - const testImportCreation = (actionResult) => { - expect(actionResult.type).toBe(IMPORT_LOADED); - }; - let url = 'base/web/client/test-resources/importer/import.json#'; - let tests = [testLoading, testImportCreation ]; - runAsyncTest(url, loadImport, tests, done); - }); - it('import creation', (done) => { - const testImportCreation = (actionResult) => { - expect(actionResult.type).toBe(IMPORT_CREATED); - }; - let url = 'base/web/client/test-resources/importer/import.json#'; - let tests = [testLoading, testImportCreation ]; - runAsyncTest(url, createImport, tests, done, [1]); - }); - it('import delete', (done) => { - const testDeleteImport = (actionResult) => { - expect(actionResult.type).toBe(IMPORT_DELETE); - expect(actionResult.id).toBe(1); - }; - let url = 'base/web/client/test-resources/importer/import.json#'; - let tests = [testLoading, testDeleteImport, testLoading ]; - runAsyncTest(url, deleteImport, tests, done, [1]); - }); - it('import run', (done) => { - const testRunImport = (actionResult) => { - expect(actionResult.type).toBe(IMPORT_RUN_SUCCESS); - expect(actionResult.importId).toBe(1); - }; - let url = 'base/web/client/test-resources/importer/import.json#'; - let tests = [testLoading, testRunImport, testLoading ]; - runAsyncTest(url, runImport, tests, done, [1]); - }); - - // layer - it('layer load', (done) => { - const testLoadLayer = (actionResult) => { - expect(actionResult.type).toBe(LAYER_LOADED); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - expect(actionResult.layer).toExist(); - }; - let url = 'base/web/client/test-resources/importer/layer.json#'; - let tests = [testLoading, testLoadLayer, testLoading ]; - runAsyncTest(url, loadLayer, tests, done, [1, 2]); - }); - - it('layer update', (done) => { - const testLoadLayer = (actionResult) => { - expect(actionResult.type).toBe(LAYER_LOADED); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - }; - let url = 'base/web/client/test-resources/importer/task.json#'; - let tests = [testLoading, testLoadLayer, testLoading ]; - runAsyncTest(url, updateLayer, tests, done, [1, 2]); - }); - - // task - it('task load', (done) => { - const testLoadLayer = () => { - - }; - const testLoadTask = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TASK_LOADED); - expect(actionResult.task).toExist(); - }; - let url = 'base/web/client/test-resources/importer/task.json#'; - let tests = [testLoading, testLoadTask, testLoadLayer, testLoading ]; - runAsyncTest(url, loadTask, tests, done); - }); - // task - it('task update', (done) => { - const testLoadLayer = () => { - - }; - const testLoadTask = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TASK_UPDATED); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - expect(actionResult.task).toExist(); - }; - const testUpdateUI = (fun) => { - expect(fun).toExist(); - fun('base/web/client/test-resources/importer/task.json#', 1, 2); - }; - let url = 'base/web/client/test-resources/importer/task.json#'; - let state = { - importer: { - selectedImport: { - id: 1, - targetWorkspace: { - workspace: { - name: "TEST" - } - } - } - } - }; - let tests = [testLoading, testLoadTask, testLoadLayer, testUpdateUI]; - runAsyncTest(url, updateTask, tests, done, [1, 2, {}], state ); - - }); - - it('task element update', (done) => { - const testLoadLayer = () => { - - }; - const testLoadTask = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TASK_UPDATED); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - expect(actionResult.task).toExist(); - }; - let url = 'base/web/client/test-resources/importer/task.json#'; - let tests = [testLoading, testLoadTask, testLoadLayer, testLoading ]; - runAsyncTest(url, updateTask, tests, done, [1, 2, {}, "target"]); - }); - it('task delete', (done) => { - const testdeleteTask = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TASK_DELETE); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - }; - let url = 'base/web/client/test-resources/importer/task.json#'; - let tests = [testLoading, testdeleteTask, testLoading ]; - runAsyncTest(url, deleteTask, tests, done, [1, 2, {}]); - }); - - // transform - it('transform load', (done) => { - const testLoadTransform = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TRANSFORM_LOAD); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - expect(actionResult.transformId).toBe(3); - expect(actionResult.transform).toExist(); - }; - let url = 'base/web/client/test-resources/importer/transform.json#'; - let tests = [testLoading, testLoadTransform, testLoading ]; - runAsyncTest(url, loadTransform, tests, done, [1, 2, 3]); - }); - // transform - it('transform update', (done) => { - const testUpdateTransform = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TRANSFORM_UPDATED); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - expect(actionResult.transformId).toBe(3); - }; - let url = 'base/web/client/test-resources/importer/transform.json#'; - let tests = [testLoading, testUpdateTransform, testLoading ]; - runAsyncTest(url, updateTransform, tests, done, [1, 2, 3]); - }); - // transform - it('transform delete', (done) => { - const testdeleteTransform = (actionResult) => { - expect(actionResult.type).toBe(IMPORTS_TRANSFORM_DELETE); - expect(actionResult.importId).toBe(1); - expect(actionResult.taskId).toBe(2); - expect(actionResult.transformId).toBe(3); - }; - let url = 'base/web/client/test-resources/importer/transform.json#'; - let tests = [testLoading, testdeleteTransform, testLoading ]; - runAsyncTest(url, deleteTransform, tests, done, [1, 2, 3]); - }); - - it('transform edit', () => { - let transform = {options: [1, 2, 3]}; - const result = editTransform(transform); - expect(result.type).toBe(IMPORTS_TRANSFORM_CHANGE); - expect(result.transform).toBe(transform); - }); - // load styler - it('load styler tool', (done) => { - const testConfigureMap = (actionResult) => { - expect(actionResult.type).toBe(MAP_CONFIG_LOADED); - expect(actionResult.config).toExist(); - expect(actionResult.config.map).toExist(); - expect(actionResult.config.map.layers).toExist(); - expect(actionResult.config.map.layers.length).toBe(2); - done(); - }; - let url = 'base/web/client/test-resources/importer/layer.json#'; - let tests = [testConfigureMap]; - runAsyncTest(url, loadStylerTool, tests, done, [], {importer: {selectedImport: {targetWorkspace: { workspace: {name: "TEST"}}}}}); - }); - // select workspace - it('load styler tool', () => { - const wsName = "worskpace_name"; - let res = selectWorkSpace(wsName); - expect(res).toExist(); - expect(res.type).toBe(IMPORTER_WORKSPACE_SELECTED); - expect(res.workspace).toBe(wsName); - }); - - // load workspaces - it('load workspaces', (done) => { - const testWorkspaces = (actionResult) => { - expect(actionResult.type).toBe(IMPORTER_WORKSPACE_LOADED); - done(); - }; - let url = 'base/web/client/test-resources/geoserver/rest/workspaces.json#'; - let tests = [testWorkspaces]; - runAsyncTest(url, loadWorkspaces, tests, done, []); - }); - // load workspaces - it('create workspace', (done) => { - const testWorkspaceCreated = (actionResult) => { - expect(actionResult.type).toBe(IMPORTER_WORKSPACE_CREATED); - done(); - }; - let url = 'base/web/client/test-resources/geoserver/rest/workspaces.json#'; - let tests = [testLoading, testWorkspaceCreated]; - runAsyncTest(url, createWorkspace, tests, done, []); - }); - // load workspaces - it('update workspace creation status', () => { - let res = dismissWorkspaceCreationStatus(); - expect(res).toExist(); - expect(res.type).toBe(IMPORTER_WORKSPACE_STATUS_CHANGE); - }); - -}); diff --git a/web/client/actions/__tests__/tasks-test.js b/web/client/actions/__tests__/tasks-test.js deleted file mode 100644 index 951b7917ae..0000000000 --- a/web/client/actions/__tests__/tasks-test.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright 2015, 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. - */ - -import expect from 'expect'; - -import { - taskSuccess, - taskStarted, - taskError, - startTask, - TASK_STARTED, - TASK_SUCCESS, - TASK_ERROR -} from '../tasks'; - -describe('Test correctness of the tasks actions', () => { - it('test taskSuccess action', () => { - let result = {value: "true"}; - let name = "myName"; - let actionPayload = null; - const retVal = taskSuccess(result, name, actionPayload); - expect(retVal).toExist(); - expect(retVal.type).toBe(TASK_SUCCESS); - expect(retVal.result).toBe(result); - expect(retVal.name).toBe(name); - expect(retVal.actionPayload).toBe(null); - }); - - it('test taskError action', () => { - let error = {value: "true"}; - let name = "myName"; - let actionPayload = null; - const retVal = taskError(error, name, actionPayload); - expect(retVal).toExist(); - expect(retVal.type).toBe(TASK_ERROR); - expect(retVal.error).toBe(error); - expect(retVal.name).toBe(name); - expect(retVal.actionPayload).toBe(null); - }); - - - it('test taskStarted action', () => { - let name = "myName"; - const retVal = taskStarted(name); - expect(retVal).toExist(); - expect(retVal.type).toBe(TASK_STARTED); - expect(retVal.name).toBe(name); - }); - - it('startTask', done => { - let started = false; - let executed = false; - let dispatchable = startTask((payload, callback) => {executed = true; expect(payload).toBe("payload"); callback(); }, "payload", "task", "actionPayload"); - dispatchable((action) => { - if (action.type === TASK_STARTED) { - expect(action.name).toBe("task"); - started = true; - } - if (action.type === TASK_SUCCESS) { - expect(action.actionPayload).toBe("actionPayload"); - expect(started).toBe(true); - expect(executed).toBe(true); - done(); - } - }); - }); -}); diff --git a/web/client/actions/importer.js b/web/client/actions/importer.js deleted file mode 100644 index 6218eaa211..0000000000 --- a/web/client/actions/importer.js +++ /dev/null @@ -1,721 +0,0 @@ -/** - * 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. - */ -import API from '../api/geoserver/Importer'; - -import Workspaces from '../api/geoserver/Workspaces'; -import { configureMap } from './config'; -import { isString } from 'lodash'; -import assign from 'object-assign'; -export const IMPORTS_LOADING = 'IMPORTS_LOADING'; -export const IMPORTS_CREATION_ERROR = 'IMPORTS_CREATION_ERROR'; -export const IMPORT_CREATED = 'IMPORT_CREATED'; - -export const IMPORTS_TASK_CREATED = 'IMPORTS_TASK_CREATED'; -export const IMPORTS_TASK_LOADED = 'IMPORTS_TASK_LOADED'; -export const IMPORTS_TASK_LOAD_ERROR = 'IMPORTS_TASK_LOAD_ERROR'; -export const IMPORTS_TASK_UPDATED = 'IMPORTS_TASK_UPDATED'; -export const IMPORTS_TASK_DELETE = 'IMPORTS_TASK_DELETE'; -export const IMPORTS_TASK_CREATION_ERROR = 'IMPORTS_TASK_CREATION_ERROR'; - -export const LAYER_LOADED = 'LAYER_LOADED'; -export const LAYER_UPDATED = 'LAYER_UPDATED'; - -export const IMPORTS_TRANSFORM_LOAD = 'IMPORTS_TRANSFORM_LOAD'; -export const IMPORTS_TRANSFORM_LOAD_ERROR = 'IMPORTS_TRANSFORM_LOAD_ERROR'; -export const IMPORTS_TRANSFORM_CHANGE = 'IMPORTS_TRANSFORM_CHANGE'; - -export const IMPORTS_TRANSFORM_DELETE = 'IMPORTS_TRANSFORM_DELETE'; -export const IMPORTS_TRANSFORM_UPDATED = 'IMPORTS_TRANSFORM_UPDATED'; - -export const IMPORTS_FILE_UPLOADED = 'IMPORTS_FILE_UPLOADED'; -export const IMPORTS_UPLOAD_PROGRESS = 'IMPORTS_UPLOAD_PROGRESS'; - -export const IMPORTS_LIST_LOADED = 'IMPORTS_LIST_LOADED'; -export const IMPORTS_LIST_LOAD_ERROR = 'IMPORTS_LIST_LOAD_ERROR'; -export const TASK_PROGRESS_UPDATED = 'TASK_PROGRESS_UPDATED'; - -export const IMPORT_LOADED = 'IMPORT_LOADED'; -export const IMPORT_LOAD_ERROR = 'IMPORT_LOAD_ERROR'; -export const IMPORT_RUN_SUCCESS = 'IMPORT_RUN_SUCCESS'; -export const IMPORT_RUN_ERROR = 'IMPORT_RUN_ERROR'; -export const IMPORT_DELETE = 'IMPORT_DELETE'; -export const IMPORT_DELETE_ERROR = 'IMPORT_DELETE_ERROR'; - -export const IMPORTER_WORKSPACE_SELECTED = 'IMPORTER_WORKSPACE_SELECTED'; -export const IMPORTER_WORKSPACE_LOADED = 'IMPORTER_WORKSPACE_LOADED'; -export const IMPORTER_WORKSPACE_CREATED = 'IMPORTER_WORKSPACE_CREATED'; -export const IMPORTER_WORKSPACE_CREATION_ERROR = 'IMPORTER_WORKSPACE_CREATION_ERROR'; -export const IMPORTER_WORKSPACE_STATUS_CHANGE = 'IMPORTER_WORKSPACE_STATUS_CHANGE'; -/** *****************/ -/* UTILITY */ -/** *****************/ - -/** - * Check if task matches with the preset. - * The match is by state, data.file.format and data.file.name - * (also regex allowed for file name). - */ -export const matchPreset = function(preset, task) { - if (preset.state && preset.state !== task.state) { - return false; - } - if (preset.data && task.data) { - if (preset.data.format && preset.data.format !== task.data.format) { - return false; - } - if (preset.data.file && preset.data.file !== task.data.file) { - try { - let patt = new RegExp(preset.data.file); - if (!patt.test(task.data.file)) { - return false; - } - } catch (e) { - return false; - } - - } - } - return true; -}; -// for the moment supports only dataStore.name with only one change -export const applyPlaceholders = function(preset, model) { - - let replaceTargetWorkspace = function(el) { - if (isString(el)) { - return el.replace("{targetWorkspace}", model.targetWorkspace && model.targetWorkspace.workspace && model.targetWorkspace.workspace.name); - } - return el; - }; - if (preset && preset.changes && preset.changes.target && preset.changes.target.dataStore && preset.changes.target.dataStore.name) { - return assign({}, preset, { - changes: assign({}, preset.changes, { - target: assign({}, preset.changes.target, { - dataStore: assign({}, preset.changes.target.dataStore, { - name: replaceTargetWorkspace(preset.changes.target.dataStore.name) - }) - }) - }) - }); - } - return preset; - -}; -/** *****************/ -/* ACTION CREATORS */ -/** *****************/ - -export function loading(details, isLoading = true) { - return { - type: IMPORTS_LOADING, - loading: isLoading, - details: details - }; -} -export function loadError(e) { - return { - type: IMPORTS_LIST_LOAD_ERROR, - error: e - }; -} - -/** IMPORT **/ -export function importCretationError(e) { - return { - type: IMPORTS_CREATION_ERROR, - error: e - }; -} -export function importCreated(importObj) { - return { - type: IMPORT_CREATED, - "import": importObj - }; -} - -export function importTaskCreated(importId, tasks) { - return { - type: IMPORTS_TASK_CREATED, - importId: importId, - tasks: tasks - }; -} - -export function importTaskUpdated(task, importId, taskId) { - return { - type: IMPORTS_TASK_UPDATED, - task, - importId, - taskId - }; -} - -export function importTaskDeleted(importId, taskId) { - return { - type: IMPORTS_TASK_DELETE, - importId, - taskId - }; -} - -export function importsLoaded(imports) { - return { - type: IMPORTS_LIST_LOADED, - imports: imports - }; -} - -export function importLoaded(importObj) { - return { - type: IMPORT_LOADED, - "import": importObj - }; -} -export function importLoadError(e) { - return { - type: IMPORT_LOAD_ERROR, - "error": e - }; -} - -export function importRunSuccess(importId) { - return { - type: IMPORT_RUN_SUCCESS, - importId - }; -} - -export function importRunError(importId, error) { - return { - type: IMPORT_RUN_ERROR, - importId, - error - }; -} -export function importDeleted(id) { - return { - type: IMPORT_DELETE, - id: id - }; -} - -export function importDeleteError(id, e) { - return { - type: IMPORT_DELETE_ERROR, - error: e, - id - }; -} - -/** TASKS **/ - -export function importTaskLoaded(task) { - return { - type: IMPORTS_TASK_LOADED, - task: task - }; -} -export function importTaskLoadError(e) { - return { - type: IMPORTS_TASK_LOAD_ERROR, - task: e - }; -} -export function importTaskCreationError(e) { - return { - type: IMPORTS_TASK_CREATION_ERROR, - error: e - }; -} - -export function layerLoaded(importId, taskId, layer) { - return { - type: LAYER_LOADED, - importId, - taskId, - layer - }; -} - -export function layerUpdated(importId, taskId, layer) { - return { - type: LAYER_LOADED, - importId, - taskId, - layer - }; -} -export function taskProgressUpdated(importId, taskId, info) { - return { - type: TASK_PROGRESS_UPDATED, - importId, - taskId, - info - }; -} -/** TRANSFORMS **/ -export function transformLoaded(importId, taskId, transformId, transform) { - return { - type: IMPORTS_TRANSFORM_LOAD, - importId, - taskId, - transformId, - transform - }; -} - -export function editTransform(transform) { - return { - type: IMPORTS_TRANSFORM_CHANGE, - transform - }; -} - -export function transformLoadError(importId, taskId, transformId, error) { - return { - type: IMPORTS_TRANSFORM_LOAD_ERROR, - importId, - taskId, - transformId, - error - }; -} -export function transformDeleted(importId, taskId, transformId) { - return { - type: IMPORTS_TRANSFORM_DELETE, - importId, - taskId, - transformId - }; -} -export function transformUpdated(importId, taskId, transformId, transform) { - return { - type: IMPORTS_TRANSFORM_UPDATED, - importId, - taskId, - transformId, - transform - }; -} -/** FILE UPLOAD **/ -export function fileUploaded(files) { - return { - type: IMPORTS_FILE_UPLOADED, - "files": files - }; -} - -export function uploadProgress(progress) { - return { - type: IMPORTS_UPLOAD_PROGRESS, - progress: progress - }; -} - -/** WORKSPACES **/ -export function selectWorkSpace(workspace) { - return { - type: IMPORTER_WORKSPACE_SELECTED, - workspace: workspace - }; -} -export function workspacesLoaded(workspaces) { - return { - type: IMPORTER_WORKSPACE_LOADED, - workspaces: workspaces - }; -} - -export function workspaceCreated(name) { - return { - type: IMPORTER_WORKSPACE_CREATED, - name - }; -} -export function workspaceCreationError(name, error) { - return { - type: IMPORTER_WORKSPACE_CREATION_ERROR, - name, - error - }; -} -/** *****************/ -/* DISPATCHERS */ -/** *****************/ - -/** IMPORT **/ -export function createImport(geoserverRestURL, body = {}) { - return (dispatch) => { - dispatch(loading()); - let options = { - headers: { - 'Content-Type': 'application/json' - } - }; - API.createImport(geoserverRestURL, body, options).then((response) => { - dispatch(importCreated(response && response.data && response.data.import)); - dispatch(loading(null, false)); - }).catch((e) => { - dispatch(importCretationError(e)); - dispatch(loading(null, false)); - }); - }; -} -export function loadImports(geoserverRestURL) { - return (dispatch) => { - dispatch(loading()); - API.getImports(geoserverRestURL).then((response) => { - dispatch(importsLoaded(response && response.data && response.data.imports)); - dispatch(loading(null, false)); - }).catch((e) => { - dispatch(loadError(e)); - dispatch(loading(null, false)); - }); - }; -} - -export function loadImport(geoserverRestURL, importId) { - return (dispatch) => { - dispatch(loading({importId: importId})); - API.loadImport(geoserverRestURL, importId).then((response) => { - dispatch(importLoaded(response && response.data && response.data.import)); - dispatch(loading({importId: importId}, false)); - }).catch((e) => { - dispatch(importLoadError(e)); - dispatch(loading({importId: importId}, false)); - }); - }; -} -export function deleteImport(geoserverRestURL, importId) { - return (dispatch) => { - dispatch(loading({importId: importId, message: "deleting"})); - API.deleteImport(geoserverRestURL, importId).then(() => { - dispatch(importDeleted(importId)); - dispatch(loading({importId: importId, message: "deleting"}, false)); - }).catch((e) => { - dispatch(importDeleteError(importId, e)); - dispatch(loading({importId: importId, message: "deleting"}, false)); - }); - }; -} - -export function runImport(geoserverRestURL, importId) { - return (dispatch, getState) => { - dispatch(loading({importId})); - API.runImport(geoserverRestURL, importId).then(() => { - dispatch(importRunSuccess(importId)); - if (getState && getState().selectedImport && getState().selectedImport.id === importId) { - dispatch(loading({importId}, false)); - dispatch(loadImport(geoserverRestURL, importId)); - - } else { - dispatch(loading({importId}, false)); - dispatch(loadImports(geoserverRestURL)); - - } - }).catch((e) => {importRunError(importId, e); }); - }; -} -/** LAYER **/ - -export function loadLayer(geoserverRestURL, importId, taskId) { - return (dispatch) => { - dispatch(loading({importId: importId, taskId: taskId, element: "layer", message: "loadinglayer"})); - return API.loadLayer(geoserverRestURL, importId, taskId).then((response) => { - dispatch(layerLoaded(importId, taskId, response && response.data && response.data.layer)); - dispatch(loading({importId: importId, taskId: taskId, element: "layer", message: "loadinglayer"}, false)); - }); - }; -} -export function updateLayer(geoserverRestURL, importId, taskId, layer) { - return (dispatch) => { - dispatch(loading({importId: importId, taskId: taskId, element: "layer", message: "loadinglayer"})); - - return API.updateLayer(geoserverRestURL, importId, taskId, layer).then((response) => { - dispatch(layerUpdated(importId, taskId, response && response.data && response.data.layer)); - dispatch(loading({importId: importId, taskId: taskId, element: "layer", message: "loadinglayer"}, false)); - }); - }; -} -/** TASKS **/ -export function loadTask(geoserverRestURL, importId, taskId) { - return (dispatch) => { - dispatch(loading({importId: importId, taskId: taskId})); - API.loadTask(geoserverRestURL, importId, taskId).then((response) => { - dispatch(importTaskLoaded(response && response.data && response.data.task)); - dispatch(loadLayer(geoserverRestURL, importId, taskId)); - dispatch(loading({importId: importId, taskId: taskId}, false)); - }).catch((e) => { - dispatch(importTaskLoadError(e)); - dispatch(loading({importId: importId, taskId: taskId}, false)); - }); - }; -} -export function updateUI(geoserverRestURL, importId, taskId) { - return (dispatch, getState) => { - let state = getState && getState() && getState().importer; - if (state && state.selectedImport && state.selectedImport.id === importId && state.selectedTask && state.selectedTask.id === taskId) { - dispatch(loadTask(geoserverRestURL, importId, taskId)); - dispatch(loading({importId, taskId}, false)); - } else if (state && state.selectedImport && state.selectedImport.id === importId) { - dispatch(loadImport(geoserverRestURL, importId)); - dispatch(loading({importId}, false)); - } else { - dispatch(loadImports(geoserverRestURL)); - dispatch(loading({importId}, false)); - } - }; -} -export function updateTask(geoserverRestURL, importId, taskId, body, element, message = "updating") { - return (dispatch) => { - let opts = { - headers: { - 'Content-Type': 'application/json' - } - }; - - dispatch(loading({importId: importId, taskId: taskId, message})); - return API.updateTask(geoserverRestURL, importId, taskId, element, body, opts).then((response) => { - dispatch(importTaskUpdated(response && response.data && response.data.task, importId, taskId)); - dispatch(loading({importId: importId, taskId: taskId}, false)); - dispatch(updateUI(geoserverRestURL, importId, taskId)); - }); - }; -} - -export function deleteTask(geoserverRestURL, importId, taskId) { - return (dispatch) => { - dispatch(loading({importId: importId, taskId: taskId, message: "deleting"})); - return API.deleteTask(geoserverRestURL, importId, taskId).then(() => { - dispatch(importTaskDeleted(importId, taskId)); - dispatch(loading({importId: importId, taskId: taskId, message: "deleting"}, false)); - dispatch(loading({importId: importId, message: "deleting"}, false)); - }); - }; -} - -export function updateProgress(geoserverRestURL, importId, taskId) { - return (dispatch) => { - return API.getTaskProgress(geoserverRestURL, importId, taskId).then((response) => { - dispatch(taskProgressUpdated(importId, taskId, response.data)); - }); - }; -} -/** TRANFORMS **/ -export function loadTransform(geoserverRestURL, importId, taskId, transformId) { - return (dispatch) => { - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"})); - return API.loadTransform(geoserverRestURL, importId, taskId, transformId).then((response) => { - let transform = response && response.data; - dispatch(transformLoaded(importId, taskId, transformId, transform)); - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"}, false)); - }).catch((e) => {transformLoadError(importId, taskId, transformId, e); }); - }; -} -export function deleteTransform(geoserverRestURL, importId, taskId, transformId) { - return (dispatch, getState) => { - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"})); - return API.deleteTransform(geoserverRestURL, importId, taskId, transformId).then(() => { - dispatch(transformDeleted(importId, taskId, transformId)); - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"}, false)); - let state = getState().importer; - if (state.selectedTask && state.selectedTask.id === taskId) { - dispatch(loadTask(geoserverRestURL, importId, taskId)); - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"}, false)); - } - }).catch((e) => {transformLoadError(importId, taskId, transformId, e); }); // TODO transform delete error - }; -} - -export function updateTransform(geoserverRestURL, importId, taskId, transformId, transform) { - return (dispatch) => { - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"})); - return API.updateTransform(geoserverRestURL, importId, taskId, transformId, transform).then((response) => { - dispatch(transformUpdated(importId, taskId, transformId, response && response.data)); - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"}, false)); - }).catch((e) => { - transformLoadError(importId, taskId, transformId, e); // TODO transform update error - dispatch(loading({importId: importId, taskId: taskId, transformId: transformId, message: "loading"}, false)); - }); - }; -} -/** PRESETS **/ -export function applyPreset(geoserverRestURL, importId, task, preset) { - - return (dispatch) => { - const applyChange = (element, change) => { // TODO better as an action - dispatch(updateTask(geoserverRestURL, importId, task.id, change, element, "applyPresets")); - }; - if (preset.changes) { - // update target, layer - Object.keys(preset.changes).forEach((element) => { - let values = preset.changes[element]; - if (Array.isArray(values)) { - values.forEach(applyChange.bind(null, element)); - } else { - applyChange(element, values); - } - }); - } - if (preset.transforms) { - preset.transforms.forEach( (transform) => { - dispatch(loading({importId: importId, taskId: task.id, message: "applyPresets"})); - API.addTransform(geoserverRestURL, importId, task.id, transform).then(() => { - dispatch(loading({importId: importId, taskId: task.id, message: "applyPresets"}, false)); - }); - }); - } - }; -} -export function applyPresets(geoserverRestURL, importId, tasks, presets) { - return (dispatch) => { - if (tasks) { - tasks.forEach( (task) => { - presets.forEach( (preset) => { - if (task.data) { - if (matchPreset(preset, task)) { - dispatch(applyPreset(geoserverRestURL, importId, task, preset)); - } - } else { - dispatch(loading({importId: importId, taskId: task.id, message: "analyzing"})); - API.loadTask(geoserverRestURL, importId, task.id).then((response) => { - dispatch(loading({importId: importId, taskId: task.id}, false)); - let completeTask = response && response.data && response.data.task; - if (matchPreset(preset, completeTask)) { - dispatch(applyPreset(geoserverRestURL, importId, completeTask, preset)); - } - }); - } - - }); - }); - } - }; -} - -export function loadWorkspaces(geoserverRestURL) { - return (dispatch) => { - Workspaces.getWorkspaces(geoserverRestURL).then((result) => { - dispatch(workspacesLoaded(result.workspaces.workspace)); - }); - }; -} - -export function createWorkspace(geoserverRestURL, name, datastores = []) { - return (dispatch) => { - dispatch(loading()); - Workspaces.createWorkspace(geoserverRestURL, name).then(() => { - dispatch(workspaceCreated(name)); - - let count = datastores.length; - if (count === 0) { - dispatch(loading(null, false)); - } else { - datastores.forEach((ds) => { - // replace placeholder (this is required because in the importer the datastore name have to be unique, out of workspace) - let datastore = ds; - let dsname = ds.dataStore && ds.dataStore.name; - let datastoreobj = assign({}, ds.dataStore, {name: dsname.replace("{workspace}", name)}); - datastore = assign({}, ds, {dataStore: datastoreobj}); - - Workspaces.createDataStore(geoserverRestURL, name, datastore).then(() => { - count--; - if (count === 0) { - dispatch(loading(null, false)); - } - }); - }); - } - }).catch((error) => { - dispatch(workspaceCreationError(name, error)); - dispatch(loading(null, false)); - - }); - }; -} - -export function dismissWorkspaceCreationStatus() { - return { - type: IMPORTER_WORKSPACE_STATUS_CHANGE, - state: null - }; -} - -/** UPLOAD **/ -export function uploadImportFiles(geoserverRestURL, importId, files, presets) { - return (dispatch, getState) => { - dispatch(loading({importId: importId, uploadingFiles: files})); - let progressOpts = { - progress: (progressEvent) => { - dispatch(uploadProgress(progressEvent.loaded / progressEvent.total)); - } - }; - API.uploadImportFiles(geoserverRestURL, importId, files, progressOpts).then((response) => { - let tasks = response && response.data && response.data.tasks || response && response.data && [response.data.task]; - dispatch(fileUploaded(files)); - dispatch(importTaskCreated(importId, tasks)); - let state = getState(); - let impState = state.importer; - if (impState && impState.selectedImport && impState.selectedImport.id === importId && tasks && tasks.length > 1) { - dispatch(loadImport(geoserverRestURL, importId)); - } - if (presets) { - let newPreset = presets.map((preset) => applyPlaceholders(preset, state && state.importer && state.importer.selectedImport)); - dispatch(applyPresets(geoserverRestURL, importId, tasks, newPreset)); - } - dispatch(loading({importId: importId}, false)); - }).catch((e) => { - dispatch(importTaskCreationError(e)); - dispatch(loading({importId: importId}, false)); - }); - }; -} - -/** STYLER **/ -export function loadStylerTool(geoserverRestURL, importId, taskId) { - return (dispatch, getState) => { - return API.loadLayer(geoserverRestURL, importId, taskId).then((layerResponse) => { - let layer = layerResponse && layerResponse.data && layerResponse.data.layer; - - let importObj = getState && getState().importer && getState().importer.selectedImport; - let workspace = importObj.targetWorkspace && importObj.targetWorkspace.workspace.name; - let stylerMapConfig = { - "version": 2, - "map": { - "projection": "EPSG:3857", - "units": "m", - "center": {"x": 0, "y": 0, "crs": "EPSG:3857"}, - "zoom": 2, - "maxExtent": [ - -20037508.34, -20037508.34, - 20037508.34, 20037508.34 - ], - "layers": [{ - "type": "osm", - "title": "Open Street Map", - "name": "mapnik", - "source": "osm", - "group": "background", - "visibility": true - }] - } - }; - let config = stylerMapConfig; - config.map.layers = (config.map.layers || []).concat({ - "type": "wms", - "url": "/geoserver/wms", - "visibility": true, - "title": layer.title, - "name": workspace + ":" + layer.name, - "group": "Styler", - "format": "image/png8" - }); - dispatch(configureMap(config)); - }); - - }; -} diff --git a/web/client/actions/share.js b/web/client/actions/share.js deleted file mode 100644 index 079294dad2..0000000000 --- a/web/client/actions/share.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright 2015, 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. - */ - -export const CHANGE_SHARE_STATE = 'CHANGE_SHARE_STATE'; - -export function changeShareState(enabled) { - return { - type: CHANGE_SHARE_STATE, - enabled: enabled - }; -} diff --git a/web/client/actions/tasks.js b/web/client/actions/tasks.js deleted file mode 100644 index ec41369929..0000000000 --- a/web/client/actions/tasks.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * 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. - */ -export const TASK_STARTED = 'TASK_STARTED'; -export const TASK_SUCCESS = 'TASK_SUCCESS'; -export const TASK_ERROR = 'TASK_ERROR'; - -export function taskSuccess(result, name, actionPayload) { - return { - type: TASK_SUCCESS, - result, - name, - actionPayload - }; -} - -export function taskStarted(name) { - return { - type: TASK_STARTED, - name - }; -} - -export function taskError(error, name, actionPayload) { - return { - type: TASK_ERROR, - error, - name, - actionPayload - }; -} - -export function startTask(task, taskPayload, name, actionPayload) { - return (dispatch) => { - dispatch(taskStarted(name)); - task(taskPayload, (result) => { - dispatch(taskSuccess(result, name, actionPayload)); - }, (error) => { - dispatch(taskError(error, name, actionPayload)); - }); - }; -} - diff --git a/web/client/api/MapConfigDAO.js b/web/client/api/MapConfigDAO.js deleted file mode 100644 index b3b49be551..0000000000 --- a/web/client/api/MapConfigDAO.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright 2015, 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. - */ -import axios from '../libs/ajax'; - -import ConfigUtils from '../utils/ConfigUtils'; -/** - * API for local config - */ -var Api = { - get: function(url) { - return axios.get(url).then((response) => { - return response.data; - }); - }, - - /** - * Returns Merged configurations from base url and GeoStore - */ - getMergedConfig: function(baseConfigURL, mapId, geoStoreBase) { - var url = ( geoStoreBase || "/mapstore/rest/geostore/" ) + "data/" + mapId; - if (!mapId) { - return Api.get(baseConfigURL); - } - - return axios.all([axios.get(baseConfigURL), axios.get(url)]) - .then( (args) => { - var baseConfig = args[0].data; - var mapConfig = args[1].data; - return ConfigUtils.mergeConfigs(baseConfig, mapConfig); - }).catch( () => { - return Api.get(baseConfigURL); - }); - } -}; - -export default Api; diff --git a/web/client/components/manager/importer/BreadCrumb.jsx b/web/client/components/manager/importer/BreadCrumb.jsx deleted file mode 100644 index 362bdbe1d8..0000000000 --- a/web/client/components/manager/importer/BreadCrumb.jsx +++ /dev/null @@ -1,68 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * 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. - */ -import React from 'react'; - -import Message from '../../I18N/Message'; - -class BreadCrumb extends React.Component { - static propTypes = { - loading: PropTypes.bool, - loadImports: PropTypes.func, - loadImport: PropTypes.func, - loadTask: PropTypes.func, - selectedImport: PropTypes.object, - selectedTask: PropTypes.object, - selectedTransform: PropTypes.object - }; - - static defaultProps = { - loadImports: () => {}, - loadImport: () => {}, - loadTask: () => {} - }; - - render() { - if ( this.props.selectedImport && this.props.selectedTask && this.props.selectedTransform) { - return (
    -
  1. {e.preventDefault(); this.props.loadImports(); }}>
  2. -
  3. {e.preventDefault(); this.props.loadImport(this.props.selectedImport.id); }}> - -
  4. -
  5. {e.preventDefault(); this.props.loadTask(this.props.selectedImport.id, this.props.selectedTask.id); }}> - Package {this.props.selectedTask.id} -
  6. -
  7. Transform {this.props.selectedTransform.id}
  8. -
); - } - if ( this.props.selectedImport && this.props.selectedTask) { - return ( -
    -
  1. {e.preventDefault(); this.props.loadImports(); }}>
  2. -
  3. {e.preventDefault(); this.props.loadImport(this.props.selectedImport.id); }}> - -
  4. -
  5. Package {this.props.selectedTask.id}
  6. -
); - } - if (this.props.selectedImport) { - return ( -
    -
  1. {e.preventDefault(); this.props.loadImports(); }}>
  2. -
  3. -
); - } - return ( -
    -
  1. -
); - } -} - -export default BreadCrumb; diff --git a/web/client/components/manager/importer/Import.jsx b/web/client/components/manager/importer/Import.jsx deleted file mode 100644 index 39749547c9..0000000000 --- a/web/client/components/manager/importer/Import.jsx +++ /dev/null @@ -1,170 +0,0 @@ -/** - * 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. - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import Spinner from 'react-spinkit'; -import OverlayTrigger from '../../misc/OverlayTrigger'; - -import Message from '../../I18N/Message'; -import TaskProgress from './TaskProgress'; -import { getbsStyleForState } from '../../../utils/ImporterUtils'; -import { Grid, Row, Panel, Label, Table, Glyphicon, Tooltip } from 'react-bootstrap'; -import './style/importer.css'; -import Button from '../../misc/Button'; - -class Task extends React.Component { - static propTypes = { - timeout: PropTypes.number, - "import": PropTypes.object, - loadImport: PropTypes.func, - loadTask: PropTypes.func, - loadStylerTool: PropTypes.func, - runImport: PropTypes.func, - updateProgress: PropTypes.func, - deleteImport: PropTypes.func, - deleteTask: PropTypes.func, - deleteAction: PropTypes.node, - placement: PropTypes.string - }; - - static contextTypes = { - router: PropTypes.object, - messages: PropTypes.object - }; - - static defaultProps = { - placement: "bottom", - deleteAction: , - timeout: 10000, - "import": {}, - loadTask: () => {}, - runImport: () => {}, - loadImport: () => {}, - loadStylerTool: () => {}, - updateProgress: () => {}, - deleteImport: () => {}, - deleteTask: () => {} - }; - - componentDidMount() { - if (this.props.import.state === "RUNNING") { - // Check if some task is running the update is not needed - this.interval = setInterval(this.props.loadImport.bind(null, this.props.import.id), this.props.timeout); - - } - } - - componentWillUnmount() { - if (this.interval) { - clearInterval(this.interval); - } - } - - renderGeneral = (importObj) => { - return (
-
-
-
-
{importObj.archive}
-
); - }; - - renderProgressTask = (task) => { - if ( task.state === "RUNNING") { - return ; - } - return null; - }; - - renderTask = (task) => { - let tooltipDelete = {this.props.deleteAction}; - return ( - {e.preventDefault(); this.props.loadTask(task.id); }} >{task.id} - {this.renderProgressTask(task)}{this.renderLoadingTask(task)} - - - - - - ); - }; - - renderLoading = () => { - if (this.props.import.loading) { - return
; - } - return null; - }; - - renderLoadingMessage = (task) => { - switch (task.message) { - case "applyPresets": - return ; - case "deleting": - return ; - case "analyzing": - return ; - default: - return null; - } - }; - - renderLoadingTask = (task) => { - if (task.loading) { - return (
- {this.renderLoadingMessage(task)} -
); - } - return null; - }; - - render() { - return ( - {this.renderLoading()}} > - - - {this.renderGeneral(this.props.import)} - - -

- - - - - - - - - - {this.props.import.tasks.map(this.renderTask)} - -
-
- - { - this.props.import.tasks.reduce((prev, cur) => prev || cur.state === "READY", false) ? - - : null - } - - -
-
- ); - } - - editDefaultStyle = (taskId) => { - this.context.router.history.push("/styler/openlayers"); - this.props.loadStylerTool(taskId); - }; -} - -export default Task; diff --git a/web/client/components/manager/importer/Importer.jsx b/web/client/components/manager/importer/Importer.jsx deleted file mode 100644 index db9ec69323..0000000000 --- a/web/client/components/manager/importer/Importer.jsx +++ /dev/null @@ -1,263 +0,0 @@ -import PropTypes from 'prop-types'; - -/** - * 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. - */ -import React from 'react'; - -import Spinner from 'react-spinkit'; -import Message from '../../I18N/Message'; -import ImportsGrid from './ImportsGrid'; -import Workspace from './Workspace'; -import FileUploader from '../../file/FileUploader'; -import Task from './Task'; -import Import from './Import'; -import Transform from './Transform'; -import { Grid, Col, Row, Alert } from 'react-bootstrap'; -import BreadCrumb from './BreadCrumb'; -import { head } from 'lodash'; - -class Importer extends React.Component { - static propTypes = { - loading: PropTypes.bool, - taskCreationError: PropTypes.object, - error: PropTypes.object, - defaultPresets: PropTypes.string, - /** - * Presets: {PRESET_ID: [changes: [{target: {}, layer: {}}], match: function() {...}, transforms: [{}, {}] }]} - */ - presets: PropTypes.object, - uploading: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]), - createImport: PropTypes.func, - runImport: PropTypes.func, - loadWorkspaces: PropTypes.func, - workspaces: PropTypes.array, - selectedWorkSpace: PropTypes.object, - selectWorkSpace: PropTypes.func, - workspaceCreationStatus: PropTypes.object, - dismissWorkspaceCreationStatus: PropTypes.func, - createWorkspace: PropTypes.func, - datastoreTemplates: PropTypes.array, - deleteImport: PropTypes.func, - updateTask: PropTypes.func, - deleteTask: PropTypes.func, - loadImports: PropTypes.func, - loadImport: PropTypes.func, - loadTask: PropTypes.func, - updateProgress: PropTypes.func, - loadLayer: PropTypes.func, - updateLayer: PropTypes.func, - loadStylerTool: PropTypes.func, - loadTransform: PropTypes.func, - updateTransform: PropTypes.func, - editTransform: PropTypes.func, - deleteTransform: PropTypes.func, - uploadImportFiles: PropTypes.func, - selectedImport: PropTypes.object, - selectedTask: PropTypes.object, - selectedTransform: PropTypes.object, - imports: PropTypes.array, - onMount: PropTypes.func - }; - - static defaultProps = { - createImport: () => {}, - loadImport: () => {}, - loadTask: () => {}, - loadLayer: () => {}, - loadTransform: () => {}, - editTransform: () => {}, - updateTransform: () => {}, - loadImports: () => {}, - updateProgress: () => {}, - deleteTransform: () => {}, - uploadImportFiles: () => {}, - loadWorkspaces: () => {}, - dismissWorkspaceCreationStatus: () => {}, - createWorkspace: () => {}, - onMount: () => {}, - imports: [] - }; - - componentDidMount() { - this.props.onMount(); - } - - getPresets = () => { - return this.props.presets && this.props.presets[this.props.defaultPresets]; - }; - - getImportCreationDefaults = () => { - let presets = this.getPresets(); - if (!presets) { - return { - importCreationDefaults: { - "import": { - "targetWorkspace": { - "workspace": { - "name": "cite" - } - } - } - } - }; - } else if (this.props.selectedWorkSpace) { - return { - "import": { - "targetWorkspace": { - "workspace": { - "name": this.props.selectedWorkSpace.value - } - } - } - }; - } - return head(presets.filter((preset) => preset.import )); - }; - - getTargetWorkspace = (selectedImport) => { - let targetWorkspace = selectedImport && selectedImport.targetWorkspace; - if (targetWorkspace) { - return targetWorkspace && targetWorkspace.workspace && targetWorkspace.workspace.name; - } - let creationDefaults = this.getImportCreationDefaults(); - let importObj = creationDefaults && creationDefaults.import || creationDefaults && creationDefaults.importCreationDefaults && creationDefaults.importCreationDefaults.import; - return importObj && importObj.targetWorkspace && importObj.targetWorkspace.workspace && importObj.targetWorkspace.workspace.name; - - - }; - - renderError = () => { - if (this.props.error) { - return There was an error during the import list loading: {this.props.error.statusText}; - } - return null; - }; - - renderLoading = () => { - if (this.props.loading) { - return
; - } - return null; - }; - - renderDetails = () => { - let breadcrumb = (); - if ( this.props.selectedImport && this.props.selectedTask && this.props.selectedTransform) { - return (
- {breadcrumb} -

Transform {this.props.selectedTransform.id}

- -
); - } - if ( this.props.selectedImport && this.props.selectedTask) { - return (
- {breadcrumb} - -
); - } - if (this.props.selectedImport) { - return (
- {breadcrumb} - -
); - } - return (
- {breadcrumb} - -
); - }; - - render() { - let message = this.props.selectedImport ? "importer.dropfileImport" : "importer.dropfile"; - return ( - - - - } - dropMessage={} - uploading={this.props.uploading} - allowUpload={this.props.selectedImport} - onBeforeUpload={this.props.createImport.bind(null, this.getImportCreationDefaults())} - onUpload={this.props.uploadImportFiles.bind(null, this.props.selectedImport && this.props.selectedImport.id)} - uploadAdditionalParams={this.getPresets()} /> - - - - - - - {this.renderLoading()} - {this.renderDetails()} - {this.renderError()} - - ); - } - - createUpdateFunction = () => { - return; - }; -} - -export default Importer; diff --git a/web/client/components/manager/importer/ImportsGrid.jsx b/web/client/components/manager/importer/ImportsGrid.jsx deleted file mode 100644 index 9f9d26171b..0000000000 --- a/web/client/components/manager/importer/ImportsGrid.jsx +++ /dev/null @@ -1,123 +0,0 @@ -/** - * 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. - */ - -import React from 'react'; -import Spinner from 'react-spinkit'; -import PropTypes from 'prop-types'; -import { Table, Glyphicon, Label, Tooltip } from 'react-bootstrap'; -import { findIndex } from 'lodash'; - -import Button from '../../misc/Button'; -import Message from '../../I18N/Message'; -import { getbsStyleForState } from '../../../utils/ImporterUtils'; -import OverlayTrigger from '../../misc/OverlayTrigger'; - -class ImportsGrid extends React.Component { - static propTypes = { - loading: PropTypes.bool, - timeout: PropTypes.number, - loadImports: PropTypes.func, - loadImport: PropTypes.func, - deleteImport: PropTypes.func, - imports: PropTypes.array, - deleteAction: PropTypes.object, - placement: PropTypes.string - }; - - static contextTypes = { - messages: PropTypes.object - }; - - static defaultProps = { - timeout: 5000, - loadImports: () => {}, - placement: "bottom", - deleteAction: , - loadImport: () => {}, - deleteImport: () => {}, - imports: [] - }; - - componentDidMount() { - this.interval = setInterval(() => {this.update(); }, this.props.timeout); - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - renderLoadingMessage = (importObj) => { - switch (importObj.message) { - case "deleting": - return ; - default: - return null; - } - }; - - renderLoadingImport = (importObj) => { - if (importObj.loading) { - return
{this.renderLoadingMessage(importObj)}
; - } - return null; - }; - - renderImportErrorMessage = (imp) => { - if (imp && imp.error) { - return ; - } - return null; - }; - - renderImport = (importObj) => { - let tooltip = {this.props.deleteAction}; - return ( - {e.preventDefault(); this.props.loadImport(importObj.id); }} >{importObj.id} - - {this.renderLoadingImport(importObj)} - {this.renderImportErrorMessage(importObj)} - - - - - - - ); - }; - - render() { - if (this.props.loading && this.props.imports.length === 0) { - return ; - } - return ( - - - - - - - - - - {this.props.imports.map(this.renderImport)} - -
- ); - } - - update = () => { - if (this.props.imports) { - let i = findIndex(this.props.imports, (importObj) => importObj.state === "RUNNING"); - if ( i >= 0 ) { - this.props.loadImports(); - } - } - }; -} - -export default ImportsGrid; diff --git a/web/client/components/manager/importer/Layer.jsx b/web/client/components/manager/importer/Layer.jsx deleted file mode 100644 index d00a211a71..0000000000 --- a/web/client/components/manager/importer/Layer.jsx +++ /dev/null @@ -1,99 +0,0 @@ - -/** - * 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. - */ - -import React from 'react'; -import PropTypes from 'prop-types'; - -import Button from '../../misc/Button'; -import { Panel } from 'react-bootstrap'; -import Message from '../../I18N/Message'; - - -class Layer extends React.Component { - static propTypes = { - layer: PropTypes.object, - loading: PropTypes.bool, - edit: PropTypes.bool, - panProps: PropTypes.object, - updateLayer: PropTypes.func - }; - - static defaultProps = { - layer: {}, - edit: true, - loading: false, - updateLayer: () => {} - }; - - state = {}; - - onChange = (event) => { - let state = {}; - state[event.target.name] = event.target.value || ""; - this.setState(state); - }; - - renderInput = (name) => { - let input; - if (name !== "description") { - input = (); - } else { - input = (