diff --git a/Jenkinsfile b/Jenkinsfile
index 68e35ad..bd84b41 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -2,7 +2,7 @@ pipeline {
agent {
docker {
image 'node:latest'
- args '-p 3011:3000'
+ args '-p 3000:3000'
}
}
environment {
@@ -25,4 +25,31 @@ pipeline {
}
}
}
-}
+ post {
+ always {
+ script {
+ properties([[$class: 'GithubProjectProperty',
+ projectUrlStr: 'https://github.com/clarity-h2020/map-component']])
+ }
+ step([$class: 'GitHubIssueNotifier',
+ issueAppend: true,
+ issueReopen: false,
+ issueLabel: 'CI',
+ issueTitle: '$JOB_NAME $BUILD_DISPLAY_NAME failed'])
+ }
+ failure {
+ emailext attachLog: true,
+ to: "pascal@cismet.de",
+ subject: "Build failed in Jenkins: ${currentBuild.fullDisplayName}",
+ body: """
FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':
+ Check console output at "${env.JOB_NAME} [${env.BUILD_NUMBER}]"
"""
+ }
+ unstable {
+ emailext attachLog: true,
+ to: "pascal@cismet.de",
+ subject: "Jenkins build became unstable: ${currentBuild.fullDisplayName}",
+ body: """UNSTABLE: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]':
+ Check console output at "${env.JOB_NAME} [${env.BUILD_NUMBER}]"
"""
+ }
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index c727b5e..ff18894 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "clarity-map-component",
- "version": "2.4.6",
+ "version": "2.5.0",
"private": true,
"license": "LGPL",
"dependencies": {
@@ -14,6 +14,7 @@
"leaflet-loading": "latest",
"leaflet-providers": "git://github.com/leaflet-extras/leaflet-providers#semver:^1.8.0",
"leaflet.nontiledlayer": "^1.0.8",
+ "leaflet.sync": "^0.2.4",
"loglevel": "^1.6.6",
"prop-types": "latest",
"query-string": "^6.10.1",
diff --git a/src/App.js b/src/App.js
index 3131f2c..2fc4d85 100644
--- a/src/App.js
+++ b/src/App.js
@@ -27,32 +27,25 @@ export default class App extends React.Component {
-
+
-
-
-
+
+
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
);
}
-}
+}
\ No newline at end of file
diff --git a/src/MapComp.css b/src/MapComp.css
deleted file mode 100644
index 7442f45..0000000
--- a/src/MapComp.css
+++ /dev/null
@@ -1,69 +0,0 @@
-.App {
- text-align: center;
-}
-
-.App-logo {
- animation: App-logo-spin infinite 20s linear;
- height: 80px;
-}
-
-.App-header {
- background-color: #222;
- height: 150px;
- padding: 20px;
- color: white;
-}
-
-.App-title {
- font-size: 1.5em;
-}
-
-.App-intro {
- font-size: large;
-}
-
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-.leaflet-container {
- width: 100%;
- height: 100%;
-}
-
-.leaflet-container {
- height: 500px;
-}
-
-.rlglc-active {
- height: 500px !important;
-}
-
-.hiddenGroup {
- display: none !important;
-}
-
-.hiddenGroupHeader {
- background-image: url(../../../../../../modules/custom/map-component/src/img/icon-pigpent.png) !important;
- background-repeat: no-repeat;
- padding-left: 15px;
- background-size: 8px 8px;
- background-position: left center;
-}
-
-.rlglc-group {
- background-image: url(../../../../../../modules/custom/map-component/src/img/icon-pigpens.png);
- background-repeat: no-repeat;
- padding-left: 10px;
- background-size: 8px 8px;
- background-position: left 10px;
-}
-
-.study-area-edit {
- margin-left: 15px;
-}
diff --git a/src/__tests__/CSISHelpers.test.js b/src/__tests__/CSISHelpers.test.js
index 604cb7b..05a59e6 100644
--- a/src/__tests__/CSISHelpers.test.js
+++ b/src/__tests__/CSISHelpers.test.js
@@ -10,8 +10,13 @@
import axios from 'axios';
import log from 'loglevel';
-import { CSISHelpers } from 'csis-helpers-js';
import express from 'express';
+
+// required because of https://github.com/clarity-h2020/simple-table-component/issues/4#issuecomment-595114163
+import 'react-app-polyfill/ie9';
+import 'react-app-polyfill/stable';
+
+import { CSISHelpers } from 'csis-helpers-js';
import apiResponseStudy from './../__fixtures__/study.json';
import apiResponseDataPackage from './../__fixtures__/dataPackage.json';
import apiResponseResources from './../__fixtures__/resources.json';
@@ -21,6 +26,9 @@ const app = express();
var server;
beforeAll(() => {
+ // required because of https://github.com/clarity-h2020/map-component/issues/43#issuecomment-595621339
+ axios.defaults.adapter = require('axios/lib/adapters/http');
+
app.get('/jsonapi/group/study', function(req, res) {
res.json(apiResponseStudy);
});
@@ -41,14 +49,21 @@ beforeAll(() => {
res.json(apiResponseResources);
});
- server = app.listen(31336, () => log.debug('Example app listening on port 31336!'));
+ // this is just unbelievable: log.debug() is not printed to console when running the tests in VSCode. WTF?!
+ server = app.listen(0, () => log.debug(`Example app listening on http://${server.address().address}:${server.address().port}`));
+ log.debug(`Example app listening on http://${server.address().address}:${server.address().port}`);
});
test('test extract study area from study json', async (done) => {
- const response = await axios.get(
- 'http://localhost:31336/jsonapi/group/study?filter[id][condition][path]=id&filter[id][condition][operator]=%3D&filter[id][condition][value]=c3609e3e-f80f-482b-9e9f-3a26226a6859'
- );
+ // does not work if bound d to ipv6 adaress. :-()
+ // const url = `http://${server.address().address}:${server.address().port}/jsonapi/group/study?filter[id][condition][path]=id&filter[id][condition][operator]=%3D&filter[id][condition][value]=c3609e3e-f80f-482b-9e9f-3a26226a6859`;
+ const url = `http://localhost:${server.address().port}/jsonapi/group/study?filter[id][condition][path]=id&filter[id][condition][operator]=%3D&filter[id][condition][value]=c3609e3e-f80f-482b-9e9f-3a26226a6859`;
+ // unbelievable: does not print to console. See https://github.com/facebook/jest/issues/2441
+ log.info(url);
+ const response = await axios.get(url);
+ // -> error 400 ?! This used to work with a fixed port. since simple things like logging don't seem
+ // to be possible with jest, and debugging tests in vscode works only 50% of the time, we disable this test.
expect.assertions(5);
expect(response).toBeDefined();
@@ -158,8 +173,16 @@ test('check for emikat id in study', () => {
afterAll(() => {
log.debug('afterAll');
- server.close(() => {
- //console.log('JSON Server closed');
- //process.exit(0);
- });
+ if(server) {
+ server.close(() => {
+ //console.log('JSON Server closed');
+ //process.exit(0);
+ });
+ } else {
+ // WTF?!!!!
+ // https://github.com/clarity-h2020/map-component/issues/43#issuecomment-595637179
+
+ // unfortunely, we'll never see this because of https://github.com/facebook/jest/issues/2441
+ log.warn('server undefined');
+ }
});
diff --git a/src/__tests__/CSISRemoteHelpers.test.js b/src/__tests__/CSISRemoteHelpers.test.js
index f300c44..2ce8eab 100644
--- a/src/__tests__/CSISRemoteHelpers.test.js
+++ b/src/__tests__/CSISRemoteHelpers.test.js
@@ -12,6 +12,11 @@
import axios from 'axios';
import log from 'loglevel';
+
+// required because of https://github.com/clarity-h2020/simple-table-component/issues/4#issuecomment-595114163
+import 'react-app-polyfill/ie9';
+import 'react-app-polyfill/stable';
+
import { CSISRemoteHelpers, CSISHelpers } from 'csis-helpers-js';
import apiResponseStudy from './../__fixtures__/study.json';
@@ -22,6 +27,9 @@ log.enableAll();
* Set auth headers for live API test
*/
beforeAll(async (done) => {
+ // required because of https://github.com/clarity-h2020/map-component/issues/43#issuecomment-595621339
+ axios.defaults.adapter = require('axios/lib/adapters/http');
+
jest.setTimeout(60000);
let cookie = process.env.COOKIE;
@@ -114,7 +122,7 @@ describe('Remote API tests with authentication', () => {
done();
});
- it.only('[DEV] test get complete Study', async (done) => {
+ it('[DEV] test get complete Study', async (done) => {
const studyGroupNode = await CSISRemoteHelpers.getStudyGroupNodeFromCsis(
undefined,
'c3609e3e-f80f-482b-9e9f-3a26226a6859'
diff --git a/src/__tests__/EMIKATHelpers.test.js b/src/__tests__/EMIKATHelpers.test.js
index a966c52..42f9e87 100644
--- a/src/__tests__/EMIKATHelpers.test.js
+++ b/src/__tests__/EMIKATHelpers.test.js
@@ -8,7 +8,11 @@
* ***************************************************
*/
-import { EMIKATHelpers } from 'csis-helpers-js';
+ // required because of https://github.com/clarity-h2020/simple-table-component/issues/4#issuecomment-595114163
+import 'react-app-polyfill/ie9';
+import 'react-app-polyfill/stable';
+
+ import { EMIKATHelpers } from 'csis-helpers-js';
test('[RELEASE] URL without EmikatId', () => {
const url =
diff --git a/src/components/CharacteriseHazardMap.js b/src/components/CharacteriseHazardMap.js
index 77b523b..abcabc0 100644
--- a/src/components/CharacteriseHazardMap.js
+++ b/src/components/CharacteriseHazardMap.js
@@ -1,8 +1,6 @@
-import React from 'react';
-import MapComponent from './commons/MapComponent';
-import BasicMap from './commons/BasicMap';
+import GenericMap from './GenericMap';
-export default class CharacteriseHazardMap extends BasicMap {
+export default class CharacteriseHazardMap extends GenericMap {
constructor(props) {
// FIXME: Warning: CharacteriseHazardMap(...): When calling super() in `CharacteriseHazardMap`,
// make sure to pass up the same props that your component's constructor was passed.
@@ -33,20 +31,4 @@ export default class CharacteriseHazardMap extends BasicMap {
console.log('characteriseHazard-map -> process URL: ' + url);
return super.processUrl(resource, includedArray, url);
}
-
- /**
- * Render the map
- */
- render() {
- return (
-
- );
- }
}
diff --git a/src/components/ExposureMap.js b/src/components/ExposureMap.js
index 647a20e..3e0d24b 100644
--- a/src/components/ExposureMap.js
+++ b/src/components/ExposureMap.js
@@ -1,8 +1,6 @@
-import React from 'react';
-import MapComponent from './commons/MapComponent';
-import BasicMap from './commons/BasicMap';
+import GenericMap from './GenericMap';
-export default class ExposureMap extends BasicMap {
+export default class ExposureMap extends GenericMap {
constructor(props) {
super({ ...props, mapSelectionId: 'eu-gl:exposure-evaluation' });
@@ -15,27 +13,4 @@ export default class ExposureMap extends BasicMap {
loading: true
};
}
-
- /**
- * Render the map
- */
- render() {
- if (
- !this.queryParams ||
- (!this.queryParams.study_uuid && !this.queryParams.resource_uuid && !this.queryParams.datapackage_uuid)
- ) {
- return super.render();
- }
-
- return (
-
- );
- }
}
diff --git a/src/components/GenericMap.js b/src/components/GenericMap.js
index 1e7b2b2..be7a7ee 100644
--- a/src/components/GenericMap.js
+++ b/src/components/GenericMap.js
@@ -1,8 +1,11 @@
import React from 'react';
+import log from 'loglevel';
import MapComponent from './commons/MapComponent';
import BasicMap from './commons/BasicMap';
+// yes, order of imports do matter
+import 'leaflet.sync';
-export default class Generic extends BasicMap {
+export default class GenericMap extends BasicMap {
constructor(props) {
super(props);
@@ -16,6 +19,21 @@ export default class Generic extends BasicMap {
};
}
+ /**
+ * Synchronise Maps. See https://github.com/jieter/Leaflet.Sync
+ */
+ componentDidUpdate() {
+ if (this.mapComponentA && this.mapComponentA.leafletMapInstance && this.mapComponentB && this.mapComponentB.leafletMapInstance) {
+ this.mapComponentA.leafletMapInstance.sync(this.mapComponentB.leafletMapInstance);
+ // WARNING: flyTo will not work if we apply it to both maps!
+ this.mapComponentB.leafletMapInstance.sync(this.mapComponentA.leafletMapInstance,
+ {
+ noInitialSync: true
+ });
+ log.debug('Map Components synchronised');
+ }
+ }
+
/**
* Logs the url on the console
*
@@ -35,18 +53,50 @@ export default class Generic extends BasicMap {
!this.queryParams ||
(!this.queryParams.study_uuid && !this.queryParams.resource_uuid && !this.queryParams.datapackage_uuid)
) {
+ // renders an error message
return super.render();
}
- return (
-
- );
+ if (this.props.isSynchronised === true) {
+ log.info('rendering two sychronised maps');
+ return (<>
+ (this.mapComponentA = mapComponent)}
+ fly='true'
+ />
+ (this.mapComponentB = mapComponent)}
+ fly='false'
+ />
+ >);
+ } else {
+ log.info('rendering one simple map: ' + this.props.isSynchronised);
+ return (
+
+ );
+ }
+
+
}
}
diff --git a/src/components/HazardLocalEffectsMap.js b/src/components/HazardLocalEffectsMap.js
index bf2770f..42ea3e0 100644
--- a/src/components/HazardLocalEffectsMap.js
+++ b/src/components/HazardLocalEffectsMap.js
@@ -1,8 +1,6 @@
-import React from 'react';
-import MapComponent from './commons/MapComponent';
-import BasicMap from './commons/BasicMap';
+import GenericMap from './GenericMap';
-export default class HazardLocalEffectsMap extends BasicMap {
+export default class HazardLocalEffectsMap extends GenericMap {
constructor(props) {
super({ ...props, mapSelectionId: 'eu-gl:hazard-characterization:local-effects' });
@@ -15,27 +13,4 @@ export default class HazardLocalEffectsMap extends BasicMap {
loading: true
};
}
-
- /**
- * Render the map
- */
- render() {
- if (
- !this.queryParams ||
- (!this.queryParams.study_uuid && !this.queryParams.resource_uuid && !this.queryParams.datapackage_uuid)
- ) {
- return super.render();
- }
-
- return (
-
- );
- }
}
diff --git a/src/components/VulnerabilityMap.js b/src/components/VulnerabilityMap.js
index cd18592..778c65d 100644
--- a/src/components/VulnerabilityMap.js
+++ b/src/components/VulnerabilityMap.js
@@ -1,11 +1,9 @@
-import React from 'react';
-import MapComponent from './commons/MapComponent';
-import BasicMap from './commons/BasicMap';
+import GenericMap from './GenericMap';
/**
* @deprecated this map is not used anymore
*/
-export default class VulnerabilityMap extends BasicMap {
+export default class VulnerabilityMap extends GenericMap {
constructor(props) {
super({ ...props, mapSelectionId: 'eu-gl:vulnerability-analysis' });
@@ -18,27 +16,4 @@ export default class VulnerabilityMap extends BasicMap {
loading: true
};
}
-
- /**
- * Render the map
- */
- render() {
- if (
- !this.queryParams ||
- (!this.queryParams.study_uuid && !this.queryParams.resource_uuid && !this.queryParams.datapackage_uuid)
- ) {
- return super.render();
- }
-
- return (
-
- );
- }
}
diff --git a/src/components/commons/MapComponent.js b/src/components/commons/MapComponent.js
index 59ea0ce..657753d 100644
--- a/src/components/commons/MapComponent.js
+++ b/src/components/commons/MapComponent.js
@@ -1,17 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Map, TileLayer, GeoJSON, WMSTileLayer, withLeaflet, LeafletConsumer } from 'react-leaflet';
+import { Map, TileLayer, GeoJSON, WMSTileLayer, withLeaflet, LeafletConsumer, ZoomControl } from 'react-leaflet';
import { ReactLeafletGroupedLayerControl as ReactLeafletGroupedLayerControlForLeafletv1 } from 'react-leaflet-grouped-layer-control';
import turf from 'turf';
import 'leaflet-loading';
import LegendComponent from './LegendComponent.js';
import 'leaflet/dist/leaflet.css';
+import log from 'loglevel';
// See https://github.com/mhasbie/react-leaflet-vectorgrid#usage-with-react-leaflet-v2
const ReactLeafletGroupedLayerControl = withLeaflet(ReactLeafletGroupedLayerControlForLeafletv1);
/**
- * Render a leaflet map with the given layers
+ * Render a leaflet map with the given layers.
+ * This is still not the actual leaflet component but another wrapper.
*/
export default class MapComponent extends React.Component {
constructor(props) {
@@ -23,11 +25,13 @@ export default class MapComponent extends React.Component {
checkedBaseLayer: props.baseLayers[0].name,
overlays: props.overlays,
exclusiveGroups: props.exclusiveGroups,
- oldOverlay: []
+ oldOverlay: [],
+ mapId: props.mapId ? props.mapId : 'simpleMap'
};
+
this.baseLayers = props.baseLayers;
this.tileLayerUrl = props.baseLayers[0].url;
- this.fly = true;
+ this.fly = props.fly ? true : false;
// the leaflet instance, retrieved from the leaflet context
// see https://stackoverflow.com/questions/51308835/how-to-use-react-leaflet-context
@@ -103,6 +107,7 @@ export default class MapComponent extends React.Component {
this.leafletMapInstance.invalidateSize();
if (this.fly && this.props.studyAreaPolygon != null) {
+ log.info('centering on study area');
this.leafletMapInstance.flyToBounds(this.getBoundsFromArea(this.props.studyAreaPolygon), null);
this.fly = false;
}
@@ -140,7 +145,7 @@ export default class MapComponent extends React.Component {
this.hideListener = [];
for (var i = 0; i < groupTitles.length; ++i) {
const el = groupTitles[i];
- var listener = function() {
+ var listener = function () {
self.showHide(el);
};
this.hideListener.push(listener);
@@ -173,7 +178,7 @@ export default class MapComponent extends React.Component {
if (nextProps.overlays !== this.props.overlays) {
this.setState({ overlays: nextProps.overlays });
const thisObj = this;
- setTimeout(function() {
+ setTimeout(function () {
thisObj.setState({ overlays: nextProps.overlays });
}, 100);
}
@@ -186,9 +191,9 @@ export default class MapComponent extends React.Component {
*/
getBoundsFromArea(area) {
const bboxArray = turf.bbox(area);
- const corner1 = [ bboxArray[1], bboxArray[0] ];
- const corner2 = [ bboxArray[3], bboxArray[2] ];
- var bounds = [ corner1, corner2 ];
+ const corner1 = [bboxArray[1], bboxArray[0]];
+ const corner2 = [bboxArray[3], bboxArray[2]];
+ var bounds = [corner1, corner2];
return bounds;
}
@@ -288,16 +293,16 @@ export default class MapComponent extends React.Component {
}
this.setState({
- overlays: [ ...newOverlays ],
+ overlays: [...newOverlays],
count: this.state.count + 1,
oldOverlay: newOverlays
});
}
onOverlayChange(newOverlays) {
- this.overlaysAllTogether = [ ...newOverlays ];
+ this.overlaysAllTogether = [...newOverlays];
this.setState({
- overlays: [ ...newOverlays ],
+ overlays: [...newOverlays],
count: this.state.count + 1
});
}
@@ -507,13 +512,19 @@ export default class MapComponent extends React.Component {
ref={(comp) => this.leafletMapInstance = comp.leafletElement}
*/}