From 88bc13c88077408f3c00d7511c65d130671ad576 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Tue, 27 Aug 2024 13:14:09 +0700 Subject: [PATCH 01/44] PB-492: Add description to exported GPX file. --- src/modules/drawing/lib/export-utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/drawing/lib/export-utils.js b/src/modules/drawing/lib/export-utils.js index de337d905..5adb8f987 100644 --- a/src/modules/drawing/lib/export-utils.js +++ b/src/modules/drawing/lib/export-utils.js @@ -55,6 +55,10 @@ export function generateGpxString(projection, features = []) { const coordinates = geom.getLinearRing().getCoordinates() clone.setGeometry(new LineString(coordinates)) } + // Set the desc attribute from description property so that it is exported to GPX in desc tag + if (clone.getProperties().description) { + clone.set('desc', clone.getProperties().description) + } return clone }) return gpxFormat.writeFeatures(normalizedFeatures, { From bd3e39d261104f85ad67fd36f432ae0b9d9af183 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Tue, 20 Aug 2024 09:45:28 +0700 Subject: [PATCH 02/44] PB-666: Upgrade ol-maplibre-layer 1.0.1 --- package-lock.json | 11 ++++++----- package.json | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3813737e..022d81d0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@fortawesome/vue-fontawesome": "^3.0.8", "@geoblocks/cesium-compass": "^0.5.0", "@geoblocks/mapfishprint": "^0.2.16", - "@geoblocks/ol-maplibre-layer": "^1.0.0", + "@geoblocks/ol-maplibre-layer": "^1.0.1", "@ivanv/vue-collapse-transition": "^1.0.2", "@mapbox/togeojson": "^0.16.2", "@popperjs/core": "^2.11.8", @@ -873,12 +873,13 @@ } }, "node_modules/@geoblocks/ol-maplibre-layer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@geoblocks/ol-maplibre-layer/-/ol-maplibre-layer-1.0.0.tgz", - "integrity": "sha512-18EWTRBBt6xB2pJaEas3k887VZUAHGgk2U3v7D/5XtPTR91kUb0OAAOfShnfrET3iwO3SnJ6c0NrJ4anw0qobA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@geoblocks/ol-maplibre-layer/-/ol-maplibre-layer-1.0.1.tgz", + "integrity": "sha512-FMwil9AISKOYLKklVdl+PRGeDpPFkZzyFETb4wCQXHCjhpahwzH5gho3AQ06VGZIDC1Sg8IXxEfsR9R8IUpccg==", + "license": "BSD-3-Clause", "peerDependencies": { "maplibre-gl": ">=2.0.4", - "ol": "^6 || ^7 || ^8 || ^9" + "ol": "^6 || ^7 || ^8 || ^9 || ^10" } }, "node_modules/@geoblocks/print": { diff --git a/package.json b/package.json index de2dbdd78..2b8386e9b 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@fortawesome/vue-fontawesome": "^3.0.8", "@geoblocks/cesium-compass": "^0.5.0", "@geoblocks/mapfishprint": "^0.2.16", - "@geoblocks/ol-maplibre-layer": "^1.0.0", + "@geoblocks/ol-maplibre-layer": "^1.0.1", "@ivanv/vue-collapse-transition": "^1.0.2", "@mapbox/togeojson": "^0.16.2", "@popperjs/core": "^2.11.8", From 100343aba41a40afbdbecc98f1ec8de1e9e4b578 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Tue, 20 Aug 2024 09:57:04 +0700 Subject: [PATCH 03/44] PB-666: Upgrade to OL v10 --- package-lock.json | 59 ++++++++++++++++++++++------------------------- package.json | 2 +- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 022d81d0c..53e1a4c9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "liang-barsky": "^1.0.5", "lodash": "^4.17.21", "maplibre-gl": "^4.5.1", - "ol": "^9.2.4", + "ol": "^10.0.0", "pako": "^2.1.0", "print-js": "^1.6.0", "proj4": "^2.11.0", @@ -214,19 +214,6 @@ "node": ">=14.0.0" } }, - "node_modules/@cesium/engine/node_modules/earcut": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" - }, - "node_modules/@cesium/engine/node_modules/rbush": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.0.tgz", - "integrity": "sha512-F5xw+166FYDZI6jEcz+sWEHL5/J+du3kQWkwqWrPKb6iVoLPZh+2KhTS4OoYqrw1v/RO1xQe6WsLwBvrUAlvXw==", - "dependencies": { - "quickselect": "^2.0.0" - } - }, "node_modules/@cesium/widgets": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@cesium/widgets/-/widgets-7.1.0.tgz", @@ -4050,9 +4037,10 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, "node_modules/earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", + "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==", + "license": "ISC" }, "node_modules/eastasianwidth": { "version": "0.2.0", @@ -6713,11 +6701,6 @@ "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" } }, - "node_modules/maplibre-gl/node_modules/earcut": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" - }, "node_modules/maplibre-gl/node_modules/pbf": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", @@ -7813,22 +7796,35 @@ } }, "node_modules/ol": { - "version": "9.2.4", - "resolved": "https://registry.npmjs.org/ol/-/ol-9.2.4.tgz", - "integrity": "sha512-bsbu4ObaAlbELMIZWnYEvX4Z9jO+OyCBshtODhDKmqYTPEfnKOX3RieCr97tpJkqWTZvyV4tS9UQDvHoCdxS+A==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ol/-/ol-10.0.0.tgz", + "integrity": "sha512-Gzfh61cQAxseCWL97VpGwbF91R2D69y3ABUewTl2H1Hjy6ipCtnoKshgO+n3WBrjsbsyS8QnkfmiJZNQGQNeOA==", + "license": "BSD-2-Clause", "dependencies": { "color-rgba": "^3.0.0", "color-space": "^2.0.1", - "earcut": "^2.2.3", + "earcut": "^3.0.0", "geotiff": "^2.0.7", - "pbf": "3.2.1", - "rbush": "^3.0.1" + "pbf": "4.0.1", + "rbush": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/openlayers" } }, + "node_modules/ol/node_modules/pbf": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz", + "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", + "license": "BSD-3-Clause", + "dependencies": { + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8439,9 +8435,10 @@ } }, "node_modules/rbush": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", - "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.0.tgz", + "integrity": "sha512-F5xw+166FYDZI6jEcz+sWEHL5/J+du3kQWkwqWrPKb6iVoLPZh+2KhTS4OoYqrw1v/RO1xQe6WsLwBvrUAlvXw==", + "license": "MIT", "dependencies": { "quickselect": "^2.0.0" } diff --git a/package.json b/package.json index 2b8386e9b..9d340ba73 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "liang-barsky": "^1.0.5", "lodash": "^4.17.21", "maplibre-gl": "^4.5.1", - "ol": "^9.2.4", + "ol": "^10.0.0", "pako": "^2.1.0", "print-js": "^1.6.0", "proj4": "^2.11.0", From f8422f1bfcd517eadb46b830d673ae7c4d3fa7ac Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Tue, 20 Aug 2024 10:34:32 +0700 Subject: [PATCH 04/44] PB-666: Fix error after upgrading. --- .../map/components/cesium/utils/olcs/FeatureConverter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/map/components/cesium/utils/olcs/FeatureConverter.ts b/src/modules/map/components/cesium/utils/olcs/FeatureConverter.ts index f58b96679..9279d420d 100644 --- a/src/modules/map/components/cesium/utils/olcs/FeatureConverter.ts +++ b/src/modules/map/components/cesium/utils/olcs/FeatureConverter.ts @@ -54,7 +54,7 @@ import { } from 'cesium' import type VectorLayer from 'ol/layer/Vector' import type ImageLayer from 'ol/layer/Image' -import type { View } from 'ol' +import type { Feature, View } from 'ol' import type Text from 'ol/style/Text' import type { ColorLike as OLColorLike, PatternDescriptor } from 'ol/colorlike' import type { Color as OLColor } from 'ol/color' @@ -1374,7 +1374,7 @@ export default class FeatureConverter { * @api */ olVectorLayerToCesium( - olLayer: VectorLayer, + olLayer: VectorLayer>, olView: View, featurePrimitiveMap: Record ): VectorLayerCounterpart { From aca65d9600e721655718d077d7dab34be7cb4557 Mon Sep 17 00:00:00 2001 From: Ismail Sunni Date: Thu, 22 Aug 2024 13:38:26 +0700 Subject: [PATCH 05/44] PB-666: Upgrade to OL 10.1.0 --- package-lock.json | 15 +++++++++++---- package.json | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53e1a4c9f..6b8378428 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "liang-barsky": "^1.0.5", "lodash": "^4.17.21", "maplibre-gl": "^4.5.1", - "ol": "^10.0.0", + "ol": "^10.1.0", "pako": "^2.1.0", "print-js": "^1.6.0", "proj4": "^2.11.0", @@ -1986,6 +1986,12 @@ "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==" }, + "node_modules/@types/rbush": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-3.0.4.tgz", + "integrity": "sha512-knSt9cCW8jj1ZSFcFeBZaX++OucmfPxxHiRwTahZfJlnQsek7O0bazTJHWD2RVj9LEoejUYF2de3/stf+QXcXw==", + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -7796,11 +7802,12 @@ } }, "node_modules/ol": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/ol/-/ol-10.0.0.tgz", - "integrity": "sha512-Gzfh61cQAxseCWL97VpGwbF91R2D69y3ABUewTl2H1Hjy6ipCtnoKshgO+n3WBrjsbsyS8QnkfmiJZNQGQNeOA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ol/-/ol-10.1.0.tgz", + "integrity": "sha512-/efepydpzhFoeczA9KAN5t7G0WpFhP46ZXEfSl6JbZ7ipQZ2axpkYB2qt0qcOUlPFYMt7/XQFApH652KB08tTg==", "license": "BSD-2-Clause", "dependencies": { + "@types/rbush": "^3.0.3", "color-rgba": "^3.0.0", "color-space": "^2.0.1", "earcut": "^3.0.0", diff --git a/package.json b/package.json index 9d340ba73..4e7c4a549 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "liang-barsky": "^1.0.5", "lodash": "^4.17.21", "maplibre-gl": "^4.5.1", - "ol": "^10.0.0", + "ol": "^10.1.0", "pako": "^2.1.0", "print-js": "^1.6.0", "proj4": "^2.11.0", From 915ae9dc055aa0e66706aa04d40802cb92904f74 Mon Sep 17 00:00:00 2001 From: Pascal Barth Date: Tue, 27 Aug 2024 09:48:10 +0200 Subject: [PATCH 06/44] Update all libs to latest --- package-lock.json | 1234 +++++++++++++++------------------------------ package.json | 48 +- 2 files changed, 426 insertions(+), 856 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b8378428..77be06f88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,43 +17,43 @@ "@ivanv/vue-collapse-transition": "^1.0.2", "@mapbox/togeojson": "^0.16.2", "@popperjs/core": "^2.11.8", - "@turf/area": "^7.0.0", - "@turf/bbox": "^7.0.0", - "@turf/boolean-contains": "^7.0.0", - "@turf/boolean-point-in-polygon": "^7.0.0", - "@turf/buffer": "^7.0.0", - "@turf/centroid": "^7.0.0", - "@turf/distance": "^7.0.0", - "@turf/explode": "^7.0.0", - "@turf/helpers": "^7.0.0", - "@turf/nearest-point": "^7.0.0", - "@turf/point-to-line-distance": "^7.0.0", + "@turf/area": "^7.1.0", + "@turf/bbox": "^7.1.0", + "@turf/boolean-contains": "^7.1.0", + "@turf/boolean-point-in-polygon": "^7.1.0", + "@turf/buffer": "^7.1.0", + "@turf/centroid": "^7.1.0", + "@turf/distance": "^7.1.0", + "@turf/explode": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@turf/nearest-point": "^7.1.0", + "@turf/point-to-line-distance": "^7.1.0", "animate.css": "^4.1.1", - "axios": "^1.7.3", + "axios": "^1.7.5", "bootstrap": "^5.3.3", "cesium": "^1.120.0", - "chart.js": "^4.4.3", + "chart.js": "^4.4.4", "chartjs-plugin-zoom": "^2.0.1", "dompurify": "^3.1.6", "file-saver": "^2.0.5", "form-data": "^4.0.0", - "geographiclib-geodesic": "^2.0.0", + "geographiclib-geodesic": "^2.1.1", "hammerjs": "^2.0.8", "jquery": "^3.7.1", "liang-barsky": "^1.0.5", "lodash": "^4.17.21", - "maplibre-gl": "^4.5.1", + "maplibre-gl": "^4.6.0", "ol": "^10.1.0", "pako": "^2.1.0", "print-js": "^1.6.0", - "proj4": "^2.11.0", + "proj4": "^2.12.0", "reproject": "^1.2.7", "sortablejs": "^1.15.2", "tippy.js": "^6.3.7", - "vue": "^3.4.35", + "vue": "^3.4.38", "vue-chartjs": "^5.3.1", - "vue-i18n": "^9.13.1", - "vue-router": "^4.4.2", + "vue-i18n": "^9.14.0", + "vue-router": "^4.4.3", "vue3-social-sharing": "^1.1.1", "vuex": "^4.1.0" }, @@ -73,7 +73,7 @@ "@vue/tsconfig": "^0.5.1", "axios-retry": "^4.5.0", "chai": "^5.1.1", - "cypress": "^13.13.2", + "cypress": "^13.13.3", "cypress-browser-permissions": "^1.1.0", "cypress-real-events": "^1.13.0", "cypress-recurse": "^1.35.3", @@ -81,15 +81,15 @@ "cypress-wait-until": "^3.0.2", "dotenv": "^16.4.5", "eslint": "^8.57.0", - "eslint-plugin-cypress": "^3.4.0", + "eslint-plugin-cypress": "^3.5.0", "eslint-plugin-markdownlint": "^0.6.0", "eslint-plugin-mocha": "^10.5.0", "eslint-plugin-prettier-vue": "^5.0.0", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-vue": "^9.27.0", "git-describe": "^4.1.1", - "googleapis": "^140.0.1", - "jsdom": "^24.1.1", + "googleapis": "^142.0.0", + "jsdom": "^25.0.0", "mime-types": "^2.1.35", "mocha-junit-reporter": "^2.2.1", "prettier": "^3.3.3", @@ -98,7 +98,7 @@ "sass": "1.77.6", "start-server-and-test": "^2.0.5", "typescript": "^5.5.4", - "vite": "^5.3.5", + "vite": "^5.4.2", "vite-node": "^2.0.5", "vite-plugin-static-copy": "^1.0.6", "vitest": "^2.0.5", @@ -950,12 +950,12 @@ "dev": true }, "node_modules/@intlify/core-base": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.13.1.tgz", - "integrity": "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.0.tgz", + "integrity": "sha512-zJn0imh9HIsZZUtt9v8T16PeVstPv6bP2YzlrYJwoF8F30gs4brZBwW2KK6EI5WYKFi3NeqX6+UU4gniz5TkGg==", "dependencies": { - "@intlify/message-compiler": "9.13.1", - "@intlify/shared": "9.13.1" + "@intlify/message-compiler": "9.14.0", + "@intlify/shared": "9.14.0" }, "engines": { "node": ">= 16" @@ -965,11 +965,11 @@ } }, "node_modules/@intlify/message-compiler": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.13.1.tgz", - "integrity": "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.0.tgz", + "integrity": "sha512-sXNsoMI0YsipSXW8SR75drmVK56tnJHoYbPXUv2Cf9lz6FzvwsosFm6JtC1oQZI/kU+n7qx0qRrEWkeYFTgETA==", "dependencies": { - "@intlify/shared": "9.13.1", + "@intlify/shared": "9.14.0", "source-map-js": "^1.0.2" }, "engines": { @@ -980,9 +980,9 @@ } }, "node_modules/@intlify/shared": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.13.1.tgz", - "integrity": "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.0.tgz", + "integrity": "sha512-r+N8KRQL7LgN1TMTs1A2svfuAU0J94Wu9wWdJVJqYsoMMLIeJxrPjazihfHpmJqfgZq0ah3Y9Q4pgWV2O90Fyg==", "engines": { "node": ">= 16" }, @@ -1232,9 +1232,9 @@ } }, "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.3.0.tgz", - "integrity": "sha512-eSiQ3E5LUSxAOY9ABXGyfNhout2iEa6mUxKeaQ9nJ8NL1NuaQYU7zKqzx/LEYcXe1neT4uYAgM1wYZj3fTSXtA==", + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.3.1.tgz", + "integrity": "sha512-5ueL4UDitzVtceQ8J4kY+Px3WK+eZTsmGwha3MBKHKqiHvKrjWWwBCIl1K8BuJSc5OFh83uI8IFNoFvQxX2uUw==", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", @@ -1243,7 +1243,7 @@ "quickselect": "^2.0.0", "rw": "^1.3.3", "sort-object": "^3.0.3", - "tinyqueue": "^2.0.3" + "tinyqueue": "^3.0.0" }, "bin": { "gl-style-format": "dist/gl-style-format.mjs", @@ -1398,9 +1398,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz", - "integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz", + "integrity": "sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==", "cpu": [ "arm" ], @@ -1411,9 +1411,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz", - "integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz", + "integrity": "sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==", "cpu": [ "arm64" ], @@ -1424,9 +1424,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz", - "integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz", + "integrity": "sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==", "cpu": [ "arm64" ], @@ -1437,9 +1437,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz", - "integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz", + "integrity": "sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==", "cpu": [ "x64" ], @@ -1450,9 +1450,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz", - "integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz", + "integrity": "sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz", + "integrity": "sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==", "cpu": [ "arm" ], @@ -1463,9 +1476,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz", - "integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz", + "integrity": "sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==", "cpu": [ "arm64" ], @@ -1476,9 +1489,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz", - "integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz", + "integrity": "sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==", "cpu": [ "arm64" ], @@ -1489,11 +1502,11 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz", - "integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz", + "integrity": "sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==", "cpu": [ - "ppc64le" + "ppc64" ], "dev": true, "optional": true, @@ -1502,9 +1515,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz", - "integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz", + "integrity": "sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==", "cpu": [ "riscv64" ], @@ -1515,9 +1528,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz", - "integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz", + "integrity": "sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==", "cpu": [ "s390x" ], @@ -1528,9 +1541,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz", - "integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz", + "integrity": "sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==", "cpu": [ "x64" ], @@ -1541,9 +1554,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz", - "integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz", + "integrity": "sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==", "cpu": [ "x64" ], @@ -1554,9 +1567,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz", - "integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz", + "integrity": "sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==", "cpu": [ "arm64" ], @@ -1567,9 +1580,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz", - "integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz", + "integrity": "sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==", "cpu": [ "ia32" ], @@ -1580,9 +1593,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz", - "integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz", + "integrity": "sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==", "cpu": [ "x64" ], @@ -1620,12 +1633,13 @@ "dev": true }, "node_modules/@turf/area": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/area/-/area-7.0.0.tgz", - "integrity": "sha512-Q/P6OGV8dJJs1BiraKFNBjtsMbz7B52mLCtgKh3syzujSREMx52RlsiOBQp8GujFMMiau+Mt25XKbVwtjHVi8Q==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-7.1.0.tgz", + "integrity": "sha512-w91FEe02/mQfMPRX2pXua48scFuKJ2dSVMF2XmJ6+BJfFiCPxp95I3+Org8+ZsYv93CDNKbf0oLNEPnuQdgs2g==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/meta": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/meta": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1633,12 +1647,13 @@ } }, "node_modules/@turf/bbox": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-7.0.0.tgz", - "integrity": "sha512-IyXG5HAsn6IZLdAtQo7aWYccjU5WsV+uzIzhGaXrh/qTVylSYmRiWgLdiekHZVED9nv9r7D/EJUMOT4zyA6POA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-7.1.0.tgz", + "integrity": "sha512-PdWPz9tW86PD78vSZj2fiRaB8JhUHy6piSa/QXb83lucxPK+HTAdzlDQMTKj5okRCU8Ox/25IR2ep9T8NdopRA==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/meta": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/meta": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1646,12 +1661,13 @@ } }, "node_modules/@turf/bearing": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-7.0.0.tgz", - "integrity": "sha512-r6eBNqqiC8OtW+xIzu0ZyciAUfM85l2LVN2qpTeEyhnaNmnPw7hDsnqwZcbqoBFSLB66MO+BLH40X5OdaoRmmA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-7.1.0.tgz", + "integrity": "sha512-X5lackrZ6FW+YhgjWxwVFRgWD1j4xm4t5VvE6EE6v/1PVaHQ5OCjf6u1oaLx5LSG+gaHUhjTlAHrn9MYPFaeTA==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1659,15 +1675,16 @@ } }, "node_modules/@turf/boolean-contains": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-7.0.0.tgz", - "integrity": "sha512-1NILJdO5OO1YrD7hYPlpahROkzd1DFA7Lcp7SxL+hTtKTp/a2iZx+K6u2qKMLUlPO1p2zhSbMfvjl1T6s/H8XQ==", - "dependencies": { - "@turf/bbox": "^7.0.0", - "@turf/boolean-point-in-polygon": "^7.0.0", - "@turf/boolean-point-on-line": "^7.0.0", - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-7.1.0.tgz", + "integrity": "sha512-ldy4j1/RVChYTYjEb4wWaE/JyF1jA87WpsB4eVLic6OcAYJGs7POF1kfKbcdkJJiRBmhI3CXNA+u+m9y4Z/j3g==", + "dependencies": { + "@turf/bbox": "^7.1.0", + "@turf/boolean-point-in-polygon": "^7.1.0", + "@turf/boolean-point-on-line": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1675,12 +1692,13 @@ } }, "node_modules/@turf/boolean-point-in-polygon": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.0.0.tgz", - "integrity": "sha512-Z9swETfICqUJ8iVLZimvIOh8r4Wrlu9/X/c/5vIEeVvG4Lu78Ztmgu1KaobZJFC93/ntOAjMBavc9aNgw7TXgQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.1.0.tgz", + "integrity": "sha512-mprVsyIQ+ijWTZwbnO4Jhxu94ZW2M2CheqLiRTsGJy0Ooay9v6Av5/Nl3/Gst7ZVXxPqMeMaFYkSzcTc87AKew==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "point-in-polygon-hao": "^1.1.0", "tslib": "^2.6.2" }, @@ -1689,12 +1707,13 @@ } }, "node_modules/@turf/boolean-point-on-line": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-7.0.0.tgz", - "integrity": "sha512-9/1hj2MxcUU4fZu+MQC6rdMsdvAYNTtfxssLrZ1dGXo+NcAoWFbZSrfk62pSJBflveyKY5kXPYY+xQfLT0NeDQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-7.1.0.tgz", + "integrity": "sha512-Kd83EjeTyY4kVMAhcW3Lb8aChwh24BUIhmpE9Or8M+ETNsFGzn9M7qtIySJHLRzKAL3letvWSKXKQPuK1AhAzg==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1702,16 +1721,17 @@ } }, "node_modules/@turf/buffer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-7.0.0.tgz", - "integrity": "sha512-viw3XjTtYVtkq5DkRDBQjXoi5QeEMhe4JHWXIfHMHs4o5F9B+lZ8+TtXWo18X5aAXknv6ib1z2syoaQdBpb5Xw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-7.1.0.tgz", + "integrity": "sha512-QM3JiCMYA19k5ouO8wJtvICX3Y8XntxVpDfHSKhFFidZcCkMTR2PWWOpwS6EoL3t75rSKw/FOLIPLZGtIu963w==", "dependencies": { - "@turf/bbox": "^7.0.0", - "@turf/center": "^7.0.0", - "@turf/helpers": "^7.0.0", + "@turf/bbox": "^7.1.0", + "@turf/center": "^7.1.0", + "@turf/helpers": "^7.1.0", "@turf/jsts": "^2.7.1", - "@turf/meta": "^7.0.0", - "@turf/projection": "^7.0.0", + "@turf/meta": "^7.1.0", + "@turf/projection": "^7.1.0", + "@types/geojson": "^7946.0.10", "d3-geo": "1.7.1" }, "funding": { @@ -1719,12 +1739,13 @@ } }, "node_modules/@turf/center": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/center/-/center-7.0.0.tgz", - "integrity": "sha512-5RZia9uuWxz2oCyd1vsNkBeraBNdwCsIo4UGRQdyswBeLFVbRwIUa7M7+2z2D7B1YIgovuLIRVfk6FeWUQXDtQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/center/-/center-7.1.0.tgz", + "integrity": "sha512-p9AvBMwNZmRg65kU27cGKHAUQnEcdz8Y7f/i5DvaMfm4e8zmawr+hzPKXaUpUfiTyLs8Xt2W9vlOmNGyH+6X3w==", "dependencies": { - "@turf/bbox": "^7.0.0", - "@turf/helpers": "^7.0.0", + "@turf/bbox": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1732,12 +1753,13 @@ } }, "node_modules/@turf/centroid": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-7.0.0.tgz", - "integrity": "sha512-TMKp5yadglNVRxX3xuk1qQDEy5JFHmlYVBamzXuD8DL8rYdVog2x4gQHrwn7xrUyAlKJ4fUZZPkYBWfW6TDWbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-7.1.0.tgz", + "integrity": "sha512-1Y1b2l+ZB1CZ+ITjUCsGqC4/tSjwm/R4OUfDztVqyyCq/VvezkLmTNqvXTGXgfP0GXkpv68iCfxF5M7QdM5pJQ==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/meta": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/meta": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1745,11 +1767,12 @@ } }, "node_modules/@turf/clone": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.0.0.tgz", - "integrity": "sha512-bQBx/wbQoGNtZzuHetLt44NMqOCnjSXcvTWm+LJ7YTmwrqZVAjISDhFxgawY/L+G3p+ya5WoxQwZWak80uYg3A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-7.1.0.tgz", + "integrity": "sha512-5R9qeWvL7FDdBIbEemd0eCzOStr09oburDvJ1hRiPCFX6rPgzcZBQ0gDmZzoF4AFcNLb5IwknbLZjVLaUGWtFA==", "dependencies": { - "@turf/helpers": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1757,12 +1780,13 @@ } }, "node_modules/@turf/distance": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-7.0.0.tgz", - "integrity": "sha512-DBPKhHABpPZ0KRduRpEaoi8MB6r1DVuyyps68VFH2Qi5H0ZnFtJFj7nQxBPZR3bVpbUq4zzu7I+MiNAd3ujFWQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-7.1.0.tgz", + "integrity": "sha512-hhNHhxCHB3ddzAGCNY4BtE29OZh+DAJPvUapQz+wOjISnlwvMcwLKvslgHWSYF536QDVe/93FEU2q67+CsZTPA==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1770,12 +1794,13 @@ } }, "node_modules/@turf/explode": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-7.0.0.tgz", - "integrity": "sha512-q7KZ/PxY9zHN4UGXaADUpsHGkj8lbexVZxdBnp0nEfTHm/ziLTAfpI15CdAknoz4Ee8k8tx7ldosVjjg7YJ3/g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-7.1.0.tgz", + "integrity": "sha512-To+GUbU6HtcHZ8S0w/dw1EbdQIOCXALTr6Ug5/IFg8hIBMJelDpVr3Smwy8uqhDRFinY2eprBwQnDPcd10eCqA==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/meta": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/meta": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1783,11 +1808,11 @@ } }, "node_modules/@turf/helpers": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.0.0.tgz", - "integrity": "sha512-vwZvxRuyjGpGXvhXSbT9mX6FK92dBMLWbMbDJ/MXQUPx17ReVPFc+6N6IcxAzZfkiCnqy7vpuq0c+/TTrQxIiA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-7.1.0.tgz", + "integrity": "sha512-dTeILEUVeNbaEeoZUOhxH5auv7WWlOShbx7QSd4s0T4Z0/iz90z9yaVCtZOLbU89umKotwKaJQltBNO9CzVgaQ==", "dependencies": { - "deep-equal": "^2.2.3", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1795,11 +1820,12 @@ } }, "node_modules/@turf/invariant": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.0.0.tgz", - "integrity": "sha512-Kayszfz3W8yJ1/cIA3/aNSzAuw7QgSp+IwsSmhLAfp4DbjV0o6sjxRZXRY2gRstZHqkNHSSEeir8V/icdO8sjA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-7.1.0.tgz", + "integrity": "sha512-OCLNqkItBYIP1nE9lJGuIUatWGtQ4rhBKAyTfFu0z8npVzGEYzvguEeof8/6LkKmTTEHW53tCjoEhSSzdRh08Q==", "dependencies": { - "@turf/helpers": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1815,25 +1841,27 @@ } }, "node_modules/@turf/meta": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.0.0.tgz", - "integrity": "sha512-cEXr13uFwhXq5mFBy0IK1U/QepE5qgk3zXpBYsla3lYV7cB83Vh+NNUR+r0/w/QoJqest1TG4H20F9tGYWPi/g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-7.1.0.tgz", + "integrity": "sha512-ZgGpWWiKz797Fe8lfRj7HKCkGR+nSJ/5aKXMyofCvLSc2PuYJs/qyyifDPWjASQQCzseJ7AlF2Pc/XQ/3XkkuA==", "dependencies": { - "@turf/helpers": "^7.0.0" + "@turf/helpers": "^7.1.0", + "@types/geojson": "^7946.0.10" }, "funding": { "url": "https://opencollective.com/turf" } }, "node_modules/@turf/nearest-point": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-7.0.0.tgz", - "integrity": "sha512-h3uLUoeo6JWTirpI499SRooqEoDxia2C/kDqAwAeXFqwxzGqGprtNA/C0bMgHfxE1M2rxORGzvgywKirpLu1dA==", - "dependencies": { - "@turf/clone": "^7.0.0", - "@turf/distance": "^7.0.0", - "@turf/helpers": "^7.0.0", - "@turf/meta": "^7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-7.1.0.tgz", + "integrity": "sha512-VyInmhqfVWp+jE7sCK95o46qc4tDjAgzbRfRjr+rTgfFS1Sndyy1PdwyNn6TjBFDxiM6e+mjMEeGPjb1smJlEg==", + "dependencies": { + "@turf/clone": "^7.1.0", + "@turf/distance": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@turf/meta": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1841,18 +1869,19 @@ } }, "node_modules/@turf/point-to-line-distance": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-7.0.0.tgz", - "integrity": "sha512-BMNy/vbvm9NjrgJq6MA3xhruy+cp/Wj+ff3fiu8Rdl5QX/dMwCeyCZuuvzCftup6GTPUhRbpe0YRFUBInGzx/g==", - "dependencies": { - "@turf/bearing": "^7.0.0", - "@turf/distance": "^7.0.0", - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", - "@turf/meta": "^7.0.0", - "@turf/projection": "^7.0.0", - "@turf/rhumb-bearing": "^7.0.0", - "@turf/rhumb-distance": "^7.0.0", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-7.1.0.tgz", + "integrity": "sha512-Ps9eTOCaiNgxDaSNQux0wAcSLcrI0y0zYFaD9HnVm+yCMRliQXneFti2XXotS+gR7TpgnLRAAzyx4VzJMSN2tw==", + "dependencies": { + "@turf/bearing": "^7.1.0", + "@turf/distance": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@turf/meta": "^7.1.0", + "@turf/projection": "^7.1.0", + "@turf/rhumb-bearing": "^7.1.0", + "@turf/rhumb-distance": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1860,13 +1889,14 @@ } }, "node_modules/@turf/projection": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-7.0.0.tgz", - "integrity": "sha512-EoPbZPZSDv0AJMfYhqnS455CVMYwPU78kHyQHeOnMR1Tc5z+TiImvyq55umhfecgpETzuDsjFkmeQ2phDKTmbA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-7.1.0.tgz", + "integrity": "sha512-3wHluMoOvXnTe7dfi0kcluTyLNG5MwGsSsK5OA98vkkLH6a1xvItn8e9GcesuT07oB2km/bgefxYEIvjQG5JCA==", "dependencies": { - "@turf/clone": "^7.0.0", - "@turf/helpers": "^7.0.0", - "@turf/meta": "^7.0.0", + "@turf/clone": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@turf/meta": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1874,12 +1904,13 @@ } }, "node_modules/@turf/rhumb-bearing": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-7.0.0.tgz", - "integrity": "sha512-4qDggFDNBbWdD+o3H+vna5eiKCAsmqAueP3T5rSEB1ier77wVgjg7cs7eTrEBbpuCbPAho7NDNdyAjgItydgLQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-7.1.0.tgz", + "integrity": "sha512-ESZt70eOljHVnQMFKIdiu8LIHuQlpZgzh2nqSfV40BrYjsjI/sBKeK+sp2cBWk88nsSDlriPuMTNh4f50Jqpkw==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -1887,12 +1918,13 @@ } }, "node_modules/@turf/rhumb-distance": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-7.0.0.tgz", - "integrity": "sha512-VAZnZcHbHHUU/Li0sj50/T6bBGRWvJ6eOZmw2aZFxxnC+AkHv4LTKDf0wNsxR03ZwGEh4uJM8OuirNugLIhAyA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-7.1.0.tgz", + "integrity": "sha512-fR1V+yC4E1tnbdThomosiLcv0PQOwbfLSPM8rSWuxbMcJtffsncWxyJ0+N1F5juuHbcdaYhlduX8ri5I0ZCejw==", "dependencies": { - "@turf/helpers": "^7.0.0", - "@turf/invariant": "^7.0.0", + "@turf/helpers": "^7.1.0", + "@turf/invariant": "^7.1.0", + "@types/geojson": "^7946.0.10", "tslib": "^2.6.2" }, "funding": { @@ -2378,36 +2410,36 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.35.tgz", - "integrity": "sha512-gKp0zGoLnMYtw4uS/SJRRO7rsVggLjvot3mcctlMXunYNsX+aRJDqqw/lV5/gHK91nvaAAlWFgdVl020AW1Prg==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", + "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.35", + "@vue/shared": "3.4.38", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.35.tgz", - "integrity": "sha512-pWIZRL76/oE/VMhdv/ovZfmuooEni6JPG1BFe7oLk5DZRo/ImydXijoZl/4kh2406boRQ7lxTYzbZEEXEhj9NQ==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", + "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", "dependencies": { - "@vue/compiler-core": "3.4.35", - "@vue/shared": "3.4.35" + "@vue/compiler-core": "3.4.38", + "@vue/shared": "3.4.38" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.35.tgz", - "integrity": "sha512-xacnRS/h/FCsjsMfxBkzjoNxyxEyKyZfBch/P4vkLRvYJwe5ChXmZZrj8Dsed/752H2Q3JE8kYu9Uyha9J6PgA==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz", + "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.35", - "@vue/compiler-dom": "3.4.35", - "@vue/compiler-ssr": "3.4.35", - "@vue/shared": "3.4.35", + "@vue/compiler-core": "3.4.38", + "@vue/compiler-dom": "3.4.38", + "@vue/compiler-ssr": "3.4.38", + "@vue/shared": "3.4.38", "estree-walker": "^2.0.2", "magic-string": "^0.30.10", "postcss": "^8.4.40", @@ -2415,12 +2447,12 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.35.tgz", - "integrity": "sha512-7iynB+0KB1AAJKk/biENTV5cRGHRdbdaD7Mx3nWcm1W8bVD6QmnH3B4AHhQQ1qZHhqFwzEzMwiytXm3PX1e60A==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz", + "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==", "dependencies": { - "@vue/compiler-dom": "3.4.35", - "@vue/shared": "3.4.35" + "@vue/compiler-dom": "3.4.38", + "@vue/shared": "3.4.38" } }, "node_modules/@vue/compiler-vue2": { @@ -2501,49 +2533,49 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.35.tgz", - "integrity": "sha512-Ggtz7ZZHakriKioveJtPlStYardwQH6VCs9V13/4qjHSQb/teE30LVJNrbBVs4+aoYGtTQKJbTe4CWGxVZrvEw==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.38.tgz", + "integrity": "sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==", "dependencies": { - "@vue/shared": "3.4.35" + "@vue/shared": "3.4.38" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.35.tgz", - "integrity": "sha512-D+BAjFoWwT5wtITpSxwqfWZiBClhBbR+bm0VQlWYFOadUUXFo+5wbe9ErXhLvwguPiLZdEF13QAWi2vP3ZD5tA==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.38.tgz", + "integrity": "sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==", "dependencies": { - "@vue/reactivity": "3.4.35", - "@vue/shared": "3.4.35" + "@vue/reactivity": "3.4.38", + "@vue/shared": "3.4.38" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.35.tgz", - "integrity": "sha512-yGOlbos+MVhlS5NWBF2HDNgblG8e2MY3+GigHEyR/dREAluvI5tuUUgie3/9XeqhPE4LF0i2wjlduh5thnfOqw==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.38.tgz", + "integrity": "sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==", "dependencies": { - "@vue/reactivity": "3.4.35", - "@vue/runtime-core": "3.4.35", - "@vue/shared": "3.4.35", + "@vue/reactivity": "3.4.38", + "@vue/runtime-core": "3.4.38", + "@vue/shared": "3.4.38", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.35.tgz", - "integrity": "sha512-iZ0e/u9mRE4T8tNhlo0tbA+gzVkgv8r5BX6s1kRbOZqfpq14qoIvCZ5gIgraOmYkMYrSEZgkkojFPr+Nyq/Mnw==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.38.tgz", + "integrity": "sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==", "dependencies": { - "@vue/compiler-ssr": "3.4.35", - "@vue/shared": "3.4.35" + "@vue/compiler-ssr": "3.4.38", + "@vue/shared": "3.4.38" }, "peerDependencies": { - "vue": "3.4.35" + "vue": "3.4.38" } }, "node_modules/@vue/shared": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.35.tgz", - "integrity": "sha512-hvuhBYYDe+b1G8KHxsQ0diDqDMA8D9laxWZhNAjE83VZb5UDaXl9Xnz7cGdDSyiHM90qqI/CyGMcpBpiDy6VVQ==" + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", + "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==" }, "node_modules/@vue/tsconfig": { "version": "0.5.1", @@ -2758,21 +2790,6 @@ "node": ">=0.10.0" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -2854,20 +2871,6 @@ "tslib": "^2.3.0" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -2884,9 +2887,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz", - "integrity": "sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.5.tgz", + "integrity": "sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -3119,6 +3122,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3241,9 +3245,9 @@ } }, "node_modules/chart.js": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", - "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz", + "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -3599,9 +3603,9 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.13.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.2.tgz", - "integrity": "sha512-PvJQU33933NvS1StfzEb8/mu2kMy4dABwCF+yd5Bi7Qly1HOVf+Bufrygee/tlmty/6j5lX+KIi8j9Q3JUMbhA==", + "version": "13.13.3", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.3.tgz", + "integrity": "sha512-hUxPrdbJXhUOTzuML+y9Av7CKoYznbD83pt8g3klgpioEha0emfx4WNIuVRx0C76r0xV2MIwAW9WYiXfVJYFQw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -3818,37 +3822,6 @@ "node": ">=6" } }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3859,6 +3832,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3871,22 +3845,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4116,6 +4074,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -4127,29 +4086,11 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "engines": { "node": ">= 0.4" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -4277,9 +4218,9 @@ } }, "node_modules/eslint-plugin-cypress": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-3.4.0.tgz", - "integrity": "sha512-Rrrr3Ri6wHqzrRr+TyUV7bDS4UnMMrFY1R1PP2F7XdGfe9txDC6lQEshyoNOWqGoPkbbeDm1x1XPc/adxemsnA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-3.5.0.tgz", + "integrity": "sha512-JZQ6XnBTNI8h1B9M7wJSFzc48SYbh7VMMKaNTQOFa3BQlnmXPrVc4PKen8R+fpv6VleiPeej6VxloGb42zdRvw==", "dev": true, "dependencies": { "globals": "^13.20.0" @@ -4966,14 +4907,6 @@ } } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -5068,14 +5001,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5123,9 +5049,9 @@ } }, "node_modules/geographiclib-geodesic": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/geographiclib-geodesic/-/geographiclib-geodesic-2.0.0.tgz", - "integrity": "sha512-qRE11UEF3Zn9VwDFf+Q1ZNn4VW2xwZWeAPiFRrKVSKn2K5lds1jOxhxgFJwbKh5YV58ME6+LGiRtm4A0CjFyiQ==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/geographiclib-geodesic/-/geographiclib-geodesic-2.1.1.tgz", + "integrity": "sha512-lkd8EUkPSByobWu9BPMHTdYA5AUZxOa8McmUNtBE9KrvUJEvSADnN6gTDmhXbi6NzdA16LtWLpSxLE/lIIRhyA==" }, "node_modules/geojson-stream": { "version": "0.1.0", @@ -5186,6 +5112,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -5333,32 +5260,46 @@ } }, "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", + "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" + "ini": "^4.1.3", + "kind-of": "^6.0.3", + "which": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=16" } }, "node_modules/global-prefix/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/global-prefix/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } }, "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dependencies": { - "isexe": "^2.0.0" + "isexe": "^3.1.1" }, "bin": { - "which": "bin/which" + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/globals": { @@ -5414,9 +5355,9 @@ } }, "node_modules/googleapis": { - "version": "140.0.1", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-140.0.1.tgz", - "integrity": "sha512-ZGvBX4mQcFXO9ACnVNg6Aqy3KtBPB5zTuue43YVLxwn8HSv8jB7w+uDKoIPSoWuxGROgnj2kbng6acXncOQRNA==", + "version": "142.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-142.0.0.tgz", + "integrity": "sha512-LsU1ynez4/KNPwnFMSDI93pBEsETNdQPCrT3kz2qgiNg5H2pW4dKW+1VmENMkZ4u9lMxA89nnXD3nqWBJ0rruQ==", "dev": true, "dependencies": { "google-auth-library": "^9.0.0", @@ -5460,6 +5401,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -5505,14 +5447,6 @@ "node": ">=0.8.0" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -5526,6 +5460,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -5537,6 +5472,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -5548,20 +5484,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, + "dev": true, "engines": { "node": ">= 0.4" }, @@ -5573,6 +5496,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -5760,60 +5684,6 @@ "node": ">=10" } }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5826,38 +5696,12 @@ "node": ">=8" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -5870,20 +5714,6 @@ "is-ci": "bin.js" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -5938,17 +5768,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5958,20 +5777,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -6008,21 +5813,6 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-retry-allowed": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", @@ -6035,31 +5825,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -6072,34 +5837,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -6118,41 +5855,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/isobject": { "version": "3.0.1", @@ -6223,9 +5930,9 @@ "dev": true }, "node_modules/jsdom": { - "version": "24.1.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz", - "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==", + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", + "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", "dev": true, "dependencies": { "cssstyle": "^4.0.1", @@ -6668,9 +6375,9 @@ "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==" }, "node_modules/maplibre-gl": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.5.1.tgz", - "integrity": "sha512-pKFDK8ZU2atwZWC8gdPVhN7Bf5HIPgtA+IG/iQ7J6WgmqSwCSmylc5q3stahWqXfx9PYUwVNJITrp1Hw96SUiA==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.6.0.tgz", + "integrity": "sha512-zobZK+fE+XM+7K81fk5pSBYWZlTGjGT0P96y2fR4DV2ry35ZBfAd0uWNatll69EgYeE+uOhN1MvEk+z1PCuyOQ==", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -6679,7 +6386,7 @@ "@mapbox/unitbezier": "^0.0.1", "@mapbox/vector-tile": "^1.3.1", "@mapbox/whoots-js": "^3.1.0", - "@maplibre/maplibre-gl-style-spec": "^20.3.0", + "@maplibre/maplibre-gl-style-spec": "^20.3.1", "@types/geojson": "^7946.0.14", "@types/geojson-vt": "3.2.5", "@types/mapbox__point-geometry": "^0.1.4", @@ -6689,7 +6396,7 @@ "earcut": "^3.0.0", "geojson-vt": "^4.0.2", "gl-matrix": "^3.4.3", - "global-prefix": "^3.0.0", + "global-prefix": "^4.0.0", "kdbush": "^4.0.2", "murmurhash-js": "^1.0.0", "pbf": "^3.3.0", @@ -6724,11 +6431,6 @@ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" }, - "node_modules/maplibre-gl/node_modules/tinyqueue": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" - }, "node_modules/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -7301,12 +7003,12 @@ ] }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -7757,46 +7459,7 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8103,14 +7766,6 @@ "resolved": "https://registry.npmjs.org/point-in-polygon-hao/-/point-in-polygon-hao-1.1.0.tgz", "integrity": "sha512-3hTIM2j/v9Lio+wOyur3kckD4NxruZhpowUbEgmyikW+a2Kppjtu1eN+AhnMQtoHW46zld88JiYWv6fxpsDrTQ==" }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/postcss": { "version": "8.4.41", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", @@ -8236,9 +7891,9 @@ } }, "node_modules/proj4": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.11.0.tgz", - "integrity": "sha512-SasuTkAx8HnWQHfIyhkdUNJorSJqINHAN3EyMWYiQRVorftz9DHz650YraFgczwgtHOxqnfuDxSNv3C8MUnHeg==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.12.0.tgz", + "integrity": "sha512-cQJxcVX7+fmAhOxoazKgk76GkGYQ5HcLod4rdy2MizhPvLdrZQJThxsHoz/TjjdxUvTm/rbozMgE0q9mdXKWIw==", "dependencies": { "mgrs": "1.0.0", "wkt-parser": "^1.3.3" @@ -8481,23 +8136,6 @@ "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", "dev": true }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", - "dependencies": { - "call-bind": "^1.0.6", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/reproject": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/reproject/-/reproject-1.2.7.tgz", @@ -8621,9 +8259,9 @@ } }, "node_modules/rollup": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz", - "integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.1.tgz", + "integrity": "sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -8636,21 +8274,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.0", - "@rollup/rollup-android-arm64": "4.14.0", - "@rollup/rollup-darwin-arm64": "4.14.0", - "@rollup/rollup-darwin-x64": "4.14.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.0", - "@rollup/rollup-linux-arm64-gnu": "4.14.0", - "@rollup/rollup-linux-arm64-musl": "4.14.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.0", - "@rollup/rollup-linux-riscv64-gnu": "4.14.0", - "@rollup/rollup-linux-s390x-gnu": "4.14.0", - "@rollup/rollup-linux-x64-gnu": "4.14.0", - "@rollup/rollup-linux-x64-musl": "4.14.0", - "@rollup/rollup-win32-arm64-msvc": "4.14.0", - "@rollup/rollup-win32-ia32-msvc": "4.14.0", - "@rollup/rollup-win32-x64-msvc": "4.14.0", + "@rollup/rollup-android-arm-eabi": "4.21.1", + "@rollup/rollup-android-arm64": "4.21.1", + "@rollup/rollup-darwin-arm64": "4.21.1", + "@rollup/rollup-darwin-x64": "4.21.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.21.1", + "@rollup/rollup-linux-arm-musleabihf": "4.21.1", + "@rollup/rollup-linux-arm64-gnu": "4.21.1", + "@rollup/rollup-linux-arm64-musl": "4.21.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.21.1", + "@rollup/rollup-linux-riscv64-gnu": "4.21.1", + "@rollup/rollup-linux-s390x-gnu": "4.21.1", + "@rollup/rollup-linux-x64-gnu": "4.21.1", + "@rollup/rollup-linux-x64-musl": "4.21.1", + "@rollup/rollup-win32-arm64-msvc": "4.21.1", + "@rollup/rollup-win32-ia32-msvc": "4.21.1", + "@rollup/rollup-win32-x64-msvc": "4.21.1", "fsevents": "~2.3.2" } }, @@ -8780,6 +8419,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -8792,20 +8432,6 @@ "node": ">= 0.4" } }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -8845,6 +8471,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -9105,17 +8732,6 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/stream-combiner": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", @@ -9289,9 +8905,9 @@ } }, "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" }, "node_modules/tinyrainbow": { "version": "1.2.0", @@ -9607,14 +9223,14 @@ } }, "node_modules/vite": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz", - "integrity": "sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", + "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" + "postcss": "^8.4.41", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -9633,6 +9249,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -9650,6 +9267,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -9964,15 +9584,15 @@ } }, "node_modules/vue": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.35.tgz", - "integrity": "sha512-+fl/GLmI4GPileHftVlCdB7fUL4aziPcqTudpTGXCT8s+iZWuOCeNEB5haX6Uz2IpRrbEXOgIFbe+XciCuGbNQ==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.38.tgz", + "integrity": "sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==", "dependencies": { - "@vue/compiler-dom": "3.4.35", - "@vue/compiler-sfc": "3.4.35", - "@vue/runtime-dom": "3.4.35", - "@vue/server-renderer": "3.4.35", - "@vue/shared": "3.4.35" + "@vue/compiler-dom": "3.4.38", + "@vue/compiler-sfc": "3.4.38", + "@vue/runtime-dom": "3.4.38", + "@vue/server-renderer": "3.4.38", + "@vue/shared": "3.4.38" }, "peerDependencies": { "typescript": "*" @@ -10017,12 +9637,12 @@ } }, "node_modules/vue-i18n": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.13.1.tgz", - "integrity": "sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.0.tgz", + "integrity": "sha512-LxmpRuCt2rI8gqU+kxeflRZMQn4D5+4M3oP3PWZdowW/ePJraHqhF7p4CuaME52mUxdw3Mmy2yAUKgfZYgCRjA==", "dependencies": { - "@intlify/core-base": "9.13.1", - "@intlify/shared": "9.13.1", + "@intlify/core-base": "9.14.0", + "@intlify/shared": "9.14.0", "@vue/devtools-api": "^6.5.0" }, "engines": { @@ -10036,9 +9656,9 @@ } }, "node_modules/vue-router": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.2.tgz", - "integrity": "sha512-1qNybkn2L7QsLzaXs8nvlQmRKp8XF8DCxZys/Jr1JpQcHsKUxTKzTxCVA1G7NfBfwRIBgCJPoujOG5lHCCNUxw==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.4.3.tgz", + "integrity": "sha512-sv6wmNKx2j3aqJQDMxLFzs/u/mjA9Z5LCgy6BE0f7yFWMjrPLnS/sPNn8ARY/FXw6byV18EFutn5lTO6+UsV5A==", "dependencies": { "@vue/devtools-api": "^6.6.3" }, @@ -10191,56 +9811,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", diff --git a/package.json b/package.json index 4e7c4a549..48c750816 100644 --- a/package.json +++ b/package.json @@ -50,43 +50,43 @@ "@ivanv/vue-collapse-transition": "^1.0.2", "@mapbox/togeojson": "^0.16.2", "@popperjs/core": "^2.11.8", - "@turf/area": "^7.0.0", - "@turf/bbox": "^7.0.0", - "@turf/boolean-contains": "^7.0.0", - "@turf/boolean-point-in-polygon": "^7.0.0", - "@turf/buffer": "^7.0.0", - "@turf/centroid": "^7.0.0", - "@turf/distance": "^7.0.0", - "@turf/explode": "^7.0.0", - "@turf/helpers": "^7.0.0", - "@turf/nearest-point": "^7.0.0", - "@turf/point-to-line-distance": "^7.0.0", + "@turf/area": "^7.1.0", + "@turf/bbox": "^7.1.0", + "@turf/boolean-contains": "^7.1.0", + "@turf/boolean-point-in-polygon": "^7.1.0", + "@turf/buffer": "^7.1.0", + "@turf/centroid": "^7.1.0", + "@turf/distance": "^7.1.0", + "@turf/explode": "^7.1.0", + "@turf/helpers": "^7.1.0", + "@turf/nearest-point": "^7.1.0", + "@turf/point-to-line-distance": "^7.1.0", "animate.css": "^4.1.1", - "axios": "^1.7.3", + "axios": "^1.7.5", "bootstrap": "^5.3.3", "cesium": "^1.120.0", - "chart.js": "^4.4.3", + "chart.js": "^4.4.4", "chartjs-plugin-zoom": "^2.0.1", "dompurify": "^3.1.6", "file-saver": "^2.0.5", "form-data": "^4.0.0", - "geographiclib-geodesic": "^2.0.0", + "geographiclib-geodesic": "^2.1.1", "hammerjs": "^2.0.8", "jquery": "^3.7.1", "liang-barsky": "^1.0.5", "lodash": "^4.17.21", - "maplibre-gl": "^4.5.1", + "maplibre-gl": "^4.6.0", "ol": "^10.1.0", "pako": "^2.1.0", "print-js": "^1.6.0", - "proj4": "^2.11.0", + "proj4": "^2.12.0", "reproject": "^1.2.7", "sortablejs": "^1.15.2", "tippy.js": "^6.3.7", - "vue": "^3.4.35", + "vue": "^3.4.38", "vue-chartjs": "^5.3.1", - "vue-i18n": "^9.13.1", - "vue-router": "^4.4.2", + "vue-i18n": "^9.14.0", + "vue-router": "^4.4.3", "vue3-social-sharing": "^1.1.1", "vuex": "^4.1.0" }, @@ -106,7 +106,7 @@ "@vue/tsconfig": "^0.5.1", "axios-retry": "^4.5.0", "chai": "^5.1.1", - "cypress": "^13.13.2", + "cypress": "^13.13.3", "cypress-browser-permissions": "^1.1.0", "cypress-real-events": "^1.13.0", "cypress-recurse": "^1.35.3", @@ -114,15 +114,15 @@ "cypress-wait-until": "^3.0.2", "dotenv": "^16.4.5", "eslint": "^8.57.0", - "eslint-plugin-cypress": "^3.4.0", + "eslint-plugin-cypress": "^3.5.0", "eslint-plugin-markdownlint": "^0.6.0", "eslint-plugin-mocha": "^10.5.0", "eslint-plugin-prettier-vue": "^5.0.0", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-vue": "^9.27.0", "git-describe": "^4.1.1", - "googleapis": "^140.0.1", - "jsdom": "^24.1.1", + "googleapis": "^142.0.0", + "jsdom": "^25.0.0", "mime-types": "^2.1.35", "mocha-junit-reporter": "^2.2.1", "prettier": "^3.3.3", @@ -131,7 +131,7 @@ "sass": "1.77.6", "start-server-and-test": "^2.0.5", "typescript": "^5.5.4", - "vite": "^5.3.5", + "vite": "^5.4.2", "vite-node": "^2.0.5", "vite-plugin-static-copy": "^1.0.6", "vitest": "^2.0.5", From 804ea1e8518533b446d89c91909774e0ad4776d2 Mon Sep 17 00:00:00 2001 From: Pascal Barth Date: Thu, 8 Aug 2024 17:11:55 +0200 Subject: [PATCH 07/44] PB-871 : add debug entries for URL override for main DI services supporting API3, WMS and WMTS base URL overrides. Changing calls to functions using these base URLs from the config.js so that they now prioritize the debug value if defined. --- src/api/features/features.api.js | 15 +++++++-- src/api/layers/layers.api.js | 18 ++++++++--- src/api/print.api.js | 20 ++++++++++-- src/api/topics.api.js | 14 +++++--- .../openlayers/OpenLayersWMSLayer.vue | 3 +- .../openlayers/OpenLayersWMTSLayer.vue | 5 ++- .../openlayers/utils/usePrint.composable.js | 2 ++ .../menu/components/LayerDescriptionPopup.vue | 26 ++++++++++++--- src/store/debug.store.js | 32 +++++++++++++++++++ src/store/modules/features.store.js | 6 ++++ .../load-layersconfig-on-lang-change.js | 14 +++++--- .../plugins/topic-change-management.plugin.js | 3 +- src/utils/layerUtils.js | 6 ++-- 13 files changed, 137 insertions(+), 27 deletions(-) diff --git a/src/api/features/features.api.js b/src/api/features/features.api.js index b104e07b5..4d5aa3281 100644 --- a/src/api/features/features.api.js +++ b/src/api/features/features.api.js @@ -113,6 +113,8 @@ export function extractOlFeatureGeodesicCoordinates(feature) { * @param {Number} [offset] Offset of how many items the identification should start after. This * enables us to do some "pagination" or "load more" (if you already have 10 features, set an * offset of 10 to get the 10 next, 20 in total). + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {Promise} */ export async function identifyOnGeomAdminLayer({ @@ -125,6 +127,7 @@ export async function identifyOnGeomAdminLayer({ lang, featureCount = DEFAULT_FEATURE_COUNT_SINGLE_POINT, offset = null, + api3UrlOverride = null, }) { if (!layer) { throw new GetFeatureInfoError('Missing layer') @@ -142,7 +145,7 @@ export async function identifyOnGeomAdminLayer({ } const imageDisplay = `${screenWidth},${screenHeight},96` const identifyResponse = await axios.get( - `${API_BASE_URL}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/identify`, + `${api3UrlOverride ?? API_BASE_URL}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/identify`, { // params described as https://api3.geo.admin.ch/services/sdiservices.html#identify-features params: { @@ -484,6 +487,8 @@ async function identifyOnExternalWmsLayer(config) { * offset of 10 to get the 10 next, 20 in total). This only works with GeoAdmin backends * @param {CoordinateSystem} config.projection Projection in which the coordinates of the features * should be expressed + * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If + * none is given, the default from config.js will be used. Default is `null` * @returns {Promise} */ export const identify = (config) => { @@ -498,6 +503,7 @@ export const identify = (config) => { projection = null, featureCount = DEFAULT_FEATURE_COUNT_SINGLE_POINT, offset = null, + api3UrlOverride = null, } = config return new Promise((resolve, reject) => { if (!layer?.id) { @@ -531,6 +537,7 @@ export const identify = (config) => { lang, featureCount, offset, + api3UrlOverride, }) .then(resolve) .catch((error) => { @@ -561,10 +568,12 @@ export const identify = (config) => { /** * @param {GeoAdminLayer} layer The layer from which the feature is part of * @param {String | Number} featureId The feature ID in the BGDI + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {string} */ -function generateFeatureUrl(layer, featureId) { - return `${API_BASE_URL}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/${layer.id}/${featureId}` +function generateFeatureUrl(layer, featureId, api3UrlOverride = null) { + return `${api3UrlOverride ?? API_BASE_URL}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/${layer.id}/${featureId}` } /** diff --git a/src/api/layers/layers.api.js b/src/api/layers/layers.api.js index 3310e286d..ebbd8de03 100644 --- a/src/api/layers/layers.api.js +++ b/src/api/layers/layers.api.js @@ -204,12 +204,16 @@ const generateClassForLayerConfig = (layerConfig, id, allOtherLayers, lang) => { * * @param {String} lang The language in which the legend should be rendered * @param {String} layerId The unique layer ID used in our backends + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {Promise} HTML content of the layer's legend */ -export const getLayerDescription = (lang, layerId) => { +export const getLayerDescription = (lang, layerId, api3UrlOverride = null) => { return new Promise((resolve, reject) => { axios - .get(`${API_BASE_URL}rest/services/all/MapServer/${layerId}/legend?lang=${lang}`) + .get( + `${api3UrlOverride ?? API_BASE_URL}rest/services/all/MapServer/${layerId}/legend?lang=${lang}` + ) .then((response) => resolve(response.data)) .catch((error) => { log.error('Error while retrieving the legend for the layer', layerId, error) @@ -222,17 +226,21 @@ export const getLayerDescription = (lang, layerId) => { * Loads the layer config from the backend and transforms it in classes defined in this API file * * @param {String} lang The ISO code for the lang in which the config should be loaded (required) + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {Promise} */ -export const loadLayersConfigFromBackend = (lang) => { +export const loadLayersConfigFromBackend = (lang, api3UrlOverride = null) => { return new Promise((resolve, reject) => { - if (!API_BASE_URL) { + if (!api3UrlOverride && !API_BASE_URL) { // this could happen if we are testing the app in unit tests, we simply reject and do nothing reject('API base URL is undefined') } else { const layersConfig = [] axios - .get(`${API_BASE_URL}rest/services/all/MapServer/layersConfig?lang=${lang}`) + .get( + `${api3UrlOverride ?? API_BASE_URL}rest/services/all/MapServer/layersConfig?lang=${lang}` + ) .then(({ data: rawLayersConfig }) => { if (Object.keys(rawLayersConfig).length > 0) { Object.keys(rawLayersConfig).forEach((rawLayerId) => { diff --git a/src/api/print.api.js b/src/api/print.api.js index a0d3ec03c..3ae75ee32 100644 --- a/src/api/print.api.js +++ b/src/api/print.api.js @@ -280,6 +280,10 @@ export class PrintError extends Error { * @param {String | null} [config.dpi=null] The DPI of the printed map. Default is `null` * @param {String | null} [config.outputFilename=null] Output file name, without extension. When * null, let the server decide. Default is `null` + * @param {String | null} [config.wmsUrlOverride=null] The base URL to access service-wms. If none + * is given, the default from config.js will be used. Default is `null` + * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If + * none is given, the default from config.js will be used. Default is `null` */ async function transformOlMapToPrintParams(olMap, config) { const { @@ -295,6 +299,8 @@ async function transformOlMapToPrintParams(olMap, config) { excludedLayerIDs = [], dpi = null, outputFilename = null, + wmsUrlOverride = null, + api3UrlOverride = null, } = config if (!qrCodeUrl) { @@ -342,7 +348,7 @@ async function transformOlMapToPrintParams(olMap, config) { }) if (printGrid) { encodedMap.layers.unshift({ - baseURL: WMS_BASE_URL, + baseURL: wmsUrlOverride ?? WMS_BASE_URL, opacity: 1, singleTile: true, type: 'WMS', @@ -377,7 +383,9 @@ async function transformOlMapToPrintParams(olMap, config) { classes: layersWithLegends.map((layer) => { return { name: layer.name, - icons: [`${API_BASE_URL}static/images/legends/${layer.id}_${lang}.png`], + icons: [ + `${api3UrlOverride ?? API_BASE_URL}static/images/legends/${layer.id}_${lang}.png`, + ], } }), } @@ -433,6 +441,10 @@ function printSpecReplacer(key, value) { * @param {String | null} [config.outputFilename=null] Output file name, without extension. When * null, let the server decide. Default is `null` * @param {String | null} [config.dpi=null] The DPI of the printed map. Default is `null` + * @param {String | null} [config.wmsUrlOverride=null] The base URL to access service-wms. If none + * is given, the default from config.js will be used. Default is `null` + * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If + * none is given, the default from config.js will be used. Default is `null` * @returns {Promise} A job running on our printing backend (needs to be polled * using {@link waitForPrintJobCompletion} to wait until its completion) */ @@ -450,6 +462,8 @@ export async function createPrintJob(map, config) { excludedLayerIDs = [], outputFilename = null, dpi = null, + wmsUrlOverride = null, + api3UrlOverride = null, } = config try { const printingSpec = await transformOlMapToPrintParams(map, { @@ -465,6 +479,8 @@ export async function createPrintJob(map, config) { excludedLayerIDs, outputFilename, dpi, + wmsUrlOverride, + api3UrlOverride, }) if (!isPrintingSpecSizeValid(printingSpec)) { throw new PrintError('Printing spec is too large', 'print_request_too_large') diff --git a/src/api/topics.api.js b/src/api/topics.api.js index ba9e8ec9d..34cbe2d30 100644 --- a/src/api/topics.api.js +++ b/src/api/topics.api.js @@ -82,12 +82,16 @@ const readTopicTreeRecursive = (node, availableLayers) => { * @param {String} lang The lang in which to load the topic tree * @param {String} topicId The topic we want to load the topic tree * @param {GeoAdminLayer[]} layersConfig All available layers for this app (the "layers config") + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {Promise<{ layers: GeoAdminLayer[]; itemIdToOpen: String[] }>} A list of topic's layers */ -export const loadTopicTreeForTopic = (lang, topicId, layersConfig) => { +export const loadTopicTreeForTopic = (lang, topicId, layersConfig, api3UrlOverride = null) => { return new Promise((resolve, reject) => { axios - .get(`${API_BASE_URL}rest/services/${topicId}/CatalogServer?lang=${lang}`) + .get( + `${api3UrlOverride ?? API_BASE_URL}rest/services/${topicId}/CatalogServer?lang=${lang}` + ) .then((response) => { const treeItems = [] const topicRoot = response.data.results.root @@ -110,11 +114,13 @@ export const loadTopicTreeForTopic = (lang, topicId, layersConfig) => { /** * Loads all topics (without their tree) from the backend. * + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {Promise<{ topics: [] }>} Raw topics from backend */ -export async function loadTopics() { +export async function loadTopics(api3UrlOverride = null) { try { - const response = await axios.get(`${API_BASE_URL}rest/services`) + const response = await axios.get(`${api3UrlOverride ?? API_BASE_URL}rest/services`) return response.data } catch (error) { log.error(`Failed to load topics from backend`, error) diff --git a/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue b/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue index 767ea3183..4da01f16e 100644 --- a/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue @@ -37,6 +37,7 @@ const { wmsLayerConfig, parentLayerOpacity, zIndex } = toRefs(props) const store = useStore() const projection = computed(() => store.state.position.projection) const currentLang = computed(() => store.state.i18n.lang) +const debugWmsBaseUrlOverride = computed(() => store.state.debug.baseUrlOverride.wms) // extracting useful info from what we've linked so far const layerId = computed(() => wmsLayerConfig.value.technicalName || wmsLayerConfig.value.id) @@ -44,7 +45,7 @@ const wmsVersion = computed(() => wmsLayerConfig.value.wmsVersion || '1.3.0') const format = computed(() => wmsLayerConfig.value.format || 'png') const gutter = computed(() => wmsLayerConfig.value.gutter || -1) const opacity = computed(() => parentLayerOpacity.value ?? wmsLayerConfig.value.opacity) -const url = computed(() => wmsLayerConfig.value.baseUrl) +const url = computed(() => debugWmsBaseUrlOverride.value ?? wmsLayerConfig.value.baseUrl) const timestamp = computed(() => getTimestampFromConfig(wmsLayerConfig.value)) const urlParams = computed(() => cloneDeep(wmsLayerConfig.value.customAttributes) ?? null) diff --git a/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue b/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue index 109604c4d..d7eb8b208 100644 --- a/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue @@ -29,6 +29,7 @@ const { wmtsLayerConfig, parentLayerOpacity, zIndex } = toRefs(props) // mapping relevant store values const store = useStore() const projection = computed(() => store.state.position.projection) +const debugWmtsBaseUrlOverride = computed(() => store.state.debug.baseUrlOverride.wmts) // extracting useful info from what we've linked so far const layerId = computed(() => wmtsLayerConfig.value.technicalName) const maxResolution = computed(() => wmtsLayerConfig.value.maxResolution) @@ -75,7 +76,9 @@ watch(wmtsTimeConfig, () => { }) function getTransformedXYZUrl() { - return getWmtsXyzUrl(wmtsLayerConfig.value, projection.value) + return getWmtsXyzUrl(wmtsLayerConfig.value, projection.value, { + baseUrlOverride: debugWmtsBaseUrlOverride.value, + }) .replace('{z}', '{TileMatrix}') .replace('{x}', '{TileCol}') .replace('{y}', '{TileRow}') diff --git a/src/modules/map/components/openlayers/utils/usePrint.composable.js b/src/modules/map/components/openlayers/utils/usePrint.composable.js index 6818d47ab..9aaed78dc 100644 --- a/src/modules/map/components/openlayers/utils/usePrint.composable.js +++ b/src/modules/map/components/openlayers/utils/usePrint.composable.js @@ -82,6 +82,8 @@ export function usePrint(map) { printGrid: printGrid, projection: store.state.position.projection, dpi: store.getters.selectedDPI, + wmsUrlOverride: store.state.debug.baseUrlOverride.wms, + api3UrlOverride: store.state.debug.baseUrlOverride.api3, }) currentJobReference.value = printJob.ref const result = await waitForPrintJobCompletion(printJob) diff --git a/src/modules/menu/components/LayerDescriptionPopup.vue b/src/modules/menu/components/LayerDescriptionPopup.vue index 73b051e72..da4b5cc8d 100644 --- a/src/modules/menu/components/LayerDescriptionPopup.vue +++ b/src/modules/menu/components/LayerDescriptionPopup.vue @@ -36,24 +36,42 @@ const attributionName = computed(() => layer.value?.attributions[0].name ?? '') const attributionUrl = computed(() => layer.value?.attributions[0].url ?? '') const isExternal = computed(() => layer.value?.isExternal ?? false) +const api3UrlOverride = computed(() => store.state.debug.baseUrlOverride.api3) + const legends = computed(() => layer.value?.legends ?? []) watch(layer, async (newLayer) => { if (!isExternal.value && layer.value) { - htmlContent.value = await getLayerDescription(currentLang.value, newLayer.id) + htmlContent.value = await getLayerDescription( + currentLang.value, + newLayer.id, + api3UrlOverride.value + ) } }) watch(layerId, async (newLayerId) => { if (!isExternal.value && layerId.value) { - htmlContent.value = await getLayerDescription(currentLang.value, newLayerId) + htmlContent.value = await getLayerDescription( + currentLang.value, + newLayerId, + api3UrlOverride.value + ) } }) onMounted(async () => { if (!isExternal.value && layer.value) { - htmlContent.value = await getLayerDescription(currentLang.value, layer.value.id) + htmlContent.value = await getLayerDescription( + currentLang.value, + layer.value.id, + api3UrlOverride.value + ) } else if (!isExternal.value && layerId.value) { - htmlContent.value = await getLayerDescription(currentLang.value, layerId.value) + htmlContent.value = await getLayerDescription( + currentLang.value, + layerId.value, + api3UrlOverride.value + ) } }) diff --git a/src/store/debug.store.js b/src/store/debug.store.js index ff5df55a0..58d1372eb 100644 --- a/src/store/debug.store.js +++ b/src/store/debug.store.js @@ -1,8 +1,28 @@ +import log from '@/utils/logging.js' + +function commitIfValidOverrideUrl(commit, url, mutationName, dispatcher) { + if (url === null) { + commit(mutationName, { baseUrl: url, dispatcher }) + } else { + try { + new URL(url) + commit(mutationName, { baseUrl: url, dispatcher }) + } catch (error) { + log.error('Invalid override URL', url, `${mutationName} wasn't called`) + } + } +} + /** Vuex module that contains debug tools things */ export default { state: { showTileDebugInfo: false, showLayerExtents: false, + baseUrlOverride: { + wms: null, + wmts: null, + api3: null, + }, }, getters: {}, actions: { @@ -15,11 +35,23 @@ export default { toggleShowLayerExtents({ commit, state }, { dispatcher }) { commit('setShowLayerExtents', { showLayerExtents: !state.showLayerExtents, dispatcher }) }, + setWmsBaseUrlOverride({ commit }, { baseUrl, dispatcher }) { + commitIfValidOverrideUrl(commit, baseUrl, 'setWmsBaseUrlOverride', dispatcher) + }, + setWmtsBaseUrlOverride({ commit }, { baseUrl, dispatcher }) { + commitIfValidOverrideUrl(commit, baseUrl, 'setWmtsBaseUrlOverride', dispatcher) + }, + setApi3BaseUrlOverride({ commit }, { baseUrl, dispatcher }) { + commitIfValidOverrideUrl(commit, baseUrl, 'setApi3BaseUrlOverride', dispatcher) + }, }, mutations: { setShowTileDebugInfo: (state, { showTileDebugInfo }) => (state.showTileDebugInfo = showTileDebugInfo), setShowLayerExtents: (state, { showLayerExtents }) => (state.showLayerExtents = showLayerExtents), + setWmsBaseUrlOverride: (state, { baseUrl }) => (state.baseUrlOverride.wms = baseUrl), + setWmtsBaseUrlOverride: (state, { baseUrl }) => (state.baseUrlOverride.wmts = baseUrl), + setApi3BaseUrlOverride: (state, { baseUrl }) => (state.baseUrlOverride.api3 = baseUrl), }, } diff --git a/src/store/modules/features.store.js b/src/store/modules/features.store.js index 9b9c0309e..9ea8bbaa3 100644 --- a/src/store/modules/features.store.js +++ b/src/store/modules/features.store.js @@ -52,6 +52,8 @@ function getFeatureCountForCoordinate(coordinate) { * @param {CoordinateSystem} config.projection Wanted projection with which to request the backend * @param {Number} [config.featureCount] How many features should be requested. If not given, will * default to 10 for single coordinate, or 50 for extents. + * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If + * none is given, the default from config.js will be used. Default is `null` * @returns {Promise} A promise that will contain all feature identified by the * different requests (won't be grouped by layer) */ @@ -66,6 +68,7 @@ const runIdentify = (config) => { lang, projection, featureCount, + api3UrlOverride = null, } = config return new Promise((resolve, reject) => { const allFeatures = [] @@ -79,6 +82,7 @@ const runIdentify = (config) => { lang, projection, featureCount, + api3UrlOverride, } // for each layer we run a backend request // NOTE: in theory for the Geoadmin layers we could run one single backend request to API3 instead of one per layer, however @@ -275,6 +279,7 @@ export default { lang: rootState.i18n.lang, projection: rootState.position.projection, featureCount, + api3UrlOverride: rootState.debug.baseUrlOverride.api3, })), ] if (features.length > 0) { @@ -322,6 +327,7 @@ export default { projection: rootState.position.projection, offset: featuresAlreadyLoaded.features.length, featureCount: featuresAlreadyLoaded.featureCountForMoreData, + api3UrlOverride: rootState.debug.baseUrlOverride.api3, }).then((moreFeatures) => { const featuresForLayer = state.selectedFeaturesByLayerId.find( (featureForLayer) => featureForLayer.layerId === layer.id diff --git a/src/store/plugins/load-layersconfig-on-lang-change.js b/src/store/plugins/load-layersconfig-on-lang-change.js index 308e64d43..7dd6b220a 100644 --- a/src/store/plugins/load-layersconfig-on-lang-change.js +++ b/src/store/plugins/load-layersconfig-on-lang-change.js @@ -20,11 +20,13 @@ const layersConfigByLang = {} * If the same language is asked another time later on, the cached version will be given. * * @param lang {String} ISO code for a language + * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is + * given, the default from config.js will be used. Default is `null` * @returns {Promise} */ -async function loadLayersConfig(lang) { +async function loadLayersConfig(lang, api3UrlOverride = null) { if (!layersConfigByLang[lang]) { - const layersConfig = await loadLayersConfigFromBackend(lang) + const layersConfig = await loadLayersConfigFromBackend(lang, api3UrlOverride) layersConfigByLang[lang] = layersConfig return layersConfig } else { @@ -37,7 +39,11 @@ const loadLayersAndTopicsConfigAndDispatchToStore = async (store, lang, topicId, log.debug( `Start loading layers config and topics lang=${lang} topic=${topicId} dispatcher=${dispatcher}` ) - const [layersConfig, rawTopics] = await Promise.all([loadLayersConfig(lang), loadTopics()]) + const [layersConfig, rawTopics] = await Promise.all([ + loadLayersConfig(lang, store.state.debug.baseUrlOverride.api3), + loadTopics(store.state.debug.baseUrlOverride.api3), + store.state.debug.baseUrlOverride.api3, + ]) const topics = parseTopics(layersConfig, rawTopics) // adding SWISSIMAGE as a possible background for 3D @@ -65,7 +71,7 @@ const loadLayersAndTopicsConfigAndDispatchToStore = async (store, lang, topicId, */ const loadLayersConfigOnLangChange = (store) => { store.subscribe((mutation) => { - if (mutation.type === SET_LANG_MUTATION_KEY) { + if ([SET_LANG_MUTATION_KEY, 'setApi3BaseUrlOverride'].includes(mutation.type)) { loadLayersAndTopicsConfigAndDispatchToStore( store, mutation.payload.lang, diff --git a/src/store/plugins/topic-change-management.plugin.js b/src/store/plugins/topic-change-management.plugin.js index de0ad5525..0be7a2b8c 100644 --- a/src/store/plugins/topic-change-management.plugin.js +++ b/src/store/plugins/topic-change-management.plugin.js @@ -86,7 +86,8 @@ const topicChangeManagementPlugin = (store) => { loadTopicTreeForTopic( store.state.i18n.lang, currentTopic.id, - store.state.layers.config + store.state.layers.config, + store.state.debug.baseUrlOverride.api3 ).then((topicTree) => { store.dispatch('setTopicTree', { layers: topicTree.layers, diff --git a/src/utils/layerUtils.js b/src/utils/layerUtils.js index 7ee7e872b..4cefae0c3 100644 --- a/src/utils/layerUtils.js +++ b/src/utils/layerUtils.js @@ -63,10 +63,12 @@ export function getTimestampFromConfig(layer) { * @param {Boolean} [options.addTimestamp=false] Add the timestamp from the time config or the * timeslider to the ur. When false the timestamp is set to `{Time}` and need to processed later * on. Default is `false` + * @param {String} [options.baseUrlOverride=null] If set, will be used as the base URL while + * building the full WMTS URL. Default is `null` * @returns {String | null} */ export function getWmtsXyzUrl(wmtsLayerConfig, projection, options = {}) { - const { addTimestamp = false } = options ?? {} + const { addTimestamp = false, baseUrlOverride = null } = options ?? {} if (wmtsLayerConfig?.type === LayerTypes.WMTS && projection) { let timestamp = '{Time}' if (addTimestamp) { @@ -76,7 +78,7 @@ export function getWmtsXyzUrl(wmtsLayerConfig, projection, options = {}) { const layerId = wmtsLayerConfig.isExternal ? wmtsLayerConfig.id : wmtsLayerConfig.technicalName - return `${wmtsLayerConfig.baseUrl}1.0.0/${layerId}/default/${timestamp}/${projection.epsgNumber}/{z}/{x}/{y}.${wmtsLayerConfig.format}` + return `${baseUrlOverride ?? wmtsLayerConfig.baseUrl}1.0.0/${layerId}/default/${timestamp}/${projection.epsgNumber}/{z}/{x}/{y}.${wmtsLayerConfig.format}` } return null } From 74300033d26b62c1489a116a9d9dc1ba961da768 Mon Sep 17 00:00:00 2001 From: Pascal Barth Date: Thu, 8 Aug 2024 17:12:27 +0200 Subject: [PATCH 08/44] PB-871 : adding debug UI modal to change URL overrides --- src/config.js | 14 +-- .../components/debug/BaseUrlOverrideModal.vue | 101 ++++++++++++++++++ .../menu/components/debug/DebugToolbar.vue | 17 +++ src/utils/utils.js | 13 +++ 4 files changed, 132 insertions(+), 13 deletions(-) create mode 100644 src/modules/menu/components/debug/BaseUrlOverrideModal.vue diff --git a/src/config.js b/src/config.js index 00e2c8bc1..a77c810dc 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,7 @@ // loading and exporting all values from the .env file as ES6 importable variables import { LV95 } from '@/utils/coordinates/coordinateSystems' +import { enforceEndingSlashInUrl } from '@/utils/utils' /** * Enum that tells for which (deployment) environment the app has been built. @@ -34,19 +35,6 @@ export const APP_VERSION = __APP_VERSION__ */ export const DEFAULT_PROJECTION = LV95 -/** - * Adds a slash at the end of the URL if there is none - * - * @param {String} url - * @returns {String} The URL with a trailing slash - */ -function enforceEndingSlashInUrl(url) { - if (url && !url.endsWith('/')) { - return `${url}/` - } - return url -} - /** * Base part of the URL to use when requesting the api3. * diff --git a/src/modules/menu/components/debug/BaseUrlOverrideModal.vue b/src/modules/menu/components/debug/BaseUrlOverrideModal.vue new file mode 100644 index 000000000..02f30be9e --- /dev/null +++ b/src/modules/menu/components/debug/BaseUrlOverrideModal.vue @@ -0,0 +1,101 @@ + + + diff --git a/src/modules/menu/components/debug/DebugToolbar.vue b/src/modules/menu/components/debug/DebugToolbar.vue index 22458ad03..71540d9bc 100644 --- a/src/modules/menu/components/debug/DebugToolbar.vue +++ b/src/modules/menu/components/debug/DebugToolbar.vue @@ -3,6 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { computed, ref } from 'vue' import { useStore } from 'vuex' +import BaseUrlOverrideModal from '@/modules/menu/components/debug/BaseUrlOverrideModal.vue' import Toggle3DLayerButton from '@/modules/menu/components/debug/Toggle3DLayerButton.vue' import { LV95, WEBMERCATOR } from '@/utils/coordinates/coordinateSystems' @@ -11,6 +12,7 @@ const dispatcher = { dispatcher: 'DebugToolbar.vue' } const store = useStore() const showDebugTool = ref(false) +const showBaseUrlOverride = ref(false) const currentProjection = computed(() => store.state.position.projection) const is3dActive = computed(() => store.state.cesium.active) @@ -37,6 +39,9 @@ function toggleShowTileDebugInfo() { function toggleShowLayerExtents() { store.dispatch('toggleShowLayerExtents', dispatcher) } +function toggleShowBaseUrlOverride() { + showBaseUrlOverride.value = !showBaseUrlOverride.value +} diff --git a/src/utils/utils.js b/src/utils/utils.js index 6d998503f..ede47333d 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -4,6 +4,19 @@ import { toLv95 } from '@/utils/coordinates/coordinateUtils' import log from '@/utils/logging' import { format } from '@/utils/numberUtils' +/** + * Adds a slash at the end of the URL if there is none + * + * @param {String} url + * @returns {String} The URL with a trailing slash + */ +export function enforceEndingSlashInUrl(url) { + if (url && !url.endsWith('/')) { + return `${url}/` + } + return url +} + /** * Check if the provided string is a valid URL * From 780a727b27e984d4005197c3a0cf1d92c36df112 Mon Sep 17 00:00:00 2001 From: Pascal Barth Date: Thu, 8 Aug 2024 17:13:05 +0200 Subject: [PATCH 09/44] PB-871 : adding debug URL params for URL override named like they were in the mf-geoadmin3's code --- src/router/storeSync/storeSync.config.js | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/router/storeSync/storeSync.config.js b/src/router/storeSync/storeSync.config.js index d3e1ff766..f074a2b4a 100644 --- a/src/router/storeSync/storeSync.config.js +++ b/src/router/storeSync/storeSync.config.js @@ -126,6 +126,36 @@ const storeSyncConfig = [ defaultValue: '', }), new TimeSliderParamConfig(), + new SimpleUrlParamConfig({ + urlParamName: 'wms_url', + mutationsToWatch: ['setWmsBaseUrlOverride'], + dispatchName: 'setWmsBaseUrlOverride', + dispatchValueName: 'baseUrl', + extractValueFromStore: (store) => store.state.debug.baseUrlOverride.wms, + keepInUrlWhenDefault: false, + valueType: String, + defaultValue: null, + }), + new SimpleUrlParamConfig({ + urlParamName: 'wmts_url', + mutationsToWatch: ['setWtmsBaseUrlOverride'], + dispatchName: 'setWtmsBaseUrlOverride', + dispatchValueName: 'baseUrl', + extractValueFromStore: (store) => store.state.debug.baseUrlOverride.wtms, + keepInUrlWhenDefault: false, + valueType: String, + defaultValue: null, + }), + new SimpleUrlParamConfig({ + urlParamName: 'api_url', + mutationsToWatch: ['setApi3BaseUrlOverride'], + dispatchName: 'setApi3BaseUrlOverride', + dispatchValueName: 'baseUrl', + extractValueFromStore: (store) => store.state.debug.baseUrlOverride.api3, + keepInUrlWhenDefault: false, + valueType: String, + defaultValue: null, + }), ] export default storeSyncConfig From c9ab30a0ada83539c09046e6e4ed143f8f6711e9 Mon Sep 17 00:00:00 2001 From: Pascal Barth Date: Tue, 13 Aug 2024 14:46:51 +0200 Subject: [PATCH 10/44] PB-871 : moving function enforceEndingSlashInUrl back into config.js it otherwise creates a circular dependency and some part of the tests can't load properly (LV95 is imported from config.js, which requires something in utils.js, which requires something in config.js, etc...) --- src/config.js | 14 +++++++++++++- .../menu/components/debug/BaseUrlOverrideModal.vue | 3 +-- src/utils/utils.js | 13 ------------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/config.js b/src/config.js index a77c810dc..40022237e 100644 --- a/src/config.js +++ b/src/config.js @@ -1,7 +1,19 @@ // loading and exporting all values from the .env file as ES6 importable variables import { LV95 } from '@/utils/coordinates/coordinateSystems' -import { enforceEndingSlashInUrl } from '@/utils/utils' + +/** + * Adds a slash at the end of the URL if there is none + * + * @param {String} url + * @returns {String} The URL with a trailing slash + */ +export function enforceEndingSlashInUrl(url) { + if (url && !url.endsWith('/')) { + return `${url}/` + } + return url +} /** * Enum that tells for which (deployment) environment the app has been built. diff --git a/src/modules/menu/components/debug/BaseUrlOverrideModal.vue b/src/modules/menu/components/debug/BaseUrlOverrideModal.vue index 02f30be9e..154f2f50c 100644 --- a/src/modules/menu/components/debug/BaseUrlOverrideModal.vue +++ b/src/modules/menu/components/debug/BaseUrlOverrideModal.vue @@ -3,9 +3,8 @@ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { ref } from 'vue' import { useStore } from 'vuex' -import { API_BASE_URL, WMS_BASE_URL, WMTS_BASE_URL } from '@/config' +import { API_BASE_URL, enforceEndingSlashInUrl, WMS_BASE_URL, WMTS_BASE_URL } from '@/config' import ModalWithBackdrop from '@/utils/components/ModalWithBackdrop.vue' -import { enforceEndingSlashInUrl } from '@/utils/utils' const dispatcher = { dispatcher: 'BaseUrlOverrideModal.vue' } diff --git a/src/utils/utils.js b/src/utils/utils.js index ede47333d..6d998503f 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -4,19 +4,6 @@ import { toLv95 } from '@/utils/coordinates/coordinateUtils' import log from '@/utils/logging' import { format } from '@/utils/numberUtils' -/** - * Adds a slash at the end of the URL if there is none - * - * @param {String} url - * @returns {String} The URL with a trailing slash - */ -export function enforceEndingSlashInUrl(url) { - if (url && !url.endsWith('/')) { - return `${url}/` - } - return url -} - /** * Check if the provided string is a valid URL * From 8f5f880e20efc423ba3d3bdd304c76da1f33bd4c Mon Sep 17 00:00:00 2001 From: Pascal Barth Date: Fri, 23 Aug 2024 08:54:46 +0200 Subject: [PATCH 11/44] PB-871 : re-arranging app config into multiple files Trying to gather common config together in a meaningfully named config file. Adding function to get base URLs, instead of direct access to constants. So that we have the opportunity to override base URLs. I didn't want to go through the store to do that. Doing so would create a lot of circular dependencies between the store, the config and components. As it's a debug tool, that's "good enough" this way. --- src/api/features/features.api.js | 18 +- src/api/feedback.api.js | 5 +- src/api/file-proxy.api.js | 4 +- src/api/files.api.js | 6 +- src/api/height.api.js | 4 +- src/api/icon.api.js | 5 +- src/api/layers/GeoAdmin3DLayer.class.js | 4 +- src/api/layers/GeoAdminVectorLayer.class.js | 4 +- src/api/layers/GeoAdminWMSLayer.class.js | 4 +- src/api/layers/GeoAdminWMTSLayer.class.js | 5 +- src/api/layers/KMLLayer.class.js | 4 +- src/api/layers/WMSCapabilitiesParser.class.js | 2 +- src/api/layers/layers.api.js | 22 +- src/api/print.api.js | 28 +- src/api/profile/profile.api.js | 4 +- src/api/qrcode.api.js | 4 +- src/api/search.api.js | 4 +- src/api/shortlink.api.js | 4 +- src/api/topics.api.js | 17 +- src/config.js | 362 ------------------ src/config/baseUrl.config.js | 181 +++++++++ src/config/index.js | 12 + src/config/map.config.js | 79 ++++ src/config/responsive.config.js | 40 ++ src/config/staging.config.js | 66 ++++ src/config/time.config.js | 14 + src/config/vectortiles.config.js | 17 + src/main.js | 42 +- src/modules/drawing/DrawingModule.vue | 2 +- .../components/DrawingSelectInteraction.vue | 2 +- .../drawing/components/DrawingTooltip.vue | 2 +- .../useModifyInteraction.composable.js | 2 +- .../useKmlDataManagement.composable.js | 2 +- src/modules/infobox/InfoboxModule.vue | 2 +- .../infobox/components/FeatureDetail.vue | 2 +- .../map/components/cesium/CesiumMap.vue | 20 +- .../map/components/cesium/CesiumWMSLayer.vue | 2 +- .../map/components/cesium/CesiumWMTSLayer.vue | 2 +- .../map/components/cesium/constants.js | 4 +- .../utils/addPrimitiveFromOLLayer.mixins.js | 2 +- .../components/footer/MapFooterAppVersion.vue | 2 +- .../openlayers/OpenLayersGPXLayer.vue | 2 +- .../openlayers/OpenLayersKMLLayer.vue | 2 +- .../components/openlayers/OpenLayersMap.vue | 2 +- .../openlayers/OpenLayersVectorLayer.vue | 2 +- .../openlayers/OpenLayersWMSLayer.vue | 9 +- .../openlayers/OpenLayersWMTSLayer.vue | 4 +- .../utils/useMapInteractions.composable.js | 3 +- .../openlayers/utils/usePrint.composable.js | 2 - .../useViewBasedOnProjection.composable.js | 3 +- .../map/components/toolbox/TimeSlider.vue | 2 +- .../menu/components/LayerDescriptionPopup.vue | 26 +- .../components/debug/BaseUrlOverrideModal.vue | 39 +- src/router/index.js | 2 +- .../BaseUrlOverrideParamConfig.class.js | 27 ++ .../storeSync/TimeSliderParamConfig.class.js | 2 +- .../__tests__/LayerParamConfig.class.spec.js | 4 +- .../__tests__/layersParamParser.spec.js | 6 +- src/router/storeSync/storeSync.config.js | 36 +- .../storeSync/storeSync.routerPlugin.js | 2 +- src/scss/media-query.mixin.scss | 2 +- src/store/debug.store.js | 39 +- src/store/index.js | 2 +- src/store/modules/features.store.js | 8 +- src/store/modules/position.store.js | 2 +- src/store/modules/ui.store.js | 5 +- .../plugins/2d-to-3d-management.plugin.js | 2 +- src/store/plugins/app-readiness.plugin.js | 2 +- .../plugins/geolocation-management.plugin.js | 4 +- .../load-layersconfig-on-lang-change.js | 14 +- .../plugins/screen-size-management.plugin.js | 2 +- .../plugins/topic-change-management.plugin.js | 3 +- src/utils/__tests__/kmlUtils.spec.js | 4 +- src/utils/__tests__/legacyKmlUtils.spec.js | 4 +- src/utils/gpxUtils.js | 2 +- src/utils/logging.js | 2 +- tests/cypress/support/drawing.js | 2 +- tests/cypress/support/utils.js | 2 +- .../cypress/tests-e2e/3d/transitionTo3d.cy.js | 2 +- tests/cypress/tests-e2e/crosshair.cy.js | 2 +- tests/cypress/tests-e2e/drawing.cy.js | 25 +- .../cypress/tests-e2e/featureSelection.cy.js | 2 +- tests/cypress/tests-e2e/feedback.cy.js | 2 +- tests/cypress/tests-e2e/geolocation.cy.js | 2 +- tests/cypress/tests-e2e/header.cy.js | 2 +- .../cypress/tests-e2e/legacyParamImport.cy.js | 2 +- tests/cypress/tests-e2e/mouseposition.cy.js | 6 +- tests/cypress/tests-e2e/print.cy.js | 4 +- tests/cypress/tests-e2e/reportProblem.cy.js | 2 +- .../tests-e2e/search/coordinates-search.cy.js | 2 +- .../tests-e2e/search/search-results.cy.js | 3 +- tests/cypress/tests-e2e/timeSlider.cy.js | 2 +- 92 files changed, 653 insertions(+), 688 deletions(-) delete mode 100644 src/config.js create mode 100644 src/config/baseUrl.config.js create mode 100644 src/config/index.js create mode 100644 src/config/map.config.js create mode 100644 src/config/responsive.config.js create mode 100644 src/config/staging.config.js create mode 100644 src/config/time.config.js create mode 100644 src/config/vectortiles.config.js create mode 100644 src/router/storeSync/BaseUrlOverrideParamConfig.class.js diff --git a/src/api/features/features.api.js b/src/api/features/features.api.js index 4d5aa3281..ebf5e53e4 100644 --- a/src/api/features/features.api.js +++ b/src/api/features/features.api.js @@ -11,7 +11,8 @@ import { ALL_YEARS_TIMESTAMP, CURRENT_YEAR_TIMESTAMP, } from '@/api/layers/LayerTimeConfigEntry.class' -import { API_BASE_URL, DEFAULT_FEATURE_COUNT_SINGLE_POINT } from '@/config' +import { getApi3BaseUrl } from '@/config/baseUrl.config' +import { DEFAULT_FEATURE_COUNT_SINGLE_POINT } from '@/config/map.config' import allCoordinateSystems, { LV95 } from '@/utils/coordinates/coordinateSystems' import { projExtent } from '@/utils/coordinates/coordinateUtils' import { createPixelExtentAround } from '@/utils/extentUtils' @@ -127,7 +128,6 @@ export async function identifyOnGeomAdminLayer({ lang, featureCount = DEFAULT_FEATURE_COUNT_SINGLE_POINT, offset = null, - api3UrlOverride = null, }) { if (!layer) { throw new GetFeatureInfoError('Missing layer') @@ -145,7 +145,7 @@ export async function identifyOnGeomAdminLayer({ } const imageDisplay = `${screenWidth},${screenHeight},96` const identifyResponse = await axios.get( - `${api3UrlOverride ?? API_BASE_URL}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/identify`, + `${getApi3BaseUrl()}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/identify`, { // params described as https://api3.geo.admin.ch/services/sdiservices.html#identify-features params: { @@ -487,8 +487,6 @@ async function identifyOnExternalWmsLayer(config) { * offset of 10 to get the 10 next, 20 in total). This only works with GeoAdmin backends * @param {CoordinateSystem} config.projection Projection in which the coordinates of the features * should be expressed - * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If - * none is given, the default from config.js will be used. Default is `null` * @returns {Promise} */ export const identify = (config) => { @@ -503,7 +501,6 @@ export const identify = (config) => { projection = null, featureCount = DEFAULT_FEATURE_COUNT_SINGLE_POINT, offset = null, - api3UrlOverride = null, } = config return new Promise((resolve, reject) => { if (!layer?.id) { @@ -537,7 +534,6 @@ export const identify = (config) => { lang, featureCount, offset, - api3UrlOverride, }) .then(resolve) .catch((error) => { @@ -568,12 +564,10 @@ export const identify = (config) => { /** * @param {GeoAdminLayer} layer The layer from which the feature is part of * @param {String | Number} featureId The feature ID in the BGDI - * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is - * given, the default from config.js will be used. Default is `null` - * @returns {string} + * @returns {String} */ -function generateFeatureUrl(layer, featureId, api3UrlOverride = null) { - return `${api3UrlOverride ?? API_BASE_URL}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/${layer.id}/${featureId}` +function generateFeatureUrl(layer, featureId) { + return `${getApi3BaseUrl()}rest/services/${layer.getTopicForIdentifyAndTooltipRequests()}/MapServer/${layer.id}/${featureId}` } /** diff --git a/src/api/feedback.api.js b/src/api/feedback.api.js index 55df661f7..929f77803 100644 --- a/src/api/feedback.api.js +++ b/src/api/feedback.api.js @@ -1,7 +1,8 @@ import axios from 'axios' import { getKmlFromUrl } from '@/api/files.api' -import { API_SERVICES_BASE_URL, APP_VERSION } from '@/config' +import { getViewerDedicatedServicesBaseUrl } from '@/config/baseUrl.config' +import { APP_VERSION } from '@/config/staging.config' import log from '@/utils/logging' /** Maximum size allowed by the backend, can be used to do validation up front */ @@ -48,7 +49,7 @@ export default async function sendFeedback(subject, text, options) { attachment, } log.debug('sending feedback with', data) - const response = await axios.post(`${API_SERVICES_BASE_URL}feedback`, data, { + const response = await axios.post(`${getViewerDedicatedServicesBaseUrl()}feedback`, data, { headers: { 'Content-Type': 'multipart/form-data', }, diff --git a/src/api/file-proxy.api.js b/src/api/file-proxy.api.js index 426a0f7f7..b9ca0faa2 100644 --- a/src/api/file-proxy.api.js +++ b/src/api/file-proxy.api.js @@ -1,7 +1,7 @@ import axios from 'axios' import { isString } from 'lodash' -import { API_SERVICE_PROXY_BASE_URL } from '@/config' +import { getServiceProxyBaseUrl } from '@/config/baseUrl.config' import log from '@/utils/logging' /** @@ -29,7 +29,7 @@ export function proxifyUrl(url) { if (!fileAsPath) { throw new Error(`Malformed URL: ${url}, can't proxify`) } - return `${API_SERVICE_PROXY_BASE_URL}${fileAsPath}` + return `${getServiceProxyBaseUrl()}${fileAsPath}` } /** diff --git a/src/api/files.api.js b/src/api/files.api.js index b4804e25a..f63f0c2ea 100644 --- a/src/api/files.api.js +++ b/src/api/files.api.js @@ -2,8 +2,8 @@ import axios, { AxiosError } from 'axios' import FormData from 'form-data' import pako from 'pako' -import getFileThroughProxy from '@/api/file-proxy.api.js' -import { API_SERVICE_KML_BASE_URL } from '@/config' +import getFileThroughProxy from '@/api/file-proxy.api' +import { getServiceKmlBaseUrl } from '@/config/baseUrl.config' import log from '@/utils/logging' /** @@ -67,7 +67,7 @@ export class KmlMetadata { } } -const kmlBaseUrl = `${API_SERVICE_KML_BASE_URL}api/kml/` +const kmlBaseUrl = `${getServiceKmlBaseUrl()}api/kml/` function validateId(id, reject) { if (!id) { diff --git a/src/api/height.api.js b/src/api/height.api.js index 5eeaa1d55..e5ee6e4f4 100644 --- a/src/api/height.api.js +++ b/src/api/height.api.js @@ -1,7 +1,7 @@ import axios from 'axios' import proj4 from 'proj4' -import { API_SERVICE_ALTI_BASE_URL } from '@/config' +import { getServiceAltiBaseUrl } from '@/config/baseUrl.config' import { LV95 } from '@/utils/coordinates/coordinateSystems' import log from '@/utils/logging' import { round } from '@/utils/numberUtils' @@ -34,7 +34,7 @@ export const requestHeight = (coordinates, projection) => { // we are giving it LV95 coordinates const lv95coords = proj4(projection.epsg, LV95.epsg, coordinates) axios - .get(`${API_SERVICE_ALTI_BASE_URL}rest/services/height`, { + .get(`${getServiceAltiBaseUrl()}rest/services/height`, { params: { easting: lv95coords[0], northing: lv95coords[1], diff --git a/src/api/icon.api.js b/src/api/icon.api.js index 58ecc9b19..5716a8fae 100644 --- a/src/api/icon.api.js +++ b/src/api/icon.api.js @@ -1,6 +1,6 @@ import axios from 'axios' -import { API_SERVICES_BASE_URL } from '@/config' +import { getViewerDedicatedServicesBaseUrl } from '@/config/baseUrl.config' import { calculateTextOffset, MEDIUM, RED } from '@/utils/featureStyleUtils' import log from '@/utils/logging' @@ -188,7 +188,8 @@ export async function loadAllIconSetsFromBackend() { const setPromises = [] const sets = [] try { - const rawSets = (await axios.get(`${API_SERVICES_BASE_URL}icons/sets`)).data.items + const rawSets = (await axios.get(`${getViewerDedicatedServicesBaseUrl()}icons/sets`)).data + .items for (const rawSet of rawSets) { const iconSet = new DrawingIconSet( rawSet.name, diff --git a/src/api/layers/GeoAdmin3DLayer.class.js b/src/api/layers/GeoAdmin3DLayer.class.js index 501a6a424..0dfcef22e 100644 --- a/src/api/layers/GeoAdmin3DLayer.class.js +++ b/src/api/layers/GeoAdmin3DLayer.class.js @@ -1,7 +1,7 @@ import { LayerAttribution } from '@/api/layers/AbstractLayer.class' import GeoAdminLayer from '@/api/layers/GeoAdminLayer.class' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { BASE_URL_3D_TILES } from '@/config' +import { get3dTilesBaseUrl } from '@/config/baseUrl.config' /** * Metadata for a 3D tile layer (Cesium layer) served by our backend @@ -29,7 +29,7 @@ export default class GeoAdmin3DLayer extends GeoAdminLayer { type: LayerTypes.VECTOR, technicalName: layerId, id: layerId, - baseUrl: BASE_URL_3D_TILES, + baseUrl: get3dTilesBaseUrl(), ensureTrailingSlashInBaseUrl: true, opacity: 1.0, visible: true, diff --git a/src/api/layers/GeoAdminVectorLayer.class.js b/src/api/layers/GeoAdminVectorLayer.class.js index 6d90d6055..3a7984fce 100644 --- a/src/api/layers/GeoAdminVectorLayer.class.js +++ b/src/api/layers/GeoAdminVectorLayer.class.js @@ -1,7 +1,7 @@ import { LayerAttribution } from '@/api/layers/AbstractLayer.class' import GeoAdminLayer from '@/api/layers/GeoAdminLayer.class' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { VECTOR_TILE_BASE_URL } from '@/config' +import { getVectorTilesBaseUrl } from '@/config/baseUrl.config' /** * Metadata for a vector tile layer (MapLibre layer) served by our backend @@ -24,7 +24,7 @@ export default class GeoAdminVectorLayer extends GeoAdminLayer { super({ name: layerId, type: LayerTypes.VECTOR, - baseUrl: VECTOR_TILE_BASE_URL, + baseUrl: getVectorTilesBaseUrl(), id: layerId, technicalName: layerId, attributions: [ diff --git a/src/api/layers/GeoAdminWMSLayer.class.js b/src/api/layers/GeoAdminWMSLayer.class.js index 909fe816e..80ac577aa 100644 --- a/src/api/layers/GeoAdminWMSLayer.class.js +++ b/src/api/layers/GeoAdminWMSLayer.class.js @@ -1,7 +1,7 @@ import GeoAdminLayer from '@/api/layers/GeoAdminLayer.class' import { InvalidLayerDataError } from '@/api/layers/InvalidLayerData.error' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { WMS_BASE_URL } from '@/config' +import { getWmsBaseUrl } from '@/config/baseUrl.config' /** * Metadata for WMS layer (WMS stands for Web Map Service). It can either be tiled (requested in @@ -73,7 +73,7 @@ export default class GeoAdminWMSLayer extends GeoAdminLayer { opacity = 1.0, visible = true, attributions = null, - baseUrl = WMS_BASE_URL, + baseUrl = getWmsBaseUrl(), format = 'png', timeConfig = null, wmsVersion = '1.3.0', diff --git a/src/api/layers/GeoAdminWMTSLayer.class.js b/src/api/layers/GeoAdminWMTSLayer.class.js index ac574872f..2d0839ae7 100644 --- a/src/api/layers/GeoAdminWMTSLayer.class.js +++ b/src/api/layers/GeoAdminWMTSLayer.class.js @@ -1,7 +1,8 @@ import GeoAdminLayer from '@/api/layers/GeoAdminLayer.class' import { InvalidLayerDataError } from '@/api/layers/InvalidLayerData.error' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { DEFAULT_GEOADMIN_MAX_WMTS_RESOLUTION, WMTS_BASE_URL } from '@/config' +import { getWmtsBaseUrl } from '@/config/baseUrl.config' +import { DEFAULT_GEOADMIN_MAX_WMTS_RESOLUTION } from '@/config/map.config' import { TILEGRID_RESOLUTIONS } from '@/utils/coordinates/SwissCoordinateSystem.class' /** @@ -69,7 +70,7 @@ export default class GeoAdminWMTSLayer extends GeoAdminLayer { format = 'png', timeConfig = null, isBackground = false, - baseUrl = WMTS_BASE_URL, + baseUrl = getWmtsBaseUrl(), isHighlightable = false, hasTooltip = false, topics = [], diff --git a/src/api/layers/KMLLayer.class.js b/src/api/layers/KMLLayer.class.js index f46283f23..847c65dc4 100644 --- a/src/api/layers/KMLLayer.class.js +++ b/src/api/layers/KMLLayer.class.js @@ -1,7 +1,7 @@ import AbstractLayer, { LayerAttribution } from '@/api/layers/AbstractLayer.class' import { InvalidLayerDataError } from '@/api/layers/InvalidLayerData.error' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { API_SERVICE_KML_BASE_URL } from '@/config' +import { getServiceKmlBaseUrl } from '@/config/baseUrl.config' import { EMPTY_KML_DATA, parseKmlName } from '@/utils/kmlUtils' /** @@ -48,7 +48,7 @@ export default class KMLLayer extends AbstractLayer { } const isLocalFile = !kmlFileUrl.startsWith('http') const attributionName = isLocalFile ? kmlFileUrl : new URL(kmlFileUrl).hostname - const isExternal = kmlFileUrl.indexOf(API_SERVICE_KML_BASE_URL) === -1 + const isExternal = kmlFileUrl.indexOf(getServiceKmlBaseUrl()) === -1 super({ name: 'KML', id: kmlFileUrl, diff --git a/src/api/layers/WMSCapabilitiesParser.class.js b/src/api/layers/WMSCapabilitiesParser.class.js index 5136fe1a8..cd19a4b71 100644 --- a/src/api/layers/WMSCapabilitiesParser.class.js +++ b/src/api/layers/WMSCapabilitiesParser.class.js @@ -9,7 +9,7 @@ import ExternalWMSLayer, { WMSDimension } from '@/api/layers/ExternalWMSLayer.cl import { CapabilitiesError } from '@/api/layers/layers-external.api' import LayerTimeConfig from '@/api/layers/LayerTimeConfig.class' import LayerTimeConfigEntry from '@/api/layers/LayerTimeConfigEntry.class' -import { WMS_SUPPORTED_VERSIONS } from '@/config' +import { WMS_SUPPORTED_VERSIONS } from '@/config/map.config' import allCoordinateSystems, { WGS84 } from '@/utils/coordinates/coordinateSystems' import log from '@/utils/logging' diff --git a/src/api/layers/layers.api.js b/src/api/layers/layers.api.js index ebbd8de03..62c102d11 100644 --- a/src/api/layers/layers.api.js +++ b/src/api/layers/layers.api.js @@ -9,7 +9,8 @@ import GeoAdminWMSLayer from '@/api/layers/GeoAdminWMSLayer.class' import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class' import LayerTimeConfig from '@/api/layers/LayerTimeConfig.class' import LayerTimeConfigEntry from '@/api/layers/LayerTimeConfigEntry.class' -import { API_BASE_URL, DEFAULT_GEOADMIN_MAX_WMTS_RESOLUTION, WMTS_BASE_URL } from '@/config' +import { getApi3BaseUrl } from '@/config/baseUrl.config' +import { DEFAULT_GEOADMIN_MAX_WMTS_RESOLUTION } from '@/config/map.config' import log from '@/utils/logging' // API file that covers the backend endpoint http://api3.geo.admin.ch/rest/services/all/MapServer/layersConfig @@ -83,7 +84,6 @@ const generateClassForLayerConfig = (layerConfig, id, allOtherLayers, lang) => { format, timeConfig, isBackground: !!isBackground, - baseUrl: WMTS_BASE_URL, isHighlightable, hasTooltip, topics, @@ -204,16 +204,12 @@ const generateClassForLayerConfig = (layerConfig, id, allOtherLayers, lang) => { * * @param {String} lang The language in which the legend should be rendered * @param {String} layerId The unique layer ID used in our backends - * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is - * given, the default from config.js will be used. Default is `null` * @returns {Promise} HTML content of the layer's legend */ -export const getLayerDescription = (lang, layerId, api3UrlOverride = null) => { +export const getLayerDescription = (lang, layerId) => { return new Promise((resolve, reject) => { axios - .get( - `${api3UrlOverride ?? API_BASE_URL}rest/services/all/MapServer/${layerId}/legend?lang=${lang}` - ) + .get(`${getApi3BaseUrl()}rest/services/all/MapServer/${layerId}/legend?lang=${lang}`) .then((response) => resolve(response.data)) .catch((error) => { log.error('Error while retrieving the legend for the layer', layerId, error) @@ -226,21 +222,17 @@ export const getLayerDescription = (lang, layerId, api3UrlOverride = null) => { * Loads the layer config from the backend and transforms it in classes defined in this API file * * @param {String} lang The ISO code for the lang in which the config should be loaded (required) - * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is - * given, the default from config.js will be used. Default is `null` * @returns {Promise} */ -export const loadLayersConfigFromBackend = (lang, api3UrlOverride = null) => { +export const loadLayersConfigFromBackend = (lang) => { return new Promise((resolve, reject) => { - if (!api3UrlOverride && !API_BASE_URL) { + if (!getApi3BaseUrl()) { // this could happen if we are testing the app in unit tests, we simply reject and do nothing reject('API base URL is undefined') } else { const layersConfig = [] axios - .get( - `${api3UrlOverride ?? API_BASE_URL}rest/services/all/MapServer/layersConfig?lang=${lang}` - ) + .get(`${getApi3BaseUrl()}rest/services/all/MapServer/layersConfig?lang=${lang}`) .then(({ data: rawLayersConfig }) => { if (Object.keys(rawLayersConfig).length > 0) { Object.keys(rawLayersConfig).forEach((rawLayerId) => { diff --git a/src/api/print.api.js b/src/api/print.api.js index 3ae75ee32..b629bbf95 100644 --- a/src/api/print.api.js +++ b/src/api/print.api.js @@ -8,7 +8,11 @@ import { import axios from 'axios' import { Circle } from 'ol/style' -import { API_BASE_URL, API_SERVICES_BASE_URL, WMS_BASE_URL } from '@/config' +import { + getApi3BaseUrl, + getViewerDedicatedServicesBaseUrl, + getWmsBaseUrl, +} from '@/config/baseUrl.config' import i18n from '@/modules/i18n' import log from '@/utils/logging' import { adjustWidth } from '@/utils/styleUtils' @@ -16,7 +20,7 @@ import { adjustWidth } from '@/utils/styleUtils' const PRINTING_DEFAULT_POLL_INTERVAL = 2000 // interval between each polling of the printing job status (ms) const PRINTING_DEFAULT_POLL_TIMEOUT = 600000 // ms (10 minutes) -const SERVICE_PRINT_URL = `${API_SERVICES_BASE_URL}print3/print/mapviewer` +const SERVICE_PRINT_URL = `${getViewerDedicatedServicesBaseUrl()}print3/print/mapviewer` const MAX_PRINT_SPEC_SIZE = 1 * 1024 * 1024 // 1MB in bytes (should be in sync with the backend) class GeoAdminCustomizer extends BaseCustomizer { @@ -280,10 +284,6 @@ export class PrintError extends Error { * @param {String | null} [config.dpi=null] The DPI of the printed map. Default is `null` * @param {String | null} [config.outputFilename=null] Output file name, without extension. When * null, let the server decide. Default is `null` - * @param {String | null} [config.wmsUrlOverride=null] The base URL to access service-wms. If none - * is given, the default from config.js will be used. Default is `null` - * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If - * none is given, the default from config.js will be used. Default is `null` */ async function transformOlMapToPrintParams(olMap, config) { const { @@ -299,8 +299,6 @@ async function transformOlMapToPrintParams(olMap, config) { excludedLayerIDs = [], dpi = null, outputFilename = null, - wmsUrlOverride = null, - api3UrlOverride = null, } = config if (!qrCodeUrl) { @@ -348,7 +346,7 @@ async function transformOlMapToPrintParams(olMap, config) { }) if (printGrid) { encodedMap.layers.unshift({ - baseURL: wmsUrlOverride ?? WMS_BASE_URL, + baseURL: getWmsBaseUrl(), opacity: 1, singleTile: true, type: 'WMS', @@ -383,9 +381,7 @@ async function transformOlMapToPrintParams(olMap, config) { classes: layersWithLegends.map((layer) => { return { name: layer.name, - icons: [ - `${api3UrlOverride ?? API_BASE_URL}static/images/legends/${layer.id}_${lang}.png`, - ], + icons: [`${getApi3BaseUrl()}static/images/legends/${layer.id}_${lang}.png`], } }), } @@ -441,10 +437,6 @@ function printSpecReplacer(key, value) { * @param {String | null} [config.outputFilename=null] Output file name, without extension. When * null, let the server decide. Default is `null` * @param {String | null} [config.dpi=null] The DPI of the printed map. Default is `null` - * @param {String | null} [config.wmsUrlOverride=null] The base URL to access service-wms. If none - * is given, the default from config.js will be used. Default is `null` - * @param {String | null} [config.api3UrlOverride=null] The base URL to access API3 services. If - * none is given, the default from config.js will be used. Default is `null` * @returns {Promise} A job running on our printing backend (needs to be polled * using {@link waitForPrintJobCompletion} to wait until its completion) */ @@ -462,8 +454,6 @@ export async function createPrintJob(map, config) { excludedLayerIDs = [], outputFilename = null, dpi = null, - wmsUrlOverride = null, - api3UrlOverride = null, } = config try { const printingSpec = await transformOlMapToPrintParams(map, { @@ -479,8 +469,6 @@ export async function createPrintJob(map, config) { excludedLayerIDs, outputFilename, dpi, - wmsUrlOverride, - api3UrlOverride, }) if (!isPrintingSpecSizeValid(printingSpec)) { throw new PrintError('Printing spec is too large', 'print_request_too_large') diff --git a/src/api/profile/profile.api.js b/src/api/profile/profile.api.js index 4e0786e0b..90eba4434 100644 --- a/src/api/profile/profile.api.js +++ b/src/api/profile/profile.api.js @@ -3,7 +3,7 @@ import proj4 from 'proj4' import ElevationProfile from '@/api/profile/ElevationProfile.class' import ElevationProfileSegment from '@/api/profile/ElevationProfileSegment.class' -import { API_SERVICE_ALTI_BASE_URL } from '@/config' +import { getServiceAltiBaseUrl } from '@/config/baseUrl.config' import { LV95 } from '@/utils/coordinates/coordinateSystems' import { removeZValues, unwrapGeometryCoordinates } from '@/utils/coordinates/coordinateUtils.js' import log from '@/utils/logging' @@ -85,7 +85,7 @@ export async function getProfileDataForChunk(chunk, startingPoint, startingDist, if (chunk.isWithinBounds) { try { const dataForChunk = await axios({ - url: `${API_SERVICE_ALTI_BASE_URL}rest/services/profile.json`, + url: `${getServiceAltiBaseUrl()}rest/services/profile.json`, method: 'POST', params: { offset: 0, diff --git a/src/api/qrcode.api.js b/src/api/qrcode.api.js index 924921398..f32a9c0ba 100644 --- a/src/api/qrcode.api.js +++ b/src/api/qrcode.api.js @@ -1,6 +1,6 @@ import axios from 'axios' -import { API_SERVICES_BASE_URL } from '@/config' +import { getViewerDedicatedServicesBaseUrl } from '@/config/baseUrl.config' import log from '@/utils/logging' /** @@ -11,7 +11,7 @@ import log from '@/utils/logging' */ export function getGenerateQRCodeUrl(url) { const encodedUrl = encodeURIComponent(url) - return `${API_SERVICES_BASE_URL}qrcode/generate?url=${encodedUrl}` + return `${getViewerDedicatedServicesBaseUrl()}qrcode/generate?url=${encodedUrl}` } /** diff --git a/src/api/search.api.js b/src/api/search.api.js index c0e6435a5..a2bf0ddba 100644 --- a/src/api/search.api.js +++ b/src/api/search.api.js @@ -1,7 +1,7 @@ import axios from 'axios' import proj4 from 'proj4' -import { API_SERVICE_SEARCH_BASE_URL } from '@/config' +import { getServiceSearchBaseUrl } from '@/config/baseUrl.config' import CoordinateSystem from '@/utils/coordinates/CoordinateSystem.class' import { LV95, WGS84 } from '@/utils/coordinates/coordinateSystems' import CustomCoordinateSystem from '@/utils/coordinates/CustomCoordinateSystem.class' @@ -95,7 +95,7 @@ export function sanitizeTitle(title = '') { * @returns Promise> */ const generateAxiosSearchRequest = (query, lang, type, cancelToken, extraParams = {}) => { - return axios.get(`${API_SERVICE_SEARCH_BASE_URL}rest/services/ech/SearchServer`, { + return axios.get(`${getServiceSearchBaseUrl()}rest/services/ech/SearchServer`, { cancelToken, params: { sr: LV95.epsgNumber, diff --git a/src/api/shortlink.api.js b/src/api/shortlink.api.js index fd7bd69f2..eb6598e4d 100644 --- a/src/api/shortlink.api.js +++ b/src/api/shortlink.api.js @@ -1,6 +1,6 @@ import axios from 'axios' -import { API_SERVICE_SHORTLINK_BASE_URL } from '@/config' +import { getServiceShortLinkBaseUrl } from '@/config/baseUrl.config' import log from '@/utils/logging' /** @@ -26,7 +26,7 @@ export function createShortLink(url, withCrosshair = false) { reject(errorMessage) } axios - .post(API_SERVICE_SHORTLINK_BASE_URL, { + .post(getServiceShortLinkBaseUrl(), { url: sanitizedUrl, }) .then((response) => { diff --git a/src/api/topics.api.js b/src/api/topics.api.js index 34cbe2d30..0271578c2 100644 --- a/src/api/topics.api.js +++ b/src/api/topics.api.js @@ -1,7 +1,8 @@ import axios from 'axios' import GeoAdminGroupOfLayers from '@/api/layers/GeoAdminGroupOfLayers.class' -import { API_BASE_URL, ENVIRONMENT } from '@/config' +import { getApi3BaseUrl } from '@/config/baseUrl.config' +import { ENVIRONMENT } from '@/config/staging.config' import { getBackgroundLayerFromLegacyUrlParams, getLayersFromLegacyUrlParams, @@ -82,16 +83,12 @@ const readTopicTreeRecursive = (node, availableLayers) => { * @param {String} lang The lang in which to load the topic tree * @param {String} topicId The topic we want to load the topic tree * @param {GeoAdminLayer[]} layersConfig All available layers for this app (the "layers config") - * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is - * given, the default from config.js will be used. Default is `null` * @returns {Promise<{ layers: GeoAdminLayer[]; itemIdToOpen: String[] }>} A list of topic's layers */ -export const loadTopicTreeForTopic = (lang, topicId, layersConfig, api3UrlOverride = null) => { +export const loadTopicTreeForTopic = (lang, topicId, layersConfig) => { return new Promise((resolve, reject) => { axios - .get( - `${api3UrlOverride ?? API_BASE_URL}rest/services/${topicId}/CatalogServer?lang=${lang}` - ) + .get(`${getApi3BaseUrl()}rest/services/${topicId}/CatalogServer?lang=${lang}`) .then((response) => { const treeItems = [] const topicRoot = response.data.results.root @@ -114,13 +111,11 @@ export const loadTopicTreeForTopic = (lang, topicId, layersConfig, api3UrlOverri /** * Loads all topics (without their tree) from the backend. * - * @param {String | null} [api3UrlOverride=null] The base URL to access API3 services. If none is - * given, the default from config.js will be used. Default is `null` * @returns {Promise<{ topics: [] }>} Raw topics from backend */ -export async function loadTopics(api3UrlOverride = null) { +export async function loadTopics() { try { - const response = await axios.get(`${api3UrlOverride ?? API_BASE_URL}rest/services`) + const response = await axios.get(`${getApi3BaseUrl()}rest/services`) return response.data } catch (error) { log.error(`Failed to load topics from backend`, error) diff --git a/src/config.js b/src/config.js deleted file mode 100644 index 40022237e..000000000 --- a/src/config.js +++ /dev/null @@ -1,362 +0,0 @@ -// loading and exporting all values from the .env file as ES6 importable variables - -import { LV95 } from '@/utils/coordinates/coordinateSystems' - -/** - * Adds a slash at the end of the URL if there is none - * - * @param {String} url - * @returns {String} The URL with a trailing slash - */ -export function enforceEndingSlashInUrl(url) { - if (url && !url.endsWith('/')) { - return `${url}/` - } - return url -} - -/** - * Enum that tells for which (deployment) environment the app has been built. - * - * @type {'development' | 'integration' | 'production'} - * @see https://en.wikipedia.org/wiki/Deployment_environment - */ -export const ENVIRONMENT = VITE_ENVIRONMENT - -/** - * Flag that tells if the app is currently running in a Cypress environment for E2E testing - * - * NOTE: this file might be imported by nodejs for external scripts therefore make sure that - * `window` exists - * - * @type Boolean - */ -export const IS_TESTING_WITH_CYPRESS = typeof window !== 'undefined' ? !!window.Cypress : false - -/** - * Current app version (from package.json) - * - * @type {String} - */ -export const APP_VERSION = __APP_VERSION__ - -/** - * Default projection to be used throughout the application - * - * @type {CoordinateSystem} - */ -export const DEFAULT_PROJECTION = LV95 - -/** - * Base part of the URL to use when requesting the api3. - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type String - */ -export const API_BASE_URL = enforceEndingSlashInUrl(import.meta.env.VITE_API_BASE_URL) - -/** - * Base part of the URL to use when requesting the alti service. - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type String - */ -export const API_SERVICE_ALTI_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_API_SERVICE_ALTI_BASE_URL -) - -/** - * Base part of the URL to use when requesting the search service. - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type String - */ -export const API_SERVICE_SEARCH_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_API_SERVICE_SEARCH_BASE_URL -) - -/** - * Base part of the URL to use when requesting icons. - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type String - */ -export const API_SERVICES_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_API_SERVICES_BASE_URL -) - -/** - * Base part of the URL to use for saving, updating or getting kml files. - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type String - */ -export const API_SERVICE_KML_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_API_SERVICE_KML_BASE_URL -) - -/** - * Base part of the URL to be using service-proxy - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type {String} - */ -export const API_SERVICE_PROXY_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_APP_SERVICE_PROXY_BASE_URL -) - -/** - * Base part of the URL to communicate with service-shortlink backend - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type {String} - */ -export const API_SERVICE_SHORTLINK_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_APP_API_SERVICE_SHORTLINK_BASE_URL -) - -/** - * Base part of the URL to use when requesting GeoJSON data (e.g. for prod - * https://data.geo.admin.ch). - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type {String} - */ -export const DATA_BASE_URL = enforceEndingSlashInUrl(import.meta.env.VITE_DATA_BASE_URL) - -/** - * Default WMTS base part of the URL to use when requesting tiles (e.g. for prod - * https://wmts.geo.admin.ch/). - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * @type {String} - */ -export const WMTS_BASE_URL = enforceEndingSlashInUrl(import.meta.env.VITE_WMTS_BASE_URL) - -/** - * Default WMS base part of the URL to use when requesting tiles (e.g. for prod - * https://wms.geo.admin.ch). - * - * This URL always end with a slash, so there's no need at add another one after it to create REST - * endpoints - * - * WMS layers tend to carry their own base URL in their metadata, be mindful of that when using this - * constant (it might be unnecessary) - * - * @type {String} - */ -export const WMS_BASE_URL = enforceEndingSlashInUrl(import.meta.env.VITE_WMS_BASE_URL) - -/** - * Root of the buckets serving 3D tiles - * - * @type {String} - */ -export const BASE_URL_3D_TILES = enforceEndingSlashInUrl(import.meta.env.VITE_APP_3D_TILES_BASE_URL) - -/** - * Default tile size to use when requesting WMS tiles with our internal WMSs (512px) - * - * Comes from - * {@link https://github.com/geoadmin/mf-geoadmin3/blob/master/src/components/map/TileGrid.js} - * - * @type {Number} - */ -export const WMS_TILE_SIZE = 512 // px - -/** - * Map view's minimal resolution Currently set so that OL scalebar displays 10 meters Scalebar about - * 1" on screen, hence about 100px. So, 10 meters/100px = 0.1 Caveat: setting resolution (minimum - * and maximum) has the precedence over zoom (minimum/maximum) - */ - -export const VIEW_MIN_RESOLUTION = 0.1 // meters/pixel - -/** - * Map default max resolution as it is set in mf-chsdi. Only layers with nonstandard resolutions - * give their resolutions. In all other cases, we need to use this default value as the max - * resolution. - * - * @type {Number} - * @see https://github.com/geoadmin/mf-chsdi3/blob/0236814544a6bf2df86598889b81ee4023494325/chsdi/models/bod.py#L119-L123 - */ -export const DEFAULT_GEOADMIN_MAX_WMTS_RESOLUTION = 0.5 // meters/pixel -/** - * Horizontal threshold for the phone view. (min-width for tablet) This will change the menu and - * also some interactions. - * - * The value is taken from the "sm" breakpoint from Bootstrap. If this value is modified, the - * variable with the same name defined in 'src/scss/media-query.mixin' must also be modified. - * - * @type {Number} - */ -export const BREAKPOINT_PHONE_WIDTH = 576 -/** - * Horizontal threshold for the phone view. (min-height for tablet) The height is needed to catch - * landscape view on mobile. - * - * If this value is modified, the variable with the same name defined in - * 'src/scss/media-query.mixin' must also be modified. - * - * @type {Number} - */ -export const BREAKPOINT_PHONE_HEIGHT = 500 -/** - * Horizontal threshold for the tablet view. (min-width for desktop) - * - * If this value is modified, the variable with the same name defined in - * 'src/scss/media-query.mixin' must also be modified. - * - * @type {Number} - */ -export const BREAKPOINT_TABLET = 768 - -/** - * The tolerance in pixel when testing if the cursor is over an element in drawing mode. - * - * @type {Number} - */ -export const DRAWING_HIT_TOLERANCE = 6 - -export const VECTOR_TILE_BASE_URL = enforceEndingSlashInUrl( - import.meta.env.VITE_APP_VECTORTILES_BASE_URL -) - -/** - * Light base map style ID - * - * From https://www.swisstopo.admin.ch/de/geodata/maps/smw/smw_lightbase.html - * - * @type {string} - */ -export const VECTOR_LIGHT_BASE_MAP_STYLE_ID = 'ch.swisstopo.leichte-basiskarte_world.vt' - -/** - * Imagery base map style ID - * - * From https://www.swisstopo.admin.ch/de/geodata/maps/smw/smw_imagerybase.html - * - * @type {string} - */ -export const VECTOR_TILES_IMAGERY_STYLE_ID = 'ch.swisstopo.leichte-basiskarte-imagery_world.vt' - -/** - * Display a big development banner on all but these hosts. - * - * @type {String[]} - */ -export const NO_WARNING_BANNER_HOSTNAMES = ['test.map.geo.admin.ch', 'map.geo.admin.ch'] - -/** - * Display a warning ribbon ('TEST') on the top-left (mobile) or bottom-left (desktop) corner on all - * these hosts. - * - * @type {String[]} - */ -export const WARNING_RIBBON_HOSTNAMES = ['test.map.geo.admin.ch'] - -/** - * WMS supported versions list - * - * @type {String[]} - */ -export const WMS_SUPPORTED_VERSIONS = ['1.3.0'] - -/** - * Display Give Feedback on all these hosts - * - * @type {String[]} - */ -export const GIVE_FEEDBACK_HOSTNAMES = ['localhost', 'sys-map.dev.bgdi.ch', 'test.map.geo.admin.ch'] - -/** - * Display Report Problem on all these hosts - * - * @type {String[]} - */ -export const REPORT_PROBLEM_HOSTNAMES = [ - 'localhost', - 'sys-map.dev.bgdi.ch', - 'sys-map.int.bgdi.ch', - 'sys-map.prod.bgdi.ch', - 'map.geo.admin.ch', -] - -/** - * The oldest year in our system is from the layer Journey Through Time (ch.swisstopo.zeitreihen) - * which has data from the year 1844 - * - * @type {Number} - */ -export const OLDEST_YEAR = 1844 - -/** - * The youngest (closest to now) year in our system, it will always be the previous year as of now - * - * @type {Number} - */ -export const YOUNGEST_YEAR = new Date().getFullYear() - -/** - * Don't show third party disclaimer for iframe with one of these hosts as src - * - * @type {String[]} - */ -export const WHITELISTED_HOSTNAMES = ['test.map.geo.admin.ch', 'map.geo.admin.ch'] - -/** - * How many features we will request our backends when identifying features under a single - * coordinate (mouse click) - * - * @type {number} - */ -export const DEFAULT_FEATURE_COUNT_SINGLE_POINT = 10 - -/** - * How many features we will request our backends when doing a rectangle selection on the map - * (CLTR+drag) - * - * There's a hard limit of 50 on our backend. - * - * @type {number} - * @see https://api3.geo.admin.ch/services/sdiservices.html#id10 - */ -export const DEFAULT_FEATURE_COUNT_RECTANGLE_SELECTION = 50 - -/** - * The width under which we no longer use floating tooltips and enforce infoboxes. - * - * Found empirically, taking the tooltip width of 350px into account - * - * @type {Number} - */ -export const MAX_WIDTH_SHOW_FLOATING_TOOLTIP = 400 - -/** - * 12.5 meters is what was used in the old viewer, see - * https://github.com/geoadmin/mf-geoadmin3/blob/ce24a27b0ca8192a0f78f7b8cc07f4e231031304/src/components/GeomUtilsService.js#L207 - * - * I tried lowering the value, but with the test GPX that were attached to the ticket PB-800 I get - * worst hiking time estimation when using something like 5m than if I use this 12.5 meters. - * - * @type {Number} - */ -export const GPX_GEOMETRY_SIMPLIFICATION_TOLERANCE = 12.5 // meters diff --git a/src/config/baseUrl.config.js b/src/config/baseUrl.config.js new file mode 100644 index 000000000..96e812a13 --- /dev/null +++ b/src/config/baseUrl.config.js @@ -0,0 +1,181 @@ +import { enforceEndingSlashInUrl } from '@/config' + +/** + * All default base URLs for services. + * + * These URLs always end with a slash, so there's no need at add another one after it to create REST + * endpoints + * + * @type {Object} + */ +export const defaultBaseUrlConfig = { + /** + * Base part of the URL to use when requesting api3 (mf-chsdi3) + * + * @type String + * @see https://github.com/geoadmin/mf-chsdi3 + */ + api3: enforceEndingSlashInUrl(import.meta.env.VITE_API_BASE_URL), + + /** + * Base part of the URL to use when requesting the alti service + * + * @type String + * @see https://github.com/geoadmin/service-alti + */ + serviceAlti: enforceEndingSlashInUrl(import.meta.env.VITE_API_SERVICE_ALTI_BASE_URL), + + /** + * Base part of the URL to use when requesting the search service. + * + * @type String + * @see https://github.com/geoadmin/service-search-wsgi + * @see https://github.com/geoadmin/service-search-sphinx + */ + serviceSearch: enforceEndingSlashInUrl(import.meta.env.VITE_API_SERVICE_SEARCH_BASE_URL), + + /** + * Base part of the URL to use when requesting services undocumented to the public, and + * tailor-made for the viewer. + * + * These are, among others : + * + * - Icons + * - Print + * - QR codes + * - Feedback + * + * @type String + * @see https://github.com/geoadmin/service-icons + * @see https://github.com/geoadmin/service-print3 + * @see https://github.com/geoadmin/service-qrcode + * @see https://github.com/geoadmin/service-feedback + */ + viewerDedicatedServices: enforceEndingSlashInUrl(import.meta.env.VITE_API_SERVICES_BASE_URL), + + /** + * Base part of the URL to use for saving, updating or getting kml files. + * + * @type String + * @see https://github.com/geoadmin/service-kml + */ + serviceKml: enforceEndingSlashInUrl(import.meta.env.VITE_API_SERVICE_KML_BASE_URL), + + /** + * Base part of the URL to be using service-proxy + * + * @type {String} + * @see https://github.com/geoadmin/service-proxy + */ + serviceProxy: enforceEndingSlashInUrl(import.meta.env.VITE_APP_SERVICE_PROXY_BASE_URL), + + /** + * Base part of the URL to communicate with service-shortlink backend + * + * @type {String} + * @see https://github.com/geoadmin/service-shortlink + */ + serviceShortLink: enforceEndingSlashInUrl( + import.meta.env.VITE_APP_API_SERVICE_SHORTLINK_BASE_URL + ), + + /** + * Base part of the URL to use when requesting GeoJSON data (e.g. for prod + * https://data.geo.admin.ch). + * + * @type {String} + */ + data: enforceEndingSlashInUrl(import.meta.env.VITE_DATA_BASE_URL), + + /** + * Default WMTS base part of the URL to use when requesting tiles (e.g. for prod + * https://wmts.geo.admin.ch/). + * + * @type {String} + * @see https://github.com/geoadmin/service-wmts + */ + wmts: enforceEndingSlashInUrl(import.meta.env.VITE_WMTS_BASE_URL), + + /** + * Default WMS base part of the URL to use when requesting tiles (e.g. for prod + * https://wms.geo.admin.ch). + * + * WMS layers tend to carry their own base URL in their metadata, be mindful of that when using + * this constant (it might be unnecessary) + * + * @type {String} + * @see https://github.com/geoadmin/service-wms + */ + wms: enforceEndingSlashInUrl(import.meta.env.VITE_WMS_BASE_URL), + + /** + * Root of the AWS S3 buckets serving 3D tiles + * + * @type {String} + */ + tiles3d: enforceEndingSlashInUrl(import.meta.env.VITE_APP_3D_TILES_BASE_URL), + + /** + * Root of the AWS S3 buckets serving vector tile styles and tiles + * + * @type {String} + */ + vectorTiles: enforceEndingSlashInUrl(import.meta.env.VITE_APP_VECTORTILES_BASE_URL), +} + +export const baseUrlOverrides = { + ...defaultBaseUrlConfig, +} +Object.keys(baseUrlOverrides).forEach((key) => (baseUrlOverrides[key] = null)) + +export function getBaseUrl(propertyName) { + return baseUrlOverrides[propertyName] ?? defaultBaseUrlConfig[propertyName] +} + +export function getApi3BaseUrl() { + return getBaseUrl('api3') +} + +export function getServiceAltiBaseUrl() { + return getBaseUrl('serviceAlti') +} + +export function getServiceSearchBaseUrl() { + return getBaseUrl('serviceSearch') +} + +export function getViewerDedicatedServicesBaseUrl() { + return getBaseUrl('viewerDedicatedServices') +} + +export function getServiceKmlBaseUrl() { + return getBaseUrl('serviceKml') +} + +export function getServiceProxyBaseUrl() { + return getBaseUrl('serviceProxy') +} + +export function getServiceShortLinkBaseUrl() { + return getBaseUrl('serviceShortLink') +} + +export function getDataBaseUrl() { + return getBaseUrl('data') +} + +export function getWmsBaseUrl() { + return getBaseUrl('wms') +} + +export function getWmtsBaseUrl() { + return getBaseUrl('wmts') +} + +export function get3dTilesBaseUrl() { + return getBaseUrl('tiles3d') +} + +export function getVectorTilesBaseUrl() { + return getBaseUrl('vectorTiles') +} diff --git a/src/config/index.js b/src/config/index.js new file mode 100644 index 000000000..2421f9950 --- /dev/null +++ b/src/config/index.js @@ -0,0 +1,12 @@ +/** + * Adds a slash at the end of the URL if there is none + * + * @param {String} url + * @returns {String} The URL with a trailing slash + */ +export function enforceEndingSlashInUrl(url) { + if (url && !url.endsWith('/')) { + return `${url}/` + } + return url +} diff --git a/src/config/map.config.js b/src/config/map.config.js new file mode 100644 index 000000000..2be7b5820 --- /dev/null +++ b/src/config/map.config.js @@ -0,0 +1,79 @@ +import { LV95 } from '@/utils/coordinates/coordinateSystems' + +/** + * Default projection to be used throughout the application + * + * @type {CoordinateSystem} + */ +export const DEFAULT_PROJECTION = LV95 + +/** + * Default tile size to use when requesting WMS tiles with our internal WMSs (512px) + * + * Comes from + * {@link https://github.com/geoadmin/mf-geoadmin3/blob/master/src/components/map/TileGrid.js} + * + * @type {Number} + */ +export const WMS_TILE_SIZE = 512 // px + +/** + * WMS supported versions list + * + * @type {String[]} + */ +export const WMS_SUPPORTED_VERSIONS = ['1.3.0'] + +/** + * Map default max resolution as it is set in mf-chsdi. Only layers with nonstandard resolutions + * give their resolutions. In all other cases, we need to use this default value as the max + * resolution. + * + * @type {Number} + * @see https://github.com/geoadmin/mf-chsdi3/blob/0236814544a6bf2df86598889b81ee4023494325/chsdi/models/bod.py#L119-L123 + */ +export const DEFAULT_GEOADMIN_MAX_WMTS_RESOLUTION = 0.5 // meters/pixel + +/** + * Map view's minimal resolution Currently set so that OL scalebar displays 10 meters Scalebar about + * 1" on screen, hence about 100px. So, 10 meters/100px = 0.1 Caveat: setting resolution (minimum + * and maximum) has the precedence over zoom (minimum/maximum) + */ +export const VIEW_MIN_RESOLUTION = 0.1 // meters/pixel + +/** + * The tolerance in pixel when testing if the cursor is over an element in drawing mode. + * + * @type {Number} + */ +export const DRAWING_HIT_TOLERANCE = 6 + +/** + * How many features we will request our backends when identifying features under a single + * coordinate (mouse click) + * + * @type {number} + */ +export const DEFAULT_FEATURE_COUNT_SINGLE_POINT = 10 + +/** + * How many features we will request our backends when doing a rectangle selection on the map + * (CLTR+drag) + * + * There's a hard limit of 50 on our backend. + * + * @type {number} + * @see https://api3.geo.admin.ch/services/sdiservices.html#id10 + */ +export const DEFAULT_FEATURE_COUNT_RECTANGLE_SELECTION = 50 + +/** + * 12.5 meters is what was used in the old viewer, see + * https://github.com/geoadmin/mf-geoadmin3/blob/ce24a27b0ca8192a0f78f7b8cc07f4e231031304/src/components/GeomUtilsService.js#L207 + * + * I tried lowering the value, but with the test GPX that were attached to the ticket PB-800 I get + * worst hiking time estimation when using something like 5m than if I use this 12.5 meters. + * + * @type {Number} + */ +export const GPX_GEOMETRY_SIMPLIFICATION_TOLERANCE = 12.5 // meters diff --git a/src/config/responsive.config.js b/src/config/responsive.config.js new file mode 100644 index 000000000..ae28ff58b --- /dev/null +++ b/src/config/responsive.config.js @@ -0,0 +1,40 @@ +/** + * Horizontal threshold for the phone view. (min-width for tablet) This will change the menu and + * also some interactions. + * + * The value is taken from the "sm" breakpoint from Bootstrap. If this value is modified, the + * variable with the same name defined in 'src/scss/media-query.mixin' must also be modified. + * + * @type {Number} + */ +export const BREAKPOINT_PHONE_WIDTH = 576 + +/** + * Horizontal threshold for the phone view. (min-height for tablet) The height is needed to catch + * landscape view on mobile. + * + * If this value is modified, the variable with the same name defined in + * 'src/scss/media-query.mixin' must also be modified. + * + * @type {Number} + */ +export const BREAKPOINT_PHONE_HEIGHT = 500 + +/** + * Horizontal threshold for the tablet view. (min-width for desktop) + * + * If this value is modified, the variable with the same name defined in + * 'src/scss/media-query.mixin' must also be modified. + * + * @type {Number} + */ +export const BREAKPOINT_TABLET = 768 + +/** + * The width under which we no longer use floating tooltips and enforce infoboxes. + * + * Found empirically, taking the tooltip width of 350px into account + * + * @type {Number} + */ +export const MAX_WIDTH_SHOW_FLOATING_TOOLTIP = 400 diff --git a/src/config/staging.config.js b/src/config/staging.config.js new file mode 100644 index 000000000..3a9d3d01c --- /dev/null +++ b/src/config/staging.config.js @@ -0,0 +1,66 @@ +/** + * Enum that tells for which (deployment) environment the app has been built. + * + * @type {'development' | 'integration' | 'production'} + * @see https://en.wikipedia.org/wiki/Deployment_environment + */ +export const ENVIRONMENT = VITE_ENVIRONMENT + +/** + * Flag that tells if the app is currently running in a Cypress environment for E2E testing + * + * NOTE: this file might be imported by nodejs for external scripts therefore make sure that + * `window` exists + * + * @type Boolean + */ +export const IS_TESTING_WITH_CYPRESS = typeof window !== 'undefined' ? !!window.Cypress : false + +/** + * Current app version (from package.json) + * + * @type {String} + */ +export const APP_VERSION = __APP_VERSION__ + +/** + * Display a big development banner on all but these hosts. + * + * @type {String[]} + */ +export const NO_WARNING_BANNER_HOSTNAMES = ['test.map.geo.admin.ch', 'map.geo.admin.ch'] + +/** + * Display a warning ribbon ('TEST') on the top-left (mobile) or bottom-left (desktop) corner on all + * these hosts. + * + * @type {String[]} + */ +export const WARNING_RIBBON_HOSTNAMES = ['test.map.geo.admin.ch'] + +/** + * Display Give Feedback on all these hosts + * + * @type {String[]} + */ +export const GIVE_FEEDBACK_HOSTNAMES = ['localhost', 'sys-map.dev.bgdi.ch', 'test.map.geo.admin.ch'] + +/** + * Display Report Problem on all these hosts + * + * @type {String[]} + */ +export const REPORT_PROBLEM_HOSTNAMES = [ + 'localhost', + 'sys-map.dev.bgdi.ch', + 'sys-map.int.bgdi.ch', + 'sys-map.prod.bgdi.ch', + 'map.geo.admin.ch', +] + +/** + * Don't show third party disclaimer for iframe with one of these hosts as src + * + * @type {String[]} + */ +export const WHITELISTED_HOSTNAMES = ['test.map.geo.admin.ch', 'map.geo.admin.ch'] diff --git a/src/config/time.config.js b/src/config/time.config.js new file mode 100644 index 000000000..355c79178 --- /dev/null +++ b/src/config/time.config.js @@ -0,0 +1,14 @@ +/** + * The oldest year in our system is from the layer Journey Through Time (ch.swisstopo.zeitreihen) + * which has data from the year 1844 + * + * @type {Number} + */ +export const OLDEST_YEAR = 1844 + +/** + * The youngest (closest to now) year in our system, it will always be the previous year as of now + * + * @type {Number} + */ +export const YOUNGEST_YEAR = new Date().getFullYear() diff --git a/src/config/vectortiles.config.js b/src/config/vectortiles.config.js new file mode 100644 index 000000000..311743fdd --- /dev/null +++ b/src/config/vectortiles.config.js @@ -0,0 +1,17 @@ +/** + * Light base map style ID + * + * From https://www.swisstopo.admin.ch/de/geodata/maps/smw/smw_lightbase.html + * + * @type {string} + */ +export const VECTOR_LIGHT_BASE_MAP_STYLE_ID = 'ch.swisstopo.leichte-basiskarte_world.vt' + +/** + * Imagery base map style ID + * + * From https://www.swisstopo.admin.ch/de/geodata/maps/smw/smw_imagerybase.html + * + * @type {string} + */ +export const VECTOR_TILES_IMAGERY_STYLE_ID = 'ch.swisstopo.leichte-basiskarte-imagery_world.vt' diff --git a/src/main.js b/src/main.js index 01c3df366..290a3715d 100644 --- a/src/main.js +++ b/src/main.js @@ -9,22 +9,22 @@ import tippy from 'tippy.js' import { createApp } from 'vue' import { - API_BASE_URL, - API_SERVICE_ALTI_BASE_URL, - API_SERVICE_KML_BASE_URL, - API_SERVICE_SEARCH_BASE_URL, - API_SERVICES_BASE_URL, - APP_VERSION, + getApi3BaseUrl, + getDataBaseUrl, + getServiceAltiBaseUrl, + getServiceKmlBaseUrl, + getServiceSearchBaseUrl, + getViewerDedicatedServicesBaseUrl, + getWmsBaseUrl, + getWmtsBaseUrl, +} from '@/config/baseUrl.config' +import { WMS_TILE_SIZE } from '@/config/map.config' +import { BREAKPOINT_PHONE_HEIGHT, BREAKPOINT_PHONE_WIDTH, BREAKPOINT_TABLET, - DATA_BASE_URL, - ENVIRONMENT, - IS_TESTING_WITH_CYPRESS, - WMS_BASE_URL, - WMS_TILE_SIZE, - WMTS_BASE_URL, -} from '@/config' +} from '@/config/responsive.config' +import { APP_VERSION, ENVIRONMENT, IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import i18n from '@/modules/i18n' import router from '@/router' import store from '@/store' @@ -38,14 +38,14 @@ log.debug('Config is', { ENVIRONMENT, IS_TESTING_WITH_CYPRESS, APP_VERSION, - API_BASE_URL, - API_SERVICES_BASE_URL, - API_SERVICE_ALTI_BASE_URL, - API_SERVICE_KML_BASE_URL, - API_SERVICE_SEARCH_BASE_URL, - DATA_BASE_URL, - WMTS_BASE_URL, - WMS_BASE_URL, + 'API3 base URL': getApi3BaseUrl(), + 'Viewer services base URL': getViewerDedicatedServicesBaseUrl(), + 'service-alti': getServiceAltiBaseUrl(), + 'service-kml': getServiceKmlBaseUrl(), + 'service-search': getServiceSearchBaseUrl(), + 'data (GeoJSON)': getDataBaseUrl(), + WMTS: getWmtsBaseUrl(), + WMS: getWmsBaseUrl(), WMS_TILE_SIZE, BREAKPOINT_PHONE_WIDTH, BREAKPOINT_PHONE_HEIGHT, diff --git a/src/modules/drawing/DrawingModule.vue b/src/modules/drawing/DrawingModule.vue index b3fab0ac4..7933662b9 100644 --- a/src/modules/drawing/DrawingModule.vue +++ b/src/modules/drawing/DrawingModule.vue @@ -4,7 +4,7 @@ import VectorSource from 'ol/source/Vector' import { computed, inject, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue' import { useStore } from 'vuex' -import { IS_TESTING_WITH_CYPRESS } from '@/config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import DrawingInteractions from '@/modules/drawing/components/DrawingInteractions.vue' import DrawingToolbox from '@/modules/drawing/components/DrawingToolbox.vue' import DrawingTooltip from '@/modules/drawing/components/DrawingTooltip.vue' diff --git a/src/modules/drawing/components/DrawingSelectInteraction.vue b/src/modules/drawing/components/DrawingSelectInteraction.vue index 120771af9..460f594db 100644 --- a/src/modules/drawing/components/DrawingSelectInteraction.vue +++ b/src/modules/drawing/components/DrawingSelectInteraction.vue @@ -10,7 +10,7 @@ import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { useStore } from 'vuex' import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' -import { DRAWING_HIT_TOLERANCE } from '@/config' +import { DRAWING_HIT_TOLERANCE } from '@/config/map.config' import useModifyInteraction from '@/modules/drawing/components/useModifyInteraction.composable' import { editingFeatureStyleFunction } from '@/modules/drawing/lib/style' import useSaveKmlOnChange from '@/modules/drawing/useKmlDataManagement.composable' diff --git a/src/modules/drawing/components/DrawingTooltip.vue b/src/modules/drawing/components/DrawingTooltip.vue index 65bcabbe1..39e85ea51 100644 --- a/src/modules/drawing/components/DrawingTooltip.vue +++ b/src/modules/drawing/components/DrawingTooltip.vue @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' import { EditableFeatureTypes } from '@/api/features/EditableFeature.class' -import { DRAWING_HIT_TOLERANCE } from '@/config' +import { DRAWING_HIT_TOLERANCE } from '@/config/map.config' import { getVertexCoordinates, pointWithinTolerance } from '@/modules/drawing/lib/drawingUtils' const cssPointer = 'cursor-pointer' diff --git a/src/modules/drawing/components/useModifyInteraction.composable.js b/src/modules/drawing/components/useModifyInteraction.composable.js index 3059f5c40..e29a027b3 100644 --- a/src/modules/drawing/components/useModifyInteraction.composable.js +++ b/src/modules/drawing/components/useModifyInteraction.composable.js @@ -8,7 +8,7 @@ import { extractOlFeatureCoordinates, extractOlFeatureGeodesicCoordinates, } from '@/api/features/features.api' -import { DRAWING_HIT_TOLERANCE } from '@/config' +import { DRAWING_HIT_TOLERANCE } from '@/config/map.config' import { editingVertexStyleFunction } from '@/modules/drawing/lib/style' import useSaveKmlOnChange from '@/modules/drawing/useKmlDataManagement.composable' import { segmentExtent, subsegments } from '@/utils/geodesicManager' diff --git a/src/modules/drawing/useKmlDataManagement.composable.js b/src/modules/drawing/useKmlDataManagement.composable.js index fbef03dcc..a1baa490a 100644 --- a/src/modules/drawing/useKmlDataManagement.composable.js +++ b/src/modules/drawing/useKmlDataManagement.composable.js @@ -3,7 +3,7 @@ import { useStore } from 'vuex' import { createKml, getKmlUrl, updateKml } from '@/api/files.api' import KMLLayer from '@/api/layers/KMLLayer.class' -import { IS_TESTING_WITH_CYPRESS } from '@/config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import { DrawingState, generateKmlString } from '@/modules/drawing/lib/export-utils' import { parseKml } from '@/utils/kmlUtils' import log from '@/utils/logging' diff --git a/src/modules/infobox/InfoboxModule.vue b/src/modules/infobox/InfoboxModule.vue index 1da2423dd..d2fa263f1 100644 --- a/src/modules/infobox/InfoboxModule.vue +++ b/src/modules/infobox/InfoboxModule.vue @@ -4,7 +4,7 @@ import { computed, ref, watch } from 'vue' import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' -import { MAX_WIDTH_SHOW_FLOATING_TOOLTIP } from '@/config' +import { MAX_WIDTH_SHOW_FLOATING_TOOLTIP } from '@/config/responsive.config' import InfoboxContent from '@/modules/infobox/components/InfoboxContent.vue' import { FeatureInfoPositions } from '@/store/modules/ui.store' import PrintButton from '@/utils/components/PrintButton.vue' diff --git a/src/modules/infobox/components/FeatureDetail.vue b/src/modules/infobox/components/FeatureDetail.vue index 2f560433e..f17882df4 100644 --- a/src/modules/infobox/components/FeatureDetail.vue +++ b/src/modules/infobox/components/FeatureDetail.vue @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' import SelectableFeature from '@/api/features/SelectableFeature.class.js' -import { WHITELISTED_HOSTNAMES } from '@/config' +import { WHITELISTED_HOSTNAMES } from '@/config/staging.config' import FeatureAreaInfo from '@/modules/infobox/components/FeatureAreaInfo.vue' import FeatureDetailDisclaimer from '@/modules/infobox/components/FeatureDetailDisclaimer.vue' import CoordinateCopySlot from '@/utils/components/CoordinateCopySlot.vue' diff --git a/src/modules/map/components/cesium/CesiumMap.vue b/src/modules/map/components/cesium/CesiumMap.vue index 335afbb2d..c0d23aa62 100644 --- a/src/modules/map/components/cesium/CesiumMap.vue +++ b/src/modules/map/components/cesium/CesiumMap.vue @@ -100,22 +100,18 @@ import { LineString, Point, Polygon } from 'ol/geom' import proj4 from 'proj4' import { mapActions, mapGetters, mapState } from 'vuex' -import { extractOlFeatureGeodesicCoordinates } from '@/api/features/features.api.js' +import { extractOlFeatureGeodesicCoordinates } from '@/api/features/features.api' import ExternalLayer from '@/api/layers/ExternalLayer.class' -import GeoAdminAggregateLayer from '@/api/layers/GeoAdminAggregateLayer.class.js' +import GeoAdminAggregateLayer from '@/api/layers/GeoAdminAggregateLayer.class' import GeoAdminGeoJsonLayer from '@/api/layers/GeoAdminGeoJsonLayer.class' import GeoAdminWMSLayer from '@/api/layers/GeoAdminWMSLayer.class' import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class' import GPXLayer from '@/api/layers/GPXLayer.class' import KMLLayer from '@/api/layers/KMLLayer.class' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { - BASE_URL_3D_TILES, - DEFAULT_PROJECTION, - IS_TESTING_WITH_CYPRESS, - WMS_BASE_URL, - WMTS_BASE_URL, -} from '@/config' +import { get3dTilesBaseUrl, getWmsBaseUrl, getWmtsBaseUrl } from '@/config/baseUrl.config' +import { DEFAULT_PROJECTION } from '@/config/map.config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import FeatureEdit from '@/modules/infobox/components/FeatureEdit.vue' import FeatureList from '@/modules/infobox/components/FeatureList.vue' import CesiumGeolocationFeedback from '@/modules/map/components/cesium/CesiumGeolocationFeedback.vue' @@ -282,9 +278,9 @@ export default { : urlWithoutScheme } const backendUsedToServe3dData = {} - backendUsedToServe3dData[`${withoutSchemeAndTrailingSlash(BASE_URL_3D_TILES)}:443`] = 18 - backendUsedToServe3dData[`${withoutSchemeAndTrailingSlash(WMTS_BASE_URL)}:443`] = 18 - backendUsedToServe3dData[`${withoutSchemeAndTrailingSlash(WMS_BASE_URL)}:443`] = 18 + backendUsedToServe3dData[`${withoutSchemeAndTrailingSlash(get3dTilesBaseUrl())}:443`] = 18 + backendUsedToServe3dData[`${withoutSchemeAndTrailingSlash(getWmtsBaseUrl())}:443`] = 18 + backendUsedToServe3dData[`${withoutSchemeAndTrailingSlash(getWmsBaseUrl())}:443`] = 18 // A per server key list of overrides to use for throttling limits. // Useful when streaming data from a known HTTP/2 or HTTP/3 server. Object.assign(RequestScheduler.requestsByServer, backendUsedToServe3dData) diff --git a/src/modules/map/components/cesium/CesiumWMSLayer.vue b/src/modules/map/components/cesium/CesiumWMSLayer.vue index bd34f24ef..c655fa4c5 100644 --- a/src/modules/map/components/cesium/CesiumWMSLayer.vue +++ b/src/modules/map/components/cesium/CesiumWMSLayer.vue @@ -10,7 +10,7 @@ import { mapState } from 'vuex' import ExternalWMSLayer from '@/api/layers/ExternalWMSLayer.class' import GeoAdminWMSLayer from '@/api/layers/GeoAdminWMSLayer.class' import { ALL_YEARS_TIMESTAMP } from '@/api/layers/LayerTimeConfigEntry.class' -import { DEFAULT_PROJECTION } from '@/config' +import { DEFAULT_PROJECTION } from '@/config/map.config' import addImageryLayerMixins from '@/modules/map/components/cesium/utils/addImageryLayer-mixins' import CoordinateSystem from '@/utils/coordinates/CoordinateSystem.class' import { WGS84 } from '@/utils/coordinates/coordinateSystems' diff --git a/src/modules/map/components/cesium/CesiumWMTSLayer.vue b/src/modules/map/components/cesium/CesiumWMTSLayer.vue index 299aeec99..a81a9c055 100644 --- a/src/modules/map/components/cesium/CesiumWMTSLayer.vue +++ b/src/modules/map/components/cesium/CesiumWMTSLayer.vue @@ -14,7 +14,7 @@ import { mapActions } from 'vuex' import ExternalWMTSLayer, { WMTSEncodingTypes } from '@/api/layers/ExternalWMTSLayer.class' import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class' -import { DEFAULT_PROJECTION } from '@/config' +import { DEFAULT_PROJECTION } from '@/config/map.config' import CoordinateSystem from '@/utils/coordinates/CoordinateSystem.class' import { WGS84 } from '@/utils/coordinates/coordinateSystems' import { getWmtsXyzUrl } from '@/utils/layerUtils' diff --git a/src/modules/map/components/cesium/constants.js b/src/modules/map/components/cesium/constants.js index 0c8ba3edb..44d27ee8f 100644 --- a/src/modules/map/components/cesium/constants.js +++ b/src/modules/map/components/cesium/constants.js @@ -1,11 +1,11 @@ -import { BASE_URL_3D_TILES } from '@/config' +import { get3dTilesBaseUrl } from '@/config/baseUrl.config' /** * 3D terrain URL * * @type {string} */ -export const TERRAIN_URL = `${BASE_URL_3D_TILES}/ch.swisstopo.terrain.3d/v1/` +export const TERRAIN_URL = `${get3dTilesBaseUrl()}/ch.swisstopo.terrain.3d/v1/` /** * The minimum distance in meters of the camera position from the terrain. diff --git a/src/modules/map/components/cesium/utils/addPrimitiveFromOLLayer.mixins.js b/src/modules/map/components/cesium/utils/addPrimitiveFromOLLayer.mixins.js index 843b5d784..29d04b783 100644 --- a/src/modules/map/components/cesium/utils/addPrimitiveFromOLLayer.mixins.js +++ b/src/modules/map/components/cesium/utils/addPrimitiveFromOLLayer.mixins.js @@ -1,7 +1,7 @@ import { PrimitiveCollection } from 'cesium' import { Vector as VectorLayer } from 'ol/layer' -import { IS_TESTING_WITH_CYPRESS } from '@/config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import { PRIMITIVE_DISABLE_DEPTH_TEST_DISTANCE } from '@/modules/map/components/cesium/constants' import addLayerToViewer from '@/modules/map/components/cesium/utils/addLayerToViewer-mixins' import FeatureConverter from '@/modules/map/components/cesium/utils/olcs/FeatureConverter' diff --git a/src/modules/map/components/footer/MapFooterAppVersion.vue b/src/modules/map/components/footer/MapFooterAppVersion.vue index 2a207f34e..148e8258c 100644 --- a/src/modules/map/components/footer/MapFooterAppVersion.vue +++ b/src/modules/map/components/footer/MapFooterAppVersion.vue @@ -2,7 +2,7 @@ import { computed, ref } from 'vue' import { useStore } from 'vuex' -import { APP_VERSION } from '@/config' +import { APP_VERSION } from '@/config/staging.config' const store = useStore() const appVersion = ref(APP_VERSION) diff --git a/src/modules/map/components/openlayers/OpenLayersGPXLayer.vue b/src/modules/map/components/openlayers/OpenLayersGPXLayer.vue index eaad6f4df..b164e8e81 100644 --- a/src/modules/map/components/openlayers/OpenLayersGPXLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersGPXLayer.vue @@ -7,7 +7,7 @@ import { computed, inject, onMounted, onUnmounted, toRefs, watch } from 'vue' import { useStore } from 'vuex' import GPXLayer from '@/api/layers/GPXLayer.class' -import { IS_TESTING_WITH_CYPRESS } from '@/config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import useAddLayerToMap from '@/modules/map/components/openlayers/utils/useAddLayerToMap.composable' import { parseGpx } from '@/utils/gpxUtils' import log from '@/utils/logging' diff --git a/src/modules/map/components/openlayers/OpenLayersKMLLayer.vue b/src/modules/map/components/openlayers/OpenLayersKMLLayer.vue index 2694e9814..b38fb0583 100644 --- a/src/modules/map/components/openlayers/OpenLayersKMLLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersKMLLayer.vue @@ -7,7 +7,7 @@ import { computed, inject, onMounted, onUnmounted, toRefs, watch } from 'vue' import { useStore } from 'vuex' import KMLLayer from '@/api/layers/KMLLayer.class' -import { IS_TESTING_WITH_CYPRESS } from '@/config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import useAddLayerToMap from '@/modules/map/components/openlayers/utils/useAddLayerToMap.composable' import { iconUrlProxyFy, parseKml } from '@/utils/kmlUtils' import log from '@/utils/logging' diff --git a/src/modules/map/components/openlayers/OpenLayersMap.vue b/src/modules/map/components/openlayers/OpenLayersMap.vue index 2330a326a..9b15f9e9a 100644 --- a/src/modules/map/components/openlayers/OpenLayersMap.vue +++ b/src/modules/map/components/openlayers/OpenLayersMap.vue @@ -4,7 +4,7 @@ import { get as getProjection } from 'ol/proj' import { computed, onMounted, provide, ref } from 'vue' import { useStore } from 'vuex' -import { IS_TESTING_WITH_CYPRESS } from '@/config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import { useLayerZIndexCalculation } from '@/modules/map/components/common/z-index.composable' import OpenLayersLayerExtents from '@/modules/map/components/openlayers/debug/OpenLayersLayerExtents.vue' import OpenLayersTileDebugInfo from '@/modules/map/components/openlayers/debug/OpenLayersTileDebugInfo.vue' diff --git a/src/modules/map/components/openlayers/OpenLayersVectorLayer.vue b/src/modules/map/components/openlayers/OpenLayersVectorLayer.vue index a857fd5c2..ff7ecd990 100644 --- a/src/modules/map/components/openlayers/OpenLayersVectorLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersVectorLayer.vue @@ -14,7 +14,7 @@ import axios from 'axios' import { computed, inject, toRefs, watch } from 'vue' import GeoAdminVectorLayer from '@/api/layers/GeoAdminVectorLayer.class' -import { VECTOR_TILES_IMAGERY_STYLE_ID } from '@/config' +import { VECTOR_TILES_IMAGERY_STYLE_ID } from '@/config/vectortiles.config' import useAddLayerToMap from '@/modules/map/components/openlayers/utils/useAddLayerToMap.composable' import log from '@/utils/logging' diff --git a/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue b/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue index 4da01f16e..3a04b5c88 100644 --- a/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersWMSLayer.vue @@ -11,12 +11,14 @@ import { useStore } from 'vuex' import ExternalWMSLayer from '@/api/layers/ExternalWMSLayer.class' import GeoAdminWMSLayer from '@/api/layers/GeoAdminWMSLayer.class' import { ALL_YEARS_TIMESTAMP } from '@/api/layers/LayerTimeConfigEntry.class' -import { WMS_TILE_SIZE } from '@/config' +import { baseUrlOverrides } from '@/config/baseUrl.config' +import { WMS_TILE_SIZE } from '@/config/map.config' import useAddLayerToMap from '@/modules/map/components/openlayers/utils/useAddLayerToMap.composable' -import { LV95 } from '@/utils/coordinates/coordinateSystems.js' +import { LV95 } from '@/utils/coordinates/coordinateSystems' import { flattenExtent } from '@/utils/coordinates/coordinateUtils' import CustomCoordinateSystem from '@/utils/coordinates/CustomCoordinateSystem.class' import { getTimestampFromConfig } from '@/utils/layerUtils' + const props = defineProps({ wmsLayerConfig: { type: [GeoAdminWMSLayer, ExternalWMSLayer], @@ -37,7 +39,6 @@ const { wmsLayerConfig, parentLayerOpacity, zIndex } = toRefs(props) const store = useStore() const projection = computed(() => store.state.position.projection) const currentLang = computed(() => store.state.i18n.lang) -const debugWmsBaseUrlOverride = computed(() => store.state.debug.baseUrlOverride.wms) // extracting useful info from what we've linked so far const layerId = computed(() => wmsLayerConfig.value.technicalName || wmsLayerConfig.value.id) @@ -45,7 +46,7 @@ const wmsVersion = computed(() => wmsLayerConfig.value.wmsVersion || '1.3.0') const format = computed(() => wmsLayerConfig.value.format || 'png') const gutter = computed(() => wmsLayerConfig.value.gutter || -1) const opacity = computed(() => parentLayerOpacity.value ?? wmsLayerConfig.value.opacity) -const url = computed(() => debugWmsBaseUrlOverride.value ?? wmsLayerConfig.value.baseUrl) +const url = computed(() => baseUrlOverrides.wms ?? wmsLayerConfig.value.baseUrl) const timestamp = computed(() => getTimestampFromConfig(wmsLayerConfig.value)) const urlParams = computed(() => cloneDeep(wmsLayerConfig.value.customAttributes) ?? null) diff --git a/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue b/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue index d7eb8b208..8f5020cf8 100644 --- a/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue +++ b/src/modules/map/components/openlayers/OpenLayersWMTSLayer.vue @@ -6,6 +6,7 @@ import { computed, inject, toRefs, watch } from 'vue' import { useStore } from 'vuex' import GeoAdminWMTSLayer from '@/api/layers/GeoAdminWMTSLayer.class' +import { baseUrlOverrides } from '@/config/baseUrl.config.js' import useAddLayerToMap from '@/modules/map/components/openlayers/utils/useAddLayerToMap.composable' import { getTimestampFromConfig, getWmtsXyzUrl, indexOfMaxResolution } from '@/utils/layerUtils' import log from '@/utils/logging' @@ -29,7 +30,6 @@ const { wmtsLayerConfig, parentLayerOpacity, zIndex } = toRefs(props) // mapping relevant store values const store = useStore() const projection = computed(() => store.state.position.projection) -const debugWmtsBaseUrlOverride = computed(() => store.state.debug.baseUrlOverride.wmts) // extracting useful info from what we've linked so far const layerId = computed(() => wmtsLayerConfig.value.technicalName) const maxResolution = computed(() => wmtsLayerConfig.value.maxResolution) @@ -77,7 +77,7 @@ watch(wmtsTimeConfig, () => { function getTransformedXYZUrl() { return getWmtsXyzUrl(wmtsLayerConfig.value, projection.value, { - baseUrlOverride: debugWmtsBaseUrlOverride.value, + baseUrlOverride: baseUrlOverrides.wmts, }) .replace('{z}', '{TileMatrix}') .replace('{x}', '{TileCol}') diff --git a/src/modules/map/components/openlayers/utils/useMapInteractions.composable.js b/src/modules/map/components/openlayers/utils/useMapInteractions.composable.js index e79e49b70..c567f0d56 100644 --- a/src/modules/map/components/openlayers/utils/useMapInteractions.composable.js +++ b/src/modules/map/components/openlayers/utils/useMapInteractions.composable.js @@ -6,7 +6,8 @@ import { useStore } from 'vuex' import LayerFeature from '@/api/features/LayerFeature.class' import LayerTypes from '@/api/layers/LayerTypes.enum' -import { DRAWING_HIT_TOLERANCE, IS_TESTING_WITH_CYPRESS } from '@/config' +import { DRAWING_HIT_TOLERANCE } from '@/config/map.config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import { useDragBoxSelect } from '@/modules/map/components/openlayers/utils/useDragBoxSelect.composable' import { handleFileContent } from '@/modules/menu/components/advancedTools/ImportFile/utils' import { ClickInfo, ClickType } from '@/store/modules/map.store' diff --git a/src/modules/map/components/openlayers/utils/usePrint.composable.js b/src/modules/map/components/openlayers/utils/usePrint.composable.js index 9aaed78dc..6818d47ab 100644 --- a/src/modules/map/components/openlayers/utils/usePrint.composable.js +++ b/src/modules/map/components/openlayers/utils/usePrint.composable.js @@ -82,8 +82,6 @@ export function usePrint(map) { printGrid: printGrid, projection: store.state.position.projection, dpi: store.getters.selectedDPI, - wmsUrlOverride: store.state.debug.baseUrlOverride.wms, - api3UrlOverride: store.state.debug.baseUrlOverride.api3, }) currentJobReference.value = printJob.ref const result = await waitForPrintJobCompletion(printJob) diff --git a/src/modules/map/components/openlayers/utils/useViewBasedOnProjection.composable.js b/src/modules/map/components/openlayers/utils/useViewBasedOnProjection.composable.js index 70caa8965..1c4157355 100644 --- a/src/modules/map/components/openlayers/utils/useViewBasedOnProjection.composable.js +++ b/src/modules/map/components/openlayers/utils/useViewBasedOnProjection.composable.js @@ -2,7 +2,8 @@ import { View } from 'ol' import { computed, onBeforeUnmount, onMounted, watch } from 'vue' import { useStore } from 'vuex' -import { IS_TESTING_WITH_CYPRESS, VIEW_MIN_RESOLUTION } from '@/config' +import { VIEW_MIN_RESOLUTION } from '@/config/map.config' +import { IS_TESTING_WITH_CYPRESS } from '@/config/staging.config' import { LV95, WEBMERCATOR } from '@/utils/coordinates/coordinateSystems' import { LV95_RESOLUTIONS } from '@/utils/coordinates/SwissCoordinateSystem.class' import log from '@/utils/logging' diff --git a/src/modules/map/components/toolbox/TimeSlider.vue b/src/modules/map/components/toolbox/TimeSlider.vue index d993767e9..06a1b3de7 100644 --- a/src/modules/map/components/toolbox/TimeSlider.vue +++ b/src/modules/map/components/toolbox/TimeSlider.vue @@ -5,7 +5,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' -import { OLDEST_YEAR, YOUNGEST_YEAR } from '@/config' +import { OLDEST_YEAR, YOUNGEST_YEAR } from '@/config/time.config' import TimeSliderDropdown from '@/modules/map/components/toolbox/TimeSliderDropdown.vue' import debounce from '@/utils/debounce' import log from '@/utils/logging' diff --git a/src/modules/menu/components/LayerDescriptionPopup.vue b/src/modules/menu/components/LayerDescriptionPopup.vue index da4b5cc8d..73b051e72 100644 --- a/src/modules/menu/components/LayerDescriptionPopup.vue +++ b/src/modules/menu/components/LayerDescriptionPopup.vue @@ -36,42 +36,24 @@ const attributionName = computed(() => layer.value?.attributions[0].name ?? '') const attributionUrl = computed(() => layer.value?.attributions[0].url ?? '') const isExternal = computed(() => layer.value?.isExternal ?? false) -const api3UrlOverride = computed(() => store.state.debug.baseUrlOverride.api3) - const legends = computed(() => layer.value?.legends ?? []) watch(layer, async (newLayer) => { if (!isExternal.value && layer.value) { - htmlContent.value = await getLayerDescription( - currentLang.value, - newLayer.id, - api3UrlOverride.value - ) + htmlContent.value = await getLayerDescription(currentLang.value, newLayer.id) } }) watch(layerId, async (newLayerId) => { if (!isExternal.value && layerId.value) { - htmlContent.value = await getLayerDescription( - currentLang.value, - newLayerId, - api3UrlOverride.value - ) + htmlContent.value = await getLayerDescription(currentLang.value, newLayerId) } }) onMounted(async () => { if (!isExternal.value && layer.value) { - htmlContent.value = await getLayerDescription( - currentLang.value, - layer.value.id, - api3UrlOverride.value - ) + htmlContent.value = await getLayerDescription(currentLang.value, layer.value.id) } else if (!isExternal.value && layerId.value) { - htmlContent.value = await getLayerDescription( - currentLang.value, - layerId.value, - api3UrlOverride.value - ) + htmlContent.value = await getLayerDescription(currentLang.value, layerId.value) } }) diff --git a/src/modules/menu/components/debug/BaseUrlOverrideModal.vue b/src/modules/menu/components/debug/BaseUrlOverrideModal.vue index 154f2f50c..f40e169ec 100644 --- a/src/modules/menu/components/debug/BaseUrlOverrideModal.vue +++ b/src/modules/menu/components/debug/BaseUrlOverrideModal.vue @@ -1,34 +1,33 @@ @@ -43,7 +42,7 @@ function onModalClose(withConfirmation) { v-model="wmsUrlOverride" type="url" class="form-control" - :placeholder="`default: ${WMS_BASE_URL}`" + :placeholder="`default: ${defaultBaseUrlConfig.wms}`" /> @@ -49,34 +72,11 @@ function toggleGeolocation() { diff --git a/src/modules/map/scss/toolbox-buttons.scss b/src/modules/map/scss/toolbox-buttons.scss index ca8356382..941204201 100644 --- a/src/modules/map/scss/toolbox-buttons.scss +++ b/src/modules/map/scss/toolbox-buttons.scss @@ -38,3 +38,8 @@ cursor: not-allowed; } } + +.toolbox-button-label { + font-size: smaller; + text-align: center; +} diff --git a/src/setup-fontawesome.js b/src/setup-fontawesome.js index 5155e7b2a..38f97d9d1 100644 --- a/src/setup-fontawesome.js +++ b/src/setup-fontawesome.js @@ -49,6 +49,7 @@ import { faImage, faInfoCircle, faLink, + faLocationArrow, faLocationPinLock, faMapMarkerAlt, faMinus, @@ -119,6 +120,7 @@ library.add( faHouse, faInfoCircle, faLink, + faLocationArrow, faLocationPinLock, faMapMarkerAlt, faMinus, diff --git a/src/store/modules/__tests__/rotation.store.spec.js b/src/store/modules/__tests__/rotation.store.spec.js index 475217930..d5d856a43 100644 --- a/src/store/modules/__tests__/rotation.store.spec.js +++ b/src/store/modules/__tests__/rotation.store.spec.js @@ -43,7 +43,10 @@ describe('Rotation is set correctly in the store', () => { expect(store.state.position.rotation).to.be.equal(0) }) it('setAngle normalizes the angle', async () => { - await store.dispatch('setRotation', 3 * Math.PI + Math.PI / 2) + await store.dispatch('setRotation', { + rotation: 3 * Math.PI + Math.PI / 2, + dispatcher: 'unit-test', + }) expect(store.state.position.rotation).to.be.closeTo(-(Math.PI / 2), 1e-9) }) }) diff --git a/src/store/modules/geolocation.store.js b/src/store/modules/geolocation.store.js index fa20e6197..17d333719 100644 --- a/src/store/modules/geolocation.store.js +++ b/src/store/modules/geolocation.store.js @@ -8,28 +8,32 @@ const state = { * @type Boolean */ active: false, + /** * Flag telling if the geolocation usage has been denied by the user in his/her browser settings * * @type Boolean */ denied: false, + /** * Flag telling if the geolocation position should always be at the center of the app * - * @type Boolean + * @type {Boolean} */ tracking: true, + /** * Device position in the current application projection [x, y] * - * @type Array + * @type {Number[] | null} */ - position: [0, 0], + position: null, + /** * Accuracy of the geolocation position, in meters * - * @type Number + * @type {Number} */ accuracy: 0, } @@ -69,6 +73,9 @@ const actions = { log.error(`Invalid geolocation accuracy: ${accuracy}`) } }, + setGeolocationData: ({ commit }, { position, accuracy, dispatcher }) => { + commit('setGeolocationData', { position, accuracy, dispatcher }) + }, } const mutations = { @@ -77,6 +84,10 @@ const mutations = { setGeolocationTracking: (state, { tracking }) => (state.tracking = tracking), setGeolocationAccuracy: (state, { accuracy }) => (state.accuracy = accuracy), setGeolocationPosition: (state, { position }) => (state.position = position), + setGeolocationData: (state, { position, accuracy }) => { + state.position = position + state.accuracy = accuracy + }, } export default { diff --git a/src/store/modules/position.store.js b/src/store/modules/position.store.js index 8687b676e..0335c9f65 100644 --- a/src/store/modules/position.store.js +++ b/src/store/modules/position.store.js @@ -55,14 +55,14 @@ const state = { /** * The display format selected for the mousetracker * - * @type String + * @type {String} */ displayedFormatId: LV95Format.id, /** * The map zoom level, which define the resolution of the view * - * @type Number + * @type {Number} */ // some unit tests fail because DEFAULT_PROJECTION is somehow not yet defined when they are run // hence the `?.` operator @@ -71,14 +71,30 @@ const state = { /** * The map rotation expressed so that -Pi < rotation <= Pi * - * @type Number + * @type {Number} */ rotation: 0, + /** + * Flag which indicates if openlayers map rotates to align with true / magnetic north (only + * possible if device has orientation capabilities) + * + * @type {Boolean} + */ + autoRotation: false, + + /** + * Flag which indicates if the device has orientation capabilities (e.g. can use map auto + * rotate) + * + * @type {Boolean} + */ + hasOrientation: false, + /** * Center of the view expressed with the current projection * - * @type Array + * @type {Number[]} */ // some unit tests fail because DEFAULT_PROJECTION is somehow not yet defined when they are run // hence the `?.` operator @@ -96,10 +112,12 @@ const state = { */ projection: DEFAULT_PROJECTION, - /** @type CrossHairs */ + /** @type {CrossHairs} */ crossHair: null, - /** @type Number[] */ + + /** @type {Number[]} */ crossHairPosition: null, + /** * Position of the view when we are in 3D, always expressed in EPSG:3857 (only projection system * that works with Cesium) @@ -128,7 +146,7 @@ const getters = { /** * Resolution of the view expressed in meter per pixel * - * @type Number + * @type {Number} */ resolution: (state) => { return state.projection.getResolutionForZoomAndCenter(state.zoom, state.center) @@ -193,12 +211,18 @@ const actions = { } commit('setZoom', { zoom: state.projection.roundZoomLevel(zoom), dispatcher }) }, - setRotation({ commit }, rotation) { + setRotation({ commit }, { rotation, dispatcher }) { if (typeof rotation !== 'number') { return } rotation = normalizeAngle(rotation) - commit('setRotation', rotation) + commit('setRotation', { rotation, dispatcher }) + }, + setAutoRotation({ commit }, { autoRotation, dispatcher }) { + commit('setAutoRotation', { autoRotation, dispatcher }) + }, + setHasOrientation({ commit }, { hasOrientation, dispatcher }) { + commit('setHasOrientation', { hasOrientation, dispatcher }) }, /** * @param commit @@ -419,7 +443,9 @@ const mutations = { setDisplayedFormatId: (state, { displayedFormatId }) => (state.displayedFormatId = displayedFormatId), setZoom: (state, { zoom }) => (state.zoom = zoom), - setRotation: (state, rotation) => (state.rotation = rotation), + setRotation: (state, { rotation }) => (state.rotation = rotation), + setAutoRotation: (state, { autoRotation }) => (state.autoRotation = autoRotation), + setHasOrientation: (state, { hasOrientation }) => (state.hasOrientation = hasOrientation), setCenter: (state, { x, y }) => (state.center = [x, y]), setCrossHair: (state, { crossHair }) => (state.crossHair = crossHair), setCrossHairPosition: (state, { crossHairPosition }) => diff --git a/src/store/plugins/geolocation-management.plugin.js b/src/store/plugins/geolocation-management.plugin.js index 443eba001..77840e040 100644 --- a/src/store/plugins/geolocation-management.plugin.js +++ b/src/store/plugins/geolocation-management.plugin.js @@ -38,6 +38,21 @@ const readPosition = (position, projection) => { return proj4(WGS84.epsg, projection.epsg, [coords.longitude, coords.latitude]) } +const centerMapOnPosition = (positionProjected, store) => { + setCenterIfInBounds(store, positionProjected) + // set zoom level if needed + let zoomLevel = STANDARD_ZOOM_LEVEL_1_25000_MAP + if (store.state.position.projection instanceof CustomCoordinateSystem) { + zoomLevel = store.state.position.projection.transformStandardZoomLevelToCustom(zoomLevel) + } + if (store.state.position.zoom != zoomLevel) { + store.dispatch('setZoom', { + zoom: zoomLevel, + ...dispatcher, + }) + } +} + const handlePositionAndDispatchToStore = (position, store) => { log.debug( `Received position from geolocation`, @@ -47,30 +62,15 @@ const handlePositionAndDispatchToStore = (position, store) => { ) errorCount = 0 // reset the error count on each successfull position const positionProjected = readPosition(position, store.state.position.projection) - store.dispatch('setGeolocationPosition', { + store.dispatch('setGeolocationData', { position: positionProjected, - ...dispatcher, - }) - store.dispatch('setGeolocationAccuracy', { accuracy: position.coords.accuracy, ...dispatcher, }) // if tracking is active, we center the view of the map on the position received and change // to the proper zoom if (store.state.geolocation.tracking) { - setCenterIfInBounds(store, positionProjected) - // set zoom level if needed - let zoomLevel = STANDARD_ZOOM_LEVEL_1_25000_MAP - if (store.state.position.projection instanceof CustomCoordinateSystem) { - zoomLevel = - store.state.position.projection.transformStandardZoomLevelToCustom(zoomLevel) - } - if (store.state.position.zoom != zoomLevel) { - store.dispatch('setZoom', { - zoom: zoomLevel, - ...dispatcher, - }) - } + centerMapOnPosition(positionProjected, store) } } @@ -134,11 +134,7 @@ const handlePositionError = (error, store, state, options = {}) => { const activeGeolocation = (store, state, options = {}) => { const { useInitial = true } = options - if ( - useInitial && - store.state.geolocation.position[0] !== 0 && - store.state.geolocation.position[1] !== 0 - ) { + if (useInitial && store.state.geolocation.position !== null) { // if we have a previous position use it first to be more reactive but set a // bad accuracy as we don't know how exact it is. setCenterIfInBounds(store, store.state.geolocation.position) @@ -202,6 +198,16 @@ const geolocationManagementPlugin = (store) => { tracking: false, ...dispatcher, }) + } else if ( + mutation.type === 'setGeolocationTracking' && + mutation.payload?.tracking === true && + mutation.payload?.dispatcher !== dispatcher.dispatcher + ) { + // If tracking has been re-enabled by clicking on the geolocation button we re-center + // the map. + if (store.state.geolocation.position !== null) { + centerMapOnPosition(store.state.geolocation.position, store) + } } }) } diff --git a/src/store/plugins/sync-camera-lonlatzoom.js b/src/store/plugins/sync-camera-lonlatzoom.js index 5f8da894b..d74fc556a 100644 --- a/src/store/plugins/sync-camera-lonlatzoom.js +++ b/src/store/plugins/sync-camera-lonlatzoom.js @@ -44,7 +44,10 @@ export default function syncCameraLonLatZoom(store) { dispatcher: self, }) store.dispatch('setZoom', { zoom, dispatcher: self }) - store.dispatch('setRotation', normalizeAngle((rotation * Math.PI) / 180)) + store.dispatch('setRotation', { + rotation: normalizeAngle((rotation * Math.PI) / 180), + dispatcher: self, + }) } }) // Subscribing to action to listen to zoomToExtent and selectResultEntry specifically. diff --git a/src/utils/numberUtils.js b/src/utils/numberUtils.js index e5b5ea706..4a7047b63 100644 --- a/src/utils/numberUtils.js +++ b/src/utils/numberUtils.js @@ -128,3 +128,25 @@ export function wrapDegrees(angleInDegrees) { export function isTimestampYYYYMMDD(timestamp) { return /^\d{4}(1[0-2]|0[1-9])(0[1-9]|[1-2][0-9]|3[0-1])$/.test(timestamp) } + +/** + * Compute the circular mean of radians angles + * + * @param {[Number]} values List of radians angles to compute the circular mean + * @returns {Number} Circular mean in radians + * @see https://en.wikipedia.org/wiki/Circular_mean + */ +export function circularMean(values) { + const sumCos = values.reduce((acc, curr) => acc + Math.cos(curr), 0) + const sumSin = values.reduce((acc, curr) => acc + Math.sin(curr), 0) + + let mean = Math.atan2(sumSin, sumCos) + // The circular mean with this formula gives a result between -180° and 180° + // So we need to correct the negative values to have only 0° - 360° + if (mean < 0) { + // Correction formula in degree would be := 2 * 180 + mean but because we use radians + // we need to convert 180° to radian => Math.PI => Math.PI * 2 = 6.2831853 + mean = 6.2831853 + mean + } + return mean +} diff --git a/tests/cypress/tests-e2e/toolboxRight.cy.js b/tests/cypress/tests-e2e/toolboxRight.cy.js index 03cd73c2f..83472abe7 100644 --- a/tests/cypress/tests-e2e/toolboxRight.cy.js +++ b/tests/cypress/tests-e2e/toolboxRight.cy.js @@ -40,7 +40,10 @@ describe('Testing the buttons of the right toolbox', () => { cy.readStoreValue('state.position.rotation').should('be.equal', 0) cy.get(compassButtonSelector).should('not.exist') - cy.writeStoreValue('setRotation', facingWest + 2 * Math.PI) + cy.writeStoreValue('setRotation', { + rotation: facingWest + 2 * Math.PI, + dispatcher: 'e2e-test', + }) checkMapRotationAndButton(facingWest) // clicking on the button should but north up again, and the button should disapaer From 38ce8c07c8abc23dc8734665c1476a6aae9990b7 Mon Sep 17 00:00:00 2001 From: Brice Schaffner Date: Mon, 12 Aug 2024 08:39:59 +0200 Subject: [PATCH 22/44] PB-154: Avoid exception when starting geolocation The initial geolocation might be invalid which creates a crash error, so we avoid it. --- src/modules/map/components/openlayers/OpenLayersMap.vue | 3 ++- src/modules/map/components/openlayers/OpenLayersMarker.vue | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/map/components/openlayers/OpenLayersMap.vue b/src/modules/map/components/openlayers/OpenLayersMap.vue index b14899ef4..69327233f 100644 --- a/src/modules/map/components/openlayers/OpenLayersMap.vue +++ b/src/modules/map/components/openlayers/OpenLayersMap.vue @@ -38,6 +38,7 @@ const store = useStore() const showTileDebugInfo = computed(() => store.state.debug.showTileDebugInfo) const showLayerExtents = computed(() => store.state.debug.showLayerExtents) const geolocationActive = computed(() => store.state.geolocation.active) +const geoPosition = computed(() => store.state.geolocation.position) const map = new Map({ controls: [] }) useViewBasedOnProjection(map) @@ -73,7 +74,7 @@ const { zIndexTileInfo, zIndexLayerExtents } = useLayerZIndexCalculation() - + diff --git a/src/modules/map/components/openlayers/OpenLayersMarker.vue b/src/modules/map/components/openlayers/OpenLayersMarker.vue index 3774035b9..9695afb99 100644 --- a/src/modules/map/components/openlayers/OpenLayersMarker.vue +++ b/src/modules/map/components/openlayers/OpenLayersMarker.vue @@ -16,7 +16,6 @@ import { randomIntBetween } from '@/utils/numberUtils' const props = defineProps({ position: { type: Array, - default: () => [0, 0], required: true, }, markerStyle: { From 1c01f01246f2efecb201bfceef5f1859d94649b7 Mon Sep 17 00:00:00 2001 From: Brice Schaffner Date: Mon, 12 Aug 2024 09:01:48 +0200 Subject: [PATCH 23/44] PB-154: Added both orientation events Not all devices uses the same orientation events, therefore added both. --- .../OpenLayersGeolocationFeedback.vue | 52 +++++-- .../OpenLayersDeviceOrientationDebugInfo.vue | 9 +- .../utils/useDeviceOrientation.composable.js | 127 +++++++++++++----- 3 files changed, 139 insertions(+), 49 deletions(-) diff --git a/src/modules/map/components/openlayers/OpenLayersGeolocationFeedback.vue b/src/modules/map/components/openlayers/OpenLayersGeolocationFeedback.vue index 91b85e5b2..c6945228d 100644 --- a/src/modules/map/components/openlayers/OpenLayersGeolocationFeedback.vue +++ b/src/modules/map/components/openlayers/OpenLayersGeolocationFeedback.vue @@ -18,28 +18,58 @@ const OpenLayersDeviceOrientationDebugInfo = defineAsyncComponent( const store = useStore() const { zIndexGeolocation } = useLayerZIndexCalculation() -const { heading, headingDegree, orientation, orientationSampled, listener } = useDeviceOrientation() +const { heading, headingDegree, orientation, orientationSampled } = useDeviceOrientation() const hasDevSiteWarning = computed(() => store.getters.hasDevSiteWarning) const geolocationPosition = computed(() => store.state.geolocation.position) const hasOrientation = computed(() => store.state.position.hasOrientation) const orientationParameters = computed(() => { - const roundIfNumber = (v, d) => (isNumber(v) ? round(v, d) : `${v}`) - return [ - { key: 'Listener', value: `${listener.value}` }, - { key: 'Absolute', value: `${orientation.value.absolute}` }, - { key: 'Alpha', value: roundIfNumber(orientation.value.degree, 2) }, - { key: 'Alpha Sampled', value: roundIfNumber(orientationSampled.value.degree, 0) }, { - key: 'webkitCompassHeading Sampled', - value: roundIfNumber(orientationSampled.value.compassHeading, 0), + title: 'Default listener', + parameters: [ + { key: 'Absolute', value: `${orientation.value.default.absolute}` }, + { key: 'Alpha', value: roundIfNumber(orientation.value.default.degree, 2) }, + { + key: 'Alpha Sampled', + value: roundIfNumber(orientationSampled.value.default.degree, 0), + }, + { + key: 'webkitCompassHeading Sampled', + value: roundIfNumber(orientationSampled.value.default.compassHeading, 0), + }, + ], + }, + { + title: 'Absolute listener', + parameters: [ + { key: 'Alpha', value: roundIfNumber(orientation.value.absolute.degree, 2) }, + { + key: 'Alpha Sampled', + value: roundIfNumber(orientationSampled.value.absolute.degree, 0), + }, + { + key: 'webkitCompassHeading Sampled', + value: roundIfNumber(orientationSampled.value.absolute.compassHeading, 0), + }, + ], + }, + { + title: 'Heading', + parameters: [ + { key: 'Heading degree', value: roundIfNumber(headingDegree.value, 0) }, + { key: 'Heading radian', value: roundIfNumber(heading.value, 6) }, + ], + }, + { + title: 'User Agent', + parameters: [{ value: navigator.userAgent }], }, - { key: 'Heading degree', value: roundIfNumber(headingDegree.value, 0) }, - { key: 'Heading radian', value: roundIfNumber(heading.value, 6) }, ] }) + +const roundIfNumber = (v, d) => (isNumber(v) ? round(v, d) : `${v}`)