diff --git a/packages/geoview-core/public/templates/config-sandbox.html b/packages/geoview-core/public/templates/config-sandbox.html index bca686496b3..b85d3027c5e 100644 --- a/packages/geoview-core/public/templates/config-sandbox.html +++ b/packages/geoview-core/public/templates/config-sandbox.html @@ -23,7 +23,7 @@ background: #282a3a; border-radius: 2px; padding: 20px 10px; - height: 600px; + height: 500px; overflow-y: auto; } @@ -92,7 +92,7 @@

Sandbox Configuration

- @@ -160,7 +161,24 @@

Sandbox Configuration


- File not validated... + +
+
+ +
+
+ +
+
+
+ + +

Sanbox Map

@@ -181,8 +199,10 @@

Sanbox Map

const isValid = false; const configAreaString = document.getElementById('configGeoview').value.replaceAll(' ', ''); document.getElementById('configGeoview').value = configAreaString; + const configUrlAreaString = document.getElementById('configUrlGeoview').value.replaceAll(' ', ''); + document.getElementById('configUrlGeoview').value = configUrlAreaString; - // Validate Button============================================================================================================ + // Config Validate Button============================================================================================================ const validateJSONButton = document.getElementById('validateConfig'); // add an event listener when a button is clicked @@ -217,6 +237,45 @@

Sanbox Map

} }); + // Config Url Validate Button======================================================================================================== + const validateURLButton = document.getElementById('validateUrlConfig'); + + // add an event listener when the button is clicked + validateURLButton.addEventListener('click', function (e) { + // get message element + const message = document.getElementById('validationMessage'); + const langue = document.getElementById('urlLanguage').value; + const configArea = document.getElementById('configGeoview'); + const configUrlArea = document.getElementById('configUrlGeoview'); + const configOutput = document.getElementById('configOutput'); + + configArea.value = configUrlArea.value; + // get config and test if URL Config is valid + const returnedValue = cgpv.api.configApi.getConfigFromUrl(configUrlArea.value); + returnedValue.then((mapConfig) => { + configOutput.value = mapConfig.getIndentedJsonString(); + + // Generate line numbers + (() => { + const textarea = document.getElementById('configOutput'); + const lineNumbersContainer = document.getElementById('outputLineNumbers'); + const lines = textarea.value.split('\n').length; + const lineNumbers = Array.from({ length: lines }, (_, index) => '').join(''); + lineNumbersContainer.innerHTML = lineNumbers; + })(); + + // set class and message + message.classList.add('config-json-valid'); + message.classList.remove('config-error'); + if (mapConfig.isValid) { + message.innerHTML = 'File is valid, see console for details...'; + document.getElementById('createMap').disabled = true; + } else { + message.innerHTML = 'File is invalid, see console for details...'; + } + }); + }); + // Create Button============================================================================================================ const createMapButton = document.getElementById('createMap'); createMapButton.disabled = true; diff --git a/packages/geoview-core/src/api/config/config-api.ts b/packages/geoview-core/src/api/config/config-api.ts index 752783e2900..36a69b4e69f 100644 --- a/packages/geoview-core/src/api/config/config-api.ts +++ b/packages/geoview-core/src/api/config/config-api.ts @@ -1,7 +1,9 @@ import { CV_DEFAULT_MAP_FEATURE_CONFIG } from '@config/types/config-constants'; -import { TypeJsonObject, toJsonObject } from '@config/types/config-types'; +import { Cast, TypeJsonValue, TypeJsonObject, toJsonObject, TypeJsonArray } from '@config/types/config-types'; import { TypeDisplayLanguage } from '@config/types/map-schema-types'; import { MapFeatureConfig } from '@config/types/classes/map-feature-config'; +import { UUIDmapConfigReader } from '@config/uuid-config-reader'; +import { logger } from '@/core//utils/logger'; /** * The API class that create configuration object. It is used to validate and read the service and layer metadata. @@ -10,12 +12,164 @@ import { MapFeatureConfig } from '@config/types/classes/map-feature-config'; */ export class ConfigApi { /** - * @static + * Parse the parameters obtained from a url. + * + * @param {string} urlParams The parameters found on the url after the ?. + * + * @returns {TypeJsonObject} Object containing the parsed params. + * @static @private + */ + static #getMapPropsFromUrlParams(urlParams: string): TypeJsonObject { + // Get parameters from path. Ex: x=123&y=456 will get {"x": 123, "z": "456"} + const obj: TypeJsonObject = {}; + + if (urlParams !== undefined) { + const params = urlParams.split('&'); + + for (let i = 0; i < params.length; i += 1) { + const param = params[i].split('='); + const key = param[0]; + const value = param[1] as TypeJsonValue; + + obj[key] = Cast(value); + } + } + + return obj; + } + + /** + * Get url parameters from url param search string. + * + * @param {objStr} objStr the url parameter string. + * + * @returns {TypeJsonObject} an object containing url parameters. + * @staric @private + */ + static #parseObjectFromUrl(objStr: string): TypeJsonObject { + const obj: TypeJsonObject = {}; + + if (objStr && objStr.length) { + // get the text in between { } + const objStrPropRegex = /(?:[{_.])(.*?)(?=[}_.])/g; + + const objStrProps = objStr.match(objStrPropRegex); + + if (objStrProps && objStrProps.length) { + // first { is kept with regex, remove + const objProps = objStrProps[0].replace(/{/g, '').split(','); + + if (objProps) { + for (let i = 0; i < objProps.length; i += 1) { + const prop = objProps[i].split(':'); + if (prop && prop.length) { + const key: string = prop[0]; + const value: string = prop[1]; + + if (prop[1] === 'true') { + obj[key] = Cast(true); + } else if (prop[1] === 'false') { + obj[key] = Cast(false); + } else { + obj[key] = Cast(value); + } + } + } + } + } + } + + return obj; + } + + /** + * Get a map feature config from url parameters. + * @param {string} urlStringParams The url parameters. + * + * @returns {Promise} A map feature configuration object generated from url parameters. + * @static @async + */ + static async getConfigFromUrl(urlStringParams: string): Promise { + // return the parameters as an object if url contains any params + const urlParams = ConfigApi.#getMapPropsFromUrlParams(urlStringParams); + + // if user provided any url parameters update + const jsonConfig = {} as TypeJsonObject; + + // update the language if provided from the map configuration. + const displayLanguage = (urlParams.l as TypeDisplayLanguage) || 'en'; + + if (Object.keys(urlParams).length && !urlParams.geoms) { + // Ex: p=3857&z=4&c=40,-100&l=en&t=dark&b={basemapId:transport,shaded:false,labeled:true}&i=dynamic&cp=details-panel,layers-panel&cc=overview-map&keys=12acd145-626a-49eb-b850-0a59c9bc7506,ccc75c12-5acc-4a6a-959f-ef6f621147b9 + + // get center + let center: string[] = []; + if (urlParams.c) center = (urlParams.c as string).split(','); + if (center.length !== 2) + center = [ + CV_DEFAULT_MAP_FEATURE_CONFIG.map.viewSettings.initialView!.zoomAndCenter![1][0]!.toString(), + CV_DEFAULT_MAP_FEATURE_CONFIG.map.viewSettings.initialView!.zoomAndCenter![1][1].toString(), + ]; + + // get zoom + let zoom = CV_DEFAULT_MAP_FEATURE_CONFIG.map.viewSettings.initialView!.zoomAndCenter![0].toString(); + if (urlParams.z) zoom = urlParams.z as string; + + jsonConfig.map = { + interaction: urlParams.i as TypeJsonObject, + viewSettings: { + initialView: { + zoomAndCenter: [parseInt(zoom, 10), [parseInt(center[0], 10), parseInt(center[1], 10)]] as TypeJsonObject, + }, + projection: parseInt(urlParams.p as string, 10) as TypeJsonObject, + }, + basemapOptions: ConfigApi.#parseObjectFromUrl(urlParams.b as string), + listOfGeoviewLayerConfig: Cast([]), + }; + + // get layer information from catalog using their uuid's if any passed from url params + if (urlParams.keys) { + try { + // Get the layers config + const promise = UUIDmapConfigReader.getGVConfigFromUUIDs( + CV_DEFAULT_MAP_FEATURE_CONFIG.serviceUrls.geocoreUrl, + displayLanguage.split('-')[0], + urlParams.keys.toString().split(',') + ); + (jsonConfig.map.listOfGeoviewLayerConfig as TypeJsonObject[]) = await promise; + } catch (error) { + // Log + logger.logError('Failed to get the GeoView layers from url keys', urlParams.keys, error); + } + } + + // get core components + if (urlParams.cc) { + (jsonConfig.components as TypeJsonArray) = (urlParams.cc as string).split(',') as TypeJsonArray; + } + + // get core packages if any + if (urlParams.cp) { + (jsonConfig.corePackages as TypeJsonArray) = (urlParams.cp as string).split(',') as TypeJsonArray; + } + + // update the version if provided from the map configuration. + jsonConfig.schemaVersionUsed = urlParams.v as TypeJsonObject; + } + + // Trace the detail config read from url + logger.logTraceDetailed('URL Config - ', jsonConfig); + + return new MapFeatureConfig(jsonConfig, displayLanguage); + } + + /** * Get the default values that are applied to the map feature configuration when the user doesn't provide a value for a field * that is covered by a default value. * @param {TypeDisplayLanguage} language The language of the map feature config we want to produce. * * @returns {MapFeatureConfig} The map feature configuration default values. + * @static */ static getDefaultMapFeatureConfig(language: TypeDisplayLanguage): MapFeatureConfig { return new MapFeatureConfig(toJsonObject(CV_DEFAULT_MAP_FEATURE_CONFIG), language); diff --git a/packages/geoview-core/src/api/config/types/classes/geoview-config/abstract-geoview-layer-config.ts b/packages/geoview-core/src/api/config/types/classes/geoview-config/abstract-geoview-layer-config.ts index 5d66906e35e..18a8784e964 100644 --- a/packages/geoview-core/src/api/config/types/classes/geoview-config/abstract-geoview-layer-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/geoview-config/abstract-geoview-layer-config.ts @@ -31,9 +31,6 @@ export abstract class AbstractGeoviewLayerConfig { /** The GeoView layer identifier. */ geoviewLayerId: string; - /** Type of GeoView layer. */ - abstract geoviewLayerType: TypeGeoviewLayerType; - /** * The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this * information. @@ -97,18 +94,21 @@ export abstract class AbstractGeoviewLayerConfig { .filter((subLayerConfig) => { return subLayerConfig; }) as ConfigBaseClass[]; - this.#validate(); } /** * Validate the object properties. Layer name and type must be set. * @private */ - #validate(): void { - if (!this.geoviewLayerName) + protected validate(): void { + if (!this.geoviewLayerName) { logger.logError(`Property geoviewLayerName is mandatory for GeoView layer ${this.geoviewLayerId} of type ${this.geoviewLayerType}.`); - if (!this.geoviewLayerType) + this.propagateError(); + } + if (!this.geoviewLayerType) { logger.logError(`Property geoviewLayerType is mandatory for GeoView layer ${this.geoviewLayerId} of type ${this.geoviewLayerType}.`); + this.propagateError(); + } } /** @@ -126,6 +126,14 @@ export abstract class AbstractGeoviewLayerConfig { */ protected abstract get geoviewLayerSchema(): string; + /** + * The getter method that returns the geoview layer type to use for the validation. + * + * @returns {string} The GeoView layer schema associated to the config. + * @protected @abstract + */ + abstract get geoviewLayerType(): TypeGeoviewLayerType; + /** * The method used to implement the class factory model that returns the instance of the class based on the sublayer * type needed. @@ -155,4 +163,13 @@ export abstract class AbstractGeoviewLayerConfig { this.#errorDetected = true; this.#mapFeatureConfig?.propagateError(); } + + /** + * The getter method that returns the isValid flag (true when the map feature config is valid). + * + * @returns {boolean} The isValid property associated to map feature config. + */ + get isValid(): boolean { + return !this.#errorDetected; + } } diff --git a/packages/geoview-core/src/api/config/types/classes/geoview-config/raster-config/esri-dynamic-config.ts b/packages/geoview-core/src/api/config/types/classes/geoview-config/raster-config/esri-dynamic-config.ts index 7812eb5c1b6..5d7de6b2506 100644 --- a/packages/geoview-core/src/api/config/types/classes/geoview-config/raster-config/esri-dynamic-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/geoview-config/raster-config/esri-dynamic-config.ts @@ -40,6 +40,7 @@ export class EsriDynamicLayerConfig extends AbstractGeoviewLayerConfig { if (!this.metadataAccessPath) { throw new Error(`metadataAccessPath is mandatory for GeoView layer ${this.geoviewLayerId} of type ${this.geoviewLayerType}.`); } + this.validate(); } /** diff --git a/packages/geoview-core/src/api/config/types/classes/geoview-config/vector-config/esri-feature-config.ts b/packages/geoview-core/src/api/config/types/classes/geoview-config/vector-config/esri-feature-config.ts index 5993e0efaae..dfba6773ebb 100644 --- a/packages/geoview-core/src/api/config/types/classes/geoview-config/vector-config/esri-feature-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/geoview-config/vector-config/esri-feature-config.ts @@ -42,6 +42,7 @@ export class EsriFeatureLayerConfig extends AbstractGeoviewLayerConfig { if (!this.metadataAccessPath) { throw new Error(`metadataAccessPath is mandatory for GeoView layer ${this.geoviewLayerId} of type ${this.geoviewLayerType}.`); } + this.validate(); } /** diff --git a/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts b/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts index acc6f9b474b..87d23cf3f7c 100644 --- a/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts @@ -125,7 +125,7 @@ export class MapFeatureConfig { this.theme = (clonedJsonConfig.theme || CV_DEFAULT_MAP_FEATURE_CONFIG.theme) as TypeDisplayTheme; this.navBar = [...((clonedJsonConfig.navBar || CV_DEFAULT_MAP_FEATURE_CONFIG.navBar) as TypeNavBarProps)]; this.appBar = Cast(defaultsDeep(clonedJsonConfig.appBar, CV_DEFAULT_MAP_FEATURE_CONFIG.appBar)); - this.footerBar = Cast(defaultsDeep(clonedJsonConfig.footerBar, CV_DEFAULT_MAP_FEATURE_CONFIG.footerBar)); + this.footerBar = Cast(clonedJsonConfig.footerBar); this.overviewMap = Cast(defaultsDeep(clonedJsonConfig.overviewMap, CV_DEFAULT_MAP_FEATURE_CONFIG.overviewMap)); this.components = [...((clonedJsonConfig.components || CV_DEFAULT_MAP_FEATURE_CONFIG.components) as TypeMapComponents)]; this.corePackages = [...((clonedJsonConfig.corePackages || CV_DEFAULT_MAP_FEATURE_CONFIG.corePackages) as TypeMapCorePackages)]; diff --git a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/abstract-base-layer-entry-config.ts b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/abstract-base-layer-entry-config.ts index 430f179d601..8ed843240a0 100644 --- a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/abstract-base-layer-entry-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/abstract-base-layer-entry-config.ts @@ -47,7 +47,7 @@ export abstract class AbstractBaseLayerEntryConfig extends ConfigBaseClass { initialSettings: TypeLayerInitialSettings, language: TypeDisplayLanguage, geoviewLayerConfig: AbstractGeoviewLayerConfig, - parentNode: ConfigBaseClass + parentNode?: ConfigBaseClass ) { super(layerConfig, initialSettings, language, geoviewLayerConfig, parentNode); // If the user has provided a source then keep it, else create an empty one. diff --git a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/group-layer-entry-config.ts b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/group-layer-entry-config.ts index c3b9d22e8f4..1010814674f 100644 --- a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/group-layer-entry-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/group-layer-entry-config.ts @@ -3,7 +3,7 @@ import { TypeJsonArray, TypeJsonObject } from '@config/types/config-types'; import { TypeDisplayLanguage, TypeLayerEntryType, TypeLayerInitialSettings } from '@config/types/map-schema-types'; import { AbstractGeoviewLayerConfig } from '@config/types/classes/geoview-config/abstract-geoview-layer-config'; import { ConfigBaseClass } from '@config/types/classes/sub-layer-config/config-base-class'; -import { layerEntryIsGroupLayer } from '../../type-guards'; +import { layerEntryIsGroupLayer } from '@config/types/type-guards'; /** * Type used to define a group of layers. It can be either subgroups or sublayers. diff --git a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/raster-leaf/esri-dynamic-layer-entry-config.ts b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/raster-leaf/esri-dynamic-layer-entry-config.ts index 19d9c1bbe48..c2dbe663049 100644 --- a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/raster-leaf/esri-dynamic-layer-entry-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/raster-leaf/esri-dynamic-layer-entry-config.ts @@ -40,7 +40,7 @@ export class EsriDynamicLayerEntryConfig extends AbstractBaseLayerEntryConfig { initialSettings: TypeLayerInitialSettings, language: TypeDisplayLanguage, geoviewLayerConfig: AbstractGeoviewLayerConfig, - parentNode: ConfigBaseClass + parentNode?: ConfigBaseClass ) { super(layerConfig, initialSettings, language, geoviewLayerConfig, parentNode); this.layerFilter = layerConfig.layerFilter as string; diff --git a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/vector-leaf/esri-feature-layer-entry-config.ts b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/vector-leaf/esri-feature-layer-entry-config.ts index a4759a298d8..54c2e9bc3bf 100644 --- a/packages/geoview-core/src/api/config/types/classes/sub-layer-config/vector-leaf/esri-feature-layer-entry-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/sub-layer-config/vector-leaf/esri-feature-layer-entry-config.ts @@ -40,7 +40,7 @@ export class EsriFeatureLayerEntryConfig extends AbstractBaseLayerEntryConfig { initialSettings: TypeLayerInitialSettings, language: TypeDisplayLanguage, geoviewLayerConfig: AbstractGeoviewLayerConfig, - parentNode: ConfigBaseClass + parentNode?: ConfigBaseClass ) { super(layerConfig, initialSettings, language, geoviewLayerConfig, parentNode); this.layerFilter = layerConfig.layerFilter as string; diff --git a/packages/geoview-core/src/api/config/types/config-constants.ts b/packages/geoview-core/src/api/config/types/config-constants.ts index 41aa8e785de..828835b7d12 100644 --- a/packages/geoview-core/src/api/config/types/config-constants.ts +++ b/packages/geoview-core/src/api/config/types/config-constants.ts @@ -9,7 +9,6 @@ import { TypeBasemapOptions, TypeDisplayTheme, TypeExternalPackages, - TypeFooterBarProps, TypeInteraction, TypeLayerEntryType, TypeListOfLocalizedLanguages, @@ -162,7 +161,6 @@ export const CV_DEFAULT_MAP_FEATURE_CONFIG = { theme: 'dark' as TypeDisplayTheme, components: ['north-arrow', 'overview-map'], appBar: { tabs: { core: ['geolocator'] } } as TypeAppBarProps, - footerBar: {} as TypeFooterBarProps, navBar: ['zoom', 'fullscreen', 'home'] as TypeNavBarProps, corePackages: [], overviewMap: undefined as TypeOverviewMapProps | undefined, diff --git a/packages/geoview-core/src/api/config/uuid-config-reader.ts b/packages/geoview-core/src/api/config/uuid-config-reader.ts new file mode 100644 index 00000000000..57cd72c1d51 --- /dev/null +++ b/packages/geoview-core/src/api/config/uuid-config-reader.ts @@ -0,0 +1,160 @@ +import axios, { AxiosResponse } from 'axios'; + +import { TypeJsonObject, TypeJsonArray, Cast } from '@config/types/config-types'; +import { CV_CONST_LAYER_TYPES, CV_CONST_SUB_LAYER_TYPES } from '@config/types/config-constants'; +import { createLocalizedString } from '@/core/utils/utilities'; +import { logger } from '@/core/utils/logger'; + +// The GeoChart Json object coming out of the GeoCore response +export type GeoChartGeoCoreConfig = TypeJsonObject & { + layers: { + layerId: string; + }; +}; // TypeJsonObject, because the definition is in the external package + +// #region GeoChart Config types + +// The GeoChart Json object expected by GeoView +export type GeoChartConfig = TypeJsonObject & { + layers: [ + { + layerId: string; + } + ]; +}; // TypeJsonObject, because the definition is in the external package + +// #endregion + +/** + * A class to generate GeoView layers config from a URL using a UUID. + * @exports + * @class UUIDmapConfigReader + */ +export class UUIDmapConfigReader { + /** + * Reads and parses Layers configs from uuid request result + * @param {TypeJsonObject} result the uuid request result + * @returns {TypeListOfGeoviewLayerConfig} layers parsed from uuid result + */ + private static getLayerConfigFromResponse(result: AxiosResponse, lang: string): TypeJsonObject[] { + // If invalid response + if (!result?.data || !result.data.reponse || !result.data.reponse.rcs || !result.data.reponse.rcs[lang]) + throw new Error('Invalid response from GeoCore service'); + if (result.data.reponse.rcs[lang].length === 0) throw new Error('No layers returned by GeoCore service'); + + const listOfGeoviewLayerConfig: TypeJsonObject[] = []; + for (let i = 0; i < (result.data.reponse.rcs[lang] as TypeJsonArray).length; i++) { + const data = result.data.reponse.rcs[lang][i]; + + if (data?.layers && (data.layers as TypeJsonArray).length > 0) { + const layer = data.layers[0]; + + if (layer) { + const { layerType, layerEntries, name, url, id } = layer; + + const isFeature = (url as string).indexOf('FeatureServer') > -1; + + if (layerType === CV_CONST_LAYER_TYPES.ESRI_DYNAMIC && !isFeature) { + const geoviewLayerConfig: TypeJsonObject = { + geoviewLayerId: `${id}` as TypeJsonObject, + geoviewLayerName: Cast(createLocalizedString(name as string)), + metadataAccessPath: Cast(createLocalizedString(url as string)), + geoviewLayerType: CV_CONST_LAYER_TYPES.ESRI_DYNAMIC as TypeJsonObject, + }; + (geoviewLayerConfig.listOfLayerEntryConfig as TypeJsonObject[]) = (layerEntries as TypeJsonArray).map( + (item): TypeJsonObject => { + return { + entryType: CV_CONST_SUB_LAYER_TYPES.RASTER_IMAGE as TypeJsonObject, + layerId: `${item.index}` as TypeJsonObject, + } as TypeJsonObject; + } + ); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (isFeature) { + for (let j = 0; j < (layerEntries as TypeJsonArray).length; j++) { + const geoviewLayerConfig: TypeJsonObject = { + geoviewLayerId: `${id}` as TypeJsonObject, + geoviewLayerName: Cast(createLocalizedString(name as string)), + metadataAccessPath: Cast(createLocalizedString(url as string)), + geoviewLayerType: CV_CONST_LAYER_TYPES.ESRI_FEATURE as TypeJsonObject, + }; + (geoviewLayerConfig.listOfLayerEntryConfig as TypeJsonObject[]) = (layerEntries as TypeJsonArray).map( + (item): TypeJsonObject => { + return { + entryType: CV_CONST_SUB_LAYER_TYPES.VECTOR as TypeJsonObject, + layerId: `${item.index}` as TypeJsonObject, + } as TypeJsonObject; + } + ); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } + } else if (layerType === CV_CONST_LAYER_TYPES.ESRI_FEATURE) { + const geoviewLayerConfig: TypeJsonObject = { + geoviewLayerId: `${id}` as TypeJsonObject, + geoviewLayerName: Cast(createLocalizedString(name as string)), + metadataAccessPath: Cast(createLocalizedString(url as string)), + geoviewLayerType: CV_CONST_LAYER_TYPES.ESRI_FEATURE as TypeJsonObject, + }; + (geoviewLayerConfig.listOfLayerEntryConfig as TypeJsonObject[]) = (layerEntries as TypeJsonArray).map( + (item): TypeJsonObject => { + return { + entryType: CV_CONST_SUB_LAYER_TYPES.VECTOR as TypeJsonObject, + layerId: `${item.index}` as TypeJsonObject, + } as TypeJsonObject; + } + ); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else { + // Log + logger.logWarning(`Layer type ${layerType} not supported`); + } + } + } + } + return listOfGeoviewLayerConfig; + } + + /** + * Reads and parses GeoChart configs from uuid request result + * @param {AxiosResponse} result the uuid request result + * @param {string} lang the language to use to read results + * @returns {GeoChartConfig[]} the list of GeoChart configs + */ + private static getGeoChartConfigFromResponse(result: AxiosResponse, lang: string): GeoChartConfig[] { + // If no geochart information + if (!result?.data || !result.data.reponse || !result.data.reponse.gcs || !Array.isArray(result.data.reponse.gcs)) return []; + + // Find all Geochart configs + const foundConfigs = result.data.reponse.gcs + .map((gcs) => gcs?.[lang]?.packages?.geochart as GeoChartGeoCoreConfig) + .filter((geochartValue) => !!geochartValue); + + // For each found config, parse + const parsedConfigs: GeoChartConfig[] = []; + foundConfigs.forEach((foundConfig) => { + // Transform GeoChartGeoCoreConfig to GeoChartConfig + parsedConfigs.push({ ...(foundConfig as object), layers: [foundConfig.layers] } as GeoChartConfig); + }); + + // Return all configs + return parsedConfigs; + } + + /** + * Generates GeoView layers and package configurations (i.e. geochart), from GeoCore API, using a list of UUIDs. + * @param {string} baseUrl the base url of GeoCore API + * @param {string} lang the language to get the config for + * @param {string[]} uuids a list of uuids to get the configurations for + * @returns {Promise} layers and geocharts read and parsed from uuids results from GeoCore + */ + static async getGVConfigFromUUIDs(baseUrl: string, lang: string, uuids: string[]): Promise { + // Build the url + const url = `${baseUrl}/vcs?lang=${lang}&id=${uuids.toString()}`; + + // Fetch the config + const result = await axios.get(url); + + // Return the parsed response + return this.getLayerConfigFromResponse(result, lang); + } +}