diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml
index 297f5e903f0..ba9065963d5 100644
--- a/common/config/rush/pnpm-lock.yaml
+++ b/common/config/rush/pnpm-lock.yaml
@@ -143,7 +143,7 @@ importers:
version: 6.3.1(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@types/react@18.3.18)(react@18.3.1)
'@mui/x-date-pickers':
specifier: ^7.20.0
- version: 7.23.3(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/material@6.3.1)(@mui/system@6.3.1)(@types/react@18.3.18)(dayjs@1.11.13)(react-dom@18.3.1)(react@18.3.1)
+ version: 7.23.6(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/material@6.3.1)(@mui/system@6.3.1)(@types/react@18.3.18)(dayjs@1.11.13)(react-dom@18.3.1)(react@18.3.1)
'@nieuwlandgeo/sldreader':
specifier: ^0.4.3
version: 0.4.3(ol@10.3.1)
@@ -200,7 +200,7 @@ importers:
version: 7.5.1(react@18.3.1)
material-react-table:
specifier: ^3.0.1
- version: 3.1.0(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/icons-material@6.3.1)(@mui/material@6.3.1)(@mui/x-date-pickers@7.23.3)(react-dom@18.3.1)(react@18.3.1)
+ version: 3.1.0(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/icons-material@6.3.1)(@mui/material@6.3.1)(@mui/x-date-pickers@7.23.6)(react-dom@18.3.1)(react@18.3.1)
ol:
specifier: ^10.2.1
version: 10.3.1
@@ -2962,8 +2962,8 @@ packages:
react-is: 19.0.0
dev: false
- /@mui/x-date-pickers@7.23.3(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/material@6.3.1)(@mui/system@6.3.1)(@types/react@18.3.18)(dayjs@1.11.13)(react-dom@18.3.1)(react@18.3.1):
- resolution: {integrity: sha512-bjTYX/QzD5ZhVZNNnastMUS3j2Hy4p4IXmJgPJ0vKvQBvUdfEO+ZF42r3PJNNde0FVT1MmTzkmdTlz0JZ6ukdw==}
+ /@mui/x-date-pickers@7.23.6(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/material@6.3.1)(@mui/system@6.3.1)(@types/react@18.3.18)(dayjs@1.11.13)(react-dom@18.3.1)(react@18.3.1):
+ resolution: {integrity: sha512-jt6rEAYLju3NZe3y2S+I5KcTiSHV79FW0jeNUEUTceg1qsPzseHbND66k3zVF0hO3N2oZtLtPywof6vN5Doe+Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@emotion/react': ^11.9.0
@@ -2971,7 +2971,7 @@ packages:
'@mui/material': ^5.15.14 || ^6.0.0
'@mui/system': ^5.15.14 || ^6.0.0
date-fns: ^2.25.0 || ^3.2.0 || ^4.0.0
- date-fns-jalali: ^2.13.0-0 || ^3.2.0-0
+ date-fns-jalali: ^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0
dayjs: ^1.10.7
luxon: ^3.0.2
moment: ^2.29.4
@@ -3005,7 +3005,7 @@ packages:
'@mui/material': 6.3.1(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
'@mui/system': 6.3.1(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@types/react@18.3.18)(react@18.3.1)
'@mui/utils': 6.3.1(@types/react@18.3.18)(react@18.3.1)
- '@mui/x-internals': 7.23.0(@types/react@18.3.18)(react@18.3.1)
+ '@mui/x-internals': 7.23.6(@types/react@18.3.18)(react@18.3.1)
'@types/react-transition-group': 4.4.12(@types/react@18.3.18)
clsx: 2.1.1
dayjs: 1.11.13
@@ -3017,8 +3017,8 @@ packages:
- '@types/react'
dev: false
- /@mui/x-internals@7.23.0(@types/react@18.3.18)(react@18.3.1):
- resolution: {integrity: sha512-bPclKpqUiJYIHqmTxSzMVZi6MH51cQsn5U+8jskaTlo3J4QiMeCYJn/gn7YbeR9GOZFp8hetyHjoQoVHKRXCig==}
+ /@mui/x-internals@7.23.6(@types/react@18.3.18)(react@18.3.1):
+ resolution: {integrity: sha512-hT1Pa4PNCnxwiauPbYMC3p4DiEF1x05Iu4C1MtC/jMJ1LtthymLmTuQ6ZQ53/R9FeqK6sYd6A6noR+vNMjp5DA==}
engines: {node: '>=14.0.0'}
peerDependencies:
react: ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -4517,8 +4517,8 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
- caniuse-lite: 1.0.30001690
- electron-to-chromium: 1.5.79
+ caniuse-lite: 1.0.30001692
+ electron-to-chromium: 1.5.80
node-releases: 2.0.19
update-browserslist-db: 1.1.2(browserslist@4.24.4)
dev: true
@@ -4592,8 +4592,8 @@ packages:
engines: {node: '>=10'}
dev: true
- /caniuse-lite@1.0.30001690:
- resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==}
+ /caniuse-lite@1.0.30001692:
+ resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==}
dev: true
/ccount@2.0.1:
@@ -5288,8 +5288,8 @@ packages:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
dev: true
- /electron-to-chromium@1.5.79:
- resolution: {integrity: sha512-nYOxJNxQ9Om4EC88BE4pPoNI8xwSFf8pU/BAeOl4Hh/b/i6V4biTAzwV7pXi3ARKeoYO5JZKMIXTryXSVer5RA==}
+ /electron-to-chromium@1.5.80:
+ resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==}
dev: true
/email-addresses@5.0.0:
@@ -6594,8 +6594,8 @@ packages:
toidentifier: 1.0.1
dev: true
- /http-parser-js@0.5.8:
- resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==}
+ /http-parser-js@0.5.9:
+ resolution: {integrity: sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==}
dev: true
/http-proxy-middleware@2.0.7(@types/express@4.17.21):
@@ -7878,7 +7878,7 @@ packages:
hasBin: true
dev: true
- /material-react-table@3.1.0(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/icons-material@6.3.1)(@mui/material@6.3.1)(@mui/x-date-pickers@7.23.3)(react-dom@18.3.1)(react@18.3.1):
+ /material-react-table@3.1.0(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/icons-material@6.3.1)(@mui/material@6.3.1)(@mui/x-date-pickers@7.23.6)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-/zPn38QhxQE7mkwLex4CojX3UP2+/+/u7NVq7CHS5d6P8LdTteJPVYXVzym/uhaXzAzFB1ojsbP7zI/y6iUdtQ==}
engines: {node: '>=16'}
peerDependencies:
@@ -7894,7 +7894,7 @@ packages:
'@emotion/styled': 11.14.0(@emotion/react@11.14.0)(@types/react@18.3.18)(react@18.3.1)
'@mui/icons-material': 6.3.1(@mui/material@6.3.1)(@types/react@18.3.18)(react@18.3.1)
'@mui/material': 6.3.1(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1)
- '@mui/x-date-pickers': 7.23.3(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/material@6.3.1)(@mui/system@6.3.1)(@types/react@18.3.18)(dayjs@1.11.13)(react-dom@18.3.1)(react@18.3.1)
+ '@mui/x-date-pickers': 7.23.6(@emotion/react@11.14.0)(@emotion/styled@11.14.0)(@mui/material@6.3.1)(@mui/system@6.3.1)(@types/react@18.3.18)(dayjs@1.11.13)(react-dom@18.3.1)(react@18.3.1)
'@tanstack/match-sorter-utils': 8.19.4
'@tanstack/react-table': 8.20.6(react-dom@18.3.1)(react@18.3.1)
'@tanstack/react-virtual': 3.11.2(react-dom@18.3.1)(react@18.3.1)
@@ -7931,8 +7931,8 @@ packages:
engines: {node: '>= 0.6'}
dev: true
- /memfs@4.15.3:
- resolution: {integrity: sha512-vR/g1SgqvKJgAyYla+06G4p/EOcEmwhYuVb1yc1ixcKf8o/sh7Zngv63957ZSNd1xrZJoinmNyDf2LzuP8WJXw==}
+ /memfs@4.17.0:
+ resolution: {integrity: sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==}
engines: {node: '>= 4.0.0'}
dependencies:
'@jsonjoy.com/json-pack': 1.1.1(tslib@2.8.1)
@@ -10198,7 +10198,7 @@ packages:
optional: true
dependencies:
colorette: 2.0.20
- memfs: 4.15.3
+ memfs: 4.17.0
mime-types: 2.1.35
on-finished: 2.4.1
range-parser: 1.2.1
@@ -10322,7 +10322,7 @@ packages:
resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==}
engines: {node: '>=0.8.0'}
dependencies:
- http-parser-js: 0.5.8
+ http-parser-js: 0.5.9
safe-buffer: 5.2.1
websocket-extensions: 0.1.4
dev: true
diff --git a/packages/geoview-core/public/templates/demos/demo-function-event.html b/packages/geoview-core/public/templates/demos/demo-function-event.html
index 2e2b02ce8ac..65e538da857 100644
--- a/packages/geoview-core/public/templates/demos/demo-function-event.html
+++ b/packages/geoview-core/public/templates/demos/demo-function-event.html
@@ -207,6 +207,9 @@
Events that will generate notifications:
const LYR_PATH_FEATURE = "esriFeatureLYR5/0";
const LYR_PATH_GEOCORE = "f4c51eaa-a6ca-48b9-a1fc-b0651da20509";
+ var CNT_GENERIC_STATUS_CHANGE = 0;
+ var CNT_SPECIFIC_STATUS_CHANGE = 0;
+
// Register a handler when the map is init
cgpv.onMapInit((mapId) => {
// !!
@@ -269,7 +272,7 @@ Events that will generate notifications:
// listen to ANY/ALL layer status at ANY time (generic event catcher)
cgpv.api.maps[mapId].layer.legendsLayerSet.onLayerStatusUpdated((sender, payload) => {
//cgpv.api.maps.Map1.notifications.addNotificationSuccess(`${payload.layer.layerPath} (generic event) status changed to ${payload.layer.layerStatus}`);
- console.log(`${payload.layer.layerPath} (generic event) status changed to ${payload.layer.layerStatus}`);
+ console.log(`${payload.layer.layerPath} (generic event ${++CNT_GENERIC_STATUS_CHANGE}) status changed to ${payload.layer.layerStatus}`);
});
// listen to layer item visibility changed event (any layers)
@@ -298,9 +301,10 @@ Events that will generate notifications:
// Check the layer status of the particular layer before registering the hook - to really know at which status the layer is.
// GV If you really want to make sure to track ALL status changes for ANY particular layer, you can use a hook such as:
// `cgpv.api.maps[mapId].layer.legendsLayerSet.onLayerStatusUpdated()`. See example in cgpv.onMapInit handler above.
+
cgpv.api.maps.Map1.layer.getLayerEntryConfig(LYR_PATH_UNIQUE)?.onLayerStatusChanged((sender, payload) => {
cgpv.api.maps.Map1.notifications.addNotificationSuccess(`${LYR_PATH_UNIQUE} (specific event) status changed to ${payload.layerStatus}`);
- console.log(`${LYR_PATH_UNIQUE} (specific event) status changed to ${payload.layerStatus}`);
+ console.log(`${LYR_PATH_UNIQUE} (specific event ${++CNT_SPECIFIC_STATUS_CHANGE}) status changed to ${payload.layerStatus}`);
});
// listen to individual layer loaded event
diff --git a/packages/geoview-core/public/templates/demos/demo-osdp-integration.html b/packages/geoview-core/public/templates/demos/demo-osdp-integration.html
index 802febaa4e4..b5881f9a557 100644
--- a/packages/geoview-core/public/templates/demos/demo-osdp-integration.html
+++ b/packages/geoview-core/public/templates/demos/demo-osdp-integration.html
@@ -244,7 +244,7 @@ OSDP Integration
/** OSDP function
* Adds layers to the map.
- *
+ *
* @param layers Array of layers.
*/
function addLayers(layers) {
diff --git a/packages/geoview-core/src/core/components/layers/left-panel/add-new-layer/add-new-layer.tsx b/packages/geoview-core/src/core/components/layers/left-panel/add-new-layer/add-new-layer.tsx
index 67315f432bc..2a223d3ab57 100644
--- a/packages/geoview-core/src/core/components/layers/left-panel/add-new-layer/add-new-layer.tsx
+++ b/packages/geoview-core/src/core/components/layers/left-panel/add-new-layer/add-new-layer.tsx
@@ -41,7 +41,7 @@ import { EsriImageLayerEntryConfig } from '@/core/utils/config/validation-classe
import { OgcWmsLayerEntryConfig } from '@/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config';
import { GeoPackage, TypeGeoPackageLayerConfig } from '@/geo/layer/geoview-layers/vector/geopackage';
import { GeoCore } from '@/geo/layer/other/geocore';
-import { GeoViewLayerAddedResult } from '@/geo/layer/layer';
+import { GeoViewLayerAddedResult, LayerApi } from '@/geo/layer/layer';
import {
CONST_LAYER_TYPES,
TypeGeoviewLayerTypeWithGeoCore,
@@ -216,7 +216,7 @@ export function AddNewLayer(): JSX.Element {
listOfLayerEntryConfig: [] as OgcWmsLayerEntryConfig[],
metadataAccessPath: accessPath,
} as TypeWMSLayerConfig;
- const wmsGeoviewLayerInstance = new WmsGeoviewClass(mapId, wmsGeoviewLayerConfig);
+ const wmsGeoviewLayerInstance = new WmsGeoviewClass(mapId, wmsGeoviewLayerConfig, LayerApi.DEBUG_WMS_LAYER_GROUP_FULL_SUB_LAYERS);
// Synchronize the geoviewLayerId.
wmsGeoviewLayerConfig.geoviewLayerId = wmsGeoviewLayerInstance.geoviewLayerId;
setGeoviewLayerInstance(wmsGeoviewLayerInstance);
@@ -248,7 +248,7 @@ export function AddNewLayer(): JSX.Element {
geoviewLayerConfig: wmsGeoviewLayerConfig,
layerId: childLayer.Name as string,
layerName: childLayer.Title as string,
- } as OgcWmsLayerEntryConfig)
+ } as unknown as OgcWmsLayerEntryConfig)
);
}
diff --git a/packages/geoview-core/src/core/utils/config/validation-classes/config-base-class.ts b/packages/geoview-core/src/core/utils/config/validation-classes/config-base-class.ts
index b570ef3e581..20f69c5f0e0 100644
--- a/packages/geoview-core/src/core/utils/config/validation-classes/config-base-class.ts
+++ b/packages/geoview-core/src/core/utils/config/validation-classes/config-base-class.ts
@@ -149,6 +149,9 @@ export abstract class ConfigBaseClass {
}
if (newLayerStatus === 'processed' && this.#waitForProcessedBeforeSendingLoaded) this.layerStatus = 'loaded';
+ // GV For quick debug, uncomment the line
+ // if (newLayerStatus === 'error') debugger;
+
// TODO: Cleanup - Commenting this and leaving it here for now.. It turns out that the parentLayerConfig property can't be trusted
// GV due to a bug with different instances of entryconfigs stored in the objects and depending how you navigate the objects, you get
// GV different instances. Example below (where 'parentLayerConfig.listOfLayerEntryConfig[0]' is indeed going back to 'uniqueValueId/uniqueValueId/4')
@@ -222,6 +225,28 @@ export abstract class ConfigBaseClass {
} as unknown as TypeJsonObject;
}
+ /**
+ * Clones the configuration class.
+ *
+ * @returns {ConfigBaseClass} The cloned ConfigBaseClass object.
+ */
+ clone(): ConfigBaseClass {
+ // Redirect to clone the object and return it
+ return this.onClone();
+ }
+
+ /**
+ * Overridable function to clone a child of a ConfigBaseClass.
+ *
+ * @returns {ConfigBaseClass} The cloned child object of a ConfigBaseClass.
+ */
+ protected onClone(): ConfigBaseClass {
+ // Crash on purpose.
+ // GV Make sure to implement a 'protected override onClone(): ConfigBaseClass' in the child-class to
+ // GV use this cloning feature. See OgcWMSLayerEntryConfig for example.
+ throw new Error(`Not implemented exception onClone on layer path ${this.layerPath}`);
+ }
+
/**
* Recursively checks the list of layer entries to see if all of them are greater than or equal to the provided layer status.
*
diff --git a/packages/geoview-core/src/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config.ts b/packages/geoview-core/src/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config.ts
index 87796dd0ba7..2a42a3b7874 100644
--- a/packages/geoview-core/src/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config.ts
+++ b/packages/geoview-core/src/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config.ts
@@ -1,5 +1,6 @@
import { CONST_LAYER_TYPES } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
import { CONST_LAYER_ENTRY_TYPES, TypeSourceImageWmsInitialConfig } from '@/geo/map/map-schema-types';
+import { ConfigBaseClass } from '@/core/utils/config/validation-classes/config-base-class';
import { AbstractBaseLayerEntryConfig } from '@/core/utils/config/validation-classes/abstract-base-layer-entry-config';
/** ******************************************************************************************************************************
@@ -40,4 +41,13 @@ export class OgcWmsLayerEntryConfig extends AbstractBaseLayerEntryConfig {
// Default value for layerConfig.source.serverType is 'mapserver'.
if (!this.source.serverType) this.source.serverType = 'mapserver';
}
+
+ /**
+ * Clones an instance of a OgcWmsLayerEntryConfig.
+ *
+ * @returns {ConfigBaseClass} The cloned OgcWmsLayerEntryConfig instance
+ */
+ protected override onClone(): ConfigBaseClass {
+ return new OgcWmsLayerEntryConfig(this);
+ }
}
diff --git a/packages/geoview-core/src/geo/layer/geoview-layers/esri-layer-common.ts b/packages/geoview-core/src/geo/layer/geoview-layers/esri-layer-common.ts
index 3a425c35211..057064a45c6 100644
--- a/packages/geoview-core/src/geo/layer/geoview-layers/esri-layer-common.ts
+++ b/packages/geoview-core/src/geo/layer/geoview-layers/esri-layer-common.ts
@@ -142,6 +142,7 @@ export function commonValidateListOfLayerEntryConfig(
// TODO: Refactor: Do not do this on the fly here anymore with the new configs (quite unpredictable)...
// Don't forget to replace the old version in the registered layers
+ // TODO: TEST GROUP LAYER TEST Officially remove setLayerEntryConfigObsolete once passed testing
MapEventProcessor.getMapViewerLayerAPI(layer.mapId).setLayerEntryConfigObsolete(groupLayerConfig);
(layer.metadata!.layers[esriIndex].subLayerIds as TypeJsonArray).forEach((layerId) => {
@@ -164,6 +165,7 @@ export function commonValidateListOfLayerEntryConfig(
// FIXME: Temporary patch to keep the behavior until those layer classes don't exist
// TODO: Refactor: Do not do this on the fly here anymore with the new configs (quite unpredictable)... (standardizing this call with the other one above for now)
+ // TODO: TEST GROUP LAYER TEST Officially remove setLayerEntryConfigObsolete once passed testing
MapEventProcessor.getMapViewerLayerAPI(layer.mapId).setLayerEntryConfigObsolete(subLayerEntryConfig);
});
diff --git a/packages/geoview-core/src/geo/layer/geoview-layers/raster/wms.ts b/packages/geoview-core/src/geo/layer/geoview-layers/raster/wms.ts
index f6bd073d178..37274e8935b 100644
--- a/packages/geoview-core/src/geo/layer/geoview-layers/raster/wms.ts
+++ b/packages/geoview-core/src/geo/layer/geoview-layers/raster/wms.ts
@@ -7,9 +7,7 @@ import { Options as SourceOptions } from 'ol/source/ImageWMS';
import WMSCapabilities from 'ol/format/WMSCapabilities';
import { Extent } from 'ol/extent';
-import cloneDeep from 'lodash/cloneDeep';
-
-import { Cast, TypeJsonArray, TypeJsonObject } from '@/core/types/global-types';
+import { TypeJsonArray, TypeJsonObject } from '@/core/types/global-types';
import { AbstractGeoViewLayer, CONST_LAYER_TYPES } from '@/geo/layer/geoview-layers/abstract-geoview-layers';
import { AbstractGeoViewRaster } from '@/geo/layer/geoview-layers/raster/abstract-geoview-raster';
import { TypeLayerEntryConfig, TypeGeoviewLayerConfig, CONST_LAYER_ENTRY_TYPES, layerEntryIsGroupLayer } from '@/geo/map/map-schema-types';
@@ -21,6 +19,7 @@ import { logger } from '@/core/utils/logger';
import { OgcWmsLayerEntryConfig } from '@/core/utils/config/validation-classes/raster-validation-classes/ogc-wms-layer-entry-config';
import { AbstractBaseLayerEntryConfig } from '@/core/utils/config/validation-classes/abstract-base-layer-entry-config';
import { GroupLayerEntryConfig } from '@/core/utils/config/validation-classes/group-layer-entry-config';
+import { ConfigBaseClass } from '@/core/utils/config/validation-classes/config-base-class';
export interface TypeWMSLayerConfig extends Omit {
geoviewLayerType: typeof CONST_LAYER_TYPES.WMS;
@@ -79,14 +78,17 @@ export const geoviewEntryIsWMS = (verifyIfGeoViewEntry: TypeLayerEntryConfig): v
export class WMS extends AbstractGeoViewRaster {
WMSStyles: string[];
+ fullSubLayers: boolean = false;
+
/** ***************************************************************************************************************************
* Initialize layer
* @param {string} mapId the id of the map
* @param {TypeWMSLayerConfig} layerConfig the layer configuration
*/
- constructor(mapId: string, layerConfig: TypeWMSLayerConfig) {
+ constructor(mapId: string, layerConfig: TypeWMSLayerConfig, fullSubLayers: boolean) {
super(CONST_LAYER_TYPES.WMS, layerConfig, mapId);
this.WMSStyles = [];
+ this.fullSubLayers = fullSubLayers;
}
/** ***************************************************************************************************************************
@@ -97,17 +99,21 @@ export class WMS extends AbstractGeoViewRaster {
// GV Layers Refactoring - Obsolete (in config)
protected override async fetchServiceMetadata(): Promise {
const metadataUrl = this.metadataAccessPath;
- if (metadataUrl) {
- const metadataAccessPathIsXmlFile = metadataUrl.slice(-4).toLowerCase() === '.xml';
+ let curatedMetadataUrl = metadataUrl;
+ if (!metadataUrl.includes('request=GetCapabilities')) {
+ curatedMetadataUrl = `${metadataUrl}?service=WMS&version=1.3.0&request=GetCapabilities`;
+ }
+ if (curatedMetadataUrl) {
+ const metadataAccessPathIsXmlFile = curatedMetadataUrl.slice(-4).toLowerCase() === '.xml';
if (metadataAccessPathIsXmlFile) {
// XML metadata is a special case that does not use GetCapabilities to get the metadata
- await this.#fetchXmlServiceMetadata(metadataUrl);
+ await this.#fetchXmlServiceMetadata(curatedMetadataUrl);
} else {
const layerConfigsToQuery = this.#getLayersToQuery();
if (layerConfigsToQuery.length === 0) {
// Use GetCapabilities to get the metadata
try {
- const metadata = await this.#getServiceMetadata(`${metadataUrl}?service=WMS&version=1.3.0&request=GetCapabilities`);
+ const metadata = await this.#getServiceMetadata(curatedMetadataUrl);
this.metadata = metadata;
this.#processMetadataInheritance();
} catch (error) {
@@ -126,9 +132,7 @@ export class WMS extends AbstractGeoViewRaster {
for (i = 0; layerConfigsToQuery[i].layerId !== layerConfig.layerId; i++);
if (i === layerIndex)
// This is the first time we execute this query
- promisedArrayOfMetadata.push(
- this.#getServiceMetadata(`${metadataUrl}?service=WMS&version=1.3.0&request=GetCapabilities&Layers=${layerConfig.layerId}`)
- );
+ promisedArrayOfMetadata.push(this.#getServiceMetadata(`${curatedMetadataUrl}&Layers=${layerConfig.layerId}`));
// query already done. Use previous returned value
else promisedArrayOfMetadata.push(promisedArrayOfMetadata[i]);
});
@@ -234,7 +238,7 @@ export class WMS extends AbstractGeoViewRaster {
*
* @param {string} layerName The layer name to be found
* @param {TypeJsonObject} layerProperty The layer property from the metadata
- * @param {number[]} pathToTheLayerProperty The path leading to the parent of the layerProperty parameter
+ * @param {number[]} pathToTheParentLayer The path leading to the parent of the layerProperty parameter
*
* @returns {number[]} An array containing the path to the layer or [] if not found.
* @private
@@ -396,7 +400,7 @@ export class WMS extends AbstractGeoViewRaster {
}
if ('Layer' in layerFound) {
- this.#createGroupLayer(layerFound, layerConfig as AbstractBaseLayerEntryConfig);
+ this.#createGroupLayer(layerFound, layerConfig as unknown as GroupLayerEntryConfig);
return;
}
@@ -409,35 +413,57 @@ export class WMS extends AbstractGeoViewRaster {
* This method create recursively dynamic group layers from the service metadata.
*
* @param {TypeJsonObject} layer The dynamic group layer metadata.
- * @param {AbstractBaseLayerEntryConfig} layerConfig The layer configurstion associated to the dynamic group.
+ * @param {GroupLayerEntryConfig} layerConfig The group layer configuration associated to the dynamic group.
* @private
*/
// GV Layers Refactoring - Obsolete (in config)
- #createGroupLayer(layer: TypeJsonObject, layerConfig: AbstractBaseLayerEntryConfig): void {
+ #createGroupLayer(layer: TypeJsonObject, layerConfig: GroupLayerEntryConfig): void {
// TODO: Refactor - createGroup is the same thing for all the layers type? group is a geoview structure.
// TO.DOCONT: Should it be handle upper in abstract class to loop in structure and launch the creation of a leaf?
// TODO: The answer is no. Even if the final structure is the same, the input structure is different for each geoview layer types.
const newListOfLayerEntryConfig: TypeLayerEntryConfig[] = [];
const arrayOfLayerMetadata = Array.isArray(layer.Layer) ? layer.Layer : ([layer.Layer] as TypeJsonArray);
+ // GV Special WMS group layer case situation...
+ // TODO: Bug - There was an issue with the layer configuration for a long time ('Private element not on object') which
+ // TO.DOCONT: was causing the loop below to fail before finishing the first loop (midway deep into 'registerLayerConfigInit()').
+ // TO.DOCONT: The fact that an exception was raised was actually provoking the behavior that we want with the UI display of
+ // TO.DOCONT: the WMS group layers (between Layers and Details tabs).
+ // TO.DOCONT: However, fixing the cloning issue and completing the loops as they should be, was causing an unwanted side-effect
+ // TO.DOCONT: with the UI.
+ // TO.DOCONT: Therefore, we're making it crash on purpose by raising a 'Processing cancelled' exception for now to keep
+ // TO.DOCONT: the behavior the same as before..
+
+ // Assign the layer name right away
+ layerConfig.layerName = layer.Title as string;
+
+ // Loop on the sub layers
arrayOfLayerMetadata.forEach((subLayer) => {
// Log for pertinent debugging purposes
logger.logTraceCore('WMS - createGroupLayer', 'Cloning the layer config', layerConfig.layerPath);
- const subLayerEntryConfig: TypeLayerEntryConfig = cloneDeep(layerConfig);
- subLayerEntryConfig.parentLayerConfig = Cast(layerConfig);
+ const subLayerEntryConfig: ConfigBaseClass = layerConfig.clone();
+ subLayerEntryConfig.parentLayerConfig = layerConfig;
subLayerEntryConfig.layerId = subLayer.Name as string;
subLayerEntryConfig.layerName = subLayer.Title as string;
- newListOfLayerEntryConfig.push(subLayerEntryConfig);
+ newListOfLayerEntryConfig.push(subLayerEntryConfig as TypeLayerEntryConfig);
// FIXME: Temporary patch to keep the behavior until those layer classes don't exist
this.getMapViewer().layer.registerLayerConfigInit(subLayerEntryConfig);
+
+ // If we don't want all sub layers (simulating the 'Private element not on object' error we had for long time)
+ if (!this.fullSubLayers) {
+ // Skip the rest on purpose (ref TODO: Bug above)
+ throw new Error('Processing cancelled');
+ }
});
- const switchToGroupLayer = Cast(layerConfig);
- switchToGroupLayer.entryType = CONST_LAYER_ENTRY_TYPES.GROUP;
- switchToGroupLayer.layerName = layer.Title as string;
- switchToGroupLayer.isMetadataLayerGroup = true;
- switchToGroupLayer.listOfLayerEntryConfig = newListOfLayerEntryConfig;
+ // TODO: Bug - Continuation of the TODO Bug above.. Purposely don't do this anymore (the throw will cause skipping of this)
+ // TO.DOCONT: in order to reproduce the old behavior now that the 'Private element' bug is fixed..
+ // TO.DOCONT: Leaving the code there, uncommented, so that if/when we remove the throw of the
+ // TO.DOCONT: 'Processing cancelled' this gets executed as would be expected
+ layerConfig.entryType = CONST_LAYER_ENTRY_TYPES.GROUP;
+ layerConfig.isMetadataLayerGroup = true;
+ layerConfig.listOfLayerEntryConfig = newListOfLayerEntryConfig;
this.validateListOfLayerEntryConfig(newListOfLayerEntryConfig);
}
diff --git a/packages/geoview-core/src/geo/layer/gv-layers/abstract-gv-layer.ts b/packages/geoview-core/src/geo/layer/gv-layers/abstract-gv-layer.ts
index 35f29637f1b..947c01b2398 100644
--- a/packages/geoview-core/src/geo/layer/gv-layers/abstract-gv-layer.ts
+++ b/packages/geoview-core/src/geo/layer/gv-layers/abstract-gv-layer.ts
@@ -393,15 +393,15 @@ export abstract class AbstractGVLayer extends AbstractBaseLayer {
/**
* Queries the legend.
- * This function raises legend querying and queried events. It calls the overridable getLegend() function.
+ * This function raises legend querying and queried events. It calls the overridable onFetchLegend() function.
* @returns {Promise} The promise when the legend (or null) will be received
*/
queryLegend(): Promise {
// Emit that the legend has been queried
this.#emitLegendQuerying();
- // Get the legend
- const promiseLegend = this.getLegend();
+ // Fetch the legend by calling the overridable function
+ const promiseLegend = this.onFetchLegend();
// Whenever the promise resolves
promiseLegend
@@ -452,8 +452,7 @@ export abstract class AbstractGVLayer extends AbstractBaseLayer {
* of the layerConfig object is undefined, the legend property of the object returned will be null.
* @returns {Promise} The legend of the layer.
*/
- async getLegend(): Promise {
- // TODO: Refactor - Layers refactoring. Rename this function to onFetchLegend() once the layers refactoring is done
+ async onFetchLegend(): Promise {
try {
const legend: TypeLegend = {
type: this.getLayerConfig().geoviewLayerConfig.geoviewLayerType,
diff --git a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-dynamic.ts b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-dynamic.ts
index 00cd055c094..a2014201b40 100644
--- a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-dynamic.ts
+++ b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-dynamic.ts
@@ -665,10 +665,10 @@ export class GVEsriDynamic extends AbstractGVRaster {
* Overrides the fetching of the legend for an Esri Dynamic layer.
* @returns {Promise} The legend of the layer or null.
*/
- override async getLegend(): Promise {
+ override async onFetchLegend(): Promise {
const layerConfig = this.getLayerConfig();
// Only raster layers need the alternate code
- if (layerConfig.getLayerMetadata()?.type !== 'Raster Layer') return super.getLegend();
+ if (layerConfig.getLayerMetadata()?.type !== 'Raster Layer') return super.onFetchLegend();
try {
if (!layerConfig) return null;
diff --git a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-image.ts b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-image.ts
index e4f6802064b..a13b91cbcf9 100644
--- a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-image.ts
+++ b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-esri-image.ts
@@ -102,7 +102,7 @@ export class GVEsriImage extends AbstractGVRaster {
* Overrides the fetching of the legend for an Esri image layer.
* @returns {Promise} The legend of the layer or null.
*/
- override async getLegend(): Promise {
+ override async onFetchLegend(): Promise {
const layerConfig = this.getLayerConfig();
try {
if (!layerConfig) return null;
diff --git a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-image-static.ts b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-image-static.ts
index 8e3960f7c02..7b89315e784 100644
--- a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-image-static.ts
+++ b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-image-static.ts
@@ -102,7 +102,7 @@ export class GVImageStatic extends AbstractGVRaster {
* Overrides the fetching of the legend for an Esri image layer.
* @returns {Promise} The legend of the layer or null.
*/
- override async getLegend(): Promise {
+ override async onFetchLegend(): Promise {
const layerConfig = this.getLayerConfig();
try {
const legendImage = await GVImageStatic.#getLegendImage(layerConfig!);
diff --git a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-wms.ts b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-wms.ts
index af8dde51d58..83d7599f46b 100644
--- a/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-wms.ts
+++ b/packages/geoview-core/src/geo/layer/gv-layers/raster/gv-wms.ts
@@ -180,9 +180,12 @@ export class GVWMS extends AbstractGVRaster {
}
}
}
- } else if (infoFormat === 'text/html') {
- featureMember = { html: response.data };
- } else featureMember = { plain_text: { '#text': response.data } };
+ } else if (response.data && response.data.length > 0) {
+ // The response has any data to show
+ if (infoFormat === 'text/html') {
+ featureMember = { html: response.data };
+ } else featureMember = { plain_text: { '#text': response.data } };
+ }
if (featureMember) {
const featureInfoResult = GVWMS.#formatWmsFeatureInfoResult(featureMember, clickCoordinate);
@@ -202,7 +205,7 @@ export class GVWMS extends AbstractGVRaster {
* Overrides the fetching of the legend for a WMS layer.
* @returns {Promise} The legend of the layer or null.
*/
- override async getLegend(): Promise {
+ override async onFetchLegend(): Promise {
try {
// Get the layer config in a loaded phase
const layerConfig = this.getLayerConfig();
@@ -214,7 +217,7 @@ export class GVWMS extends AbstractGVRaster {
// If more than 1
if (this.WMSStyles.length > 1) {
for (let i = 0; i < this.WMSStyles.length; i++) {
- // TODO: refactor - does this await in a loop may haev an impact on performance?
+ // TODO: refactor - does this await in a loop may have an impact on performance?
// TO.DOCONT: In this case here, when glancing at the code, the only reason to await would be if the order that the styleLegend
// TO.DOCONT: get added to the styleLegends array MUST be the same order as they are in the WMSStyles array (as in they are 2 arrays with same indexes pointers).
// TO.DOCONT: Without the await, WMSStyles[2] stuff could be associated with something in styleLegends[1] position for example (1<>2).
@@ -251,7 +254,7 @@ export class GVWMS extends AbstractGVRaster {
return legend;
} catch (error) {
// Log
- logger.logError('gv-wms.getLegend()\n', error);
+ logger.logError('gv-wms.onFetchLegend()\n', error);
return null;
}
}
diff --git a/packages/geoview-core/src/geo/layer/layer.ts b/packages/geoview-core/src/geo/layer/layer.ts
index 1db09858a60..674e9d499bc 100644
--- a/packages/geoview-core/src/geo/layer/layer.ts
+++ b/packages/geoview-core/src/geo/layer/layer.ts
@@ -165,6 +165,9 @@ export class LayerApi {
// Maximum time duration to wait when registering a layer for the time slider
static #MAX_WAIT_TIME_SLIDER_REGISTRATION = 20000;
+ // Temporary debugging flag indicating if we want the WMS group layers to have their sub layers fully blown up
+ static DEBUG_WMS_LAYER_GROUP_FULL_SUB_LAYERS = false;
+
/**
* Initializes layer types and listen to add/remove layer events from outside
* @param {MapViewer} mapViewer - A reference to the map viewer
@@ -639,7 +642,7 @@ export class LayerApi {
} else if (layerConfigIsCSV(geoviewLayerConfig)) {
layerBeingAdded = new CSV(this.getMapId(), geoviewLayerConfig);
} else if (layerConfigIsWMS(geoviewLayerConfig)) {
- layerBeingAdded = new WMS(this.getMapId(), geoviewLayerConfig);
+ layerBeingAdded = new WMS(this.getMapId(), geoviewLayerConfig, LayerApi.DEBUG_WMS_LAYER_GROUP_FULL_SUB_LAYERS);
} else if (layerConfigIsEsriDynamic(geoviewLayerConfig)) {
layerBeingAdded = new EsriDynamic(this.getMapId(), geoviewLayerConfig);
} else if (layerConfigIsEsriFeature(geoviewLayerConfig)) {
@@ -1202,12 +1205,19 @@ export class LayerApi {
// Remove layer info from registered layers
this.getLayerEntryConfigIds().forEach((registeredLayerPath) => {
if (registeredLayerPath.startsWith(`${layerPath}/`) || registeredLayerPath === layerPath) {
- // Remove ol layer
+ // Remove actual OL layer from the map
if (this.getOLLayer(registeredLayerPath)) this.mapViewer.map.removeLayer(this.getOLLayer(registeredLayerPath) as BaseLayer);
- // Unregister layer
+
+ // Unregister layer config from the application
this.unregisterLayerConfig(this.getLayerEntryConfig(registeredLayerPath)!);
- // Remove from registered layers
+
+ // Remove from registered layer configs
delete this.#layerEntryConfigs[registeredLayerPath];
+ delete this.#geoviewLayers[registeredLayerPath];
+
+ // Remove from registered layers
+ delete this.#gvLayers[registeredLayerPath];
+ delete this.#olLayers[registeredLayerPath];
}
});
diff --git a/packages/geoview-core/src/geo/utils/projection.ts b/packages/geoview-core/src/geo/utils/projection.ts
index 2163caa1d0a..b5dde4d2366 100644
--- a/packages/geoview-core/src/geo/utils/projection.ts
+++ b/packages/geoview-core/src/geo/utils/projection.ts
@@ -29,6 +29,7 @@ export abstract class Projection {
3578: 'EPSG:3578',
LCC: 'EPSG:3978',
3979: 'EPSG:3979',
+ 42101: 'EPSG:42101',
102100: 'EPSG:102100', // TODO: Minor - The official name of this projection is ESRI:102100 (not EPSG:102100). However, for the purpose of simplification in GeoView code base, we name it with EPSG prefix.
102184: 'EPSG:102184', // TODO: Minor - The official name of this projection is ESRI:102184 (not EPSG:102184). However, for the purpose of simplification in GeoView code base, we name it with EPSG prefix.
102190: 'EPSG:102190', // TODO: Minor - The official name of this projection is ESRI:102190 (not EPSG:102190). However, for the purpose of simplification in GeoView code base, we name it with EPSG prefix.
@@ -414,6 +415,21 @@ function init4269Projection(): void {
if (projection) Projection.PROJECTIONS['4269'] = projection;
}
+/**
+ * Initializes the EPSG:42101 projection
+ */
+function init42101Projection(): void {
+ proj4.defs(
+ Projection.PROJECTION_NAMES[42101],
+ '+proj=lcc +lat_0=0 +lon_0=-95 +lat_1=49 +lat_2=77 +x_0=0 +y_0=-8000000 +datum=WGS84 +units=m +no_defs +type=crs'
+ );
+ register(proj4);
+
+ const projection = olGetProjection(Projection.PROJECTION_NAMES[42101]);
+
+ if (projection) Projection.PROJECTIONS['42101'] = projection;
+}
+
/**
* Initializes the EPSG:3979 projection
*/
@@ -499,6 +515,7 @@ initCSRS98Projection();
init3578Projection();
init3979Projection();
init4269Projection();
+init42101Projection();
init102100Projection();
init102184Projection();
init102190Projection();
diff --git a/packages/geoview-core/src/geo/utils/renderer/esri-renderer.ts b/packages/geoview-core/src/geo/utils/renderer/esri-renderer.ts
index 9afd8a5c097..731ee1ca66a 100644
--- a/packages/geoview-core/src/geo/utils/renderer/esri-renderer.ts
+++ b/packages/geoview-core/src/geo/utils/renderer/esri-renderer.ts
@@ -324,7 +324,8 @@ function getStyleGeometry(settings: TypeKindOfVectorSettings): TypeStyleGeometry
*/
function processUniqueValueRenderer(renderer: EsriUniqueValueRenderer): TypeLayerStyleConfig | undefined {
const style: TypeLayerStyleConfig = {};
- const fields = [renderer.field1];
+ const fields = [];
+ if (renderer.field1) fields.push(renderer.field1);
if (renderer.field2) fields.push(renderer.field2);
if (renderer.field3) fields.push(renderer.field3);