From ce9bf2cb556fe149a18cb5dfb381b137fd565c48 Mon Sep 17 00:00:00 2001 From: Alex <alexandre.roy@nrcan-rncan.gc.ca> Date: Mon, 12 Feb 2024 16:16:05 -0500 Subject: [PATCH] GeoCore implementation update Add-Layer fix when adding GeoCore layer with uuid GeoChart linkage with GeoCore --- .../public/configs/sample-config.json | 2 +- .../geoview-core/schema-default-config.json | 2 +- packages/geoview-core/schema.json | 4 +- .../geochart-event-processor.ts | 100 ++- .../map-event-processor.ts | 18 +- .../core/components/details/details-panel.tsx | 14 +- .../add-new-layer/add-new-layer.tsx | 29 +- .../geochart-state.ts | 14 +- .../core/utils/config/config-validation.ts | 11 +- .../src/core/utils/config/config.ts | 7 +- .../utils/config/reader/div-config-reader.ts | 7 +- .../utils/config/reader/json-config-reader.ts | 7 +- .../utils/config/reader/url-config-reader.ts | 35 +- .../utils/config/reader/uuid-config-reader.ts | 568 ++++++++++-------- packages/geoview-core/src/geo/layer/layer.ts | 44 +- .../src/geo/layer/other/geocore.ts | 121 +++- .../src/geo/map/map-schema-types.ts | 8 +- .../geoview-geochart/src/geochart-panel.tsx | 10 +- .../geoview-geochart/src/geochart-parsing.ts | 2 +- .../geoview-geochart/src/geochart-types.ts | 2 +- packages/geoview-geochart/src/geochart.tsx | 2 +- 21 files changed, 608 insertions(+), 399 deletions(-) diff --git a/packages/geoview-core/public/configs/sample-config.json b/packages/geoview-core/public/configs/sample-config.json index 9d1aca6286f..86aafc8ddbb 100644 --- a/packages/geoview-core/public/configs/sample-config.json +++ b/packages/geoview-core/public/configs/sample-config.json @@ -125,7 +125,7 @@ }, "externalPackages": [], "serviceUrls": { - "keys": "https://geocore.api.geo.ca" + "geocoreUrl": "https://geocore.api.geo.ca" }, "suportedLanguages": ["en", "fr"], "version": "1.0" diff --git a/packages/geoview-core/schema-default-config.json b/packages/geoview-core/schema-default-config.json index cd370d84fa4..3e334e80dbf 100644 --- a/packages/geoview-core/schema-default-config.json +++ b/packages/geoview-core/schema-default-config.json @@ -27,7 +27,7 @@ "corePackages": [], "externalPackages": [], "serviceUrls": { - "keys": "https://geocore.api.geo.ca", + "geocoreUrl": "https://geocore.api.geo.ca", "geolocator": "https://geolocator.api.geo.ca?keys=geonames,nominatim,locate" }, "suportedLanguages": [ diff --git a/packages/geoview-core/schema.json b/packages/geoview-core/schema.json index 8d39f24f89b..22e5ade7d49 100644 --- a/packages/geoview-core/schema.json +++ b/packages/geoview-core/schema.json @@ -1728,7 +1728,7 @@ "type": "object", "description": "Service endpoint urls", "properties": { - "keys": { + "geocoreUrl": { "type": "string", "default": "https://geocore.api.geo.ca", "description": "Service end point to access API for layers specification (loading and plugins parameters). By default it is GeoCore but can be another endpoint with similar output." @@ -1742,7 +1742,7 @@ "description": "Service end point to access geo location of searched value." } }, - "required": ["keys"] + "required": ["geocoreUrl"] }, "TypeDisplayLanguage": { "enum": ["en", "fr"], diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts index 4856d25e701..a6c4f479a56 100644 --- a/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts +++ b/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts @@ -1,5 +1,8 @@ -import { TypeArrayOfLayerData, TypeJsonObject } from '@/core/types/global-types'; +import { GeoviewStoreType } from '@/core/stores'; +import { TypeArrayOfLayerData } from '@/core/types/global-types'; import { GeoChartStoreByLayerPath, IGeochartState } from '@/core/stores/store-interface-and-intial-values/geochart-state'; +import { GeoChartConfig } from '@/core/utils/config/reader/uuid-config-reader'; +import { logger } from '@/core/utils/logger'; import { AbstractEventProcessor, BatchedPropagationLayerDataArrayByMap } from '../abstract-event-processor'; @@ -23,6 +26,36 @@ export class GeochartEventProcessor extends AbstractEventProcessor { // The longer the delay, the longer it'll take to update the UI. The delay can be bypassed using the layer path bypass method. static timeDelayBetweenPropagationsForBatch = 2000; + /** + * Overrides initialization of the GeoChart Event Processor + * @param {GeoviewStoreType} store The store associated with the GeoChart Event Processor + * @returns An array of the subscriptions callbacks which were created + */ + protected onInitialize(store: GeoviewStoreType): Array<() => void> | void { + // Checks for added and removed layers with time dimension + const unsubLayerRemoved = store.subscribe( + (state) => state.mapState.layerOrder, + (cur, prev) => { + // Log + logger.logTraceCoreStoreSubscription('GEOCHART EVENT PROCESSOR - layerOrder', cur); + + // For each chart config keys + Object.keys(store.getState().geochartState.geochartChartsConfig).forEach((chartLayerPath: string) => { + // If it was in the layerdata array and is not anymore + if (prev.includes(chartLayerPath) && !cur.includes(chartLayerPath)) { + // Remove it + GeochartEventProcessor.removeGeochartChart(store.getState().mapId, chartLayerPath); + + // Log + logger.logDebug('Removed GeoChart configs for layer path:', chartLayerPath); + } + }); + } + ); + + return [unsubLayerRemoved]; + } + /** * Shortcut to get the Geochart state for a given map id * @param {string} mapId The mapId @@ -36,23 +69,21 @@ export class GeochartEventProcessor extends AbstractEventProcessor { } /** - * Set the default layers from configuration. + * Sets the default layers from configuration. * In the store, the GeoChart configurations are stored in an object with layerPath as its property name * (to retrieve the configuration per layer faster). * * @param {string} mapId the map id - * @param {TypeJsonObject} charts The array of JSON configuration for geochart + * @param {GeoChartConfig[]} charts The array of JSON configuration for GeoChart */ - static setGeochartCharts(mapId: string, charts: TypeJsonObject[]): void { + static setGeochartCharts(mapId: string, charts: GeoChartConfig[]): void { // The store object representation const chartData: GeoChartStoreByLayerPath = {}; // Loop on the charts - // eslint-disable-next-line @typescript-eslint/no-explicit-any - charts.forEach((chartInfo: any) => { + charts.forEach((chartInfo) => { // For each layer path - // eslint-disable-next-line @typescript-eslint/no-explicit-any - chartInfo.layers.forEach((layer: any) => { + chartInfo.layers.forEach((layer) => { // Get the layer path const layerPath = layer.layerId; chartData[layerPath] = chartInfo; @@ -61,10 +92,59 @@ export class GeochartEventProcessor extends AbstractEventProcessor { // set store charts config this.getGeochartState(mapId)?.actions.setGeochartCharts(chartData); + + // TODO: Also update the layer array in other store state to inform the later has a geochart attached to it (when code is done over there) + } + + /** + * Adds a GeoChart Configuration to the specified map id and layer path + * @param {string} mapId The map ID + * @param {string} layerPath The layer path + * @param {GeoChartConfig} chartConfig The Geochart Configuration + */ + static addGeochartChart(mapId: string, layerPath: string, chartConfig: GeoChartConfig): void { + // The processor needs an initialized chart store which is only initialized if the Geochart plugin exists. + // Therefore, we validate its existence first. + if (!this.getGeochartState(mapId)) return; + + // Config to add + const toAdd: GeoChartStoreByLayerPath = {}; + toAdd[layerPath] = chartConfig; + + // Update the layer data array in the store + this.getGeochartState(mapId)!.actions.setGeochartCharts({ ...this.getGeochartState(mapId)?.geochartChartsConfig, ...toAdd }); + + // TODO: Also update the layer array in other store state to inform the later has a geochart attached to it (when code is done over there) + } + + /** + * Removes a GeoChart Configuration at the specified map id and layer path + * @param {string} mapId The map ID + * @param {string} layerPath The layer path + */ + static removeGeochartChart(mapId: string, layerPath: string): void { + // The processor needs an initialized chart store which is only initialized if the Geochart plugin exists. + // Therefore, we validate its existence first. + if (!this.getGeochartState(mapId)) return; + if (!this.getGeochartState(mapId)?.geochartChartsConfig) return; + + // Config to remove + if (Object.keys(this.getGeochartState(mapId)!.geochartChartsConfig).includes(layerPath)) { + // Grab the config + const chartConfigs = this.getGeochartState(mapId)!.geochartChartsConfig; + + // Delete the config + delete chartConfigs[layerPath]; + + // Update the layer data array in the store + this.getGeochartState(mapId)!.actions.setGeochartCharts({ ...chartConfigs }); + + // TODO: Also update the layer array in other store state to inform the later has a geochart attached to it (when code is done over there) + } } /** - * Propagate feature info layer sets to the store and the also in a batched manner. + * Propagates feature info layer sets to the store and the also in a batched manner. * @param {string} mapId The map id * @param {string} layerDataArray The layer data array to propagate in the store */ @@ -81,7 +161,7 @@ export class GeochartEventProcessor extends AbstractEventProcessor { } /** - * Propagate feature info layer sets to the store in a batched manner, every 'timeDelayBetweenPropagationsForBatch' millisecond. + * Propagates feature info layer sets to the store in a batched manner, every 'timeDelayBetweenPropagationsForBatch' millisecond. * This is used to provide another 'layerDataArray', in the store, which updates less often so that we save a couple 'layerDataArray' * update triggers in the components that are listening to the store array. * The propagation can be bypassed using the store 'layerDataArrayBatchLayerPathBypass' state which tells the process to diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts index c2a4de57328..69de269b8bb 100644 --- a/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts +++ b/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts @@ -38,7 +38,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (cur, prev) => { if (cur !== prev) { // Log (too annoying, already have trace in EVENT_MAP_LOADED handler that works well) - // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - mapLoaded (changed)', cur); + // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - mapLoaded (changed)', mapId, cur); api.event.emit(mapPayload(EVENT_NAMES.MAP.EVENT_MAP_LOADED, mapId, store.getState().mapState.mapElement!)); } @@ -51,7 +51,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (cur, prev) => { if (cur !== prev) { // Log (too annoying, already have trace in EVENT_MAP_MOVE_END handler that works well) - // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - centerCoordinates (changed)', cur); + // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - centerCoordinates (changed)', mapId, cur); api.event.emit(lngLatPayload(EVENT_NAMES.MAP.EVENT_MAP_MOVE_END, mapId, cur)); } @@ -63,7 +63,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (cur, prev) => { if (cur! && cur !== prev) { // Log (too annoying, already have trace in EVENT_MAP_POINTER_MOVE handler that works well) - // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - pointerPosition (changed)', cur); + // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - pointerPosition (changed)', mapId, cur); api.event.emit(mapMouseEventPayload(EVENT_NAMES.MAP.EVENT_MAP_POINTER_MOVE, mapId, cur)); } @@ -75,7 +75,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (cur, prev) => { if (cur! && cur !== prev) { // Log (this event is raised, and we currently have no handles for it, by design) - logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - currentProjection (changed)', cur); + logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - currentProjection (changed)', mapId, cur); api.event.emit(mapViewProjectionPayload(EVENT_NAMES.MAP.EVENT_MAP_VIEW_PROJECTION_CHANGE, mapId, cur!)); } @@ -87,7 +87,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (cur, prev) => { if (cur && cur !== prev) { // Log (too annoying, already have trace in EVENT_MAP_SINGLE_CLICK handler that works well) - // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - currentProjection (changed)', cur); + // logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - currentProjection (changed)', mapId, cur); api.event.emit(mapMouseEventPayload(EVENT_NAMES.MAP.EVENT_MAP_SINGLE_CLICK, mapId, cur)); } @@ -99,7 +99,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (cur, prev) => { if (cur! && cur !== prev) { // Log - logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - zoom (changed)', cur); + logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - zoom (changed)', mapId, cur); api.event.emit(numberPayload(EVENT_NAMES.MAP.EVENT_MAP_ZOOM_END, mapId, cur)); } @@ -113,7 +113,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (state) => state.mapState.highlightedFeatures, (curFeatures, prevFeatures) => { // Log - logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - highlightedFeatures', curFeatures); + logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - highlightedFeatures', mapId, curFeatures); if (curFeatures.length === 0) api.maps[mapId].layer.featureHighlight.removeHighlight('all'); else { @@ -137,7 +137,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (state) => state.mapState.selectedFeatures, (curFeatures, prevFeatures) => { // Log - logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - selectedFeatures', curFeatures); + logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - selectedFeatures', mapId, curFeatures); // TODO: on reload, layer object is undefined, need to test for now and solve in #1580 if (curFeatures.length === 0 && api.maps[mapId].layer !== undefined) api.maps[mapId].layer.featureHighlight.resetAnimation('all'); @@ -162,7 +162,7 @@ export class MapEventProcessor extends AbstractEventProcessor { (state) => state.layerState.legendLayers, (cur) => { // Log - logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - legendLayers', cur); + logger.logTraceCoreStoreSubscription('MAP EVENT PROCESSOR - legendLayers', mapId, cur); const orderedLayerPaths = MapEventProcessor.evaluateLayerPathsFromLegendsArray(cur); const prevLayerOrder = [...store.getState().mapState.layerOrder]; diff --git a/packages/geoview-core/src/core/components/details/details-panel.tsx b/packages/geoview-core/src/core/components/details/details-panel.tsx index 1fd554b04e7..b14dda53253 100644 --- a/packages/geoview-core/src/core/components/details/details-panel.tsx +++ b/packages/geoview-core/src/core/components/details/details-panel.tsx @@ -65,7 +65,7 @@ export function DetailsPanel(): JSX.Element { // #region MAIN HOOKS SECTION *************************************************************************************** /** - * Check if feature is in the store checkedFeatures array + * Checks if feature is in the store checkedFeatures array * * @param {TypeFeatureInfoEntry} feature The feature to check * @returns {boolean} true if feature is in checkedFeatures @@ -83,7 +83,7 @@ export function DetailsPanel(): JSX.Element { ); /** - * Helper function to clear the highlighed features when they are not checked. + * Clears the highlighed features when they are not checked. * @param {TypeArrayOfFeatureInfoEntries} arrayToClear The array to clear of the unchecked features */ const clearHighlightsUnchecked = useCallback( @@ -100,7 +100,7 @@ export function DetailsPanel(): JSX.Element { ); /** - * Get the label for the number of features of a layer. + * Gets the label for the number of features of a layer. * @returns string */ const getNumFeaturesLabel = useCallback( @@ -115,7 +115,7 @@ export function DetailsPanel(): JSX.Element { ); /** - * Memoize the layers list for the LayerList component and centralizing indexing purposes. + * Memoizes the layers list for the LayerList component and centralizing indexing purposes. */ const memoLayersList = useMemo(() => { // Log @@ -140,7 +140,7 @@ export function DetailsPanel(): JSX.Element { }, [visibleLayers, arrayOfLayerDataBatch, getNumFeaturesLabel]); /** - * Memoize the selected layer for the LayerList component. + * Memoizes the selected layer for the LayerList component. */ const memoLayerSelectedItem = useMemo(() => { // Log @@ -149,7 +149,7 @@ export function DetailsPanel(): JSX.Element { }, [memoLayersList, selectedLayerPath]); /** - * Memoize the selected layer data. + * Memoizes the selected layer data. */ const memoSelectedLayerData = useMemo(() => { // Log @@ -158,7 +158,7 @@ export function DetailsPanel(): JSX.Element { }, [arrayOfLayerDataBatch, selectedLayerPath]); /** - * Memoize the selected layer data features. + * Memoizes the selected layer data features. */ const memoSelectedLayerDataFeatures = useMemo(() => { // Log 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 a7056f26d48..8c1d191daf0 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 @@ -14,16 +14,13 @@ import { TypeEsriFeatureLayerConfig, TypeEsriFeatureLayerEntryConfig, TypeEsriImageLayerEntryConfig, - TypeGeoCoreLayerConfig, TypeGeoJSONLayerConfig, TypeGeoJSONLayerEntryConfig, TypeGeoPackageLayerConfig, TypeGeoPackageLayerEntryConfig, - TypeGeocoreLayerEntryConfig, TypeGeoviewLayerConfig, TypeGeoviewLayerType, TypeLayerEntryConfig, - TypeLayerEntryType, TypeListOfGeoviewLayerConfig, TypeListOfLayerEntryConfig, TypeOgcWmsLayerEntryConfig, @@ -39,7 +36,7 @@ import { ButtonPropsLayerPanel, SelectChangeEvent, TypeJsonArray, TypeJsonObject import { useGeoViewMapId } from '@/core/stores/geoview-store'; import { createLocalizedString } from '@/core/utils/utilities'; import { useLayerStoreActions, useLayersList } from '@/core/stores/store-interface-and-intial-values/layer-state'; -import { Cast, Config, api, generateId } from '@/app'; +import { Cast, Config, api } from '@/app'; import { logger } from '@/core/utils/logger'; import { EsriImage, TypeEsriImageLayerConfig } from '@/geo/layer/geoview-layers/raster/esri-image'; @@ -98,10 +95,10 @@ export function AddNewLayer(): JSX.Element { // const acceptedFiles = ["*.json"]; useEffect(() => { - // eslint-disable-next-line no-console - console.log('layersList ', layersList); + // Log + logger.logTraceUseEffect('layersList ', layersList); + // setIsLoading(false); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [layersList]); const sxClasses = { @@ -413,19 +410,9 @@ export function AddNewLayer(): JSX.Element { try { const isValid = layerURL.indexOf('/') === -1 && layerURL.replaceAll('-', '').length === 32; if (!isValid) throw new Error('err'); - const geoCoreGeoviewLayerConfig = { - geoviewLayerId: generateId(), - geoviewLayerType: 'geoCore', - listOfLayerEntryConfig: [ - new TypeGeocoreLayerEntryConfig({ - schemaTag: 'geoCore' as TypeGeoviewLayerType, - entryType: 'geoCore' as TypeLayerEntryType, - layerId: layerURL, - } as TypeGeocoreLayerEntryConfig), - ] as TypeGeocoreLayerEntryConfig[], - } as TypeGeoCoreLayerConfig; + const geoCoreGeoviewLayerInstance = new GeoCore(mapId); - const layers = await geoCoreGeoviewLayerInstance.createLayers(geoCoreGeoviewLayerConfig); + const layers = await geoCoreGeoviewLayerInstance.createLayersFromUUID(layerURL); if (layers.length === 1) { if (layers[0].length === 1) { setLayerName(layers[0][0].geoviewLayerName!.en! as string); @@ -843,6 +830,10 @@ export function AddNewLayer(): JSX.Element { (layerList as TypeListOfGeoviewLayerConfig).forEach((geoviewLayerConfig) => { api.maps[mapId].layer.addGeoviewLayer(geoviewLayerConfig); }); + } else if (layerEntries.length > 0) { + (layerEntries as TypeListOfGeoviewLayerConfig).forEach((geoviewLayerConfig) => { + api.maps[mapId].layer.addGeoviewLayer(geoviewLayerConfig); + }); } } else if (geoviewLayerInstance) { geoviewLayerInstance.geoviewLayerName = createLocalizedString(layerName); diff --git a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts index 7561bb01d75..17d1952c52f 100644 --- a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts +++ b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts @@ -1,14 +1,14 @@ import { useStore } from 'zustand'; +import { TypeArrayOfLayerData } from '@/api/events/payloads/get-feature-info-payload'; +import { GeoChartConfig } from '@/core/utils/config/reader/uuid-config-reader'; + import { useGeoViewStore } from '../stores-managers'; import { TypeGetStore, TypeSetStore } from '../geoview-store'; -import { TypeArrayOfLayerData } from '@/api/events/payloads/get-feature-info-payload'; export type GeoChartStoreByLayerPath = { - [layerPath: string]: ChartInfo; + [layerPath: string]: GeoChartConfig; }; -export type ChartInfo = unknown; // unknown, because the definition is in the external package - // #region INTERFACES export interface IGeochartState { @@ -29,6 +29,12 @@ export interface IGeochartState { // #endregion INTERFACES +/** + * Initializes a Geochart state object. + * @param {TypeSetStore} set The store set callback function + * @param {TypeSetStore} get The store get callback function + * @returns {IGeochartState} The Geochart state object + */ export function initializeGeochartState(set: TypeSetStore, get: TypeGetStore): IGeochartState { const init = { geochartChartsConfig: {}, diff --git a/packages/geoview-core/src/core/utils/config/config-validation.ts b/packages/geoview-core/src/core/utils/config/config-validation.ts index a0612690ff9..365a0db4cdf 100644 --- a/packages/geoview-core/src/core/utils/config/config-validation.ts +++ b/packages/geoview-core/src/core/utils/config/config-validation.ts @@ -65,6 +65,13 @@ export class ConfigValidation { /** The language that will be used to display the GeoView layer. */ private _displayLanguage: TypeDisplayLanguage; + // TODO: Refactor - Environment - How to edit this configuration easily per environment? + /** The default geocore url */ + static CONFIG_GEOCORE_URL = 'https://geocore-stage.api.geo.ca'; + + /** The default geolocator url */ + static CONFIG_GEOLOCATOR_URL = 'https://geolocator.api.geo.ca?keys=geonames,nominatim,locate'; + /** default configuration if provided configuration is missing or wrong */ private _defaultMapFeaturesConfig: TypeMapFeaturesConfig = { mapId: '', @@ -92,8 +99,8 @@ export class ConfigValidation { corePackages: [], overviewMap: undefined, serviceUrls: { - keys: 'https://geocore.api.geo.ca', - geolocator: 'https://geolocator.api.geo.ca?keys=geonames,nominatim,locate', + geocoreUrl: ConfigValidation.CONFIG_GEOCORE_URL, + geolocator: ConfigValidation.CONFIG_GEOLOCATOR_URL, }, displayLanguage: 'en', triggerReadyCallback: false, diff --git a/packages/geoview-core/src/core/utils/config/config.ts b/packages/geoview-core/src/core/utils/config/config.ts index 756c565a70d..51eea78cdf7 100644 --- a/packages/geoview-core/src/core/utils/config/config.ts +++ b/packages/geoview-core/src/core/utils/config/config.ts @@ -8,8 +8,6 @@ import { JsonConfigReader } from './reader/json-config-reader'; import { URLmapConfigReader } from './reader/url-config-reader'; import { logger } from '@/core/utils/logger'; -export const catalogUrl = 'https://maps.canada.ca/geonetwork/srv/api/v2/docs'; - // ****************************************************************************************************************************** // ****************************************************************************************************************************** /** ***************************************************************************************************************************** @@ -168,7 +166,10 @@ export class Config { const shared = this.mapElement.getAttribute('data-shared'); if (shared === 'true') { // check if config params have been passed - const urlParamsConfig = await URLmapConfigReader.getMapFeaturesConfig(this.mapId); + const urlParamsConfig = await URLmapConfigReader.getMapFeaturesConfig( + this.configValidation.defaultMapFeaturesConfig.serviceUrls.geocoreUrl, + this.mapId + ); // use the url params config if provided if (urlParamsConfig) mapFeaturesConfig = { ...urlParamsConfig }; diff --git a/packages/geoview-core/src/core/utils/config/reader/div-config-reader.ts b/packages/geoview-core/src/core/utils/config/reader/div-config-reader.ts index 98348b7c488..4d5d9b4937d 100644 --- a/packages/geoview-core/src/core/utils/config/reader/div-config-reader.ts +++ b/packages/geoview-core/src/core/utils/config/reader/div-config-reader.ts @@ -3,9 +3,7 @@ import { TypeMapFeaturesConfig } from '@/core/types/global-types'; import { isJsonString, removeCommentsFromJSON } from '../../utilities'; import { logger } from '@/core/utils/logger'; -// ****************************************************************************************************************************** -// ****************************************************************************************************************************** -/** ***************************************************************************************************************************** +/** * A class to read the configuration of the GeoView map features from an online div. The configuration is provided in an HTML div * whose class name is "geoview-map". The div tag also has the attributes id to set the map id, data-lang to specify the display * language and data-config to provide the map configuration. @@ -17,9 +15,8 @@ import { logger } from '@/core/utils/logger'; * @exports * @class URLmapConfigReader */ -// ****************************************************************************************************************************** export class InlineDivConfigReader { - /** *************************************************************************************************************************** + /** * Get the config object from inline map element div. * @param {string} mapId The ID of the map. * @param {Element} mapElement The map element. diff --git a/packages/geoview-core/src/core/utils/config/reader/json-config-reader.ts b/packages/geoview-core/src/core/utils/config/reader/json-config-reader.ts index c2118a1656e..7c5301e0545 100644 --- a/packages/geoview-core/src/core/utils/config/reader/json-config-reader.ts +++ b/packages/geoview-core/src/core/utils/config/reader/json-config-reader.ts @@ -2,16 +2,13 @@ import { TypeMapFeaturesConfig } from '@/core/types/global-types'; import { logger } from '@/core/utils/logger'; -// ****************************************************************************************************************************** -// ****************************************************************************************************************************** -/** ***************************************************************************************************************************** +/** * A class to process GeoView map features configuration from JSON file. * @exports * @class URLmapConfigReader */ -// ****************************************************************************************************************************** export class JsonConfigReader { - /** *************************************************************************************************************************** + /** * Get the config object from json file * @param {string} mapId the ID of the map. * @param {Element} mapElement the map element diff --git a/packages/geoview-core/src/core/utils/config/reader/url-config-reader.ts b/packages/geoview-core/src/core/utils/config/reader/url-config-reader.ts index 014df88bc88..b053d734004 100644 --- a/packages/geoview-core/src/core/utils/config/reader/url-config-reader.ts +++ b/packages/geoview-core/src/core/utils/config/reader/url-config-reader.ts @@ -9,21 +9,18 @@ import { TypeMapComponents, } from '@/geo/map/map-schema-types'; import { Cast, TypeJsonObject, TypeJsonValue, TypeMapFeaturesConfig } from '@/core/types/global-types'; -import { catalogUrl } from '../config'; import { UUIDmapConfigReader } from './uuid-config-reader'; import { ConfigValidation } from '../config-validation'; import { logger } from '../../logger'; +import { getLocalizedMessage, replaceParams, showError } from '@/app'; -// ****************************************************************************************************************************** -// ****************************************************************************************************************************** -/** ***************************************************************************************************************************** +/** * A class to process GeoView map features configuration from a URL. * @exports * @class URLmapConfigReader */ -// ****************************************************************************************************************************** export class URLmapConfigReader { - /** *************************************************************************************************************************** + /** * Parse the search parameters passed from a url * * @param {string} urlPath A url path with parameters "?..." @@ -49,7 +46,7 @@ export class URLmapConfigReader { return obj; } - /** *************************************************************************************************************************** + /** * Get url parameters from url param search string * * @param {objStr} objStr the url parameters string @@ -91,13 +88,13 @@ export class URLmapConfigReader { return obj; } - /** *************************************************************************************************************************** + /** * Get map config from url parameters * @param {string} mapId the map ID of the GeoView map. * * @returns {Promise<TypeMapFeaturesConfig | undefined>} A map features configuration object generated from url parameters */ - static async getMapFeaturesConfig(mapId: string): Promise<TypeMapFeaturesConfig | undefined> { + static async getMapFeaturesConfig(baseUrl: string, mapId: string): Promise<TypeMapFeaturesConfig | undefined> { // instanciate the configValidation object used to validate map config attributes and define default values. const configValidation = new ConfigValidation(); @@ -132,9 +129,20 @@ export class URLmapConfigReader { // get layer information from catalog using their uuid's if any passed from url params if (urlParams.keys) { - const requestUrl = `${catalogUrl}/${displayLanguage.split('-')[0]}/${urlParams.keys}`; - // TODO: issue 1742, list of layers always empty - listOfGeoviewLayerConfig = await UUIDmapConfigReader.getGVlayersConfigFromUUID(mapId, requestUrl); + try { + // Get the layers config + const promise = UUIDmapConfigReader.getGVConfigFromUUIDs( + baseUrl, + displayLanguage.split('-')[0], + urlParams.keys.toString().split(',') + ); + listOfGeoviewLayerConfig = (await promise).layers; + } catch (error) { + // Log + logger.logError('Failed to get the GeoView layers from url keys', urlParams.keys, error); + const message = replaceParams([error as TypeJsonValue, mapId], getLocalizedMessage(mapId, 'validation.layer.loadfailed')); + showError(mapId, message); + } } // get core components @@ -163,6 +171,9 @@ export class URLmapConfigReader { listOfGeoviewLayerConfig, extraOptions: {}, }, + serviceUrls: { + geocoreUrl: baseUrl, + }, components, corePackages, suportedLanguages: ['en', 'fr'], diff --git a/packages/geoview-core/src/core/utils/config/reader/uuid-config-reader.ts b/packages/geoview-core/src/core/utils/config/reader/uuid-config-reader.ts index 12bba526874..9b462a9070f 100644 --- a/packages/geoview-core/src/core/utils/config/reader/uuid-config-reader.ts +++ b/packages/geoview-core/src/core/utils/config/reader/uuid-config-reader.ts @@ -1,6 +1,6 @@ import axios, { AxiosResponse } from 'axios'; -import { TypeJsonObject, TypeJsonArray, TypeJsonValue } from '@/core/types/global-types'; +import { TypeJsonObject, TypeJsonArray } from '@/core/types/global-types'; import { TypeEsriDynamicLayerEntryConfig, TypeImageStaticLayerEntryConfig, @@ -20,90 +20,87 @@ import { TypeGeoJSONLayerConfig, TypeGeoJSONLayerEntryConfig } from '@/geo/layer import { TypeGeoPackageLayerConfig, TypeGeoPackageLayerEntryConfig } from '@/geo/layer/geoview-layers/vector/geopackage'; import { TypeXYZTilesConfig, TypeXYZTilesLayerEntryConfig } from '@/geo/layer/geoview-layers/raster/xyz-tiles'; import { TypeVectorTilesConfig, TypeVectorTilesLayerEntryConfig } from '@/geo/layer/geoview-layers/raster/vector-tiles'; -import { showError, replaceParams, getLocalizedMessage, createLocalizedString } from '@/core/utils/utilities'; +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 + +// The GeoChart Json object expected by GeoView +export type GeoChartConfig = TypeJsonObject & { + layers: [ + { + layerId: string; + } + ]; +}; // TypeJsonObject, because the definition is in the external package + +// The returned parsed response +export type UUIDmapConfigReaderResponse = { + layers: TypeListOfGeoviewLayerConfig; + geocharts?: GeoChartConfig[]; +}; + +/** * A class to generate GeoView layers config from a URL using a UUID. * @exports * @class UUIDmapConfigReader */ -// ****************************************************************************************************************************** export class UUIDmapConfigReader { - /** *************************************************************************************************************************** - * Generate layer configs from uuid request result - * + /** + * 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<TypeJsonObject>): TypeListOfGeoviewLayerConfig { - const listOfGeoviewLayerConfig: TypeListOfGeoviewLayerConfig = []; + private static getLayerConfigFromResponse(result: AxiosResponse<TypeJsonObject>, lang: string): TypeListOfGeoviewLayerConfig { + // 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) { - for (let i = 0; i < (result.data as TypeJsonArray).length; i++) { - const data = result.data[i]; + const listOfGeoviewLayerConfig: TypeListOfGeoviewLayerConfig = []; + 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 (data?.layers && (data.layers as TypeJsonArray).length > 0) { + const layer = data.layers[0]; - if (layer) { - const { layerType, layerEntries, name, url, id, serverType } = layer; + if (layer) { + const { layerType, layerEntries, name, url, id, serverType } = layer; - const isFeature = (url as string).indexOf('FeatureServer') > -1; + const isFeature = (url as string).indexOf('FeatureServer') > -1; - if (layerType === CONST_LAYER_TYPES.ESRI_DYNAMIC && !isFeature) { - const geoviewLayerConfig: TypeEsriDynamicLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'esriDynamic', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeEsriDynamicLayerEntryConfig => { - const esriDynamicLayerEntryConfig = new TypeEsriDynamicLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'esriDynamic', - entryType: 'raster-image', - layerId: `${item.index}`, - source: { - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeEsriDynamicLayerEntryConfig); - return esriDynamicLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (isFeature) { - for (let j = 0; j < (layerEntries as TypeJsonArray).length; j++) { - const featureUrl = `${url}/${layerEntries[j].index}`; - const geoviewLayerConfig: TypeEsriFeatureLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(featureUrl), - geoviewLayerType: 'esriFeature', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeEsriFeatureLayerEntryConfig => { - const esriFeatureLayerEntryConfig = new TypeEsriFeatureLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'esriFeature', - entryType: 'vector', - layerId: `${item.index}`, - source: { - format: 'EsriJSON', - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeEsriFeatureLayerEntryConfig); - return esriFeatureLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } - } else if (layerType === CONST_LAYER_TYPES.ESRI_FEATURE) { + if (layerType === CONST_LAYER_TYPES.ESRI_DYNAMIC && !isFeature) { + const geoviewLayerConfig: TypeEsriDynamicLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'esriDynamic', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeEsriDynamicLayerEntryConfig => { + const esriDynamicLayerEntryConfig = new TypeEsriDynamicLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'esriDynamic', + entryType: 'raster-image', + layerId: `${item.index}`, + source: { + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeEsriDynamicLayerEntryConfig); + return esriDynamicLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (isFeature) { + for (let j = 0; j < (layerEntries as TypeJsonArray).length; j++) { + const featureUrl = `${url}/${layerEntries[j].index}`; const geoviewLayerConfig: TypeEsriFeatureLayerConfig = { geoviewLayerId: `${id}`, geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), + metadataAccessPath: createLocalizedString(featureUrl), geoviewLayerType: 'esriFeature', listOfLayerEntryConfig: [], }; @@ -121,209 +118,256 @@ export class UUIDmapConfigReader { return esriFeatureLayerEntryConfig; }); listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.WMS) { - const geoviewLayerConfig: TypeWMSLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'ogcWms', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeOgcWmsLayerEntryConfig => { - const wmsLayerEntryConfig = new TypeOgcWmsLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'ogcWms', - entryType: 'raster-image', - layerId: `${item.id}`, - source: { - dataAccessPath: createLocalizedString(url as string), - serverType: (serverType === undefined ? 'mapserver' : serverType) as TypeOfServer, - }, - } as TypeOgcWmsLayerEntryConfig); - return wmsLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.WFS) { - const geoviewLayerConfig: TypeWFSLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'ogcWfs', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeWfsLayerEntryConfig => { - const wfsLayerEntryConfig = new TypeWfsLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'ogcWfs', - entryType: 'vector', - layerId: `${item.id}`, - source: { - format: 'WFS', - strategy: 'all', - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeWfsLayerEntryConfig); - return wfsLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.OGC_FEATURE) { - const geoviewLayerConfig: TypeOgcFeatureLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'ogcFeature', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeOgcFeatureLayerEntryConfig => { - const ogcFeatureLayerEntryConfig = new TypeOgcFeatureLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'ogcFeature', - entryType: 'vector', - layerId: `${item.id}`, - source: { - format: 'featureAPI', - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeOgcFeatureLayerEntryConfig); - return ogcFeatureLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.GEOJSON) { - const geoviewLayerConfig: TypeGeoJSONLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'GeoJSON', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeGeoJSONLayerEntryConfig => { - const geoJSONLayerEntryConfig = new TypeGeoJSONLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'GeoJSON', - entryType: 'vector', - layerId: `${item.id}`, - source: { - format: 'GeoJSON', - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeGeoJSONLayerEntryConfig); - return geoJSONLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.XYZ_TILES) { - const geoviewLayerConfig: TypeXYZTilesConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'xyzTiles', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeXYZTilesLayerEntryConfig => { - const xyzTilesLayerEntryConfig = new TypeXYZTilesLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'xyzTiles', - entryType: 'raster-tile', - layerId: `${item.id}`, - source: { - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeXYZTilesLayerEntryConfig); - return xyzTilesLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.VECTOR_TILES) { - const geoviewLayerConfig: TypeVectorTilesConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'vectorTiles', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeVectorTilesLayerEntryConfig => { - const vectorTilesLayerEntryConfig = new TypeVectorTilesLayerEntryConfig({ - schemaTag: 'vectorTiles', - entryType: 'raster-tile', - layerId: `${item.id}`, - tileGrid: item.tileGrid as unknown as TypeTileGrid, - source: { - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeVectorTilesLayerEntryConfig); - return vectorTilesLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.GEOPACKAGE) { - const geoviewLayerConfig: TypeGeoPackageLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'GeoPackage', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeGeoPackageLayerEntryConfig => { - const geoPackageLayerEntryConfig = new TypeGeoPackageLayerEntryConfig({ - geoviewLayerConfig, - schemaTag: 'GeoPackage', - entryType: 'vector', - layerId: `${item.id}`, - source: { - format: 'GeoPackage', - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeGeoPackageLayerEntryConfig); - return geoPackageLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else if (layerType === CONST_LAYER_TYPES.IMAGE_STATIC) { - const geoviewLayerConfig: TypeImageStaticLayerConfig = { - geoviewLayerId: `${id}`, - geoviewLayerName: createLocalizedString(name as string), - metadataAccessPath: createLocalizedString(url as string), - geoviewLayerType: 'imageStatic', - listOfLayerEntryConfig: [], - }; - geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeImageStaticLayerEntryConfig => { - const imageStaticLayerEntryConfig = new TypeImageStaticLayerEntryConfig({ - schemaTag: 'imageStatic', - entryType: 'raster-image', - layerId: `${item.id}`, - source: { - dataAccessPath: createLocalizedString(url as string), - }, - } as TypeImageStaticLayerEntryConfig); - return imageStaticLayerEntryConfig; - }); - listOfGeoviewLayerConfig.push(geoviewLayerConfig); - } else { - // Log - logger.logWarning(`Layer type ${layerType} not supported`); } + } else if (layerType === CONST_LAYER_TYPES.ESRI_FEATURE) { + const geoviewLayerConfig: TypeEsriFeatureLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'esriFeature', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeEsriFeatureLayerEntryConfig => { + const esriFeatureLayerEntryConfig = new TypeEsriFeatureLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'esriFeature', + entryType: 'vector', + layerId: `${item.index}`, + source: { + format: 'EsriJSON', + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeEsriFeatureLayerEntryConfig); + return esriFeatureLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.WMS) { + const geoviewLayerConfig: TypeWMSLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'ogcWms', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeOgcWmsLayerEntryConfig => { + const wmsLayerEntryConfig = new TypeOgcWmsLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'ogcWms', + entryType: 'raster-image', + layerId: `${item.id}`, + source: { + dataAccessPath: createLocalizedString(url as string), + serverType: (serverType === undefined ? 'mapserver' : serverType) as TypeOfServer, + }, + } as TypeOgcWmsLayerEntryConfig); + return wmsLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.WFS) { + const geoviewLayerConfig: TypeWFSLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'ogcWfs', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeWfsLayerEntryConfig => { + const wfsLayerEntryConfig = new TypeWfsLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'ogcWfs', + entryType: 'vector', + layerId: `${item.id}`, + source: { + format: 'WFS', + strategy: 'all', + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeWfsLayerEntryConfig); + return wfsLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.OGC_FEATURE) { + const geoviewLayerConfig: TypeOgcFeatureLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'ogcFeature', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeOgcFeatureLayerEntryConfig => { + const ogcFeatureLayerEntryConfig = new TypeOgcFeatureLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'ogcFeature', + entryType: 'vector', + layerId: `${item.id}`, + source: { + format: 'featureAPI', + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeOgcFeatureLayerEntryConfig); + return ogcFeatureLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.GEOJSON) { + const geoviewLayerConfig: TypeGeoJSONLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'GeoJSON', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeGeoJSONLayerEntryConfig => { + const geoJSONLayerEntryConfig = new TypeGeoJSONLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'GeoJSON', + entryType: 'vector', + layerId: `${item.id}`, + source: { + format: 'GeoJSON', + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeGeoJSONLayerEntryConfig); + return geoJSONLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.XYZ_TILES) { + const geoviewLayerConfig: TypeXYZTilesConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'xyzTiles', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeXYZTilesLayerEntryConfig => { + const xyzTilesLayerEntryConfig = new TypeXYZTilesLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'xyzTiles', + entryType: 'raster-tile', + layerId: `${item.id}`, + source: { + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeXYZTilesLayerEntryConfig); + return xyzTilesLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.VECTOR_TILES) { + const geoviewLayerConfig: TypeVectorTilesConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'vectorTiles', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeVectorTilesLayerEntryConfig => { + const vectorTilesLayerEntryConfig = new TypeVectorTilesLayerEntryConfig({ + schemaTag: 'vectorTiles', + entryType: 'raster-tile', + layerId: `${item.id}`, + tileGrid: item.tileGrid as unknown as TypeTileGrid, + source: { + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeVectorTilesLayerEntryConfig); + return vectorTilesLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.GEOPACKAGE) { + const geoviewLayerConfig: TypeGeoPackageLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'GeoPackage', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeGeoPackageLayerEntryConfig => { + const geoPackageLayerEntryConfig = new TypeGeoPackageLayerEntryConfig({ + geoviewLayerConfig, + schemaTag: 'GeoPackage', + entryType: 'vector', + layerId: `${item.id}`, + source: { + format: 'GeoPackage', + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeGeoPackageLayerEntryConfig); + return geoPackageLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else if (layerType === CONST_LAYER_TYPES.IMAGE_STATIC) { + const geoviewLayerConfig: TypeImageStaticLayerConfig = { + geoviewLayerId: `${id}`, + geoviewLayerName: createLocalizedString(name as string), + metadataAccessPath: createLocalizedString(url as string), + geoviewLayerType: 'imageStatic', + listOfLayerEntryConfig: [], + }; + geoviewLayerConfig.listOfLayerEntryConfig = (layerEntries as TypeJsonArray).map((item): TypeImageStaticLayerEntryConfig => { + const imageStaticLayerEntryConfig = new TypeImageStaticLayerEntryConfig({ + schemaTag: 'imageStatic', + entryType: 'raster-image', + layerId: `${item.id}`, + source: { + dataAccessPath: createLocalizedString(url as string), + }, + } as TypeImageStaticLayerEntryConfig); + return imageStaticLayerEntryConfig; + }); + listOfGeoviewLayerConfig.push(geoviewLayerConfig); + } else { + // Log + logger.logWarning(`Layer type ${layerType} not supported`); } } } } - return listOfGeoviewLayerConfig; } - /** *************************************************************************************************************************** - * Generate GeoView layers config from a URL using a UUID. - * @param {string} mapId the ID of the map. - * @param {string} requestUrl the URL to request result - * @param {Element} mapElement the map element - * - * @returns {Promise<TypeGeoviewLayerConfig>} layers parsed from uuid result + /** + * Reads and parses GeoChart configs from uuid request result + * @param {AxiosResponse<GeoChartGeoCoreConfig>} result the uuid request result + * @param {string} lang the language to use to read results + * @returns {GeoChartConfig[]} the list of GeoChart configs */ - static async getGVlayersConfigFromUUID(mapId: string, requestUrl: string): Promise<TypeListOfGeoviewLayerConfig> { - try { - const result = await axios.get<TypeJsonObject>(requestUrl); - return this.getLayerConfigFromResponse(result); - } catch (error: unknown) { - // Log - logger.logError('Failed to get the GeoView layer from UUI', requestUrl, error); - const message = replaceParams([error as TypeJsonValue, mapId], getLocalizedMessage(mapId, 'validation.layer.loadfailed')); - showError(mapId, message); - } - return []; + private static getGeoChartConfigFromResponse(result: AxiosResponse<GeoChartGeoCoreConfig>, 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 geocharts configurations, 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<UUIDmapConfigReaderResponse>} layers and geocharts read and parsed from uuids results from GeoCore + */ + static async getGVConfigFromUUIDs(baseUrl: string, lang: string, uuids: string[]): Promise<UUIDmapConfigReaderResponse> { + // Build the url + const url = `${baseUrl}/vcs?lang=${lang}&id=${uuids.toString()}`; + + // Fetch the config + const result = await axios.get<GeoChartGeoCoreConfig>(url); + + // Return the parsed response + return { + layers: this.getLayerConfigFromResponse(result, lang), + geocharts: this.getGeoChartConfigFromResponse(result, lang), + }; } } diff --git a/packages/geoview-core/src/geo/layer/layer.ts b/packages/geoview-core/src/geo/layer/layer.ts index 6c4723be651..3b1a6ec597c 100644 --- a/packages/geoview-core/src/geo/layer/layer.ts +++ b/packages/geoview-core/src/geo/layer/layer.ts @@ -80,7 +80,7 @@ export class Layer { featureHighlight: FeatureHighlight; /** - * Initialize layer types and listen to add/remove layer events from outside + * Initializes layer types and listen to add/remove layer events from outside * * @param {string} mapId a reference to the map */ @@ -189,7 +189,7 @@ export class Layer { } /** - * Delete the event handler functions associated to the Layer instance. + * Deletes the event handler functions associated to the Layer instance. */ deleteEventHandlerFunctionsOfThisLayerInstance() { api.event.off(EVENT_NAMES.LAYER.EVENT_ADD_LAYER, this.mapId, this.eventHandlerFunctions!.addLayer); @@ -197,7 +197,7 @@ export class Layer { } /** - * Load layers that was passed in with the map config + * Loads layers that was passed in with the map config * * @param {TypeGeoviewLayerConfig[]} geoviewLayerConfigs an optional array containing layers passed within the map config */ @@ -232,7 +232,7 @@ export class Layer { } /** - * Validate the geoview layer configuration array to eliminate duplicate entries and inform the user. + * Validates the geoview layer configuration array to eliminate duplicate entries and inform the user. * @param {TypeGeoviewLayerConfig[]} geoviewLayerConfigs The geoview layer configurations to validate. * * @returns {TypeGeoviewLayerConfig} The new configuration with duplicate entries eliminated. @@ -257,7 +257,7 @@ export class Layer { } /** - * Print an error message for the duplicate geoview layer configuration. + * Prints an error message for the duplicate geoview layer configuration. * @param {TypeGeoviewLayerConfig} geoviewLayerConfig The geoview layer configuration in error. */ private printDuplicateGeoviewLayerConfigError(geoviewLayerConfig: TypeGeoviewLayerConfig) { @@ -272,7 +272,7 @@ export class Layer { } /** - * This method returns the GeoView instance associated to a specific layer path. The first element of the layerPath + * Returns the GeoView instance associated to a specific layer path. The first element of the layerPath * is the geoviewLayerId. * @param {string} layerPath The layer path to the layer's configuration. * @@ -285,7 +285,7 @@ export class Layer { } /** - * Method used to verify if a layer is registered. Returns true if registered. + * Verifies if a layer is registered. Returns true if registered. * @param {TypeLayerEntryConfig} layerConfig The layer configuration to test. * * @returns {boolean} Returns true if the layer configuration is registered. @@ -296,7 +296,7 @@ export class Layer { } /** - * Add the layer to the map if valid. If not (is a string) emit an error + * Adds the layer to the map if valid. If not (is a string) emit an error * @param {any} geoviewLayer the layer config */ addToMap(geoviewLayer: AbstractGeoViewLayer): void { @@ -325,7 +325,7 @@ export class Layer { } /** - * Remove a layer from the map using its layer path. The path may point to the root geoview layer + * Removes a layer from the map using its layer path. The path may point to the root geoview layer * or a sub layer. * * @param {string} partialLayerPath the path of the layer to be removed @@ -363,7 +363,7 @@ export class Layer { }; /** - * Add a layer to the map + * Adds a layer to the map * * @param {TypeGeoviewLayerConfig} geoviewLayerConfig the geoview layer configuration to add * @param {TypeListOfLocalizedLanguages} optionalSuportedLanguages an optional list of supported language @@ -389,7 +389,21 @@ export class Layer { }; /** - * Remove a geoview layer from the map + * Adds a Geoview Layer by GeoCore UUID. + * Example: cgpv.api.maps['UIM10'].layer.addGeoviewLayerByGeoCoreUUID('21b821cf-0f1c-40ee-8925-eab12d357668') + * @param mapId The map id to add to + * @param uuid The GeoCore UUID + */ + addGeoviewLayerByGeoCoreUUID = async (uuid: string): Promise<void> => { + const geoCoreGeoviewLayerInstance = new GeoCore(this.mapId); + const layers = await geoCoreGeoviewLayerInstance.createLayersFromUUID(uuid); + layers[0].forEach((geoviewLayerConfig) => { + api.maps[this.mapId].layer.addGeoviewLayer(geoviewLayerConfig); + }); + }; + + /** + * Removes a geoview layer from the map * * @param {TypeGeoviewLayerConfig} geoviewLayer the layer configuration to remove */ @@ -400,7 +414,7 @@ export class Layer { }; /** - * Remove all geoview layers from the map + * Removes all geoview layers from the map */ removeAllGeoviewLayers = () => { Object.keys(this.geoviewLayers).forEach((layerId: string) => { @@ -411,7 +425,7 @@ export class Layer { }; /** - * Search for a layer using its id and return the layer data + * Searches for a layer using its id and return the layer data * * @param {string} geoviewLayerId the layer id to look for * @returns the found layer data object @@ -485,7 +499,7 @@ export class Layer { }; /** - * Highlight layer or sublayer on map + * Highlights layer or sublayer on map * * @param {string} layerPath ID of layer to highlight */ @@ -520,7 +534,7 @@ export class Layer { } /** - * Remove layer or sublayer highlight + * Removes layer or sublayer highlight */ removeHighlightLayer(): void { api.maps[this.mapId].layer.featureHighlight.removeBBoxHighlight(); diff --git a/packages/geoview-core/src/geo/layer/other/geocore.ts b/packages/geoview-core/src/geo/layer/other/geocore.ts index 0a73634a36d..aeeedf23d64 100644 --- a/packages/geoview-core/src/geo/layer/other/geocore.ts +++ b/packages/geoview-core/src/geo/layer/other/geocore.ts @@ -1,7 +1,12 @@ -/* eslint-disable no-param-reassign */ import defaultsDeep from 'lodash/defaultsDeep'; -import { api } from '@/app'; -import { catalogUrl } from '@/core/utils/config/config'; +import { TypeJsonValue, api, generateId, getLocalizedMessage, replaceParams, showError } from '@/app'; +import { UUIDmapConfigReader, UUIDmapConfigReaderResponse } from '@/core/utils/config/reader/uuid-config-reader'; +import { ConfigValidation } from '@/core/utils/config/config-validation'; +import { AppEventProcessor } from '@/api/event-processors/event-processor-children/app-event-processor'; +import { GeochartEventProcessor } from '@/api/event-processors/event-processor-children/geochart-event-processor'; +import { logger } from '@/core/utils/logger'; +import { MapEventProcessor } from '@/api/event-processors/event-processor-children/map-event-processor'; + import { TypeLayerEntryConfig, TypeGeoviewLayerConfig, @@ -10,11 +15,9 @@ import { TypeLocalizedString, layerEntryIsGroupLayer, TypeListOfLayerEntryConfig, + TypeLayerEntryType, } from '../../map/map-schema-types'; -import { CONST_LAYER_TYPES } from '../geoview-layers/abstract-geoview-layers'; -import { UUIDmapConfigReader } from '@/core/utils/config/reader/uuid-config-reader'; -import { ConfigValidation } from '@/core/utils/config/config-validation'; -import { AppEventProcessor } from '@/api/event-processors/event-processor-children/app-event-processor'; +import { CONST_LAYER_TYPES, TypeGeoviewLayerType } from '../geoview-layers/abstract-geoview-layers'; export interface TypeGeoCoreLayerConfig extends Omit<TypeGeoviewLayerConfig, 'listOfLayerEntryConfig'> { geoviewLayerType: 'geoCore'; @@ -61,7 +64,7 @@ export class GeoCore { private configValidation = new ConfigValidation(); /** - * Initialize layer + * Constructor * @param {string} mapId the id of the map */ constructor(mapId: string) { @@ -69,37 +72,94 @@ export class GeoCore { } /** - * Get GeoView layer configurations list from the UUIDs of the list of layer entry configurations. + * Builds a Geocore Layer Config from a given UUID + * @param {string} uuid the given uuid to build the Geocore Layer Config with + * @returns {TypeGeoCoreLayerConfig} the GeoCore Layer Config + */ + static buildGeocoreLayerConfigFromUUID(uuid: string): TypeGeoCoreLayerConfig { + return { + geoviewLayerId: generateId(), + geoviewLayerType: 'geoCore', + listOfLayerEntryConfig: [ + new TypeGeocoreLayerEntryConfig({ + schemaTag: 'geoCore' as TypeGeoviewLayerType, + entryType: 'geoCore' as TypeLayerEntryType, + layerId: uuid, + } as TypeGeocoreLayerEntryConfig), + ] as TypeGeocoreLayerEntryConfig[], + } as TypeGeoCoreLayerConfig; + } + + /** + * Gets GeoView layer configurations list from the given UUID. Creates the GeoCore Layer Config in the process. + * + * @param {string} uuid the given uuid to build the Geocore Layer Config with + * @returns {Promise<TypeListOfGeoviewLayerConfig[]>} the GeoCore Layer Config promise + */ + createLayersFromUUID(uuid: string): Promise<TypeListOfGeoviewLayerConfig[]> { + // Create the config + const geocoreConfig = GeoCore.buildGeocoreLayerConfigFromUUID(uuid); + + // Create the layers + return this.createLayers(geocoreConfig); + } + + /** + * Gets GeoView layer configurations list from the UUIDs of the list of layer entry configurations. * * @param {TypeGeocoreLayerEntryConfig} geocoreLayerConfig the layer configuration * @returns {Promise<TypeListOfGeoviewLayerConfig>} list of layer configurations to add to the map */ - createLayers(geocoreLayerConfig: TypeGeoCoreLayerConfig): Promise<TypeListOfGeoviewLayerConfig[]> { - const arrayOfListOfGeoviewLayerConfig = new Promise<TypeListOfGeoviewLayerConfig[]>((resolve) => { - const url = geocoreLayerConfig.metadataAccessPath || `${catalogUrl}/${api.maps[this.mapId].getDisplayLanguage()}`; - const promiseOfLayerConfigs: Promise<TypeListOfGeoviewLayerConfig>[] = []; - geocoreLayerConfig.listOfLayerEntryConfig.forEach((layerConfig: TypeLayerEntryConfig) => { - const requestUrl = `${url}/${layerConfig.layerId}`; - promiseOfLayerConfigs.push(UUIDmapConfigReader.getGVlayersConfigFromUUID(this.mapId, requestUrl)); + async createLayers(geocoreLayerConfig: TypeGeoCoreLayerConfig): Promise<TypeListOfGeoviewLayerConfig[]> { + // Get the map config + const mapConfig = MapEventProcessor.getGeoViewMapConfig(this.mapId); + + // For each layer entry config in the list + const promiseOfLayerConfigs: Promise<UUIDmapConfigReaderResponse>[] = []; + geocoreLayerConfig.listOfLayerEntryConfig.forEach((layerConfig: TypeLayerEntryConfig) => { + // Get the language + const lang = api.maps[this.mapId].getDisplayLanguage(); + + // Generate the url + // TODO: Check - Is the metadataAccessPath still used? Because it seems to be incompatible with the rest now? + const url = geocoreLayerConfig.metadataAccessPath?.[lang] || `${mapConfig!.serviceUrls.geocoreUrl}`; + + try { + // Get the GV config from UUID + promiseOfLayerConfigs.push(UUIDmapConfigReader.getGVConfigFromUUIDs(url, lang, [layerConfig.layerId])); + } catch (error) { + // Log + logger.logError('Failed to get the GeoView layer from UUI', layerConfig.layerId, error); + const message = replaceParams([error as TypeJsonValue, this.mapId], getLocalizedMessage(this.mapId, 'validation.layer.loadfailed')); + showError(this.mapId, message); + } + }); + + // Wait until all configs processed + const listOfLayerCreated = await Promise.all(promiseOfLayerConfigs); + + // For each config + listOfLayerCreated.forEach((listOfGeoviewLayerConfig, index) => { + listOfGeoviewLayerConfig.layers.forEach((geoviewLayerConfig) => { + this.copyConfigSettingsOverGeocoreSettings(geocoreLayerConfig.listOfLayerEntryConfig[index], geoviewLayerConfig); }); - Promise.all(promiseOfLayerConfigs).then((listOfLayerCreated) => { - listOfLayerCreated.forEach((listOfGeoviewLayerConfig, index) => { - listOfGeoviewLayerConfig.forEach((geoviewLayerConfig) => { - this.copyConfigSettingsOverGeocoreSettings(geocoreLayerConfig.listOfLayerEntryConfig[index], geoviewLayerConfig); - }); - this.configValidation.validateListOfGeoviewLayerConfig( - AppEventProcessor.getSupportedLanguages(this.mapId), - listOfGeoviewLayerConfig - ); - }); - resolve(listOfLayerCreated); + this.configValidation.validateListOfGeoviewLayerConfig( + AppEventProcessor.getSupportedLanguages(this.mapId), + listOfGeoviewLayerConfig.layers + ); + + // For each found geochart associated with the Geocore UUID + listOfGeoviewLayerConfig.geocharts?.forEach((geochartConfig) => { + // Add a GeoChart + GeochartEventProcessor.addGeochartChart(this.mapId, geochartConfig.layers[0].layerId as string, geochartConfig); }); }); - return arrayOfListOfGeoviewLayerConfig; + + return listOfLayerCreated.map((config) => config.layers); } /** - * Copy the config settings over the geocore values (config values have priority). + * Copies the config settings over the geocore values (config values have priority). * * @param {TypeGeocoreLayerEntryConfig} geocoreLayerEntryConfig The config file settings * @param {TypeGeoviewLayerConfig} geoviewLayerConfig The settings returned by the geocore service @@ -109,6 +169,7 @@ export class GeoCore { geoviewLayerConfig: TypeGeoviewLayerConfig ) { if (geocoreLayerEntryConfig.geocoreLayerName) + // eslint-disable-next-line no-param-reassign geoviewLayerConfig.geoviewLayerName = { ...geocoreLayerEntryConfig.geocoreLayerName, } as TypeLocalizedString; @@ -127,6 +188,7 @@ export class GeoCore { } else throw new Error(`Geocore group id ${layerEntryFromService.layerId} should be defined as a group in the configuration`); } else { + // eslint-disable-next-line no-param-reassign arrayFromService[i] = defaultsDeep(layerEntryFromConfig, layerEntryFromService); // Force a found property to the layerEntryFromConfig object Object.assign(layerEntryFromConfig, { found: true }); @@ -135,6 +197,7 @@ export class GeoCore { } return false; }); + // eslint-disable-next-line no-param-reassign if (!entryFound) arrayFromService[i].layerId = ''; }); for (let i = layerArrayFromService.length - 1; i >= 0; i--) diff --git a/packages/geoview-core/src/geo/map/map-schema-types.ts b/packages/geoview-core/src/geo/map/map-schema-types.ts index 9bc37fed77b..de3114f9b10 100644 --- a/packages/geoview-core/src/geo/map/map-schema-types.ts +++ b/packages/geoview-core/src/geo/map/map-schema-types.ts @@ -1489,6 +1489,8 @@ export const VALID_DISPLAY_THEME: TypeDisplayTheme[] = ['dark', 'light', 'geo.ca export type TypeMapFeaturesInstance = { /** map configuration. */ map: TypeMapConfig; + /** Service URLs. */ + serviceUrls: TypeServiceUrls; /** Display theme, default = geo.ca. */ theme?: TypeDisplayTheme; /** Nav bar properies. */ @@ -1505,9 +1507,6 @@ export type TypeMapFeaturesInstance = { corePackages?: TypeMapCorePackages; /** List of external packages. */ externalPackages?: TypeExternalPackages; - /** Service URLs. */ - // ?: Is this attribute realy needed, it is used nowhere in our code. If you delete it, update the doc (docs\app\map-config\README.md) - serviceUrls?: TypeServiceUrls; /** * ISO 639-1 code indicating the languages supported by the configuration file. It will use value(s) provided here to * access bilangual configuration nodes. For value(s) provided here, each bilingual configuration node MUST provide a value. @@ -1712,8 +1711,7 @@ export type TypeServiceUrls = { * Service end point to access API for layers specification (loading and plugins parameters). By default it is GeoCore but can * be another endpoint with similar output. */ - // ?: key or keys - The description only talk about a single service endpoint and the type is not an array but a string. - keys: string; + geocoreUrl: string; /** * An optional proxy to be used for dealing with same-origin issues. URL must either be a relative path on the same server * or an absolute path on a server which sets CORS headers. diff --git a/packages/geoview-geochart/src/geochart-panel.tsx b/packages/geoview-geochart/src/geochart-panel.tsx index e9740d32264..258c00eb4fc 100644 --- a/packages/geoview-geochart/src/geochart-panel.tsx +++ b/packages/geoview-geochart/src/geochart-panel.tsx @@ -58,7 +58,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { const handleIsEnlargeClicked = useCallback( (isEnlarge: boolean) => { // Log - logger.logTraceUseCallback('GEOCHART-PANEL - is enlarge', isEnlarge); + logger.logTraceUseCallback('GEOCHART-PANEL - handleIsEnlargeClicked', isEnlarge); // We need to redraw when the canvas isn't 'showing' in the DOM and when the user resizes the canvas placeholder. cgpv.api.maps[mapId].plugins.geochart.redrawChart(); @@ -67,7 +67,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { ); /** - * Get the label for the number of features of a layer. + * Gets the label for the number of features of a layer. * @returns string */ const getNumFeaturesLabel = useCallback( @@ -89,7 +89,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { const handleLayerChange = useCallback( (layer: LayerListEntry): void => { // Log - logger.logTraceUseCallback('GEOCHART-PANEL - layer', layer); + logger.logTraceUseCallback('GEOCHART-PANEL - handleLayerChange', layer); // Set the selected layer path in the store which will in turn trigger the store listeners on this component setSelectedLayerPath(layer.layerPath); @@ -100,7 +100,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { // Reacts when the array of layer data updates const memoLayersList = useMemo(() => { // Log - logger.logTraceUseMemo('GEOCHART-PANEL - ArrayOfLayerData', storeArrayOfLayerData); + logger.logTraceUseMemo('GEOCHART-PANEL - memoLayersList', storeArrayOfLayerData); // Set the layers list return visibleLayers @@ -121,7 +121,7 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { }, [visibleLayers, storeArrayOfLayerData, configObj, getNumFeaturesLabel]); /** - * Memoize the selected layer for the LayerList component. + * Memoizes the selected layer for the LayerList component. */ const memoLayerSelectedItem = useMemo(() => { // Log diff --git a/packages/geoview-geochart/src/geochart-parsing.ts b/packages/geoview-geochart/src/geochart-parsing.ts index b88900a5da2..39e1f04b7e2 100644 --- a/packages/geoview-geochart/src/geochart-parsing.ts +++ b/packages/geoview-geochart/src/geochart-parsing.ts @@ -32,7 +32,7 @@ const findLayerConfig = ( // If still not found if (!foundConfigLyr) { // Find the config that works with the layer (if any) - const layerConfigs = c.layers!.filter((x: GeoViewGeoChartConfigLayer) => { + const layerConfigs = c.layers.filter((x: GeoViewGeoChartConfigLayer) => { return x.layerId === layerId; }); diff --git a/packages/geoview-geochart/src/geochart-types.ts b/packages/geoview-geochart/src/geochart-types.ts index 3111f8c040f..87c3b1ad987 100644 --- a/packages/geoview-geochart/src/geochart-types.ts +++ b/packages/geoview-geochart/src/geochart-types.ts @@ -11,7 +11,7 @@ export type PluginGeoChartConfig<TType extends ChartType> = { * Definition of options for each type of chart used for by the plugin. */ export type GeoViewGeoChartConfig<TType extends ChartType> = GeoChartConfig<TType> & { - layers?: GeoViewGeoChartConfigLayer[]; + layers: GeoViewGeoChartConfigLayer[]; }; /** diff --git a/packages/geoview-geochart/src/geochart.tsx b/packages/geoview-geochart/src/geochart.tsx index d1acb3e184b..d6585ac66c7 100644 --- a/packages/geoview-geochart/src/geochart.tsx +++ b/packages/geoview-geochart/src/geochart.tsx @@ -136,7 +136,7 @@ export function GeoChart(props: GeoChartProps): JSX.Element { ); /** - * Memoize the fetching of the correct config based on the provided layers array (TypeArrayOfLayerData). + * Memoizes the fetching of the correct config based on the provided layers array (TypeArrayOfLayerData). */ const memoAllInfo = useMemo(() => { // Find the right config/layer/data for what we want based on the layerDataArray